From 39c0402bd80a7f9a9e9e50045486ead7ec766205 Mon Sep 17 00:00:00 2001 From: nattthebear Date: Fri, 22 May 2020 13:53:34 -0400 Subject: [PATCH] Starting to work on some api stuff ngp only for now --- waterbox/nyma/Interfaces.cpp | 37 ++++- waterbox/nyma/NymaCore.cpp | 269 +++++++++++++++++++++++++++++++++++ waterbox/nyma/common.mak | 3 +- waterbox/nyma/common/nyma.h | 4 + waterbox/nyma/ngp.cpp | 13 ++ waterbox/nyma/ngp.mak | 3 +- 6 files changed, 322 insertions(+), 7 deletions(-) create mode 100644 waterbox/nyma/NymaCore.cpp create mode 100644 waterbox/nyma/common/nyma.h create mode 100644 waterbox/nyma/ngp.cpp diff --git a/waterbox/nyma/Interfaces.cpp b/waterbox/nyma/Interfaces.cpp index 7e7c895503..3f05ff2d30 100644 --- a/waterbox/nyma/Interfaces.cpp +++ b/waterbox/nyma/Interfaces.cpp @@ -6,6 +6,9 @@ #include "mednafen/src/mednafen-driver.h" #include "mednafen/src/player.h" +#include +#include + namespace Mednafen { MDFNGI *MDFNGameInfo = NULL; @@ -17,16 +20,40 @@ namespace Mednafen } // mednafen-driver.h + static int curindent = 0; void MDFN_indent(int indent) - {} + { + curindent += indent; + if(curindent < 0) + { + fprintf(stderr, "MDFN_indent negative!\n"); + curindent = 0; + } + } void MDFN_printf(const char *format, ...) noexcept - {} + { + for (int i = 0; i < curindent; i++) + putchar('\t'); + va_list argp; + va_start(argp, format); + vprintf(format, argp); + va_end(argp); + } void MDFND_OutputNotice(MDFN_NoticeType t, const char* s) noexcept - {} + { + fputs(s, t == MDFN_NOTICE_ERROR ? stderr : stdout); + fputc('\n', t == MDFN_NOTICE_ERROR ? stderr : stdout); + } void MDFND_OutputInfo(const char* s) noexcept - {} + { + puts(s); + } void MDFN_Notify(MDFN_NoticeType t, const char* format, ...) noexcept - {} + { + va_list argp; + va_start(argp, format); + vfprintf(t == MDFN_NOTICE_ERROR ? stderr : stdout, format, argp); + } void MDFND_MidSync(EmulateSpecStruct *espec, const unsigned flags) {} diff --git a/waterbox/nyma/NymaCore.cpp b/waterbox/nyma/NymaCore.cpp new file mode 100644 index 0000000000..5b44c5097a --- /dev/null +++ b/waterbox/nyma/NymaCore.cpp @@ -0,0 +1,269 @@ +#include "mednafen/src/types.h" +#include +#include +#include +#include +#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 * MAX_PORT_DATA]; + +ECL_EXPORT bool Init(const InitData& data) +{ + try + { + SetupMDFNGameInfo(); + + 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, 0, 8, 16, 24) + ); + EES = new EmulateSpecStruct(); + EES->surface = Surf; + EES->VideoFormatChanged = true; + EES->LineWidths = new int32_t[Game->fb_height]; + EES->SoundBuf = samples; + EES->SoundBufMaxSize = 22050; + EES->SoundFormatChanged = true; + EES->SoundRate = 44100; + + GameFile gf({ + &NVFS, + "", + std::unique_ptr(new FileStream(data.FileNameFull, FileStream::MODE_READ, false)).get(), + data.FileNameExt, + data.FileNameBase, + &NVFS, + "", + data.FileNameBase + }); + + Game->Load(&gf); + } + catch(...) + { + return false; + } + return true; +} + +struct MyFrameInfo: public FrameInfo +{ + // true to skip video rendering + int32_t SkipRendering; + // 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; // TODO: Was this supposed to be total or delta? + memcpy(frame.SoundBuffer, EES->SoundBuf, EES->SoundBufSize * 4); + frame.Samples = EES->SoundBufSize; + + // TODO: Use linewidths + int w = EES->DisplayRect.w; + int h = EES->DisplayRect.h; + frame.Width = w; + frame.Height = h; + int srcp = Game->fb_width; + int dstp = Game->fb_height; + uint32_t* src = pixels + EES->DisplayRect.x + EES->DisplayRect.y * srcp; + uint32_t* dst = pixels; + for (int line = 0; line < h; line++) + { + memcpy(dst, src, w * 4); + src += srcp; + dst += dstp; + } +} + +ECL_EXPORT void SetLayers(uint64_t layers) +{ + Game->SetLayerEnableMask(layers); +} + +ECL_EXPORT void GetMemoryAreas(MemoryArea* m) +{} + +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; + struct NDeviceInfo + { + const char *ShortName; + const char *FullName; + const char *Description; + uint32_t Flags; + uint32_t ByteLength; + struct NInput + { + const char *SettingName; + const char *Name; + int16_t ConfigOrder; + uint16_t BitOffset; + InputDeviceInputType Type; // uint8_t + uint8_t Flags; + uint8_t BitSize; + uint8_t _Padding; + union + { + struct + { + const char* ExcludeName; + } Button; + struct + { + // negative, then positive + const char* SettingName[2]; + const char* Name[2]; + } Axis; + struct + { + struct + { + const char* SettingName; + const char* Name; + const char* Description; + }* Positions; + uint32_t NumPositions; + uint32_t DefaultPosition; + } Switch; + struct + { + struct + { + const char* ShortName; + const char* Name; + int32_t Color; // (msb)0RGB(lsb), -1 for unused. + int32_t _Padding; + }* States; + uint32_t NumStates; + } Status; + }; + } Inputs[256]; + } Devices[32]; +}; + +NPortInfo PortInfos[MAX_PORTS] = {}; + +ECL_EXPORT NPortInfo* GetInputDevices() +{ + for (unsigned port = 0; port < MAX_PORTS && port < Game->PortInfo.size(); port++) + { + auto& a = PortInfos[port]; + auto& x = Game->PortInfo[port]; + a.ShortName = x.ShortName; + a.FullName = x.FullName; + a.DefaultDeviceShortName = x.DefaultDevice; + for (unsigned dev = 0; dev < 32 && dev < x.DeviceInfo.size(); dev++) + { + auto& b = a.Devices[dev]; + auto& y = x.DeviceInfo[dev]; + b.ShortName = y.ShortName; + b.FullName = y.FullName; + b.Description = y.Description; + b.Flags = y.Flags; + b.ByteLength = y.IDII.InputByteSize; + for (unsigned input = 0; input < 256 && input < y.IDII.size(); input++) + { + auto& c = b.Inputs[input]; + auto& z = y.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; + switch (z.Type) + { + case IDIT_BUTTON: + case IDIT_BUTTON_CAN_RAPID: + c.Button.ExcludeName = z.Button.ExcludeName; + break; + case IDIT_SWITCH: + c.Switch.NumPositions = z.Switch.NumPos; + c.Switch.DefaultPosition = z.Switch.DefPos; + c.Switch.Positions = (decltype(c.Switch.Positions))calloc(z.Switch.NumPos, sizeof(*c.Switch.Positions)); + for (unsigned i = 0; i < z.Switch.NumPos; i++) + { + c.Switch.Positions[i].SettingName = z.Switch.Pos[i].SettingName; + c.Switch.Positions[i].Name = z.Switch.Pos[i].Name; + c.Switch.Positions[i].Description = z.Switch.Pos[i].Description; + } + break; + case IDIT_STATUS: + c.Status.NumStates = z.Status.NumStates; + c.Status.States = (decltype(c.Status.States))calloc(z.Status.NumStates, sizeof(*c.Status.States)); + for (unsigned i = 0; i < z.Status.NumStates; i++) + { + c.Status.States[i].ShortName = z.Status.States[i].ShortName; + c.Status.States[i].Name = z.Status.States[i].Name; + c.Status.States[i].Color = z.Status.States[i].Color; + } + break; + case IDIT_AXIS: + case IDIT_AXIS_REL: + c.Axis.SettingName[0] = z.Axis.sname_dir[0]; + c.Axis.SettingName[1] = z.Axis.sname_dir[1]; + c.Axis.Name[0] = z.Axis.name_dir[0]; + c.Axis.Name[1] = z.Axis.name_dir[1]; + break; + default: + // other types have no extended information + break; + } + } + } + } + return PortInfos; +} + +ECL_EXPORT void SetInputDevices(const char** devices) +{ + for (unsigned port = 0; port < MAX_PORTS && devices[port]; port++) + { + Game->SetInput(port, devices[port], &InputPortData[port * MAX_PORT_DATA]); + } +} diff --git a/waterbox/nyma/common.mak b/waterbox/nyma/common.mak index 30ccfbb4f7..051cb857d4 100644 --- a/waterbox/nyma/common.mak +++ b/waterbox/nyma/common.mak @@ -47,5 +47,6 @@ SRCS := \ $(call cdir,trio) \ $(call cdir,cputest) \ $(call cppdir,compress) \ + $(call cppdir,video) \ $(filter-out %generate.cpp,$(call cppdir,sound)) \ - Interfaces.cpp + Interfaces.cpp NymaCore.cpp diff --git a/waterbox/nyma/common/nyma.h b/waterbox/nyma/common/nyma.h new file mode 100644 index 0000000000..a391c1108b --- /dev/null +++ b/waterbox/nyma/common/nyma.h @@ -0,0 +1,4 @@ +#pragma once + +// the one linked core should set the MDFNGameInfo global +void SetupMDFNGameInfo(); diff --git a/waterbox/nyma/ngp.cpp b/waterbox/nyma/ngp.cpp new file mode 100644 index 0000000000..48acb40608 --- /dev/null +++ b/waterbox/nyma/ngp.cpp @@ -0,0 +1,13 @@ +#include "mednafen/src/types.h" +#include "nyma.h" +#include +#include "mednafen/src/ngp/neopop.h" + +using namespace MDFN_IEN_NGP; + +extern Mednafen::MDFNGI EmulatedNGP; + +void SetupMDFNGameInfo() +{ + Mednafen::MDFNGameInfo = &EmulatedNGP; +} diff --git a/waterbox/nyma/ngp.mak b/waterbox/nyma/ngp.mak index 8f782fc593..82aeceeeb6 100644 --- a/waterbox/nyma/ngp.mak +++ b/waterbox/nyma/ngp.mak @@ -2,6 +2,7 @@ include common.mak SRCS += \ $(call cppdir,ngp) \ - $(call cppdir,hw_cpu/z80-fuse) + $(call cppdir,hw_cpu/z80-fuse) \ + ngp.cpp include ../common.mak