2024-01-10 18:48:57 +00:00
|
|
|
#pragma once
|
|
|
|
|
2024-03-06 15:21:04 +00:00
|
|
|
#include "jaffarCommon/serializers/contiguous.hpp"
|
|
|
|
#include "jaffarCommon/serializers/differential.hpp"
|
|
|
|
#include "jaffarCommon/logger.hpp"
|
2024-01-28 15:02:58 +00:00
|
|
|
#include "controller.hpp"
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
// Size of image generated in graphics buffer
|
2024-01-20 10:21:34 +00:00
|
|
|
static const uint16_t image_width = 256;
|
|
|
|
static const uint16_t image_height = 240;
|
2024-01-15 19:56:58 +00:00
|
|
|
|
2024-01-28 15:02:58 +00:00
|
|
|
class NESInstanceBase
|
2024-01-10 18:48:57 +00:00
|
|
|
{
|
2024-01-20 10:21:34 +00:00
|
|
|
public:
|
|
|
|
|
2024-01-28 15:02:58 +00:00
|
|
|
NESInstanceBase() = default;
|
|
|
|
virtual ~NESInstanceBase() = default;
|
2024-01-20 10:21:34 +00:00
|
|
|
|
2024-07-21 13:11:25 +00:00
|
|
|
inline void advanceState(const std::string &input)
|
2024-01-20 10:21:34 +00:00
|
|
|
{
|
2024-07-21 13:11:25 +00:00
|
|
|
// Storage for the decoded input
|
|
|
|
quickNES::Controller::input_t decodedInput;
|
|
|
|
|
|
|
|
// Getting decoded input from the input string
|
|
|
|
decodeInput(input, &decodedInput);
|
|
|
|
|
|
|
|
// Calling advance state with the decoded input
|
|
|
|
advanceState(&decodedInput);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void advanceState(const void* decodedInputBuffer)
|
|
|
|
{
|
|
|
|
// Casting decoded input to the right type
|
|
|
|
const auto decodedInput = (quickNES::Controller::input_t*) decodedInputBuffer;
|
2024-01-21 14:34:15 +00:00
|
|
|
|
|
|
|
// Parsing power
|
2024-07-21 13:11:25 +00:00
|
|
|
if (decodedInput->power == true) JAFFAR_THROW_LOGIC("Power button pressed, but not supported.");
|
2024-01-21 14:34:15 +00:00
|
|
|
|
|
|
|
// Parsing reset
|
2024-07-21 13:11:25 +00:00
|
|
|
if (decodedInput->reset == true) doSoftReset();
|
2024-01-21 14:34:15 +00:00
|
|
|
|
2024-07-21 13:11:25 +00:00
|
|
|
// Running specified inputs
|
|
|
|
advanceStateImpl(decodedInput->port1, decodedInput->port2);
|
|
|
|
}
|
2024-01-21 14:34:15 +00:00
|
|
|
|
2024-07-21 13:11:25 +00:00
|
|
|
inline size_t getDecodedInputSize() const
|
|
|
|
{
|
|
|
|
return sizeof(quickNES::Controller::input_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void decodeInput(const std::string &input, void* decodedInputBuffer) const
|
|
|
|
{
|
|
|
|
const auto decodedInput = (quickNES::Controller::input_t*) decodedInputBuffer;
|
|
|
|
bool isInputValid = _controller.parseInputString(input, decodedInput);
|
|
|
|
if (isInputValid == false) JAFFAR_THROW_LOGIC("Move provided cannot be parsed: '%s'\n", input.c_str());
|
2024-01-20 10:21:34 +00:00
|
|
|
}
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-21 14:34:15 +00:00
|
|
|
inline void setController1Type(const std::string& type)
|
2024-01-20 10:21:34 +00:00
|
|
|
{
|
2024-01-21 14:34:15 +00:00
|
|
|
bool isTypeRecognized = false;
|
|
|
|
|
2024-03-19 18:47:30 +00:00
|
|
|
if (type == "None") { _controller.setController1Type(quickNES::Controller::controller_t::none); isTypeRecognized = true; }
|
|
|
|
if (type == "Joypad") { _controller.setController1Type(quickNES::Controller::controller_t::joypad); isTypeRecognized = true; }
|
|
|
|
if (type == "FourScore1") { _controller.setController1Type(quickNES::Controller::controller_t::fourscore1); isTypeRecognized = true; }
|
|
|
|
if (type == "FourScore2") { _controller.setController1Type(quickNES::Controller::controller_t::fourscore2); isTypeRecognized = true; }
|
2024-01-21 14:34:15 +00:00
|
|
|
|
2024-03-06 15:21:04 +00:00
|
|
|
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Input type not recognized: '%s'\n", type.c_str());
|
2024-01-20 10:21:34 +00:00
|
|
|
}
|
2024-01-10 19:11:49 +00:00
|
|
|
|
2024-01-21 14:34:15 +00:00
|
|
|
inline void setController2Type(const std::string& type)
|
2024-01-20 10:21:34 +00:00
|
|
|
{
|
2024-01-21 14:34:15 +00:00
|
|
|
bool isTypeRecognized = false;
|
|
|
|
|
2024-03-19 18:47:30 +00:00
|
|
|
if (type == "None") { _controller.setController2Type(quickNES::Controller::controller_t::none); isTypeRecognized = true; }
|
|
|
|
if (type == "Joypad") { _controller.setController2Type(quickNES::Controller::controller_t::joypad); isTypeRecognized = true; }
|
|
|
|
if (type == "FourScore1") { _controller.setController2Type(quickNES::Controller::controller_t::fourscore1); isTypeRecognized = true; }
|
|
|
|
if (type == "FourScore2") { _controller.setController2Type(quickNES::Controller::controller_t::fourscore2); isTypeRecognized = true; }
|
2024-01-21 14:34:15 +00:00
|
|
|
|
2024-03-06 15:21:04 +00:00
|
|
|
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Input type not recognized: '%s'\n", type.c_str());
|
2024-01-20 10:21:34 +00:00
|
|
|
}
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-20 10:21:34 +00:00
|
|
|
inline void enableRendering() { _doRendering = true; };
|
|
|
|
inline void disableRendering() { _doRendering = false; };
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-28 15:02:58 +00:00
|
|
|
inline bool loadROM(const uint8_t* romData, const size_t romSize)
|
2024-01-20 10:21:34 +00:00
|
|
|
{
|
|
|
|
// Actually loading rom file
|
2024-01-28 15:02:58 +00:00
|
|
|
auto status = loadROMImpl(romData, romSize);
|
2024-01-20 10:21:34 +00:00
|
|
|
|
|
|
|
// Detecting full state size
|
2024-02-09 19:43:42 +00:00
|
|
|
_stateSize = getFullStateSize();
|
2024-01-28 15:02:58 +00:00
|
|
|
|
|
|
|
// Returning status
|
|
|
|
return status;
|
2024-01-27 19:02:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void enableStateBlock(const std::string& block)
|
|
|
|
{
|
|
|
|
// Calling implementation
|
|
|
|
enableStateBlockImpl(block);
|
|
|
|
|
|
|
|
// Recalculating State size
|
2024-02-09 19:43:42 +00:00
|
|
|
_stateSize = getFullStateSize();
|
2024-01-27 19:02:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void disableStateBlock(const std::string& block)
|
|
|
|
{
|
|
|
|
// Calling implementation
|
|
|
|
disableStateBlockImpl(block);
|
2024-01-20 10:21:34 +00:00
|
|
|
|
2024-01-27 19:02:05 +00:00
|
|
|
// Recalculating State Size
|
2024-02-09 19:43:42 +00:00
|
|
|
_stateSize = getFullStateSize();
|
2024-01-20 10:21:34 +00:00
|
|
|
}
|
|
|
|
|
2024-02-09 19:43:42 +00:00
|
|
|
virtual size_t getFullStateSize() const = 0;
|
|
|
|
virtual size_t getDifferentialStateSize() const = 0;
|
|
|
|
|
2024-01-20 10:21:34 +00:00
|
|
|
// Virtual functions
|
|
|
|
|
2024-01-29 18:47:52 +00:00
|
|
|
virtual uint8_t *getLowMem() const = 0;
|
|
|
|
virtual size_t getLowMemSize() const = 0;
|
2024-01-28 18:57:24 +00:00
|
|
|
|
2024-02-09 19:43:42 +00:00
|
|
|
virtual void serializeState(jaffarCommon::serializer::Base& serializer) const = 0;
|
|
|
|
virtual void deserializeState(jaffarCommon::deserializer::Base& deserializer) = 0;
|
2024-02-06 16:54:39 +00:00
|
|
|
|
2024-01-20 10:21:34 +00:00
|
|
|
virtual void doSoftReset() = 0;
|
|
|
|
virtual void doHardReset() = 0;
|
|
|
|
virtual std::string getCoreName() const = 0;
|
2024-01-28 18:57:24 +00:00
|
|
|
virtual void *getInternalEmulatorPointer() = 0;
|
2024-07-13 12:09:11 +00:00
|
|
|
virtual void setNTABBlockSize(const size_t size) { };
|
2024-01-20 10:21:34 +00:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
2024-01-27 19:02:05 +00:00
|
|
|
virtual void enableStateBlockImpl(const std::string& block) = 0;
|
|
|
|
virtual void disableStateBlockImpl(const std::string& block) = 0;
|
2024-01-28 15:02:58 +00:00
|
|
|
virtual bool loadROMImpl(const uint8_t* romData, const size_t romSize) = 0;
|
2024-03-19 18:47:30 +00:00
|
|
|
virtual void advanceStateImpl(const quickNES::Controller::port_t controller1, const quickNES::Controller::port_t controller2) = 0;
|
2024-01-20 10:21:34 +00:00
|
|
|
|
2024-01-27 19:02:05 +00:00
|
|
|
// Storage for the light state size
|
|
|
|
size_t _stateSize;
|
2024-01-20 10:21:34 +00:00
|
|
|
|
|
|
|
// Flag to determine whether to enable/disable rendering
|
|
|
|
bool _doRendering = true;
|
|
|
|
|
|
|
|
private:
|
2024-01-21 14:34:15 +00:00
|
|
|
|
|
|
|
// Controller class for input parsing
|
2024-03-19 18:47:30 +00:00
|
|
|
quickNES::Controller _controller;
|
2024-01-10 18:48:57 +00:00
|
|
|
};
|