BizHawk/waterbox/nyma/NymaCore.cpp

399 lines
9.0 KiB
C++

#include "mednafen/src/types.h"
#include <emulibc.h>
#include <waterboxcore.h>
#include <mednafen/mednafen.h>
#include <stdint.h>
#include "mednafen/src/FileStream.h"
#include "nyma.h"
using namespace Mednafen;
#define Game MDFNGameInfo
static EmulateSpecStruct* EES;
static MDFN_Surface* Surf;
static uint32_t* pixels;
static int16_t* samples;
struct InitData
{
const char* FileNameBase;
const char* FileNameExt;
const char* FileNameFull;
};
enum { MAX_PORTS = 16 };
enum { MAX_PORT_DATA = 16 };
static uint8_t InputPortData[(MAX_PORTS + 1) * MAX_PORT_DATA];
ECL_EXPORT void PreInit()
{
SetupMDFNGameInfo();
}
static void Setup()
{
pixels = new uint32_t[Game->fb_width * Game->fb_height];
samples = new int16_t[22050 * 2];
Surf = new MDFN_Surface(
pixels, Game->fb_width, Game->fb_height, Game->fb_width,
MDFN_PixelFormat(MDFN_COLORSPACE_RGB, 16, 8, 0, 24)
);
EES = new EmulateSpecStruct();
EES->surface = Surf;
EES->VideoFormatChanged = true;
EES->LineWidths = new int32_t[Game->fb_height];
memset(EES->LineWidths, 0xff, Game->fb_height * sizeof(int32_t));
EES->SoundBuf = samples;
EES->SoundBufMaxSize = 22050;
EES->SoundFormatChanged = true;
EES->SoundRate = 44100;
}
ECL_EXPORT bool InitRom(const InitData& data)
{
try
{
Setup();
std::unique_ptr<Stream> gamestream(new FileStream(data.FileNameFull, FileStream::MODE_READ, false));
GameFile gf({
&NVFS,
"",
gamestream.get(),
data.FileNameExt,
data.FileNameBase,
&NVFS,
"",
data.FileNameBase
});
Game->Load(&gf);
}
catch(...)
{
return false;
}
return true;
}
void StartGameWithCds(int numdisks);
ECL_EXPORT bool InitCd(int numdisks)
{
try
{
Setup();
StartGameWithCds(numdisks);
}
catch(...)
{
return false;
}
return true;
}
struct MyFrameInfo: public FrameInfo
{
// true to skip video rendering
int16_t SkipRendering;
int16_t SkipSoundening;
// a single MDFN_MSC_* command to run at the start of this frame; 0 if none
int32_t Command;
// raw data for each input port, assumed to be MAX_PORTS * MAX_PORT_DATA long
uint8_t* InputPortData;
};
ECL_EXPORT void FrameAdvance(MyFrameInfo& frame)
{
EES->skip = frame.SkipRendering;
if (frame.Command)
Game->DoSimpleCommand(frame.Command);
memcpy(InputPortData, frame.InputPortData, sizeof(InputPortData));
Game->TransformInput();
Game->Emulate(EES);
EES->VideoFormatChanged = false;
EES->SoundFormatChanged = false;
frame.Cycles = EES->MasterCycles;
if (!frame.SkipSoundening)
{
memcpy(frame.SoundBuffer, EES->SoundBuf, EES->SoundBufSize * 4);
frame.Samples = EES->SoundBufSize;
}
if (!frame.SkipRendering)
{
int h = EES->DisplayRect.h;
int lineStart = EES->DisplayRect.y;
int lineEnd = lineStart + h;
auto multiWidth = EES->LineWidths[0] != -1;
int w;
if (multiWidth)
{
w = 0;
for (int line = lineStart; line < lineEnd; line++)
w = std::max(w, EES->LineWidths[line]);
}
else
{
w = EES->DisplayRect.w;
}
frame.Width = w;
frame.Height = h;
int srcp = Game->fb_width;
int dstp = w;
uint32_t* src = pixels + EES->DisplayRect.x + EES->DisplayRect.y * srcp;
uint32_t* dst = frame.VideoBuffer;
for (int line = lineStart; line < lineEnd; line++)
{
memcpy(dst, src, (multiWidth ? EES->LineWidths[line] : w) * sizeof(uint32_t));
src += srcp;
dst += dstp;
}
}
}
struct SystemInfo
{
int32_t MaxWidth;
int32_t MaxHeight;
int32_t NominalWidth;
int32_t NominalHeight;
int32_t VideoSystem;
int32_t FpsFixed;
};
SystemInfo SI;
ECL_EXPORT SystemInfo* GetSystemInfo()
{
SI.MaxWidth = Game->fb_width;
SI.MaxHeight = Game->fb_height;
SI.NominalWidth = Game->nominal_width;
SI.NominalHeight = Game->nominal_height;
SI.VideoSystem = Game->VideoSystem;
SI.FpsFixed = Game->fps;
return &SI;
}
ECL_EXPORT const char* GetLayerData()
{
return Game->LayerNames;
}
ECL_EXPORT void SetLayers(uint64_t layers)
{
Game->SetLayerEnableMask(layers);
}
ECL_EXPORT void SetInputCallback(void (*cb)())
{}
// same information as PortInfo, but easier to marshal
struct NPortInfo
{
const char* ShortName;
const char* FullName;
const char* DefaultDeviceShortName;
uint32_t NumDevices;
};
struct NDeviceInfo
{
const char* ShortName;
const char* FullName;
const char* Description;
uint32_t Flags;
uint32_t ByteLength;
uint32_t NumInputs;
};
struct NInputInfo
{
const char* SettingName;
const char* Name;
int16_t ConfigOrder;
uint16_t BitOffset;
InputDeviceInputType Type; // uint8_t
uint8_t Flags;
uint8_t BitSize;
};
struct NButtonInfo
{
const char* ExcludeName;
};
struct NAxisInfo
{
// negative, then positive
const char* SettingName[2];
const char* Name[2];
};
struct NSwitchInfo
{
uint32_t NumPositions;
uint32_t DefaultPosition;
struct Position
{
const char* SettingName;
const char* Name;
const char* Description;
};
};
struct NStatusInfo
{
uint32_t NumStates;
struct State
{
const char* ShortName;
const char* Name;
int32_t Color; // (msb)0RGB(lsb), -1 for unused.
int32_t _Padding;
};
};
ECL_EXPORT uint32_t GetNumPorts()
{
return Game->PortInfo.size();
}
ECL_EXPORT NPortInfo& GetPort(uint32_t port)
{
auto& a = *(NPortInfo*)InputPortData;
auto& x = Game->PortInfo[port];
a.ShortName = x.ShortName;
a.FullName = x.FullName;
a.DefaultDeviceShortName = x.DefaultDevice;
a.NumDevices = x.DeviceInfo.size();
return a;
}
ECL_EXPORT NDeviceInfo& GetDevice(uint32_t port, uint32_t dev)
{
auto& b = *(NDeviceInfo*)InputPortData;
auto& y = Game->PortInfo[port].DeviceInfo[dev];
b.ShortName = y.ShortName;
b.FullName = y.FullName;
b.Description = y.Description;
b.Flags = y.Flags;
b.ByteLength = y.IDII.InputByteSize;
b.NumInputs = y.IDII.size();
return b;
}
ECL_EXPORT NInputInfo& GetInput(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NInputInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input];
c.SettingName = z.SettingName;
c.Name = z.Name;
c.ConfigOrder = z.ConfigOrder;
c.BitOffset = z.BitOffset;
c.Type = z.Type;
c.Flags = z.Flags;
c.BitSize = z.BitSize;
return c;
}
ECL_EXPORT NButtonInfo& GetButton(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NButtonInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Button;
c.ExcludeName = z.ExcludeName;
return c;
}
ECL_EXPORT NSwitchInfo& GetSwitch(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NSwitchInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Switch;
c.NumPositions = z.NumPos;
c.DefaultPosition = z.DefPos;
return c;
}
ECL_EXPORT NSwitchInfo::Position& GetSwitchPosition(uint32_t port, uint32_t dev, uint32_t input, int i)
{
auto& c = *(NSwitchInfo::Position*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Switch;
c.SettingName = z.Pos[i].SettingName;
c.Name = z.Pos[i].Name;
c.Description = z.Pos[i].Description;
return c;
}
ECL_EXPORT NStatusInfo& GetStatus(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NStatusInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Status;
c.NumStates = z.NumStates;
return c;
}
ECL_EXPORT NStatusInfo::State& GetStatusState(uint32_t port, uint32_t dev, uint32_t input, int i)
{
auto& c = *(NStatusInfo::State*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Status;
c.ShortName = z.States[i].ShortName;
c.Name = z.States[i].Name;
c.Color = z.States[i].Color;
return c;
}
ECL_EXPORT NAxisInfo& GetAxis(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NAxisInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Axis;
c.SettingName[0] = z.sname_dir[0];
c.SettingName[1] = z.sname_dir[1];
c.Name[0] = z.name_dir[0];
c.Name[1] = z.name_dir[1];
return c;
}
ECL_EXPORT void SetInputDevices(const char** devices)
{
for (unsigned port = 0; port < MAX_PORTS && devices[port]; port++)
{
std::string dev(devices[port]);
Game->SetInput(port, dev.c_str(), &InputPortData[port * MAX_PORT_DATA]);
}
}
struct NSetting
{
const char* Name;
const char* Description;
const char* SettingsKey;
const char* DefaultValue;
const char* Min;
const char* Max;
uint32_t Flags;
uint32_t Type;
};
struct NEnumValue
{
const char* Name;
const char* Description;
const char* Value;
};
ECL_EXPORT void IterateSettings(int index, NSetting& s)
{
auto& a = Game->Settings[index];
if (a.name)
{
s.Name = a.description;
s.Description = a.description_extra;
s.SettingsKey = a.name;
s.DefaultValue = a.default_value;
s.Min = a.minimum;
s.Max = a.maximum;
s.Flags = a.flags;
s.Type = a.type;
}
}
ECL_EXPORT void IterateSettingEnums(int index, int enumIndex, NEnumValue& e)
{
auto& a = Game->Settings[index].enum_list[enumIndex];
if (a.string)
{
e.Name = a.description;
e.Description = a.description_extra;
e.Value = a.string;
}
}