mirror of https://github.com/AxioDL/metaforce.git
Initial fixNES integration
This commit is contained in:
parent
c84845c9a5
commit
93fc2d8072
|
@ -34,3 +34,6 @@
|
||||||
[submodule "rapidjson"]
|
[submodule "rapidjson"]
|
||||||
path = rapidjson
|
path = rapidjson
|
||||||
url = https://github.com/Tencent/rapidjson.git
|
url = https://github.com/Tencent/rapidjson.git
|
||||||
|
[submodule "NESEmulator/fixNES"]
|
||||||
|
path = NESEmulator/fixNES
|
||||||
|
url = https://github.com/jackoalan/fixNES.git
|
||||||
|
|
|
@ -199,7 +199,9 @@ add_definitions(-DZE_ATHENA_TYPES=1)
|
||||||
set(ZEUS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/specter/zeus/include)
|
set(ZEUS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/specter/zeus/include)
|
||||||
include_directories(${ATHENA_INCLUDE_DIR} ${LOGVISOR_INCLUDE_DIR} ${HECL_INCLUDE_DIR}
|
include_directories(${ATHENA_INCLUDE_DIR} ${LOGVISOR_INCLUDE_DIR} ${HECL_INCLUDE_DIR}
|
||||||
${NOD_INCLUDE_DIR} ${ZEUS_INCLUDE_DIR} ${BOO_INCLUDE_DIR} ${AMUSE_INCLUDE_DIR}
|
${NOD_INCLUDE_DIR} ${ZEUS_INCLUDE_DIR} ${BOO_INCLUDE_DIR} ${AMUSE_INCLUDE_DIR}
|
||||||
${SPECTER_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
${SPECTER_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/NESEmulator)
|
||||||
|
add_subdirectory(NESEmulator)
|
||||||
add_subdirectory(DataSpec)
|
add_subdirectory(DataSpec)
|
||||||
add_subdirectory(kabufuda)
|
add_subdirectory(kabufuda)
|
||||||
include_directories(${KABUFUDA_INCLUDE_DIR})
|
include_directories(${KABUFUDA_INCLUDE_DIR})
|
||||||
|
|
|
@ -97,7 +97,7 @@ target_link_libraries(urde
|
||||||
UrdeLocales
|
UrdeLocales
|
||||||
UrdeIcons
|
UrdeIcons
|
||||||
UrdeBadging
|
UrdeBadging
|
||||||
RuntimeCommon
|
RuntimeCommon NESEmulator
|
||||||
specter specter-fonts freetype ${DATA_SPEC_LIBS}
|
specter specter-fonts freetype ${DATA_SPEC_LIBS}
|
||||||
hecl-full hecl-blender-addon
|
hecl-full hecl-blender-addon
|
||||||
athena-core nod logvisor athena-libyaml amuse boo
|
athena-core nod logvisor athena-libyaml amuse boo
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/DataSpec ${CMAKE_SOURCE_DIR}/Runtime ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
file(GLOB MAPPER_SRCS fixNES/mapper/*.c)
|
||||||
|
add_library(NESEmulator CNESEmulator.hpp CNESEmulator.cpp CNESShader.hpp CNESShader.cpp malloc.h
|
||||||
|
fixNES/apu.c fixNES/audio_fds.c fixNES/audio_mmc5.c fixNES/audio_vrc6.c fixNES/audio_vrc7.c
|
||||||
|
fixNES/audio_n163.c fixNES/audio_s5b.c fixNES/cpu.c fixNES/ppu.c fixNES/mem.c fixNES/input.c
|
||||||
|
fixNES/mapper.c fixNES/mapperList.c fixNES/fm2play.c fixNES/vrc_irq.c ${MAPPER_SRCS})
|
|
@ -0,0 +1,804 @@
|
||||||
|
#include "CNESEmulator.hpp"
|
||||||
|
#include "CNESShader.hpp"
|
||||||
|
#include "CGameState.hpp"
|
||||||
|
#include "Input/CFinalInput.hpp"
|
||||||
|
#include "logvisor/logvisor.hpp"
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <cstring>
|
||||||
|
#include "malloc.h"
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <cctype>
|
||||||
|
#include <ctime>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
static urde::MP1::CNESEmulator* EmulatorInst = nullptr;
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
|
#include "fixNES/mapper.h"
|
||||||
|
#include "fixNES/cpu.h"
|
||||||
|
#include "fixNES/ppu.h"
|
||||||
|
#include "fixNES/mem.h"
|
||||||
|
#include "fixNES/input.h"
|
||||||
|
#include "fixNES/fm2play.h"
|
||||||
|
#include "fixNES/apu.h"
|
||||||
|
#include "fixNES/audio_fds.h"
|
||||||
|
#include "fixNES/audio_vrc7.h"
|
||||||
|
#include "fixNES/mapper_h/nsf.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 FIX94
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WINDOWS_BUILD 1
|
||||||
|
#define DEBUG_HZ 0
|
||||||
|
#define DEBUG_MAIN_CALLS 0
|
||||||
|
#define DEBUG_KEY 0
|
||||||
|
#define DEBUG_LOAD_INFO 1
|
||||||
|
|
||||||
|
std::chrono::steady_clock::time_point s_tp = std::chrono::steady_clock::now();
|
||||||
|
static std::chrono::milliseconds::rep GetTickCount()
|
||||||
|
{
|
||||||
|
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - s_tp).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *VERSION_STRING = "fixNES Alpha v1.0.5";
|
||||||
|
static char window_title[256];
|
||||||
|
static char window_title_pause[256];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FTYPE_UNK = 0,
|
||||||
|
FTYPE_NES,
|
||||||
|
FTYPE_NSF,
|
||||||
|
FTYPE_FDS,
|
||||||
|
FTYPE_QD,
|
||||||
|
#if ZIPSUPPORT
|
||||||
|
FTYPE_ZIP,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nesEmuFdsSetup(uint8_t *src, uint8_t *dst);
|
||||||
|
|
||||||
|
static int emuFileType = FTYPE_UNK;
|
||||||
|
static char emuFileName[1024];
|
||||||
|
static uint8_t *emuNesROM = NULL;
|
||||||
|
static uint32_t emuNesROMsize = 0;
|
||||||
|
static char emuSaveName[1024];
|
||||||
|
static uint8_t *emuPrgRAM = NULL;
|
||||||
|
static uint32_t emuPrgRAMsize = 0;
|
||||||
|
//used externally
|
||||||
|
uint32_t textureImage[0xF000];
|
||||||
|
bool nesPause = false;
|
||||||
|
bool ppuDebugPauseFrame = false;
|
||||||
|
bool doOverscan = true;
|
||||||
|
bool nesPAL = false;
|
||||||
|
bool nesEmuNSFPlayback = false;
|
||||||
|
|
||||||
|
static bool inPause = false;
|
||||||
|
static bool inOverscanToggle = false;
|
||||||
|
static bool inResize = false;
|
||||||
|
static bool inDiskSwitch = false;
|
||||||
|
static bool inReset = false;
|
||||||
|
|
||||||
|
#if WINDOWS_BUILD
|
||||||
|
//#include <windows.h>
|
||||||
|
//typedef bool (APIENTRY *PFNWGLSWAPINTERVALEXTPROC) (int interval);
|
||||||
|
//PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
|
||||||
|
#if DEBUG_HZ
|
||||||
|
static int emuFrameStart = 0;
|
||||||
|
static int emuTimesCalled = 0;
|
||||||
|
static int emuTotalElapsed = 0;
|
||||||
|
#endif
|
||||||
|
#if DEBUG_MAIN_CALLS
|
||||||
|
static int emuMainFrameStart = 0;
|
||||||
|
static int emuMainTimesCalled = 0;
|
||||||
|
static int emuMainTimesSkipped = 0;
|
||||||
|
static int emuMainTotalElapsed = 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DOTS 341
|
||||||
|
|
||||||
|
#define VISIBLE_DOTS 256
|
||||||
|
#define VISIBLE_LINES 240
|
||||||
|
|
||||||
|
static uint32_t linesToDraw = VISIBLE_LINES;
|
||||||
|
static const uint32_t visibleImg = VISIBLE_DOTS*VISIBLE_LINES*4;
|
||||||
|
static uint8_t scaleFactor = 2;
|
||||||
|
static bool emuSaveEnabled = false;
|
||||||
|
static bool emuFdsHasSideB = false;
|
||||||
|
static uint32_t mainLoopRuns;
|
||||||
|
static uint32_t mainLoopPos;
|
||||||
|
static uint16_t ppuCycleTimer;
|
||||||
|
static uint16_t cpuCycleTimer;
|
||||||
|
//from input.c
|
||||||
|
extern uint8_t inValReads[8];
|
||||||
|
//from mapper.c
|
||||||
|
extern bool mapperUse78A;
|
||||||
|
//from m32.c
|
||||||
|
extern bool m32_singlescreen;
|
||||||
|
|
||||||
|
static volatile bool emuRenderFrame = false;
|
||||||
|
|
||||||
|
//used externally
|
||||||
|
bool emuSkipVsync = false;
|
||||||
|
bool emuSkipFrame = false;
|
||||||
|
|
||||||
|
//static uint32_t mCycles = 0;
|
||||||
|
static uint16_t mainClock = 1;
|
||||||
|
static uint16_t apuClock = 1;
|
||||||
|
static uint16_t ppuClock = 1;
|
||||||
|
static uint16_t vrc7Clock = 1;
|
||||||
|
|
||||||
|
extern bool fdsSwitch;
|
||||||
|
|
||||||
|
int audioUpdate()
|
||||||
|
{
|
||||||
|
if (!EmulatorInst)
|
||||||
|
return 0;
|
||||||
|
return EmulatorInst->audioUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace urde::MP1
|
||||||
|
{
|
||||||
|
|
||||||
|
bool CNESEmulator::EmulatorConstructed = false;
|
||||||
|
static logvisor::Module Log("CNESEmulator");
|
||||||
|
|
||||||
|
#define NESEMUP_ROM_OFFSET 0xa3f8
|
||||||
|
|
||||||
|
#define METROID_PAL false
|
||||||
|
#define METROID_MAPPER 1
|
||||||
|
#define METROID_SAVE_ENABLED false
|
||||||
|
#define METROID_TRAINER false
|
||||||
|
#define METROID_PRG_SIZE (8 * 0x4000)
|
||||||
|
#define METROID_CHR_SIZE (0 * 0x2000)
|
||||||
|
#define METROID_PRG_RAM_SIZE 0x2000
|
||||||
|
|
||||||
|
CNESEmulator::CNESEmulator()
|
||||||
|
{
|
||||||
|
if (EmulatorConstructed)
|
||||||
|
Log.report(logvisor::Fatal, "Attempted constructing more than 1 CNESEmulator");
|
||||||
|
EmulatorConstructed = true;
|
||||||
|
|
||||||
|
CDvdFile NESEmuFile("NESemuP.rel");
|
||||||
|
if (NESEmuFile)
|
||||||
|
{
|
||||||
|
m_nesEmuPBuf.reset(new u8[0x20000]);
|
||||||
|
m_dvdReq = NESEmuFile.AsyncSeekRead(m_nesEmuPBuf.get(), 0x20000, ESeekOrigin::Begin, NESEMUP_ROM_OFFSET);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, "Unable to open NESemuP.rel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNESEmulator::InitializeEmulator()
|
||||||
|
{
|
||||||
|
emuNesROMsize = 0x20000;
|
||||||
|
emuNesROM = (uint8_t*)malloc(emuNesROMsize);
|
||||||
|
DecompressROM(m_nesEmuPBuf.get(), emuNesROM);
|
||||||
|
m_nesEmuPBuf.reset();
|
||||||
|
|
||||||
|
puts(VERSION_STRING);
|
||||||
|
strcpy(window_title, VERSION_STRING);
|
||||||
|
memset(textureImage,0,visibleImg);
|
||||||
|
emuFileType = FTYPE_UNK;
|
||||||
|
memset(emuFileName,0,1024);
|
||||||
|
memset(emuSaveName,0,1024);
|
||||||
|
|
||||||
|
nesPAL = METROID_PAL;
|
||||||
|
uint8_t mapper = METROID_MAPPER;
|
||||||
|
emuSaveEnabled = METROID_SAVE_ENABLED;
|
||||||
|
bool trainer = METROID_TRAINER;
|
||||||
|
uint32_t prgROMsize = METROID_PRG_SIZE;
|
||||||
|
uint32_t chrROMsize = METROID_CHR_SIZE;
|
||||||
|
emuPrgRAMsize = METROID_PRG_RAM_SIZE;
|
||||||
|
emuPrgRAM = (uint8_t*)malloc(emuPrgRAMsize);
|
||||||
|
uint8_t *prgROM = emuNesROM;
|
||||||
|
if(trainer)
|
||||||
|
{
|
||||||
|
memcpy(emuPrgRAM+0x1000,prgROM,0x200);
|
||||||
|
prgROM += 512;
|
||||||
|
}
|
||||||
|
uint8_t *chrROM = NULL;
|
||||||
|
if(chrROMsize)
|
||||||
|
{
|
||||||
|
chrROM = emuNesROM+prgROMsize;
|
||||||
|
if(trainer) chrROM += 512;
|
||||||
|
}
|
||||||
|
apuInitBufs();
|
||||||
|
cpuInit();
|
||||||
|
ppuInit();
|
||||||
|
memInit();
|
||||||
|
apuInit();
|
||||||
|
inputInit();
|
||||||
|
ppuSetNameTblVertical();
|
||||||
|
#if DEBUG_LOAD_INFO
|
||||||
|
printf("Used Mapper: %i\n", mapper);
|
||||||
|
printf("PRG: 0x%x bytes PRG RAM: 0x%x bytes CHR: 0x%x bytes\n", prgROMsize, emuPrgRAMsize, chrROMsize);
|
||||||
|
#endif
|
||||||
|
if(!mapperInit(mapper, prgROM, prgROMsize, emuPrgRAM, emuPrgRAMsize, chrROM, chrROMsize))
|
||||||
|
{
|
||||||
|
printf("Mapper init failed!\n");
|
||||||
|
free(emuNesROM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if DEBUG_LOAD_INFO
|
||||||
|
printf("Trainer: %i Saving: %i VRAM Mode: Vertical\n", trainer, emuSaveEnabled);
|
||||||
|
#endif
|
||||||
|
sprintf(window_title, "%s NES - %s\n", nesPAL ? "PAL" : "NTSC", VERSION_STRING);
|
||||||
|
|
||||||
|
sprintf(window_title_pause, "%s (Pause)", window_title);
|
||||||
|
#if WINDOWS_BUILD
|
||||||
|
#if DEBUG_HZ
|
||||||
|
emuFrameStart = GetTickCount();
|
||||||
|
#endif
|
||||||
|
#if DEBUG_MAIN_CALLS
|
||||||
|
emuMainFrameStart = GetTickCount();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
cpuCycleTimer = nesPAL ? 16 : 12;
|
||||||
|
//do full frame per update loop
|
||||||
|
ppuCycleTimer = nesPAL ? 5 : 4;
|
||||||
|
mainLoopRuns = nesPAL ? DOTS*ppuCycleTimer : DOTS*ppuCycleTimer;
|
||||||
|
//mainLoopRuns *= ppuLinesTotal;
|
||||||
|
mainLoopPos = mainLoopRuns;
|
||||||
|
|
||||||
|
CGraphics::CommitResources([this](boo::IGraphicsDataFactory::Context& ctx)
|
||||||
|
{
|
||||||
|
m_texture = ctx.newDynamicTexture(VISIBLE_DOTS, linesToDraw,
|
||||||
|
boo::TextureFormat::RGBA8,
|
||||||
|
boo::TextureClampMode::ClampToEdgeNearest);
|
||||||
|
Vert verts[4] =
|
||||||
|
{
|
||||||
|
{{-1.f, -1.f, 0.f}, {0.f, 1.f}},
|
||||||
|
{{-1.f, 1.f, 0.f}, {0.f, 0.f}},
|
||||||
|
{{ 1.f, -1.f, 0.f}, {1.f, 1.f}},
|
||||||
|
{{ 1.f, 1.f, 0.f}, {1.f, 0.f}},
|
||||||
|
};
|
||||||
|
m_vbo = ctx.newStaticBuffer(boo::BufferUse::Vertex, verts, sizeof(Vert), 4);
|
||||||
|
m_uniBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(Uniform), 1);
|
||||||
|
m_shadBind = CNESShader::BuildShaderDataBinding(ctx, m_vbo, m_uniBuf, m_texture);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
//double useFreq = 223740;
|
||||||
|
double useFreq = apuGetFrequency();
|
||||||
|
m_booVoice = CAudioSys::GetVoiceEngine()->allocateNewStereoVoice(useFreq, this);
|
||||||
|
m_booVoice->start();
|
||||||
|
uint32_t apuBufSz = apuGetBufSize();
|
||||||
|
m_audioBufBlock.reset(new u8[apuBufSz * NUM_AUDIO_BUFFERS]);
|
||||||
|
for (int i=0 ; i<NUM_AUDIO_BUFFERS ; ++i)
|
||||||
|
m_audioBufs[i] = m_audioBufBlock.get() + apuBufSz * i;
|
||||||
|
|
||||||
|
EmulatorInst = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNESEmulator::DeinitializeEmulator()
|
||||||
|
{
|
||||||
|
//printf("\n");
|
||||||
|
emuRenderFrame = false;
|
||||||
|
m_booVoice->stop();
|
||||||
|
m_booVoice.reset();
|
||||||
|
apuDeinitBufs();
|
||||||
|
if(emuNesROM != NULL)
|
||||||
|
{
|
||||||
|
if(!nesEmuNSFPlayback && fdsEnabled)
|
||||||
|
{
|
||||||
|
FILE *save = fopen(emuSaveName, "wb");
|
||||||
|
if(save)
|
||||||
|
{
|
||||||
|
if(emuFdsHasSideB)
|
||||||
|
fwrite(emuNesROM,1,0x20000,save);
|
||||||
|
else
|
||||||
|
fwrite(emuNesROM,1,0x10000,save);
|
||||||
|
fclose(save);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(emuNesROM);
|
||||||
|
}
|
||||||
|
emuNesROM = NULL;
|
||||||
|
if(emuPrgRAM != NULL)
|
||||||
|
{
|
||||||
|
if(emuSaveEnabled)
|
||||||
|
{
|
||||||
|
FILE *save = fopen(emuSaveName, "wb");
|
||||||
|
if(save)
|
||||||
|
{
|
||||||
|
fwrite(emuPrgRAM,1,emuPrgRAMsize,save);
|
||||||
|
fclose(save);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(emuPrgRAM);
|
||||||
|
}
|
||||||
|
emuPrgRAM = NULL;
|
||||||
|
//printf("Bye!\n");
|
||||||
|
|
||||||
|
EmulatorInst = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CNESEmulator::~CNESEmulator()
|
||||||
|
{
|
||||||
|
if (EmulatorInst)
|
||||||
|
DeinitializeEmulator();
|
||||||
|
EmulatorConstructed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CNESEmulator::audioUpdate()
|
||||||
|
{
|
||||||
|
uint8_t *data = apuGetBuf();
|
||||||
|
if(data != NULL && m_procBufs)
|
||||||
|
{
|
||||||
|
--m_procBufs;
|
||||||
|
memmove(m_audioBufs[m_headBuf], data, apuGetBufSize());
|
||||||
|
//printf("PUSH\n");
|
||||||
|
++m_headBuf;
|
||||||
|
if (m_headBuf == NUM_AUDIO_BUFFERS)
|
||||||
|
m_headBuf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (!m_procBufs)
|
||||||
|
//printf("OVERRUN\n");
|
||||||
|
|
||||||
|
return m_procBufs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t AudioFrameSz = 2 * sizeof(int16_t);
|
||||||
|
|
||||||
|
size_t CNESEmulator::supplyAudio(boo::IAudioVoice& voice, size_t frames, int16_t* data)
|
||||||
|
{
|
||||||
|
size_t remFrames = frames;
|
||||||
|
while (remFrames)
|
||||||
|
{
|
||||||
|
if (m_posInBuf == apuGetBufSize())
|
||||||
|
{
|
||||||
|
++m_tailBuf;
|
||||||
|
if (m_tailBuf == NUM_AUDIO_BUFFERS)
|
||||||
|
m_tailBuf = 0;
|
||||||
|
m_posInBuf = 0;
|
||||||
|
++m_procBufs;
|
||||||
|
//printf("POP\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_procBufs == NUM_AUDIO_BUFFERS)
|
||||||
|
{
|
||||||
|
memset(data, 0, remFrames * AudioFrameSz);
|
||||||
|
//printf("UNDERRUN\n");
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t copySz = std::min(apuGetBufSize() - m_posInBuf, remFrames * AudioFrameSz);
|
||||||
|
memmove(data, m_audioBufs[m_tailBuf] + m_posInBuf, copySz);
|
||||||
|
data += copySz / sizeof(int16_t);
|
||||||
|
m_posInBuf += copySz;
|
||||||
|
remFrames -= copySz / AudioFrameSz;
|
||||||
|
}
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CATCHUP_SKIP 1
|
||||||
|
#if CATCHUP_SKIP
|
||||||
|
static int catchupFrames = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void CNESEmulator::NesEmuMainLoop()
|
||||||
|
{
|
||||||
|
int start = GetTickCount();
|
||||||
|
int loopCount = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if((!emuSkipVsync && emuRenderFrame) || nesPause)
|
||||||
|
{
|
||||||
|
#if (WINDOWS_BUILD && DEBUG_MAIN_CALLS)
|
||||||
|
emuMainTimesSkipped++;
|
||||||
|
#endif
|
||||||
|
//printf("LC RENDER: %d\n", loopCount);
|
||||||
|
m_texture->load(textureImage, visibleImg);
|
||||||
|
emuRenderFrame = false;
|
||||||
|
#if CATCHUP_SKIP
|
||||||
|
if (catchupFrames)
|
||||||
|
--catchupFrames;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++loopCount;
|
||||||
|
if(mainClock == cpuCycleTimer)
|
||||||
|
{
|
||||||
|
//runs every 8th cpu clock
|
||||||
|
if(apuClock == 8)
|
||||||
|
{
|
||||||
|
if(!apuCycle())
|
||||||
|
{
|
||||||
|
#if (WINDOWS_BUILD && DEBUG_MAIN_CALLS)
|
||||||
|
emuMainTimesSkipped++;
|
||||||
|
#endif
|
||||||
|
#if CATCHUP_SKIP
|
||||||
|
catchupFrames = 0;
|
||||||
|
#endif
|
||||||
|
//printf("LC SKIP\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
apuClock = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
apuClock++;
|
||||||
|
//runs every cpu cycle
|
||||||
|
apuClockTimers();
|
||||||
|
//main CPU clock
|
||||||
|
if(!cpuCycle())
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
//mapper related irqs
|
||||||
|
if(mapperCycle != NULL)
|
||||||
|
mapperCycle();
|
||||||
|
//mCycles++;
|
||||||
|
//channel timer updates
|
||||||
|
apuLenCycle();
|
||||||
|
mainClock = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mainClock++;
|
||||||
|
if(ppuClock == ppuCycleTimer)
|
||||||
|
{
|
||||||
|
if(!ppuCycle())
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
if(ppuDrawDone())
|
||||||
|
{
|
||||||
|
//printf("%i\n",mCycles);
|
||||||
|
//mCycles = 0;
|
||||||
|
emuRenderFrame = true;
|
||||||
|
if(fm2playRunning())
|
||||||
|
fm2playUpdate();
|
||||||
|
#if (WINDOWS_BUILD && DEBUG_HZ)
|
||||||
|
emuTimesCalled++;
|
||||||
|
int end = GetTickCount();
|
||||||
|
emuTotalElapsed += end - emuFrameStart;
|
||||||
|
if(emuTotalElapsed >= 1000)
|
||||||
|
{
|
||||||
|
printf("\r%iHz ", emuTimesCalled);
|
||||||
|
emuTimesCalled = 0;
|
||||||
|
emuTotalElapsed = 0;
|
||||||
|
}
|
||||||
|
emuFrameStart = end;
|
||||||
|
#endif
|
||||||
|
if(ppuDebugPauseFrame)
|
||||||
|
{
|
||||||
|
ppuDebugPauseFrame = false;
|
||||||
|
nesPause = true;
|
||||||
|
}
|
||||||
|
if(nesEmuNSFPlayback)
|
||||||
|
nsfVsync();
|
||||||
|
}
|
||||||
|
ppuClock = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ppuClock++;
|
||||||
|
if(fdsEnabled)
|
||||||
|
fdsAudioMasterUpdate();
|
||||||
|
if(vrc7enabled)
|
||||||
|
{
|
||||||
|
if(vrc7Clock == 432)
|
||||||
|
{
|
||||||
|
vrc7AudioCycle();
|
||||||
|
vrc7Clock = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vrc7Clock++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((loopCount % 5000) == 0 && GetTickCount() - start >= 14)
|
||||||
|
{
|
||||||
|
#if CATCHUP_SKIP
|
||||||
|
if (catchupFrames < 50)
|
||||||
|
++catchupFrames;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(true);
|
||||||
|
|
||||||
|
int end = GetTickCount();
|
||||||
|
printf("%dms\n", end - start);
|
||||||
|
|
||||||
|
#if (WINDOWS_BUILD && DEBUG_MAIN_CALLS)
|
||||||
|
emuMainTimesCalled++;
|
||||||
|
int end = GetTickCount();
|
||||||
|
//printf("%dms\n", end - start);
|
||||||
|
emuMainTotalElapsed += end - emuMainFrameStart;
|
||||||
|
if(emuMainTotalElapsed >= 1000)
|
||||||
|
{
|
||||||
|
printf("\r%i calls, %i skips ", emuMainTimesCalled, emuMainTimesSkipped);
|
||||||
|
fflush(stdout);
|
||||||
|
emuMainTimesCalled = 0;
|
||||||
|
emuMainTimesSkipped = 0;
|
||||||
|
emuMainTotalElapsed = 0;
|
||||||
|
}
|
||||||
|
emuMainFrameStart = end;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nesEmuFdsSetup(uint8_t *src, uint8_t *dst)
|
||||||
|
{
|
||||||
|
memcpy(dst, src, 0x38);
|
||||||
|
memcpy(dst+0x3A, src+0x38, 2);
|
||||||
|
uint16_t cDiskPos = 0x3E;
|
||||||
|
uint16_t cROMPos = 0x3A;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if(src[cROMPos] != 0x03)
|
||||||
|
break;
|
||||||
|
memcpy(dst+cDiskPos, src+cROMPos, 0x10);
|
||||||
|
uint16_t copySize = (*(uint16_t*)(src+cROMPos+0xD))+1;
|
||||||
|
cDiskPos+=0x12;
|
||||||
|
cROMPos+=0x10;
|
||||||
|
memcpy(dst+cDiskPos, src+cROMPos, copySize);
|
||||||
|
cDiskPos+=copySize+2;
|
||||||
|
cROMPos+=copySize;
|
||||||
|
} while(cROMPos < 0xFFDC && cDiskPos < 0xFFFF);
|
||||||
|
printf("%04x -> %04x\n", cROMPos, cDiskPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNESEmulator::DecompressROM(u8* dataIn, u8* dataOut, u32 dataOutLen, u8 descrambleSeed,
|
||||||
|
u32 checkDataLen, u32 checksumMagic)
|
||||||
|
{
|
||||||
|
for (int i=0 ; i<256 ; ++i)
|
||||||
|
{
|
||||||
|
descrambleSeed += dataIn[i];
|
||||||
|
dataIn[i] = descrambleSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0 ; i<128 ; ++i)
|
||||||
|
std::swap(dataIn[255 - i], dataIn[i]);
|
||||||
|
|
||||||
|
struct BitstreamState
|
||||||
|
{
|
||||||
|
u32 x0_remBits = 0;
|
||||||
|
u32 x4_lastByte;
|
||||||
|
u8* x8_ptr;
|
||||||
|
BitstreamState(u8* ptr) : x8_ptr(ptr) {}
|
||||||
|
} bState = {dataIn + 256};
|
||||||
|
|
||||||
|
u8* dataOutAlpha = dataOut;
|
||||||
|
while (dataOutLen != 0)
|
||||||
|
{
|
||||||
|
u32 r12 = 0;
|
||||||
|
|
||||||
|
if (bState.x0_remBits == 0)
|
||||||
|
{
|
||||||
|
bState.x4_lastByte = *bState.x8_ptr;
|
||||||
|
bState.x8_ptr += 1;
|
||||||
|
bState.x0_remBits = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 r11 = r12 << 1;
|
||||||
|
if (bState.x4_lastByte & 0x80)
|
||||||
|
r11 |= 1;
|
||||||
|
|
||||||
|
bState.x4_lastByte <<= 1;
|
||||||
|
bState.x0_remBits -= 1;
|
||||||
|
|
||||||
|
if (r11 == 1)
|
||||||
|
{
|
||||||
|
r12 = 0;
|
||||||
|
|
||||||
|
for (int i=0 ; i<4 ; ++i)
|
||||||
|
{
|
||||||
|
if (bState.x0_remBits == 0)
|
||||||
|
{
|
||||||
|
bState.x4_lastByte = *bState.x8_ptr;
|
||||||
|
bState.x8_ptr += 1;
|
||||||
|
bState.x0_remBits = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r12 <<= 1;
|
||||||
|
if (bState.x4_lastByte & 0x80)
|
||||||
|
r12 |= 1;
|
||||||
|
|
||||||
|
bState.x4_lastByte <<= 1;
|
||||||
|
bState.x0_remBits -= 1;
|
||||||
|
|
||||||
|
if (bState.x0_remBits == 0)
|
||||||
|
{
|
||||||
|
bState.x4_lastByte = *bState.x8_ptr;
|
||||||
|
bState.x8_ptr += 1;
|
||||||
|
bState.x0_remBits = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r12 <<= 1;
|
||||||
|
if (bState.x4_lastByte & 0x80)
|
||||||
|
r12 |= 1;
|
||||||
|
|
||||||
|
bState.x4_lastByte <<= 1;
|
||||||
|
bState.x0_remBits -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dataOutAlpha++ = dataIn[r12 + 73];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r12 = 0;
|
||||||
|
|
||||||
|
if (bState.x0_remBits == 0)
|
||||||
|
{
|
||||||
|
bState.x4_lastByte = *bState.x8_ptr;
|
||||||
|
bState.x8_ptr += 1;
|
||||||
|
bState.x0_remBits = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r11 = r12 << 1;
|
||||||
|
if (bState.x4_lastByte & 0x80)
|
||||||
|
r11 |= 1;
|
||||||
|
|
||||||
|
bState.x4_lastByte <<= 1;
|
||||||
|
bState.x0_remBits -= 1;
|
||||||
|
|
||||||
|
if (r11 == 1)
|
||||||
|
{
|
||||||
|
r12 = 0;
|
||||||
|
|
||||||
|
for (int i=0 ; i<3 ; ++i)
|
||||||
|
{
|
||||||
|
if (bState.x0_remBits == 0)
|
||||||
|
{
|
||||||
|
bState.x4_lastByte = *bState.x8_ptr;
|
||||||
|
bState.x8_ptr += 1;
|
||||||
|
bState.x0_remBits = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r12 <<= 1;
|
||||||
|
if (bState.x4_lastByte & 0x80)
|
||||||
|
r12 |= 1;
|
||||||
|
|
||||||
|
bState.x4_lastByte <<= 1;
|
||||||
|
bState.x0_remBits -= 1;
|
||||||
|
|
||||||
|
if (bState.x0_remBits == 0)
|
||||||
|
{
|
||||||
|
bState.x4_lastByte = *bState.x8_ptr;
|
||||||
|
bState.x8_ptr += 1;
|
||||||
|
bState.x0_remBits = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r12 <<= 1;
|
||||||
|
if (bState.x4_lastByte & 0x80)
|
||||||
|
r12 |= 1;
|
||||||
|
|
||||||
|
bState.x4_lastByte <<= 1;
|
||||||
|
bState.x0_remBits -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dataOutAlpha++ = dataIn[r12 + 9];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r12 = 0;
|
||||||
|
|
||||||
|
if (bState.x0_remBits == 0)
|
||||||
|
{
|
||||||
|
bState.x4_lastByte = *bState.x8_ptr;
|
||||||
|
bState.x8_ptr += 1;
|
||||||
|
bState.x0_remBits = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r11 = r12 << 1;
|
||||||
|
if (bState.x4_lastByte & 0x80)
|
||||||
|
r11 |= 1;
|
||||||
|
|
||||||
|
bState.x4_lastByte <<= 1;
|
||||||
|
bState.x0_remBits -= 1;
|
||||||
|
|
||||||
|
if (r11 == 1)
|
||||||
|
{
|
||||||
|
r12 = 0;
|
||||||
|
|
||||||
|
for (int i=0 ; i<3 ; ++i)
|
||||||
|
{
|
||||||
|
if (bState.x0_remBits == 0)
|
||||||
|
{
|
||||||
|
bState.x4_lastByte = *bState.x8_ptr;
|
||||||
|
bState.x8_ptr += 1;
|
||||||
|
bState.x0_remBits = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r12 <<= 1;
|
||||||
|
if (bState.x4_lastByte & 0x80)
|
||||||
|
r12 |= 1;
|
||||||
|
|
||||||
|
bState.x4_lastByte <<= 1;
|
||||||
|
bState.x0_remBits -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dataOutAlpha++ = dataIn[r12 + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dataOutAlpha++ = dataIn[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--dataOutLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 tmpWord = 0;
|
||||||
|
for (int i=0 ; i<checkDataLen ; ++i)
|
||||||
|
{
|
||||||
|
tmpWord ^= dataOut[i];
|
||||||
|
for (int j=0 ; j<8 ; ++j)
|
||||||
|
{
|
||||||
|
if (tmpWord & 0x1)
|
||||||
|
tmpWord = (tmpWord >> 1) ^ checksumMagic;
|
||||||
|
else
|
||||||
|
tmpWord = (tmpWord >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataOut[checkDataLen - 1] = (tmpWord >> 8) & 0xff;
|
||||||
|
dataOut[checkDataLen - 2] = tmpWord & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNESEmulator::ProcessUserInput(const CFinalInput& input, int)
|
||||||
|
{
|
||||||
|
inValReads[BUTTON_UP] = input.DDPUp() | input.DLAUp();
|
||||||
|
inValReads[BUTTON_DOWN] = input.DDPDown() | input.DLADown();
|
||||||
|
inValReads[BUTTON_LEFT] = input.DDPLeft() | input.DLALeft();
|
||||||
|
inValReads[BUTTON_RIGHT] = input.DDPRight() | input.DLARight();
|
||||||
|
inValReads[BUTTON_A] = input.DA();
|
||||||
|
inValReads[BUTTON_B] = input.DB();
|
||||||
|
inValReads[BUTTON_SELECT] = input.DZ();
|
||||||
|
inValReads[BUTTON_START] = input.DStart();
|
||||||
|
if (input.PL())
|
||||||
|
x20_wantsQuit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNESEmulator::Update()
|
||||||
|
{
|
||||||
|
if (!EmulatorInst)
|
||||||
|
{
|
||||||
|
if (m_dvdReq && m_dvdReq->IsComplete())
|
||||||
|
{
|
||||||
|
m_dvdReq.reset();
|
||||||
|
InitializeEmulator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NesEmuMainLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const float NESAspect = VISIBLE_DOTS / float(VISIBLE_LINES);
|
||||||
|
|
||||||
|
void CNESEmulator::Draw(const zeus::CColor& mulColor, bool filtering)
|
||||||
|
{
|
||||||
|
if (!EmulatorInst)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float aspect = g_Viewport.x8_width / float(g_Viewport.xc_height);
|
||||||
|
float widthFac = NESAspect / aspect;
|
||||||
|
|
||||||
|
Uniform uniform = {zeus::CMatrix4f{}, mulColor};
|
||||||
|
uniform.m_matrix[0][0] = widthFac;
|
||||||
|
m_uniBuf->load(&uniform, sizeof(Uniform));
|
||||||
|
|
||||||
|
CGraphics::SetShaderDataBinding(m_shadBind);
|
||||||
|
CGraphics::DrawArray(0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNESEmulator::LoadState(const u8* state)
|
||||||
|
{
|
||||||
|
memmove(x39_loadState, state, 18);
|
||||||
|
x38_stateLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
#ifndef __URDE_CNESEMULATOR_HPP__
|
||||||
|
#define __URDE_CNESEMULATOR_HPP__
|
||||||
|
|
||||||
|
#include "RetroTypes.hpp"
|
||||||
|
#include "zeus/CColor.hpp"
|
||||||
|
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
|
||||||
|
#include "boo/audiodev/IAudioVoice.hpp"
|
||||||
|
#include "zeus/CMatrix4f.hpp"
|
||||||
|
|
||||||
|
namespace urde
|
||||||
|
{
|
||||||
|
class CFinalInput;
|
||||||
|
class IDvdRequest;
|
||||||
|
|
||||||
|
namespace MP1
|
||||||
|
{
|
||||||
|
|
||||||
|
#define NUM_AUDIO_BUFFERS 10
|
||||||
|
|
||||||
|
class CNESEmulator : public boo::IAudioVoiceCallback
|
||||||
|
{
|
||||||
|
static bool EmulatorConstructed;
|
||||||
|
|
||||||
|
std::unique_ptr<u8[]> m_nesEmuPBuf;
|
||||||
|
std::shared_ptr<IDvdRequest> m_dvdReq;
|
||||||
|
|
||||||
|
struct Vert
|
||||||
|
{
|
||||||
|
zeus::CVector3f m_pos;
|
||||||
|
zeus::CVector2f m_uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Uniform
|
||||||
|
{
|
||||||
|
zeus::CMatrix4f m_matrix;
|
||||||
|
zeus::CColor m_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
boo::ObjToken<boo::ITextureD> m_texture;
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> m_uniBuf;
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> m_vbo;
|
||||||
|
boo::ObjToken<boo::IShaderDataBinding> m_shadBind;
|
||||||
|
|
||||||
|
std::unique_ptr<u8[]> m_audioBufBlock;
|
||||||
|
u8* m_audioBufs[NUM_AUDIO_BUFFERS];
|
||||||
|
int m_headBuf = 0;
|
||||||
|
int m_tailBuf = 0;
|
||||||
|
int m_procBufs = NUM_AUDIO_BUFFERS;
|
||||||
|
size_t m_posInBuf = 0;
|
||||||
|
boo::ObjToken<boo::IAudioVoice> m_booVoice;
|
||||||
|
|
||||||
|
bool x20_wantsQuit = false;
|
||||||
|
u8 x21_saveState[18];
|
||||||
|
bool x34_wantsLoad = false;
|
||||||
|
bool x38_stateLoaded = false;
|
||||||
|
u8 x39_loadState[18];
|
||||||
|
static void DecompressROM(u8* dataIn, u8* dataOut, u32 dataOutLen = 0x20000, u8 descrambleSeed = 0xe9,
|
||||||
|
u32 checkDataLen = 0x1FFFC, u32 checksumMagic = 0xA663);
|
||||||
|
void InitializeEmulator();
|
||||||
|
void DeinitializeEmulator();
|
||||||
|
void NesEmuMainLoop();
|
||||||
|
public:
|
||||||
|
CNESEmulator();
|
||||||
|
~CNESEmulator();
|
||||||
|
void ProcessUserInput(const CFinalInput& input, int);
|
||||||
|
void Update();
|
||||||
|
void Draw(const zeus::CColor& mulColor, bool filtering);
|
||||||
|
void LoadState(const u8* state);
|
||||||
|
const u8* GetSaveState() const { return x21_saveState; }
|
||||||
|
bool WantsQuit() const { return x20_wantsQuit; }
|
||||||
|
bool WantsLoad() const { return x34_wantsLoad; }
|
||||||
|
|
||||||
|
int audioUpdate();
|
||||||
|
void preSupplyAudio(boo::IAudioVoice& voice, double dt) {}
|
||||||
|
size_t supplyAudio(boo::IAudioVoice& voice, size_t frames, int16_t* data);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __URDE_CNESEMULATOR_HPP__
|
|
@ -0,0 +1,337 @@
|
||||||
|
#include "CNESShader.hpp"
|
||||||
|
#include "Graphics/CGraphics.hpp"
|
||||||
|
|
||||||
|
namespace urde::MP1
|
||||||
|
{
|
||||||
|
|
||||||
|
boo::ObjToken<boo::IShaderPipeline> CNESShader::g_Pipeline;
|
||||||
|
boo::ObjToken<boo::IVertexFormat> CNESShader::g_VtxFmt;
|
||||||
|
|
||||||
|
static const char* VS_GLSL =
|
||||||
|
"#version 330\n"
|
||||||
|
BOO_GLSL_BINDING_HEAD
|
||||||
|
"layout(location=0) in vec4 posIn;\n"
|
||||||
|
"layout(location=1) in vec4 uvIn;\n"
|
||||||
|
"\n"
|
||||||
|
"UBINDING0 uniform TexuredQuadUniform\n"
|
||||||
|
"{\n"
|
||||||
|
" mat4 mtx;\n"
|
||||||
|
" vec4 color;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" vec4 color;\n"
|
||||||
|
" vec2 uv;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"SBINDING(0) out VertToFrag vtf;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" vtf.color = color;\n"
|
||||||
|
" vtf.uv = uvIn.xy;\n"
|
||||||
|
" gl_Position = mtx * vec4(posIn.xyz, 1.0);\n"
|
||||||
|
" gl_Position = FLIPFROMGL(gl_Position);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static const char* FS_GLSL =
|
||||||
|
"#version 330\n"
|
||||||
|
BOO_GLSL_BINDING_HEAD
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" vec4 color;\n"
|
||||||
|
" vec2 uv;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"SBINDING(0) in VertToFrag vtf;\n"
|
||||||
|
"layout(location=0) out vec4 colorOut;\n"
|
||||||
|
"TBINDING0 uniform sampler2D tex;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" colorOut = vtf.color * vec4(texture(tex, vtf.uv).bgr, 1.0);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
static const char* VS_HLSL =
|
||||||
|
"struct VertData\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 posIn : POSITION;\n"
|
||||||
|
" float4 uvIn : UV;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"cbuffer TexuredQuadUniform : register(b0)\n"
|
||||||
|
"{\n"
|
||||||
|
" float4x4 mat;\n"
|
||||||
|
" float4 color;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 position : SV_Position;\n"
|
||||||
|
" float4 color : COLOR;\n"
|
||||||
|
" float2 uv : UV;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"VertToFrag main(in VertData v)\n"
|
||||||
|
"{\n"
|
||||||
|
" VertToFrag vtf;\n"
|
||||||
|
" vtf.color = color;\n"
|
||||||
|
" vtf.uv = v.uvIn.xy;\n"
|
||||||
|
" vtf.position = mul(mat, float4(v.posIn.xyz, 1.0));\n"
|
||||||
|
" return vtf;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static const char* FS_HLSL =
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 position : SV_Position;\n"
|
||||||
|
" float4 color : COLOR;\n"
|
||||||
|
" float2 uv : UV;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"Texture2D tex : register(t0);\n"
|
||||||
|
"SamplerState samp : register(s3);\n"
|
||||||
|
"\n"
|
||||||
|
"float4 main(in VertToFrag vtf) : SV_Target0\n"
|
||||||
|
"{\n"
|
||||||
|
" return vtf.color * float4(tex.Sample(samp, vtf.uv).bgr, 1.0);\n"
|
||||||
|
"}\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOO_HAS_METAL
|
||||||
|
static const char* VS_METAL =
|
||||||
|
"#include <metal_stdlib>\n"
|
||||||
|
"using namespace metal;\n"
|
||||||
|
"struct VertData\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 posIn [[ attribute(0) ]];\n"
|
||||||
|
" float4 uvIn [[ attribute(1) ]];\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct TexuredQuadUniform\n"
|
||||||
|
"{\n"
|
||||||
|
" float4x4 mat;\n"
|
||||||
|
" float4 color;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 position [[ position ]];\n"
|
||||||
|
" float4 color;\n"
|
||||||
|
" float2 uv;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"vertex VertToFrag vmain(VertData v [[ stage_in ]], constant TexuredQuadUniform& tqu [[ buffer(2) ]])\n"
|
||||||
|
"{\n"
|
||||||
|
" VertToFrag vtf;\n"
|
||||||
|
" vtf.color = tqu.color;\n"
|
||||||
|
" vtf.uv = v.uvIn.xy;\n"
|
||||||
|
" vtf.position = tqu.mat * float4(v.posIn.xyz, 1.0);\n"
|
||||||
|
" return vtf;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
|
||||||
|
static const char* FS_METAL =
|
||||||
|
"#include <metal_stdlib>\n"
|
||||||
|
"using namespace metal;\n"
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 position [[ position ]];\n"
|
||||||
|
" float4 color;\n"
|
||||||
|
" float2 uv;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"fragment float4 fmain(VertToFrag vtf [[ stage_in ]],\n"
|
||||||
|
" sampler clampSamp [[ sampler(3) ]],\n"
|
||||||
|
" texture2d<float> tex [[ texture(0) ]])\n"
|
||||||
|
"{\n"
|
||||||
|
" return vtf.color * float4(tex.sample(clampSamp, vtf.uv).bgr, 1.0);\n"
|
||||||
|
"}\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOO_HAS_GL
|
||||||
|
void CNESShader::Initialize(boo::GLDataFactory::Context& ctx)
|
||||||
|
{
|
||||||
|
const char* texNames[] = {"tex"};
|
||||||
|
const char* uniNames[] = {"TexuredQuadUniform"};
|
||||||
|
g_Pipeline = ctx.newShaderPipeline(VS_GLSL, FS_GLSL, 1, texNames, 1, uniNames, boo::BlendFactor::SrcAlpha,
|
||||||
|
boo::BlendFactor::InvSrcAlpha, boo::Primitive::TriStrips,
|
||||||
|
boo::ZTest::None, false, true, false, boo::CullMode::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
boo::ObjToken<boo::IShaderDataBinding> CNESShader::BuildShaderDataBinding(boo::GLDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex)
|
||||||
|
{
|
||||||
|
const boo::VertexElementDescriptor VtxVmt[] =
|
||||||
|
{
|
||||||
|
{vbo.get(), nullptr, boo::VertexSemantic::Position4},
|
||||||
|
{vbo.get(), nullptr, boo::VertexSemantic::UV4}
|
||||||
|
};
|
||||||
|
boo::ObjToken<boo::IGraphicsBuffer> bufs[] = {uniBuf.get()};
|
||||||
|
boo::PipelineStage stages[] = {boo::PipelineStage::Vertex};
|
||||||
|
boo::ObjToken<boo::ITexture> texs[] = {tex.get()};
|
||||||
|
return ctx.newShaderDataBinding(g_Pipeline,
|
||||||
|
ctx.newVertexFormat(2, VtxVmt), vbo.get(), nullptr, nullptr,
|
||||||
|
1, bufs, stages, nullptr, nullptr, 1, texs, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
void CNESShader::Initialize(boo::ID3DDataFactory::Context& ctx)
|
||||||
|
{
|
||||||
|
const boo::VertexElementDescriptor VtxVmt[] =
|
||||||
|
{
|
||||||
|
{nullptr, nullptr, boo::VertexSemantic::Position4},
|
||||||
|
{nullptr, nullptr, boo::VertexSemantic::UV4}
|
||||||
|
};
|
||||||
|
g_VtxFmt = ctx.newVertexFormat(2, VtxVmt);
|
||||||
|
g_Pipeline = ctx.newShaderPipeline(VS_HLSL, FS_HLSL, nullptr, nullptr, nullptr,
|
||||||
|
g_VtxFmt, boo::BlendFactor::SrcAlpha,
|
||||||
|
boo::BlendFactor::InvSrcAlpha, boo::Primitive::TriStrips,
|
||||||
|
boo::ZTest::None, false, true, false, boo::CullMode::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
boo::ObjToken<boo::IShaderDataBinding> CNESShader::BuildShaderDataBinding(boo::ID3DDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex)
|
||||||
|
{
|
||||||
|
boo::ObjToken<boo::IGraphicsBuffer> bufs[] = {filter.m_uniBuf.get()};
|
||||||
|
boo::ObjToken<boo::ITexture> texs[] = {filter.m_booTex.get()};
|
||||||
|
return cctx.newShaderDataBinding(SelectPipeline(type, filter.m_gequal), s_VtxFmt,
|
||||||
|
filter.m_vbo.get(), nullptr, nullptr, 1, bufs,
|
||||||
|
nullptr, nullptr, nullptr, 1, texs, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOO_HAS_METAL
|
||||||
|
void CNESShader::Initialize(boo::MetalDataFactory::Context& ctx)
|
||||||
|
{
|
||||||
|
const boo::VertexElementDescriptor VtxVmt[] =
|
||||||
|
{
|
||||||
|
{nullptr, nullptr, boo::VertexSemantic::Position4},
|
||||||
|
{nullptr, nullptr, boo::VertexSemantic::UV4}
|
||||||
|
};
|
||||||
|
g_VtxFmt = ctx.newVertexFormat(2, VtxVmt);
|
||||||
|
g_Pipeline = ctx.newShaderPipeline(VS_METAL, FS_METAL, nullptr, nullptr,
|
||||||
|
g_VtxFmt, boo::BlendFactor::SrcAlpha,
|
||||||
|
boo::BlendFactor::InvSrcAlpha, boo::Primitive::TriStrips,
|
||||||
|
boo::ZTest::None, false, true, false, boo::CullMode::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
boo::ObjToken<boo::IShaderDataBinding> CNESShader::BuildShaderDataBinding(boo::MetalDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex)
|
||||||
|
{
|
||||||
|
boo::ObjToken<boo::IGraphicsBuffer> bufs[] = {uniBuf.get()};
|
||||||
|
boo::ObjToken<boo::ITexture> texs[] = {tex.get()};
|
||||||
|
return ctx.newShaderDataBinding(g_Pipeline, g_VtxFmt,
|
||||||
|
vbo.get(), nullptr, nullptr, 1, bufs,
|
||||||
|
nullptr, nullptr, nullptr, 1, texs, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOO_HAS_VULKAN
|
||||||
|
void CNESShader::Initialize(boo::VulkanDataFactory::Context& ctx)
|
||||||
|
{
|
||||||
|
const boo::VertexElementDescriptor VtxVmt[] =
|
||||||
|
{
|
||||||
|
{nullptr, nullptr, boo::VertexSemantic::Position4},
|
||||||
|
{nullptr, nullptr, boo::VertexSemantic::UV4}
|
||||||
|
};
|
||||||
|
g_VtxFmt = ctx.newVertexFormat(2, VtxVmt);
|
||||||
|
g_Pipeline = ctx.newShaderPipeline(VS_GLSL, FS_GLSL, g_VtxFmt, boo::BlendFactor::SrcAlpha,
|
||||||
|
boo::BlendFactor::InvSrcAlpha, boo::Primitive::TriStrips,
|
||||||
|
boo::ZTest::None, false, true, false, boo::CullMode::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
boo::ObjToken<boo::IShaderDataBinding> CNESShader::BuildShaderDataBinding(boo::VulkanDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex)
|
||||||
|
{
|
||||||
|
boo::ObjToken<boo::IGraphicsBuffer> bufs[] = {filter.m_uniBuf.get()};
|
||||||
|
boo::ObjToken<boo::ITexture> texs[] = {filter.m_booTex.get()};
|
||||||
|
return cctx.newShaderDataBinding(SelectPipeline(type, filter.m_gequal,
|
||||||
|
filter.m_booTex->type() == boo::TextureType::Render), s_VtxFmt,
|
||||||
|
filter.m_vbo.get(), nullptr, nullptr, 1, bufs,
|
||||||
|
nullptr, nullptr, nullptr, 1, texs, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
boo::ObjToken<boo::IShaderDataBinding> CNESShader::BuildShaderDataBinding(boo::IGraphicsDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex)
|
||||||
|
{
|
||||||
|
switch (ctx.platform())
|
||||||
|
{
|
||||||
|
#if BOO_HAS_GL
|
||||||
|
case boo::IGraphicsDataFactory::Platform::OpenGL:
|
||||||
|
return BuildShaderDataBinding(static_cast<boo::GLDataFactory::Context&>(ctx), vbo, uniBuf, tex);
|
||||||
|
#endif
|
||||||
|
#if _WIN32
|
||||||
|
case boo::IGraphicsDataFactory::Platform::D3D11:
|
||||||
|
case boo::IGraphicsDataFactory::Platform::D3D12:
|
||||||
|
return BuildShaderDataBinding(static_cast<boo::ID3DDataFactory::Context&>(ctx), vbo, uniBuf, tex);
|
||||||
|
#endif
|
||||||
|
#if BOO_HAS_METAL
|
||||||
|
case boo::IGraphicsDataFactory::Platform::Metal:
|
||||||
|
return BuildShaderDataBinding(static_cast<boo::MetalDataFactory::Context&>(ctx), vbo, uniBuf, tex);
|
||||||
|
#endif
|
||||||
|
#if BOO_HAS_VULKAN
|
||||||
|
case boo::IGraphicsDataFactory::Platform::Vulkan:
|
||||||
|
return BuildShaderDataBinding(static_cast<boo::VulkanDataFactory::Context&>(ctx), vbo, uniBuf, tex);
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNESShader::Initialize()
|
||||||
|
{
|
||||||
|
if (!CGraphics::g_BooFactory)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CGraphics::CommitResources(
|
||||||
|
[&](boo::IGraphicsDataFactory::Context& ctx) -> bool
|
||||||
|
{
|
||||||
|
switch (ctx.platform())
|
||||||
|
{
|
||||||
|
#if BOO_HAS_GL
|
||||||
|
case boo::IGraphicsDataFactory::Platform::OpenGL:
|
||||||
|
Initialize(static_cast<boo::GLDataFactory::Context&>(ctx));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if _WIN32
|
||||||
|
case boo::IGraphicsDataFactory::Platform::D3D11:
|
||||||
|
case boo::IGraphicsDataFactory::Platform::D3D12:
|
||||||
|
Initialize(static_cast<boo::ID3DDataFactory::Context&>(ctx));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if BOO_HAS_METAL
|
||||||
|
case boo::IGraphicsDataFactory::Platform::Metal:
|
||||||
|
Initialize(static_cast<boo::MetalDataFactory::Context&>(ctx));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if BOO_HAS_VULKAN
|
||||||
|
case boo::IGraphicsDataFactory::Platform::Vulkan:
|
||||||
|
Initialize(static_cast<boo::VulkanDataFactory::Context&>(ctx));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNESShader::Shutdown()
|
||||||
|
{
|
||||||
|
g_Pipeline.reset();
|
||||||
|
g_VtxFmt.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef URDE_CNESSHADER_HPP
|
||||||
|
#define URDE_CNESSHADER_HPP
|
||||||
|
|
||||||
|
#include "boo/graphicsdev/GL.hpp"
|
||||||
|
#include "boo/graphicsdev/Metal.hpp"
|
||||||
|
#include "boo/graphicsdev/D3D.hpp"
|
||||||
|
#include "boo/graphicsdev/Vulkan.hpp"
|
||||||
|
|
||||||
|
namespace urde::MP1
|
||||||
|
{
|
||||||
|
|
||||||
|
class CNESShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#if BOO_HAS_GL
|
||||||
|
static void Initialize(boo::GLDataFactory::Context& ctx);
|
||||||
|
static boo::ObjToken<boo::IShaderDataBinding> BuildShaderDataBinding(boo::GLDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex);
|
||||||
|
#endif
|
||||||
|
#if _WIN32
|
||||||
|
static void Initialize(boo::ID3DDataFactory::Context& ctx);
|
||||||
|
static boo::ObjToken<boo::IShaderDataBinding> BuildShaderDataBinding(boo::ID3DDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex);
|
||||||
|
#endif
|
||||||
|
#if BOO_HAS_METAL
|
||||||
|
static void Initialize(boo::MetalDataFactory::Context& ctx);
|
||||||
|
static boo::ObjToken<boo::IShaderDataBinding> BuildShaderDataBinding(boo::MetalDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex);
|
||||||
|
#endif
|
||||||
|
#if BOO_HAS_VULKAN
|
||||||
|
static void Initialize(boo::VulkanDataFactory::Context& ctx);
|
||||||
|
static boo::ObjToken<boo::IShaderDataBinding> BuildShaderDataBinding(boo::VulkanDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex);
|
||||||
|
#endif
|
||||||
|
static void Initialize();
|
||||||
|
static void Shutdown();
|
||||||
|
|
||||||
|
static boo::ObjToken<boo::IShaderDataBinding> BuildShaderDataBinding(boo::IGraphicsDataFactory::Context& ctx,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferS> vbo,
|
||||||
|
boo::ObjToken<boo::IGraphicsBufferD> uniBuf,
|
||||||
|
boo::ObjToken<boo::ITextureD> tex);
|
||||||
|
|
||||||
|
static boo::ObjToken<boo::IShaderPipeline> g_Pipeline;
|
||||||
|
static boo::ObjToken<boo::IVertexFormat> g_VtxFmt;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // URDE_CNESSHADER_HPP
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 25527a513dc635fa87014970618fbfb7dfe3e5c6
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef URDE_NESEMULATOR_MALLOC_H
|
||||||
|
#define URDE_NESEMULATOR_MALLOC_H
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <stdlib.h>
|
||||||
|
#else
|
||||||
|
#include <../include/malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // URDE_NESEMULATOR_MALLOC_H
|
|
@ -76,7 +76,7 @@ public:
|
||||||
|
|
||||||
void StartMixing()
|
void StartMixing()
|
||||||
{
|
{
|
||||||
m_voice->start();
|
//m_voice->start();
|
||||||
}
|
}
|
||||||
void StopMixing()
|
void StopMixing()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1223,9 +1223,9 @@ void CFrontEndUI::SFusionBonusFrame::DoAdvance(CGuiTableGroup* caller)
|
||||||
}
|
}
|
||||||
else if (g_GameState->SystemOptions().GetPlayerBeatFusion())
|
else if (g_GameState->SystemOptions().GetPlayerBeatFusion())
|
||||||
{
|
{
|
||||||
x8_action = EAction::None;
|
//x8_action = EAction::None;
|
||||||
CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
|
CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
|
||||||
//x8_action = EAction::PlayNESMetroid;
|
x8_action = EAction::PlayNESMetroid;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1564,15 +1564,15 @@ bool CFrontEndUI::SNesEmulatorFrame::Update(float dt, CSaveGameScreen* saveUi)
|
||||||
void CFrontEndUI::SNesEmulatorFrame::Draw(CSaveGameScreen* saveUi) const
|
void CFrontEndUI::SNesEmulatorFrame::Draw(CSaveGameScreen* saveUi) const
|
||||||
{
|
{
|
||||||
zeus::CColor mulColor = zeus::CColor::skWhite;
|
zeus::CColor mulColor = zeus::CColor::skWhite;
|
||||||
bool doDraw = (saveUi && saveUi->GetUIType() != CSaveGameScreen::EUIType::SaveReady) ? false : true;
|
bool blackout = saveUi && saveUi->GetUIType() != CSaveGameScreen::EUIType::SaveReady;
|
||||||
|
|
||||||
if (doDraw)
|
if (blackout)
|
||||||
mulColor = zeus::CColor::skBlack;
|
mulColor = zeus::CColor::skBlack;
|
||||||
else if (x8_quitScreen)
|
else if (x8_quitScreen)
|
||||||
mulColor = zeus::CColor{0.376470f, 0.376470f, 0.376470f, 1.f};
|
mulColor = zeus::CColor{0.376470f, 0.376470f, 0.376470f, 1.f};
|
||||||
|
|
||||||
x4_nesEmu->Draw(mulColor, x15_enableFiltering);
|
x4_nesEmu->Draw(mulColor, x15_enableFiltering);
|
||||||
if (!doDraw && x8_quitScreen)
|
if (!blackout && x8_quitScreen)
|
||||||
x8_quitScreen->Draw();
|
x8_quitScreen->Draw();
|
||||||
|
|
||||||
if (x10_remTime >= 7.5f)
|
if (x10_remTime >= 7.5f)
|
||||||
|
@ -2007,7 +2007,7 @@ CFrontEndUI::CFrontEndUI()
|
||||||
m_touchBar = NewFrontEndUITouchBar();
|
m_touchBar = NewFrontEndUITouchBar();
|
||||||
m_touchBar->SetPhase(CFrontEndUITouchBar::EPhase::None);
|
m_touchBar->SetPhase(CFrontEndUITouchBar::EPhase::None);
|
||||||
|
|
||||||
x14_phase = EPhase::ExitFrontEnd;
|
//x14_phase = EPhase::ExitFrontEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrontEndUI::StartSlideShow(CArchitectureQueue& queue)
|
void CFrontEndUI::StartSlideShow(CArchitectureQueue& queue)
|
||||||
|
@ -2533,7 +2533,7 @@ static const float AudioFadeTimeB[] =
|
||||||
|
|
||||||
CIOWin::EMessageReturn CFrontEndUI::Update(float dt, CArchitectureQueue& queue)
|
CIOWin::EMessageReturn CFrontEndUI::Update(float dt, CArchitectureQueue& queue)
|
||||||
{
|
{
|
||||||
if (xdc_saveUI && x50_curScreen >= EScreen::FileSelect)
|
if (xdc_saveUI && (x50_curScreen >= EScreen::FileSelect || true))
|
||||||
{
|
{
|
||||||
switch (xdc_saveUI->Update(dt))
|
switch (xdc_saveUI->Update(dt))
|
||||||
{
|
{
|
||||||
|
@ -2636,6 +2636,11 @@ CIOWin::EMessageReturn CFrontEndUI::Update(float dt, CArchitectureQueue& queue)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xec_emuFrme = std::make_unique<SNesEmulatorFrame>();
|
||||||
|
xdc_saveUI->ResetCardDriver();
|
||||||
|
}
|
||||||
|
|
||||||
if (xd2_deferSlideShow)
|
if (xd2_deferSlideShow)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,7 +11,6 @@ set(MP1_SOURCES
|
||||||
CTweaks.hpp CTweaks.cpp
|
CTweaks.hpp CTweaks.cpp
|
||||||
CInGameTweakManager.hpp CInGameTweakManager.cpp
|
CInGameTweakManager.hpp CInGameTweakManager.cpp
|
||||||
CGBASupport.hpp CGBASupport.cpp
|
CGBASupport.hpp CGBASupport.cpp
|
||||||
CNESEmulator.hpp CNESEmulator.cpp
|
|
||||||
CMainFlow.hpp CMainFlow.cpp
|
CMainFlow.hpp CMainFlow.cpp
|
||||||
CMFGame.hpp CMFGame.cpp
|
CMFGame.hpp CMFGame.cpp
|
||||||
CPlayMovie.hpp CPlayMovie.cpp
|
CPlayMovie.hpp CPlayMovie.cpp
|
||||||
|
|
|
@ -1,228 +0,0 @@
|
||||||
#include "CNESEmulator.hpp"
|
|
||||||
#include "CGameState.hpp"
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
namespace urde::MP1
|
|
||||||
{
|
|
||||||
|
|
||||||
void CNESEmulator::DescrambleROM(u8* dataIn, u8* dataOut, u32 dataOutLen, u8 descrambleInit,
|
|
||||||
u32 descramble2Len, u32 descramble2Magic)
|
|
||||||
{
|
|
||||||
for (int i=0 ; i<256 ; ++i)
|
|
||||||
{
|
|
||||||
descrambleInit += dataIn[i];
|
|
||||||
dataIn[i] = descrambleInit;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0 ; i<128 ; ++i)
|
|
||||||
std::swap(dataIn[255 - i], dataIn[i]);
|
|
||||||
|
|
||||||
struct BitstreamState
|
|
||||||
{
|
|
||||||
u32 x0_remBits = 0;
|
|
||||||
u32 x4_lastByte;
|
|
||||||
u8* x8_ptr;
|
|
||||||
BitstreamState(u8* ptr) : x8_ptr(ptr) {}
|
|
||||||
} bState = {dataIn + 256};
|
|
||||||
|
|
||||||
u8* dataOutAlpha = dataOut;
|
|
||||||
while (dataOutLen != 0)
|
|
||||||
{
|
|
||||||
u32 r12 = 0;
|
|
||||||
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 r11 = r12 << 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r11 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
|
|
||||||
if (r11 == 1)
|
|
||||||
{
|
|
||||||
r12 = 0;
|
|
||||||
|
|
||||||
for (int i=0 ; i<4 ; ++i)
|
|
||||||
{
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dataOutAlpha++ = dataIn[r12 + 73];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r12 = 0;
|
|
||||||
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r11 = r12 << 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r11 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
|
|
||||||
if (r11 == 1)
|
|
||||||
{
|
|
||||||
r12 = 0;
|
|
||||||
|
|
||||||
for (int i=0 ; i<3 ; ++i)
|
|
||||||
{
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dataOutAlpha++ = dataIn[r12 + 9];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r12 = 0;
|
|
||||||
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r11 = r12 << 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r11 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
|
|
||||||
if (r11 == 1)
|
|
||||||
{
|
|
||||||
r12 = 0;
|
|
||||||
|
|
||||||
for (int i=0 ; i<3 ; ++i)
|
|
||||||
{
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dataOutAlpha++ = dataIn[r12 + 1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*dataOutAlpha++ = dataIn[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
--dataOutLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 tmpWord = 0;
|
|
||||||
for (int i=0 ; i<descramble2Len ; ++i)
|
|
||||||
{
|
|
||||||
tmpWord ^= dataOut[i];
|
|
||||||
for (int j=0 ; j<8 ; ++j)
|
|
||||||
{
|
|
||||||
if (tmpWord & 0x1)
|
|
||||||
tmpWord = (tmpWord >> 1) ^ descramble2Magic;
|
|
||||||
else
|
|
||||||
tmpWord = (tmpWord >> 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dataOut[descramble2Len - 1] = (tmpWord >> 8) & 0xff;
|
|
||||||
dataOut[descramble2Len - 2] = tmpWord & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CNESEmulator::ProcessUserInput(const CFinalInput& input, int)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CNESEmulator::Update()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CNESEmulator::Draw(const zeus::CColor& mulColor, bool filtering)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CNESEmulator::LoadState(const u8* state)
|
|
||||||
{
|
|
||||||
memmove(x39_loadState, state, 18);
|
|
||||||
x38_stateLoaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
#ifndef __URDE_CNESEMULATOR_HPP__
|
|
||||||
#define __URDE_CNESEMULATOR_HPP__
|
|
||||||
|
|
||||||
#include "RetroTypes.hpp"
|
|
||||||
#include "zeus/CColor.hpp"
|
|
||||||
|
|
||||||
namespace urde
|
|
||||||
{
|
|
||||||
class CFinalInput;
|
|
||||||
|
|
||||||
namespace MP1
|
|
||||||
{
|
|
||||||
|
|
||||||
class CNESEmulator
|
|
||||||
{
|
|
||||||
bool x20_wantsQuit = false;
|
|
||||||
u8 x21_saveState[18];
|
|
||||||
bool x34_wantsLoad = false;
|
|
||||||
bool x38_stateLoaded = false;
|
|
||||||
u8 x39_loadState[18];
|
|
||||||
static void DescrambleROM(u8* dataIn, u8* dataOut, u32 dataOutLen = 0x20000, u8 descrambleInit = 0xe9,
|
|
||||||
u32 descramble2Len = 0x1FFFC, u32 descramble2Magic = 0xA663);
|
|
||||||
public:
|
|
||||||
void ProcessUserInput(const CFinalInput& input, int);
|
|
||||||
void Update();
|
|
||||||
void Draw(const zeus::CColor& mulColor, bool filtering);
|
|
||||||
void LoadState(const u8* state);
|
|
||||||
const u8* GetSaveState() const { return x21_saveState; }
|
|
||||||
bool WantsQuit() const { return x20_wantsQuit; }
|
|
||||||
bool WantsLoad() const { return x34_wantsLoad; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __URDE_CNESEMULATOR_HPP__
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "Graphics/Shaders/CAABoxShader.hpp"
|
#include "Graphics/Shaders/CAABoxShader.hpp"
|
||||||
#include "Graphics/Shaders/CWorldShadowShader.hpp"
|
#include "Graphics/Shaders/CWorldShadowShader.hpp"
|
||||||
#include "Graphics/Shaders/CParticleSwooshShaders.hpp"
|
#include "Graphics/Shaders/CParticleSwooshShaders.hpp"
|
||||||
|
#include "NESEmulator/CNESShader.hpp"
|
||||||
#include "Audio/CStreamAudioManager.hpp"
|
#include "Audio/CStreamAudioManager.hpp"
|
||||||
#include "CGBASupport.hpp"
|
#include "CGBASupport.hpp"
|
||||||
|
|
||||||
|
@ -297,6 +298,7 @@ CMain::BooSetter::BooSetter(boo::IGraphicsDataFactory* factory,
|
||||||
TMultiBlendShader<CTextSupportShader>::Initialize();
|
TMultiBlendShader<CTextSupportShader>::Initialize();
|
||||||
TMultiBlendShader<CScanLinesFilter>::Initialize();
|
TMultiBlendShader<CScanLinesFilter>::Initialize();
|
||||||
TMultiBlendShader<CRandomStaticFilter>::Initialize();
|
TMultiBlendShader<CRandomStaticFilter>::Initialize();
|
||||||
|
CNESShader::Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMain::RegisterResourceTweaks()
|
void CMain::RegisterResourceTweaks()
|
||||||
|
@ -693,6 +695,7 @@ void CMain::Shutdown()
|
||||||
TMultiBlendShader<CScanLinesFilter>::Shutdown();
|
TMultiBlendShader<CScanLinesFilter>::Shutdown();
|
||||||
TMultiBlendShader<CRandomStaticFilter>::Shutdown();
|
TMultiBlendShader<CRandomStaticFilter>::Shutdown();
|
||||||
CFluidPlaneShader::Shutdown();
|
CFluidPlaneShader::Shutdown();
|
||||||
|
CNESShader::Shutdown();
|
||||||
CGraphics::ShutdownBoo();
|
CGraphics::ShutdownBoo();
|
||||||
ShutdownDiscord();
|
ShutdownDiscord();
|
||||||
}
|
}
|
||||||
|
|
|
@ -326,7 +326,7 @@ void CAuxWeapon::Fire(float dt, bool underwater, CPlayerState::EBeamId currentBe
|
||||||
|
|
||||||
CWeapon::EProjectileAttrib attrib = CWeapon::EProjectileAttrib::None;
|
CWeapon::EProjectileAttrib attrib = CWeapon::EProjectileAttrib::None;
|
||||||
if (chargeState == EChargeState::Charged)
|
if (chargeState == EChargeState::Charged)
|
||||||
attrib = CGameProjectile::GetBeamAttribType(type) | CWeapon::EProjectileAttrib::Unknown1;
|
attrib = CGameProjectile::GetBeamAttribType(type) | CWeapon::EProjectileAttrib::ComboShot;
|
||||||
|
|
||||||
if (chargeState == EChargeState::Normal)
|
if (chargeState == EChargeState::Normal)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,9 +43,6 @@ public:
|
||||||
void DeleteProjectileLight(CStateManager&);
|
void DeleteProjectileLight(CStateManager&);
|
||||||
void CreateProjectileLight(std::string_view, const CLight&, CStateManager&);
|
void CreateProjectileLight(std::string_view, const CLight&, CStateManager&);
|
||||||
void Chase(float, CStateManager&);
|
void Chase(float, CStateManager&);
|
||||||
EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
|
|
||||||
const CWeaponMode&, int) const
|
|
||||||
{ return EWeaponCollisionResponseTypes::Projectile; }
|
|
||||||
TUniqueId GetHomingTargetId() const { return x2c0_homingTargetId; }
|
TUniqueId GetHomingTargetId() const { return x2c0_homingTargetId; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,14 +235,12 @@ void CGunWeapon::Fire(bool underwater, float dt, EChargeState chargeState, const
|
||||||
if (chargeState == EChargeState::Charged)
|
if (chargeState == EChargeState::Charged)
|
||||||
attribs |= CWeapon::EProjectileAttrib::Charged;
|
attribs |= CWeapon::EProjectileAttrib::Charged;
|
||||||
|
|
||||||
/*
|
|
||||||
CEnergyProjectile* proj = new CEnergyProjectile(true, x144_weapons[int(chargeState)], x1c0_weaponType,
|
CEnergyProjectile* proj = new CEnergyProjectile(true, x144_weapons[int(chargeState)], x1c0_weaponType,
|
||||||
xf, x1c8_playerMaterial, dInfo, mgr.AllocateUniqueId(),
|
xf, x1c8_playerMaterial, dInfo, mgr.AllocateUniqueId(),
|
||||||
kInvalidAreaId, x1c4_playerId, homingTarget, attribs,
|
kInvalidAreaId, x1c4_playerId, homingTarget, attribs,
|
||||||
underwater, scale, {}, -1, false);
|
underwater, scale, {}, -1, false);
|
||||||
mgr.AddObject(proj);
|
mgr.AddObject(proj);
|
||||||
proj->Think(dt, mgr);
|
proj->Think(dt, mgr);
|
||||||
*/
|
|
||||||
|
|
||||||
if (chargeState == EChargeState::Charged)
|
if (chargeState == EChargeState::Charged)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "CWeapon.hpp"
|
#include "CWeapon.hpp"
|
||||||
#include "World/CActorParameters.hpp"
|
#include "World/CActorParameters.hpp"
|
||||||
|
#include "World/CScriptWater.hpp"
|
||||||
|
#include "CStateManager.hpp"
|
||||||
#include "TCastTo.hpp"
|
#include "TCastTo.hpp"
|
||||||
|
|
||||||
namespace urde
|
namespace urde
|
||||||
|
@ -10,7 +12,7 @@ CWeapon::CWeapon(TUniqueId uid, TAreaId aid, bool active, TUniqueId owner, EWeap
|
||||||
const CMaterialList& mList, const CDamageInfo&, EProjectileAttrib attribs, CModelData&& mData)
|
const CMaterialList& mList, const CDamageInfo&, EProjectileAttrib attribs, CModelData&& mData)
|
||||||
: CActor(uid, active, name, CEntityInfo(aid, CEntity::NullConnectionList), xf, std::move(mData), mList,
|
: CActor(uid, active, name, CEntityInfo(aid, CEntity::NullConnectionList), xf, std::move(mData), mList,
|
||||||
CActorParameters::None(), kInvalidUniqueId)
|
CActorParameters::None(), kInvalidUniqueId)
|
||||||
, xf8_(filter)
|
, xf8_filter(filter)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,4 +21,93 @@ void CWeapon::Accept(urde::IVisitor& visitor)
|
||||||
visitor.Visit(this);
|
visitor.Visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CWeapon::Think(float dt, CStateManager& mgr)
|
||||||
|
{
|
||||||
|
x148_curTime += dt;
|
||||||
|
if ((xe8_projectileAttribs & EProjectileAttrib::DamageFalloff) == EProjectileAttrib::DamageFalloff)
|
||||||
|
{
|
||||||
|
float damMul = std::max(0.f, 1.f - x148_curTime * x14c_damageFalloffSpeed);
|
||||||
|
x12c_curDamageInfo.SetDamage(x110_origDamageInfo.GetDamage() * damMul);
|
||||||
|
x12c_curDamageInfo.SetRadius(x110_origDamageInfo.GetRadius() * damMul);
|
||||||
|
x12c_curDamageInfo.SetKnockBackPower(x110_origDamageInfo.GetKnockBackPower() * damMul);
|
||||||
|
x12c_curDamageInfo.SetWeaponMode(x110_origDamageInfo.GetWeaponMode());
|
||||||
|
x12c_curDamageInfo.SetNoImmunity(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x12c_curDamageInfo = x110_origDamageInfo;
|
||||||
|
}
|
||||||
|
CEntity::Think(dt, mgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWeapon::Render(const CStateManager&) const
|
||||||
|
{
|
||||||
|
// Empty
|
||||||
|
}
|
||||||
|
|
||||||
|
EWeaponCollisionResponseTypes CWeapon::GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
|
||||||
|
const CWeaponMode&, int) const
|
||||||
|
{
|
||||||
|
return EWeaponCollisionResponseTypes::Projectile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWeapon::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager& mgr)
|
||||||
|
{
|
||||||
|
bool doRipple = true;
|
||||||
|
float mag = 0.f;
|
||||||
|
switch (xf0_weaponType)
|
||||||
|
{
|
||||||
|
case EWeaponType::Power:
|
||||||
|
mag = 0.1f;
|
||||||
|
break;
|
||||||
|
case EWeaponType::Ice:
|
||||||
|
mag = 0.3f;
|
||||||
|
break;
|
||||||
|
case EWeaponType::Wave:
|
||||||
|
mag = 0.1f;
|
||||||
|
break;
|
||||||
|
case EWeaponType::Plasma:
|
||||||
|
break;
|
||||||
|
case EWeaponType::Missile:
|
||||||
|
mag = 0.5f;
|
||||||
|
break;
|
||||||
|
case EWeaponType::Phazon:
|
||||||
|
mag = 0.1f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
doRipple = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::None &&
|
||||||
|
state != EFluidState::InFluid)
|
||||||
|
mag += 0.5f;
|
||||||
|
if ((xe8_projectileAttribs & EProjectileAttrib::Charged) != EProjectileAttrib::None)
|
||||||
|
mag += 0.25f;
|
||||||
|
if (mag > 1.f)
|
||||||
|
mag = 1.f;
|
||||||
|
|
||||||
|
if (doRipple)
|
||||||
|
{
|
||||||
|
zeus::CVector3f pos = GetTranslation();
|
||||||
|
pos.z = water.GetTriggerBoundsWR().max.z;
|
||||||
|
if ((xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::None)
|
||||||
|
{
|
||||||
|
if (!water.CanRippleAtPoint(pos))
|
||||||
|
doRipple = false;
|
||||||
|
}
|
||||||
|
else if (state == EFluidState::InFluid)
|
||||||
|
{
|
||||||
|
doRipple = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doRipple)
|
||||||
|
{
|
||||||
|
water.GetFluidPlane().AddRipple(mag, x8_uid, pos, water, mgr);
|
||||||
|
mgr.GetFluidPlaneManager()->CreateSplash(x8_uid, mgr, water, pos, mag,
|
||||||
|
state == EFluidState::EnteredFluid || state == EFluidState::LeftFluid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,12 @@ public:
|
||||||
Wave = (1 << 4),
|
Wave = (1 << 4),
|
||||||
Plasma = (1 << 5),
|
Plasma = (1 << 5),
|
||||||
Phazon = (1 << 6),
|
Phazon = (1 << 6),
|
||||||
Unknown1 = (1 << 7),
|
ComboShot = (1 << 7),
|
||||||
Bombs = (1 << 8),
|
Bombs = (1 << 8),
|
||||||
PowerBombs = (1 << 9),
|
PowerBombs = (1 << 9),
|
||||||
ArmCannon = (1 << 11),
|
ArmCannon = (1 << 11),
|
||||||
BigStrike = (1 << 12),
|
BigStrike = (1 << 12),
|
||||||
|
DamageFalloff = (1 << 13),
|
||||||
StaticInterference = (1 << 14),
|
StaticInterference = (1 << 14),
|
||||||
KeepInCinematic = (1 << 17),
|
KeepInCinematic = (1 << 17),
|
||||||
};
|
};
|
||||||
|
@ -35,12 +36,12 @@ private:
|
||||||
TUniqueId xec_ownerId;
|
TUniqueId xec_ownerId;
|
||||||
EWeaponType xf0_weaponType;
|
EWeaponType xf0_weaponType;
|
||||||
u32 xf4_;
|
u32 xf4_;
|
||||||
CMaterialFilter xf8_;
|
CMaterialFilter xf8_filter;
|
||||||
u32 x10c_;
|
u32 x10c_;
|
||||||
CDamageInfo x110_;
|
CDamageInfo x110_origDamageInfo;
|
||||||
CDamageInfo x12c_;
|
CDamageInfo x12c_curDamageInfo;
|
||||||
float x148_;
|
float x148_curTime;
|
||||||
float x14c_;
|
float x14c_damageFalloffSpeed;
|
||||||
float x150_damageDuration;
|
float x150_damageDuration;
|
||||||
float x154_interferenceDuration;
|
float x154_interferenceDuration;
|
||||||
public:
|
public:
|
||||||
|
@ -49,27 +50,25 @@ public:
|
||||||
const CMaterialList& mList, const CDamageInfo&, EProjectileAttrib attribs, CModelData&& mData);
|
const CMaterialList& mList, const CDamageInfo&, EProjectileAttrib attribs, CModelData&& mData);
|
||||||
|
|
||||||
virtual void Accept(IVisitor &visitor);
|
virtual void Accept(IVisitor &visitor);
|
||||||
bool HasAttrib(EProjectileAttrib) const;
|
bool HasAttrib(EProjectileAttrib attrib) const
|
||||||
|
{ return (int(xe8_projectileAttribs) & int(attrib)) == int(attrib); }
|
||||||
EProjectileAttrib GetAttribField() const { return xe8_projectileAttribs; }
|
EProjectileAttrib GetAttribField() const { return xe8_projectileAttribs; }
|
||||||
const CMaterialFilter& GetFilter() const;
|
const CMaterialFilter& GetFilter() const { return xf8_filter; }
|
||||||
void SetFilter(const CMaterialFilter&);
|
void SetFilter(const CMaterialFilter& filter) { xf8_filter = filter; }
|
||||||
TUniqueId GetOwnerId() const { return xec_ownerId; }
|
TUniqueId GetOwnerId() const { return xec_ownerId; }
|
||||||
void SetOwnerId(TUniqueId oid) { xec_ownerId = oid; }
|
void SetOwnerId(TUniqueId oid) { xec_ownerId = oid; }
|
||||||
EWeaponType GetType() const;
|
EWeaponType GetType() const { return xf0_weaponType; }
|
||||||
const CDamageInfo& GetDamageInfo() const;
|
const CDamageInfo& GetDamageInfo() const { return x12c_curDamageInfo; }
|
||||||
CDamageInfo& DamageInfo();
|
CDamageInfo& DamageInfo() { return x12c_curDamageInfo; }
|
||||||
void SetDamageInfo(const CDamageInfo&);
|
void SetDamageInfo(const CDamageInfo& dInfo) { x12c_curDamageInfo = dInfo; }
|
||||||
float GetDamageDuration() const { return x150_damageDuration; }
|
float GetDamageDuration() const { return x150_damageDuration; }
|
||||||
float GetInterferenceDuration() const { return x154_interferenceDuration; }
|
float GetInterferenceDuration() const { return x154_interferenceDuration; }
|
||||||
|
|
||||||
void Think(float, CStateManager &) {}
|
void Think(float, CStateManager &);
|
||||||
void Render(const CStateManager&) const {}
|
void Render(const CStateManager&) const;
|
||||||
EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
|
EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
|
||||||
const CWeaponMode&, int) const
|
const CWeaponMode&, int) const;
|
||||||
{
|
void FluidFXThink(EFluidState state, CScriptWater& water, CStateManager& mgr);
|
||||||
return EWeaponCollisionResponseTypes::Default;
|
|
||||||
}
|
|
||||||
void FluidFXThink(EFluidState, CScriptWater&, CStateManager&) {}
|
|
||||||
};
|
};
|
||||||
ENABLE_BITWISE_ENUM(CWeapon::EProjectileAttrib)
|
ENABLE_BITWISE_ENUM(CWeapon::EProjectileAttrib)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,14 +43,18 @@ public:
|
||||||
CDamageInfo& operator=(const DataSpec::SShotParam& other);
|
CDamageInfo& operator=(const DataSpec::SShotParam& other);
|
||||||
|
|
||||||
const CWeaponMode& GetWeaponMode() const { return x0_weaponMode; }
|
const CWeaponMode& GetWeaponMode() const { return x0_weaponMode; }
|
||||||
|
void SetWeaponMode(const CWeaponMode& mode) { x0_weaponMode = mode; }
|
||||||
float GetRadius() const { return x10_radius; }
|
float GetRadius() const { return x10_radius; }
|
||||||
void SetRadius(float r) { x10_radius = r; }
|
void SetRadius(float r) { x10_radius = r; }
|
||||||
float GetKnockBackPower() const { return x14_knockback; }
|
float GetKnockBackPower() const { return x14_knockback; }
|
||||||
|
void SetKnockBackPower(float k) { x14_knockback = k; }
|
||||||
float GetDamage() const { return x8_damage; }
|
float GetDamage() const { return x8_damage; }
|
||||||
|
void SetDamage(float d) { x8_damage = d; }
|
||||||
float GetDamage(const CDamageVulnerability& dVuln) const;
|
float GetDamage(const CDamageVulnerability& dVuln) const;
|
||||||
float GetRadiusDamage() const { return xc_radiusDamage; }
|
float GetRadiusDamage() const { return xc_radiusDamage; }
|
||||||
float GetRadiusDamage(const CDamageVulnerability& dVuln) const;
|
float GetRadiusDamage(const CDamageVulnerability& dVuln) const;
|
||||||
bool NoImmunity() const { return x18_noImmunity; }
|
bool NoImmunity() const { return x18_noImmunity; }
|
||||||
|
void SetNoImmunity(bool b) { x18_noImmunity = b; }
|
||||||
void MultiplyDamage(float m)
|
void MultiplyDamage(float m)
|
||||||
{
|
{
|
||||||
x8_damage *= m;
|
x8_damage *= m;
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
#include "CFluidPlaneManager.hpp"
|
#include "CFluidPlaneManager.hpp"
|
||||||
|
#include "CScriptWater.hpp"
|
||||||
|
#include "CExplosion.hpp"
|
||||||
|
#include "CStateManager.hpp"
|
||||||
|
|
||||||
namespace urde
|
namespace urde
|
||||||
{
|
{
|
||||||
|
@ -14,7 +17,11 @@ CFluidPlaneManager::CFluidPlaneManager()
|
||||||
|
|
||||||
void CFluidPlaneManager::CFluidProfile::Clear()
|
void CFluidPlaneManager::CFluidProfile::Clear()
|
||||||
{
|
{
|
||||||
|
x0_ = 0.f;
|
||||||
|
x4_ = 0.f;
|
||||||
|
x8_ = 0.f;
|
||||||
|
xc_ = 0.f;
|
||||||
|
x10_ = 0.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFluidPlaneManager::StartFrame(bool b)
|
void CFluidPlaneManager::StartFrame(bool b)
|
||||||
|
@ -25,7 +32,14 @@ void CFluidPlaneManager::StartFrame(bool b)
|
||||||
|
|
||||||
void CFluidPlaneManager::Update(float dt)
|
void CFluidPlaneManager::Update(float dt)
|
||||||
{
|
{
|
||||||
|
x11c_uvT += dt;
|
||||||
|
x0_rippleManager.Update(dt);
|
||||||
|
for (CSplashRecord& record : x18_splashes)
|
||||||
|
{
|
||||||
|
record.SetTime(record.GetTime() + dt);
|
||||||
|
if (record.GetTime() > 9999.f)
|
||||||
|
record.SetTime(9999.f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float CFluidPlaneManager::GetLastRippleDeltaTime(TUniqueId rippler) const
|
float CFluidPlaneManager::GetLastRippleDeltaTime(TUniqueId rippler) const
|
||||||
|
@ -35,13 +49,47 @@ float CFluidPlaneManager::GetLastRippleDeltaTime(TUniqueId rippler) const
|
||||||
|
|
||||||
float CFluidPlaneManager::GetLastSplashDeltaTime(TUniqueId splasher) const
|
float CFluidPlaneManager::GetLastSplashDeltaTime(TUniqueId splasher) const
|
||||||
{
|
{
|
||||||
return 0.f;
|
float newestTime = 9999.f;
|
||||||
|
for (const CSplashRecord& record : x18_splashes)
|
||||||
|
if (record.GetUniqueId() == splasher && newestTime > record.GetTime())
|
||||||
|
newestTime = record.GetTime();
|
||||||
|
return newestTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFluidPlaneManager::CreateSplash(TUniqueId splasher, CStateManager& mgr, const CScriptWater& water,
|
void CFluidPlaneManager::CreateSplash(TUniqueId splasher, CStateManager& mgr, const CScriptWater& water,
|
||||||
const zeus::CVector3f& pos, float factor, bool)
|
const zeus::CVector3f& pos, float factor, bool sfx)
|
||||||
{
|
{
|
||||||
|
if (water.CanRippleAtPoint(pos))
|
||||||
|
{
|
||||||
|
float oldestTime = 0.f;
|
||||||
|
CSplashRecord* oldestRecord = nullptr;
|
||||||
|
for (CSplashRecord& record : x18_splashes)
|
||||||
|
{
|
||||||
|
if (record.GetTime() > oldestTime)
|
||||||
|
{
|
||||||
|
oldestRecord = &record;
|
||||||
|
oldestTime = record.GetTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldestRecord)
|
||||||
|
*oldestRecord = CSplashRecord(0.f, splasher);
|
||||||
|
else
|
||||||
|
x18_splashes.emplace_back(0.f, splasher);
|
||||||
|
float splashScale = water.GetSplashEffectScale(factor);
|
||||||
|
if (water.GetSplashEffect(factor))
|
||||||
|
{
|
||||||
|
CExplosion* expl = new CExplosion(*water.GetSplashEffect(factor), mgr.AllocateUniqueId(), true,
|
||||||
|
CEntityInfo(water.GetAreaIdAlways(), CEntity::NullConnectionList),
|
||||||
|
"Splash", zeus::CTransform(zeus::CMatrix3f::skIdentityMatrix3f, pos),
|
||||||
|
1, zeus::CVector3f{splashScale}, water.GetSplashColor());
|
||||||
|
mgr.AddObject(expl);
|
||||||
|
}
|
||||||
|
if (sfx)
|
||||||
|
{
|
||||||
|
CSfxManager::AddEmitter(water.GetSplashSound(factor), pos, zeus::CVector3f::skUp,
|
||||||
|
true, false, 0x7f, kInvalidAreaId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 CFluidPlaneManager::RippleValues[64][64] = {};
|
u8 CFluidPlaneManager::RippleValues[64][64] = {};
|
||||||
|
|
|
@ -13,11 +13,14 @@ class CFluidPlaneManager
|
||||||
{
|
{
|
||||||
class CSplashRecord
|
class CSplashRecord
|
||||||
{
|
{
|
||||||
|
float x0_time = 0.f;
|
||||||
|
TUniqueId x4_id;
|
||||||
public:
|
public:
|
||||||
CSplashRecord(TUniqueId id);
|
CSplashRecord(float time, TUniqueId id) : x0_time(time), x4_id(id) {}
|
||||||
void SetTime(float t);
|
void SetTime(float t) { x0_time = t; }
|
||||||
float GetTime() const;
|
float GetTime() const { return x0_time; }
|
||||||
TUniqueId GetUniqueId() const;
|
void SetUniqueId(TUniqueId id) { x4_id = id; }
|
||||||
|
TUniqueId GetUniqueId() const { return x4_id; }
|
||||||
};
|
};
|
||||||
|
|
||||||
CRippleManager x0_rippleManager;
|
CRippleManager x0_rippleManager;
|
||||||
|
@ -28,6 +31,11 @@ class CFluidPlaneManager
|
||||||
|
|
||||||
class CFluidProfile
|
class CFluidProfile
|
||||||
{
|
{
|
||||||
|
float x0_ = 0.f;
|
||||||
|
float x4_ = 0.f;
|
||||||
|
float x8_ = 0.f;
|
||||||
|
float xc_ = 0.f;
|
||||||
|
float x10_ = 0.f;
|
||||||
public:
|
public:
|
||||||
void Clear();
|
void Clear();
|
||||||
};
|
};
|
||||||
|
@ -46,7 +54,7 @@ public:
|
||||||
float GetLastRippleDeltaTime(TUniqueId rippler) const;
|
float GetLastRippleDeltaTime(TUniqueId rippler) const;
|
||||||
float GetLastSplashDeltaTime(TUniqueId splasher) const;
|
float GetLastSplashDeltaTime(TUniqueId splasher) const;
|
||||||
void CreateSplash(TUniqueId splasher, CStateManager& mgr, const CScriptWater& water,
|
void CreateSplash(TUniqueId splasher, CStateManager& mgr, const CScriptWater& water,
|
||||||
const zeus::CVector3f& pos, float factor, bool);
|
const zeus::CVector3f& pos, float factor, bool sfx);
|
||||||
rstl::reserved_vector<CSplashRecord, 32>& SplashRecords() { return x18_splashes; }
|
rstl::reserved_vector<CSplashRecord, 32>& SplashRecords() { return x18_splashes; }
|
||||||
const CRippleManager& GetRippleManager() const { return x0_rippleManager; }
|
const CRippleManager& GetRippleManager() const { return x0_rippleManager; }
|
||||||
CRippleManager& RippleManager() { return x0_rippleManager; }
|
CRippleManager& RippleManager() { return x0_rippleManager; }
|
||||||
|
|
|
@ -23,7 +23,12 @@ void CRippleManager::SetTime(float)
|
||||||
|
|
||||||
void CRippleManager::Update(float dt)
|
void CRippleManager::Update(float dt)
|
||||||
{
|
{
|
||||||
|
for (CRipple& ripple : x4_ripples)
|
||||||
|
{
|
||||||
|
ripple.SetTime(ripple.GetTime() + dt);
|
||||||
|
if (ripple.GetTime() > 9999.f)
|
||||||
|
ripple.SetTime(9999.f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float CRippleManager::GetLastRippleDeltaTime(TUniqueId rippler) const
|
float CRippleManager::GetLastRippleDeltaTime(TUniqueId rippler) const
|
||||||
|
|
|
@ -552,14 +552,14 @@ EWeaponCollisionResponseTypes CScriptWater::GetCollisionResponseType(const zeus:
|
||||||
return EWeaponCollisionResponseTypes::Water;
|
return EWeaponCollisionResponseTypes::Water;
|
||||||
}
|
}
|
||||||
|
|
||||||
s16 CScriptWater::GetSplashSound(float dt) const
|
u16 CScriptWater::GetSplashSound(float mag) const
|
||||||
{
|
{
|
||||||
return x298_splashSounds[GetSplashIndex(dt)];
|
return x298_splashSounds[GetSplashIndex(mag)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::experimental::optional<TLockedToken<CGenDescription>>& CScriptWater::GetSplashEffect(float dt) const
|
const std::experimental::optional<TLockedToken<CGenDescription>>& CScriptWater::GetSplashEffect(float mag) const
|
||||||
{
|
{
|
||||||
return x264_splashEffects[GetSplashIndex(dt)];
|
return x264_splashEffects[GetSplashIndex(mag)];
|
||||||
}
|
}
|
||||||
|
|
||||||
float CScriptWater::GetSplashEffectScale(float dt) const
|
float CScriptWater::GetSplashEffectScale(float dt) const
|
||||||
|
@ -572,9 +572,9 @@ float CScriptWater::GetSplashEffectScale(float dt) const
|
||||||
return ((1.f - s) * (s * kSplashScales[idx * 2])) + kSplashScales[idx];
|
return ((1.f - s) * (s * kSplashScales[idx * 2])) + kSplashScales[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CScriptWater::GetSplashIndex(float dt) const
|
u32 CScriptWater::GetSplashIndex(float mag) const
|
||||||
{
|
{
|
||||||
auto idx = u32(dt * 3.f);
|
auto idx = u32(mag * 3.f);
|
||||||
return (idx < 3 ? idx : idx - 1);
|
return (idx < 3 ? idx : idx - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ public:
|
||||||
EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
|
EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
|
||||||
const CWeaponMode&, int) const;
|
const CWeaponMode&, int) const;
|
||||||
|
|
||||||
s16 GetSplashSound(float) const;
|
u16 GetSplashSound(float) const;
|
||||||
const std::experimental::optional<TLockedToken<CGenDescription>>& GetSplashEffect(float) const;
|
const std::experimental::optional<TLockedToken<CGenDescription>>& GetSplashEffect(float) const;
|
||||||
float GetSplashEffectScale(float) const;
|
float GetSplashEffectScale(float) const;
|
||||||
u32 GetSplashIndex(float) const;
|
u32 GetSplashIndex(float) const;
|
||||||
|
|
2
hecl
2
hecl
|
@ -1 +1 @@
|
||||||
Subproject commit 2490ec82ae2ee1777852fa5322fdf244913cbc7b
|
Subproject commit 3454e81f97ae951b85cd4a9e18bb800f6123163e
|
Loading…
Reference in New Issue