Adding simulated netboard; all linked games except Sega Rally 2 working at full speed.

This commit is contained in:
Matthew Daniels 2021-04-14 01:20:45 +00:00
parent 98d4f1c6f6
commit 5a570ce7fe
19 changed files with 1389 additions and 657 deletions

View file

@ -34,11 +34,12 @@
[ Global ] ; Input settings can only be read from the global section! [ Global ] ; Input settings can only be read from the global section!
; Network board - experimental build for win32 only ; Network board
EmulateNet = 0 Network = 0
port_in = 1970 SimulateNet = 1
port_out = 1971 PortIn = 1970
addr_out = "127.0.0.1" PortOut = 1971
AddressOut = "127.0.0.1"
; Common ; Common
InputStart1 = "KEY_1,JOY1_BUTTON9" InputStart1 = "KEY_1,JOY1_BUTTON9"

View file

@ -169,7 +169,8 @@ ifeq ($(strip $(NET_BOARD)),1)
SRC_FILES += \ SRC_FILES += \
Src/Network/TCPReceive.cpp \ Src/Network/TCPReceive.cpp \
Src/Network/TCPSend.cpp \ Src/Network/TCPSend.cpp \
Src/Network/NetBoard.cpp Src/Network/NetBoard.cpp \
Src/Network/SimNetBoard.cpp
endif endif
ifeq ($(strip $(ENABLE_DEBUGGER)),1) ifeq ($(strip $(ENABLE_DEBUGGER)),1)

View file

@ -30,6 +30,9 @@
#include "ConsoleDebugger.h" #include "ConsoleDebugger.h"
#include "CPUDebug.h" #include "CPUDebug.h"
#include "Label.h" #include "Label.h"
#ifdef NET_BOARD
#include "Network/NetBoard.h"
#endif // NET_BOARD
#include <cstdio> #include <cstdio>
#include <string> #include <string>
@ -302,7 +305,9 @@ namespace Debugger
#ifdef NET_BOARD #ifdef NET_BOARD
CCPUDebug *CSupermodelDebugger::CreateNetBoardCPUDebug(::CModel3 * model3) CCPUDebug *CSupermodelDebugger::CreateNetBoardCPUDebug(::CModel3 * model3)
{ {
CNetBoard *netBrd = model3->GetNetBoard(); CNetBoard *netBrd = dynamic_cast<CNetBoard*>(model3->GetNetBoard());
if (!netBrd)
return NULL;
if (!netBrd->IsAttached()) if (!netBrd->IsAttached())
return NULL; return NULL;
CMusashi68KDebug *cpu = new CMusashi68KDebug("NET68K", netBrd->GetM68K()); CMusashi68KDebug *cpu = new CMusashi68KDebug("NET68K", netBrd->GetM68K());

View file

@ -18,7 +18,7 @@ struct Game
uint32_t real3d_pci_id = 0; // overrides default Real3D PCI ID for stepping (0 for default) uint32_t real3d_pci_id = 0; // overrides default Real3D PCI ID for stepping (0 for default)
float real3d_status_bit_set_percent_of_frame = 0; // overrides default status bit timing (0 for default) float real3d_status_bit_set_percent_of_frame = 0; // overrides default status bit timing (0 for default)
uint32_t encryption_key = 0; uint32_t encryption_key = 0;
std::string netboard_present; bool netboard_present;
enum Inputs enum Inputs
{ {

View file

@ -202,7 +202,7 @@ static void PopulateGameInfo(Game *game, const Util::Config::Node &game_node)
game->real3d_pci_id = game_node["hardware/real3d_pci_id"].ValueAsDefault<uint32_t>(0); game->real3d_pci_id = game_node["hardware/real3d_pci_id"].ValueAsDefault<uint32_t>(0);
game->real3d_status_bit_set_percent_of_frame = game_node["hardware/real3d_status_bit_set_percent_of_frame"].ValueAsDefault<float>(0); game->real3d_status_bit_set_percent_of_frame = game_node["hardware/real3d_status_bit_set_percent_of_frame"].ValueAsDefault<float>(0);
game->encryption_key = game_node["hardware/encryption_key"].ValueAsDefault<uint32_t>(0); game->encryption_key = game_node["hardware/encryption_key"].ValueAsDefault<uint32_t>(0);
game->netboard_present = game_node["hardware/netboard"].ValueAsDefault<std::string>("false"); game->netboard_present = game_node["hardware/netboard"].ValueAsDefault<bool>("false");
std::map<std::string, uint32_t> input_flags std::map<std::string, uint32_t> input_flags
{ {

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,9 @@
#include "Model3/IEmulator.h" #include "Model3/IEmulator.h"
#include "Model3/JTAG.h" #include "Model3/JTAG.h"
#include "Model3/Crypto.h" #include "Model3/Crypto.h"
#ifdef NET_BOARD
#include "Network/INetBoard.h"
#endif // NET_BOARD
#include "Util/NewConfig.h" #include "Util/NewConfig.h"
/* /*
@ -140,9 +143,9 @@ public:
* Returns a reference to the net board. * Returns a reference to the net board.
* Returns: * Returns:
* Pointer to CNetBoard object. * Pointer to CNetBoard or CSimNetBoard object.
*/ */
CNetBoard * GetNetBoard(void); INetBoard * GetNetBoard(void);
#endif #endif
/* /*
@ -306,7 +309,7 @@ private:
CCrypto m_cryptoDevice; // Encryption device CCrypto m_cryptoDevice; // Encryption device
CJTAG m_jtag; // JTAG interface CJTAG m_jtag; // JTAG interface
#ifdef NET_BOARD #ifdef NET_BOARD
CNetBoard NetBoard; // Net board INetBoard *NetBoard; // Net board
bool m_runNetBoard; bool m_runNetBoard;
#endif #endif

47
Src/Network/INetBoard.h Normal file
View file

@ -0,0 +1,47 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011-2020 Bart Trzynadlowski, Nik Henson, Ian Curtis,
** Harry Tuttle, and Spindizzi
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDED_INETBOARD_H
#define INCLUDED_INETBOARD_H
#include "Types.h"
#include "Game.h"
#include "BlockFile.h"
class INetBoard
{
public:
virtual void SaveState(CBlockFile* SaveState) = 0;
virtual void LoadState(CBlockFile* SaveState) = 0;
virtual void RunFrame(void) = 0;
virtual void Reset(void) = 0;
virtual bool IsAttached(void) = 0;
virtual bool IsRunning(void) = 0;
virtual bool Init(UINT8* netRAMPtr, UINT8* netBufferPtr) = 0;
virtual void GetGame(Game) = 0;
};
#endif

View file

@ -61,35 +61,35 @@
// change port/ip you want, I only tested in local on same machine (watch your firewall) // change port/ip you want, I only tested in local on same machine (watch your firewall)
// //
// add for master // add for master
// EmulateNet=1 // Network=1
// port_in = 1970 // PortIn = 1970
// port_out = 1971 // PortOut = 1971
// addr_out = "127.0.0.1" // addr_out = "127.0.0.1"
// //
// add for slave // add for slave
// EmulateNet=1 // Network=1
// port_in = 1971 // PortIn = 1971
// port_out = 1970 // PortOut = 1970
// addr_out = "127.0.0.1" // addr_out = "127.0.0.1"
// //
// or in case of 3 cabs // or in case of 3 cabs
// //
// add for master // add for master
// EmulateNet=1 // Network=1
// port_in = 1970 // PortIn = 1970
// port_out = 1971 // PortOut = 1971
// addr_out = "127.0.0.1" // addr_out = "127.0.0.1"
// //
// add for slave1 // add for slave1
// EmulateNet=1 // Network=1
// port_in = 1971 // PortIn = 1971
// port_out = 1972 // PortOut = 1972
// addr_out = "127.0.0.1" // addr_out = "127.0.0.1"
// //
// add for slave2 // add for slave2
// EmulateNet=1 // Network=1
// port_in = 1972 // PortIn = 1972
// port_out = 1970 // PortOut = 1970
// addr_out = "127.0.0.1" // addr_out = "127.0.0.1"
//#define NET_DEBUG //#define NET_DEBUG
@ -1095,9 +1095,7 @@ bool CNetBoard::Init(UINT8 * netRAMPtr, UINT8 *netBufferPtr)
netRAM = netRAMPtr; netRAM = netRAMPtr;
netBuffer = netBufferPtr; netBuffer = netBufferPtr;
std::string netboard_present = Gameinfo.netboard_present; m_attached = Gameinfo.netboard_present && m_config["Network"].ValueAs<bool>();
std::transform(netboard_present.begin(), netboard_present.end(), netboard_present.begin(), ::tolower);
m_attached = (netboard_present.compare("true") == 0) ? true : false;
test_irq = 0; test_irq = 0;
@ -1159,14 +1157,14 @@ bool CNetBoard::Init(UINT8 * netRAMPtr, UINT8 *netBufferPtr)
//netsocks //netsocks
port_in = m_config["port_in"].ValueAs<unsigned>(); port_in = m_config["PortIn"].ValueAs<unsigned>();
port_out = m_config["port_out"].ValueAs<unsigned>(); port_out = m_config["PortOut"].ValueAs<unsigned>();
addr_out = m_config["addr_out"].ValueAs<std::string>(); addr_out = m_config["AddressOut"].ValueAs<std::string>();
nets = std::make_unique<TCPSend>(addr_out, port_out); nets = std::make_unique<TCPSend>(addr_out, port_out);
netr = std::make_unique<TCPReceive>(port_in); netr = std::make_unique<TCPReceive>(port_in);
if (m_config["EmulateNet"].ValueAs<bool>() && m_attached) { if (m_config["Network"].ValueAs<bool>() && m_attached) {
while (!nets->Connect()) { while (!nets->Connect()) {
printf("Connecting to %s:%i ..\n", addr_out.c_str(), port_out); printf("Connecting to %s:%i ..\n", addr_out.c_str(), port_out);
} }
@ -1189,7 +1187,6 @@ CNetBoard::CNetBoard(const Util::Config::Node &config) : m_config(config)
ioreg = NULL; ioreg = NULL;
ctrlrw = NULL; ctrlrw = NULL;
CodeReady = false;
test_irq = 0; test_irq = 0;
int5 = false; int5 = false;
@ -1224,12 +1221,10 @@ void CNetBoard::LoadState(CBlockFile * SaveState)
{ {
} }
bool CNetBoard::RunFrame(void) void CNetBoard::RunFrame(void)
{ {
if (!CodeReady) if (!IsRunning())
{ return;
return true;
}
M68KSetContext(&M68K); M68KSetContext(&M68K);
@ -1269,8 +1264,6 @@ bool CNetBoard::RunFrame(void)
M68KRun((4000000 / 60)); M68KRun((4000000 / 60));
M68KGetContext(&M68K); M68KGetContext(&M68K);
return true;
} }
void CNetBoard::Reset(void) void CNetBoard::Reset(void)
@ -1311,6 +1304,11 @@ bool CNetBoard::IsAttached(void)
return m_attached; return m_attached;
} }
bool CNetBoard::IsRunning(void)
{
return m_attached && ((ioreg[0xc0] == 0xff) || (ioreg[0xc0] == 0x01));
}
void CNetBoard::GetGame(Game gameinfo) void CNetBoard::GetGame(Game gameinfo)
{ {
Gameinfo = gameinfo; Gameinfo = gameinfo;

View file

@ -27,13 +27,14 @@
#include "CPU/Bus.h" #include "CPU/Bus.h"
#include "OSD/Thread.h" #include "OSD/Thread.h"
#include <memory> #include <memory>
#include "INetBoard.h"
#include "TCPSend.h" #include "TCPSend.h"
#include "TCPSendAsync.h" #include "TCPSendAsync.h"
#include "TCPReceive.h" #include "TCPReceive.h"
//#define NET_BUF_SIZE 32800 // 16384 not enough //#define NET_BUF_SIZE 32800 // 16384 not enough
class CNetBoard : public IBus class CNetBoard : public IBus, public INetBoard
{ {
public: public:
@ -48,12 +49,13 @@ public:
void SaveState(CBlockFile *SaveState); void SaveState(CBlockFile *SaveState);
void LoadState(CBlockFile *SaveState); void LoadState(CBlockFile *SaveState);
bool RunFrame(void); void RunFrame(void);
void Reset(void); void Reset(void);
// Returns a reference to the 68K CPU context // Returns a reference to the 68K CPU context
M68KCtx *GetM68K(void); M68KCtx *GetM68K(void);
bool IsAttached(void); bool IsAttached(void);
bool IsRunning(void);
bool CodeReady; bool CodeReady;
bool Init(UINT8 *netRAMPtr, UINT8 *netBufferPtr); bool Init(UINT8 *netRAMPtr, UINT8 *netBufferPtr);

549
Src/Network/SimNetBoard.cpp Normal file
View file

@ -0,0 +1,549 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011-2020 Bart Trzynadlowski, Nik Henson, Ian Curtis,
** Harry Tuttle, and Spindizzi
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
#include <chrono>
#include <thread>
#include "Supermodel.h"
#include "SimNetBoard.h"
// these make 16-bit read/writes much neater
#define RAM16 *(uint16_t*)&RAM
#define CommRAM16 *(uint16_t*)&CommRAM
#define ioreg16 *(uint16_t*)&ioreg
static const uint64_t netGUID = 0x5bf177da34872;
inline bool CSimNetBoard::IsGame(const char* gameName)
{
return (m_gameInfo.name == gameName) || (m_gameInfo.parent == gameName);
}
CSimNetBoard::CSimNetBoard(const Util::Config::Node& config) : m_config(config)
{
m_running = true;
}
CSimNetBoard::~CSimNetBoard(void)
{
m_running = false;
if (m_connectThread.joinable())
m_connectThread.join();
}
void CSimNetBoard::SaveState(CBlockFile* SaveState)
{
}
void CSimNetBoard::LoadState(CBlockFile* SaveState)
{
}
bool CSimNetBoard::Init(uint8_t* netRAMPtr, uint8_t* netBufferPtr)
{
RAM = netRAMPtr;
CommRAM = netBufferPtr;
ioreg = netBufferPtr + 0x10000;
m_attached = m_gameInfo.netboard_present && m_config["Network"].ValueAs<bool>();
if (!m_attached)
return 0;
if (IsGame("daytona2") || IsGame("harley") || IsGame("scud") || IsGame("srally2") ||
IsGame("skichamp") || IsGame("spikeout") || IsGame("spikeofe"))
m_gameType = GameType::one;
else if (IsGame("lemans24") || IsGame("von2") || IsGame("dirtdvls"))
m_gameType = GameType::two;
else
return ErrorLog("Game not recognized or supported");
m_state = State::start;
//netsocks
port_in = m_config["PortIn"].ValueAs<unsigned>();
port_out = m_config["PortOut"].ValueAs<unsigned>();
addr_out = m_config["AddressOut"].ValueAs<std::string>();
nets = std::make_unique<TCPSend>(addr_out, port_out);
netr = std::make_unique<TCPReceive>(port_in);
return 0;
}
void CSimNetBoard::RunFrame(void)
{
if (!IsRunning())
return;
switch (m_state)
{
case State::start:
if (!m_connected && !m_connectThread.joinable())
m_connectThread = std::thread(&CSimNetBoard::ConnectProc, this);
ioreg16[0x88] = 0;
ioreg16[0x8a] = IsGame("dirtdvls") ? 0x4004 : 0xe000;
m_state = State::init;
break;
case State::init:
memset(CommRAM, 0, 0x10000);
if (m_gameType == GameType::one)
{
if (ioreg16[0x88] & 0x8000) // has main board changed this register?
{
ioreg[0] |= 0x01; // simulate IRQ 2 ack
if (ioreg16[0x88] == 0xf000)
{
// initialization complete
ioreg16[0x8a] = 0;
CommRAM16[0x72] = FLIPENDIAN16(0x1); // is this necessary?
m_state = State::testing;
}
ioreg16[0x88] = 0; // 0 should work for all init subroutines
}
}
else
{
// type 2 performs initialization on its own
ioreg16[0x8a] = 0;
m_state = State::testing;
m_counter = 0;
}
break;
case State::testing:
if (m_gameType == GameType::one)
{
ioreg16[0x88] += 1; // type 1 games require this to be incremented every frame
if (!m_connected)
break;
uint8_t numMachines, machineIndex;
if (RAM16[0x400] == 0) // master
{
// flush receive buffer
while (netr->CheckDataAvailable())
{
netr->Receive();
}
// check all linked instances have the same GUID
nets->Send(&netGUID, sizeof(netGUID));
auto& recv_data = netr->Receive();
if (recv_data.empty())
break;
uint64_t testGUID;
memcpy(&testGUID, &recv_data[0], recv_data.size());
if (testGUID != netGUID)
testGUID = 0;
// send the GUID for one more loop
nets->Send(&testGUID, sizeof(testGUID));
netr->Receive();
if (testGUID != netGUID)
{
ErrorLog("unable to verify connection. Make sure all machines are using same build!");
m_state = State::error;
break;
}
// master has an index of zero
machineIndex = 0;
nets->Send(&machineIndex, sizeof(machineIndex));
// receive back the number of other linked machines
recv_data = netr->Receive();
if (recv_data.empty())
break;
numMachines = recv_data[0];
// send the number of other linked machines
nets->Send(&numMachines, sizeof(numMachines));
netr->Receive();
}
else
{
// receive GUID from the previous machine and check it matches
auto& recv_data = netr->Receive();
if (recv_data.empty())
break;
uint64_t testGUID;
memcpy(&testGUID, &recv_data[0], recv_data.size());
if (testGUID != netGUID)
testGUID = 0;
nets->Send(&testGUID, sizeof(testGUID));
// one more time, in case a later machine has a GUID mismatch
recv_data = netr->Receive();
if (recv_data.empty())
break;
memcpy(&testGUID, &recv_data[0], recv_data.size());
if (testGUID != netGUID)
testGUID = 0;
nets->Send(&testGUID, sizeof(testGUID));
if (testGUID != netGUID)
{
ErrorLog("unable to verify connection. Make sure all machines are using same build!");
m_state = State::error;
break;
}
// receive the previous machine's index, increment it, send it to the next machine
recv_data = netr->Receive();
if (recv_data.empty())
break;
machineIndex = recv_data[0] + 1;
nets->Send(&machineIndex, sizeof(machineIndex));
// receive the number of other linked machines and forward it on
recv_data = netr->Receive();
if (recv_data.empty())
break;
numMachines = recv_data[0];
nets->Send(&numMachines, sizeof(numMachines));
}
m_numMachines = numMachines + 1;
ioreg16[0x88] = 0; // supposed to cycle between 0 and 1 (also 2 for Daytona 2); doesn't seem to matter
ioreg16[0x8a] = 0x2021 + (numMachines * 0x20) + machineIndex;
CommRAM16[0x0] = RAM16[0x400]; // 0 if master, 1 if slave
CommRAM16[0x2] = numMachines;
CommRAM16[0x4] = machineIndex;
m_counter = 0;
CommRAM16[0x6] = 0;
m_segmentSize = RAM16[0x404];
// don't know if these are actually required, but it never hurts to include them
CommRAM16[0x8] = FLIPENDIAN16(0x100 + m_segmentSize);
CommRAM16[0xa] = FLIPENDIAN16(RAM16[0x402] - m_segmentSize - 1);
CommRAM16[0xc] = FLIPENDIAN16(0x100);
CommRAM16[0xe] = FLIPENDIAN16(RAM16[0x402] - m_segmentSize + 0x200);
m_state = State::ready;
}
else
{
if (!m_connected)
break;
// we have to track both playable and non-playable machines for type 2
struct
{
uint8_t total;
uint8_t playable;
} numMachines, machineIndex;
if (RAM16[0x200] == 0) // master
{
// flush receive buffer
while (netr->CheckDataAvailable())
netr->Receive();
// check all linked instances have the same GUID
nets->Send(&netGUID, sizeof(netGUID));
auto& recv_data = netr->Receive();
if (recv_data.empty())
break;
uint64_t testGUID;
memcpy(&testGUID, &recv_data[0], recv_data.size());
if (testGUID != netGUID)
testGUID = 0;
// send the GUID for one more loop
nets->Send(&testGUID, sizeof(testGUID));
netr->Receive();
if (testGUID != netGUID)
{
ErrorLog("unable to verify connection. Make sure all machines are using same build!");
m_state = State::error;
break;
}
// master has indices set to zero
machineIndex.total = 0, machineIndex.playable = 0;
nets->Send(&machineIndex, sizeof(machineIndex));
// receive back the number of other linked machines
recv_data = netr->Receive();
if (recv_data.empty())
break;
memcpy(&numMachines, &recv_data[0], recv_data.size());
// send the number of other linked machines
nets->Send(&numMachines, sizeof(numMachines));
netr->Receive();
}
else if (RAM16[0x200] < 0x8000) // slave
{
// receive GUID from the previous machine and check it matches
auto& recv_data = netr->Receive();
if (recv_data.empty())
break;
uint64_t testGUID;
memcpy(&testGUID, &recv_data[0], recv_data.size());
if (testGUID != netGUID)
testGUID = 0;
nets->Send(&testGUID, sizeof(testGUID));
// one more time, in case a later machine has a GUID mismatch
recv_data = netr->Receive();
if (recv_data.empty())
break;
memcpy(&testGUID, &recv_data[0], recv_data.size());
if (testGUID != netGUID)
testGUID = 0;
nets->Send(&testGUID, sizeof(testGUID));
if (testGUID != netGUID)
{
ErrorLog("unable to verify connection. Make sure all machines are using same build!");
m_state = State::error;
break;
}
// receive the indices of the previous machine and increment them
recv_data = netr->Receive();
if (recv_data.empty())
break;
memcpy(&machineIndex, &recv_data[0], recv_data.size());
machineIndex.total++, machineIndex.playable++;
// send our indices to the next machine
nets->Send(&machineIndex, sizeof(machineIndex));
// receive the number of machines
recv_data = netr->Receive();
if (recv_data.empty())
break;
memcpy(&numMachines, &recv_data[0], recv_data.size());
// forward the number of machines
nets->Send(&numMachines, sizeof(numMachines));
}
else
{
// relay/satellite
// receive GUID from the previous machine and check it matches
auto& recv_data = netr->Receive();
if (recv_data.empty())
break;
uint64_t testGUID;
memcpy(&testGUID, &recv_data[0], recv_data.size());
if (testGUID != netGUID)
testGUID = 0;
nets->Send(&testGUID, sizeof(testGUID));
// one more time, in case a later machine has a GUID mismatch
recv_data = netr->Receive();
if (recv_data.empty())
break;
memcpy(&testGUID, &recv_data[0], recv_data.size());
if (testGUID != netGUID)
testGUID = 0;
nets->Send(&testGUID, sizeof(testGUID));
if (testGUID != netGUID)
{
ErrorLog("unable to verify connection. Make sure all machines are using same build!");
m_state = State::error;
break;
}
// receive the indices of the previous machine; don't increment the playable index
recv_data = netr->Receive();
if (recv_data.empty())
break;
memcpy(&machineIndex, &recv_data[0], recv_data.size());
machineIndex.total++;
// send our indices to the next machine
nets->Send(&machineIndex, sizeof(machineIndex));
// receive the number of machines
recv_data = netr->Receive();
if (recv_data.empty())
break;
memcpy(&numMachines, &recv_data[0], recv_data.size());
// forward the number of machines
nets->Send(&numMachines, sizeof(numMachines));
// indicate that this machine is a relay/satellite
if (!IsGame("dirtdvls"))
machineIndex.playable |= 0x80;
}
// if there are no other linked machines, only continue if Supermodel is linked to itself
// there might be more than one machine set to master which would cause glitches
if ((numMachines.total == 0) && ((port_in != port_out) || !addr_out.compare("127.0.0.1")))
{
ErrorLog("no slave machines detected. Make sure only one machine is set to master!");
if (IsGame("dirtdvls"))
ioreg16[0x8a] = 0x8085; // seems like the netboard code writers really liked their CPU model numbers
m_state = State::error;
break;
}
m_numMachines = numMachines.total + 1;
ioreg16[0x88] = 5; // probably not necessary
if (IsGame("dirtdvls"))
ioreg16[0x8a] = (numMachines.playable << 4) | machineIndex.playable | 0x7400;
else
ioreg16[0x8a] = (numMachines.playable << 8) | machineIndex.playable;
CommRAM16[0x0] = RAM16[0x200]; // master/slave/relay status
CommRAM16[0x2] = (numMachines.playable << 8) | numMachines.total;
CommRAM16[0x4] = (machineIndex.playable << 8) | machineIndex.total;
m_counter = 0;
CommRAM16[0x6] = 0;
m_segmentSize = RAM16[0x204];
// don't know if these are actually required, but it never hurts to include them
CommRAM16[0x8] = FLIPENDIAN16(0x100 + m_segmentSize);
CommRAM16[0xa] = FLIPENDIAN16(RAM16[0x206]);
CommRAM16[0xc] = FLIPENDIAN16(0x100);
CommRAM16[0xe] = FLIPENDIAN16(RAM16[0x206] + 0x80);
m_state = State::ready;
}
break;
case State::ready:
m_counter++;
CommRAM16[0x6] = FLIPENDIAN16(m_counter);
if (IsGame("spikeofe")) // temporary hack for spikeout final edition (avoids comm error)
{
nets->Send(CommRAM + 0x100, m_segmentSize * m_numMachines);
auto& recv_data = netr->Receive();
if (recv_data.size() == 0)
{
// link broken - send an "empty" packet to alert other machines
nets->Send(nullptr, 0);
m_state = State::error;
ioreg16[0x8a] = 0x40; // send "link broken" message to mainboard
break;
}
memcpy(CommRAM + 0x100 + m_segmentSize, recv_data.data(), recv_data.size());
}
else
{
// we only send what we need to; helps cut down on bandwidth
// each machine has to receive back its own data (TODO: copy this data manually?)
for (int i = 0; i < m_numMachines; i++)
{
nets->Send(CommRAM + 0x100 + i * m_segmentSize, m_segmentSize);
auto& recv_data = netr->Receive();
if (recv_data.size() == 0)
{
// link broken - send an "empty" packet to alert other machines
nets->Send(nullptr, 0);
m_state = State::error;
if (m_gameType == GameType::one)
ioreg16[0x8a] = 0x40; // send "link broken" message to mainboard
break;
}
memcpy(CommRAM + 0x100 + (i + 1) * m_segmentSize, recv_data.data(), recv_data.size());
}
}
break;
case State::error:
// do nothing
break;
}
}
void CSimNetBoard::Reset(void)
{
// if netboard was active, send an "empty" packet so the other machines don't get stuck waiting for data
if (m_state == State::ready)
{
nets->Send(nullptr, 0);
netr->Receive();
}
ioreg[0xc0] = 0;
m_state = State::start;
}
bool CSimNetBoard::IsAttached(void)
{
return m_attached;
}
bool CSimNetBoard::IsRunning(void)
{
return (ioreg[0xc0] == 0xff) || (ioreg[0xc0] == 0x01); // there's probably a better way of checking
}
void CSimNetBoard::GetGame(Game gameInfo)
{
m_gameInfo = gameInfo;
}
void CSimNetBoard::ConnectProc(void)
{
using namespace std::chrono_literals;
if (m_connected)
return;
printf("Connecting to %s:%i ..\n", addr_out.c_str(), port_out);
// wait until TCPSend has connected to the next machine
while (!nets->Connect())
{
if (!m_running)
return;
}
// wait until TCPReceive has accepted a connection from the previous machine
while (!netr->Connected())
{
if (!m_running)
return;
std::this_thread::sleep_for(1ms);
}
printf("Successfully connected.\n");
m_connected = true;
}

99
Src/Network/SimNetBoard.h Normal file
View file

@ -0,0 +1,99 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011-2020 Bart Trzynadlowski, Nik Henson, Ian Curtis,
** Harry Tuttle, and Spindizzi
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDED_SIMNETBOARD_H
#define INCLUDED_SIMNETBOARD_H
#include <cstdint>
#include "TCPSend.h"
#include "TCPReceive.h"
#include "INetBoard.h"
enum class State
{
start,
init,
testing,
ready,
error
};
enum class GameType
{
unknown,
one, // all games except those listed below
two // Le Mans 24, Virtual-On, Dirt Devils
};
class CSimNetBoard : public INetBoard
{
public:
CSimNetBoard(const Util::Config::Node& config);
~CSimNetBoard(void);
void SaveState(CBlockFile* SaveState);
void LoadState(CBlockFile* SaveState);
bool Init(uint8_t* netRAMPtr, uint8_t* netBufferPtr);
void RunFrame(void);
void Reset(void);
bool IsAttached(void);
bool IsRunning(void);
void GetGame(Game gameInfo);
private:
// Config
const Util::Config::Node& m_config;
uint8_t* RAM = nullptr;
uint8_t* CommRAM = nullptr;
uint8_t* ioreg = nullptr;
// netsock
uint16_t port_in = 0;
uint16_t port_out = 0;
std::string addr_out = "";
std::thread m_connectThread;
std::atomic_bool m_running = false;
std::atomic_bool m_connected = false;
std::unique_ptr<TCPSend> nets = nullptr;
std::unique_ptr<TCPReceive> netr = nullptr;
Game m_gameInfo;
GameType m_gameType = GameType::unknown;
State m_state = State::start;
uint8_t m_numMachines = 0;
uint16_t m_counter = 0;
uint16_t m_segmentSize = 0;
bool m_attached = false;
inline bool IsGame(const char* gameName);
void ConnectProc(void);
};
#endif

View file

@ -152,3 +152,8 @@ void TCPReceive::ListenFunc()
} }
} }
bool TCPReceive::Connected()
{
return (m_receiveSocket != 0);
}

View file

@ -36,6 +36,7 @@ public:
bool CheckDataAvailable(int timeoutMS = 0); // timeoutMS -1 = wait forever until data arrives, 0 = no waiting, 1+ wait time in milliseconds bool CheckDataAvailable(int timeoutMS = 0); // timeoutMS -1 = wait forever until data arrives, 0 = no waiting, 1+ wait time in milliseconds
std::vector<char>& Receive(); std::vector<char>& Receive();
bool Connected();
private: private:

View file

@ -60,13 +60,13 @@ bool TCPSend::Send(const void * data, int length)
DPRINTF("Sending %i bytes\n", length); DPRINTF("Sending %i bytes\n", length);
if (!length) {
return true; // 0 sized packet will blow our connex
}
int sent = 0; int sent = 0;
sent = SDLNet_TCP_Send(m_socket, &length, sizeof(int)); // pack the length at the start of transmission. sent = SDLNet_TCP_Send(m_socket, &length, sizeof(int)); // pack the length at the start of transmission.
if (!length)
return true; // 0 sized packet will blow our connex
sent = SDLNet_TCP_Send(m_socket, data, length); sent = SDLNet_TCP_Send(m_socket, data, length);
if (sent < length) { if (sent < length) {

View file

@ -1425,7 +1425,8 @@ static Util::Config::Node DefaultConfig()
config.Set("SDLConstForceThreshold", "30"); config.Set("SDLConstForceThreshold", "30");
#ifdef NET_BOARD #ifdef NET_BOARD
// NetBoard // NetBoard
config.Set("EmulateNet", false); config.Set("Network", false);
config.Set("SimulateNet", true);
#endif #endif
#else #else
config.Set("InputSystem", "sdl"); config.Set("InputSystem", "sdl");
@ -1507,8 +1508,10 @@ static void Help(void)
puts(""); puts("");
#ifdef NET_BOARD #ifdef NET_BOARD
puts("Net Options:"); puts("Net Options:");
puts(" -no-net Disable net board emulation [Default]"); puts(" -no-net Disable net board [Default]");
puts(" -net Enable net board emulation (requires -no-threads)"); puts(" -net Enable net board");
puts(" -simulate-netboard Simulate the net board [Default]");
puts(" -emulate-netboard Emulate the net board (requires -no-threads)");
puts(""); puts("");
#endif #endif
puts("Input Options:"); puts("Input Options:");
@ -1610,8 +1613,10 @@ static ParsedCommandLine ParseCommandLine(int argc, char **argv)
{ "-legacy-scsp", { "LegacySoundDSP", true } }, { "-legacy-scsp", { "LegacySoundDSP", true } },
{ "-new-scsp", { "LegacySoundDSP", false } }, { "-new-scsp", { "LegacySoundDSP", false } },
#ifdef NET_BOARD #ifdef NET_BOARD
{ "-net", { "EmulateNet", true } }, { "-net", { "Network", true } },
{ "-no-net", { "EmulateNet", false } }, { "-no-net", { "Network", false } },
{ "-simulate-netboard", { "SimulateNet", true } },
{ "-emulate-netboard", { "SimulateNet", false } },
#endif #endif
{ "-no-force-feedback", { "ForceFeedback", false } }, { "-no-force-feedback", { "ForceFeedback", false } },
{ "-force-feedback", { "ForceFeedback", true } }, { "-force-feedback", { "ForceFeedback", true } },

View file

@ -38,11 +38,11 @@
/****************************************************************************** /******************************************************************************
Program-Wide Definitions Program-Wide Definitions
******************************************************************************/ ******************************************************************************/
#include "Version.h"
#include "Version.h"
/****************************************************************************** /******************************************************************************
OS-Dependent (OSD) Items OS-Dependent (OSD) Items
@ -112,7 +112,7 @@
All primary header files for modules used throughout Supermodel are included All primary header files for modules used throughout Supermodel are included
here, except for external packages and APIs. here, except for external packages and APIs.
******************************************************************************/ ******************************************************************************/
#include "BlockFile.h" #include "BlockFile.h"
#include "Graphics/New3D/New3D.h" #include "Graphics/New3D/New3D.h"
#include "Graphics/Render2D.h" #include "Graphics/Render2D.h"
@ -152,9 +152,6 @@
#include "Model3/DriveBoard/JoystickBoard.h" #include "Model3/DriveBoard/JoystickBoard.h"
#include "Model3/DriveBoard/SkiBoard.h" #include "Model3/DriveBoard/SkiBoard.h"
#include "Model3/DriveBoard/BillBoard.h" #include "Model3/DriveBoard/BillBoard.h"
#ifdef NET_BOARD
#include "Network/NetBoard.h"
#endif
#include "Model3/Model3.h" #include "Model3/Model3.h"

View file

@ -343,6 +343,7 @@ xcopy /D /Y "$(ProjectDir)..\Config\*" "$(TargetDir)Config"</Command>
<ClCompile Include="..\Src\Model3\SoundBoard.cpp" /> <ClCompile Include="..\Src\Model3\SoundBoard.cpp" />
<ClCompile Include="..\Src\Model3\TileGen.cpp" /> <ClCompile Include="..\Src\Model3\TileGen.cpp" />
<ClCompile Include="..\Src\Network\NetBoard.cpp" /> <ClCompile Include="..\Src\Network\NetBoard.cpp" />
<ClCompile Include="..\Src\Network\SimNetBoard.cpp" />
<ClCompile Include="..\Src\Network\TCPReceive.cpp" /> <ClCompile Include="..\Src\Network\TCPReceive.cpp" />
<ClCompile Include="..\Src\Network\TCPSend.cpp" /> <ClCompile Include="..\Src\Network\TCPSend.cpp" />
<ClCompile Include="..\Src\OSD\Logger.cpp" /> <ClCompile Include="..\Src\OSD\Logger.cpp" />
@ -517,7 +518,9 @@ xcopy /D /Y "$(ProjectDir)..\Config\*" "$(TargetDir)Config"</Command>
<ClInclude Include="..\Src\Model3\RTC72421.h" /> <ClInclude Include="..\Src\Model3\RTC72421.h" />
<ClInclude Include="..\Src\Model3\SoundBoard.h" /> <ClInclude Include="..\Src\Model3\SoundBoard.h" />
<ClInclude Include="..\Src\Model3\TileGen.h" /> <ClInclude Include="..\Src\Model3\TileGen.h" />
<ClInclude Include="..\Src\Network\INetBoard.h" />
<ClInclude Include="..\Src\Network\NetBoard.h" /> <ClInclude Include="..\Src\Network\NetBoard.h" />
<ClInclude Include="..\Src\Network\SimNetBoard.h" />
<ClInclude Include="..\Src\Network\TCPReceive.h" /> <ClInclude Include="..\Src\Network\TCPReceive.h" />
<ClInclude Include="..\Src\Network\TCPSend.h" /> <ClInclude Include="..\Src\Network\TCPSend.h" />
<ClInclude Include="..\Src\OSD\Audio.h" /> <ClInclude Include="..\Src\OSD\Audio.h" />

View file

@ -144,6 +144,15 @@
<Filter Include="Header Files\Model3\DriveBoard"> <Filter Include="Header Files\Model3\DriveBoard">
<UniqueIdentifier>{5adb385b-66b5-4aec-9f7c-37a82388f0d2}</UniqueIdentifier> <UniqueIdentifier>{5adb385b-66b5-4aec-9f7c-37a82388f0d2}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Header Files\Graphics">
<UniqueIdentifier>{aff86ef8-d9ca-471a-8839-9094616dab52}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Graphics\Legacy">
<UniqueIdentifier>{08ed9259-68ad-49c9-b013-978b5806f96a}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Graphics\New">
<UniqueIdentifier>{fdb4e5a0-a0ec-4865-a5e6-56eb54c36a2d}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\Src\BlockFile.cpp"> <ClCompile Include="..\Src\BlockFile.cpp">
@ -455,6 +464,9 @@
<ClCompile Include="..\Src\Model3\DriveBoard\WheelBoard.cpp"> <ClCompile Include="..\Src\Model3\DriveBoard\WheelBoard.cpp">
<Filter>Source Files\Model3\DriveBoard</Filter> <Filter>Source Files\Model3\DriveBoard</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Src\Network\SimNetBoard.cpp">
<Filter>Source Files\Network</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<MASM Include="..\Src\CPU\68K\Turbo68K\Turbo68K.asm"> <MASM Include="..\Src\CPU\68K\Turbo68K\Turbo68K.asm">
@ -688,57 +700,6 @@
<ClInclude Include="..\Src\Debugger\CPU\Z80Debug.h"> <ClInclude Include="..\Src\Debugger\CPU\Z80Debug.h">
<Filter>Header Files\Debugger\CPU</Filter> <Filter>Header Files\Debugger\CPU</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Src\Graphics\IRender3D.h">
<Filter>Source Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Render2D.h">
<Filter>Source Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Shader.h">
<Filter>Source Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Shaders2D.h">
<Filter>Source Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Legacy3D\Legacy3D.h">
<Filter>Source Files\Graphics\Legacy</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Legacy3D\Shaders3D.h">
<Filter>Source Files\Graphics\Legacy</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Legacy3D\TextureRefs.h">
<Filter>Source Files\Graphics\Legacy</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Mat4.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Model.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\New3D.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\PolyHeader.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DShader.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Texture.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\TextureSheet.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\VBO.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Vec.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DData.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Model3\Crypto.h"> <ClInclude Include="..\Src\Model3\Crypto.h">
<Filter>Header Files\Model3</Filter> <Filter>Header Files\Model3</Filter>
</ClInclude> </ClInclude>
@ -748,18 +709,9 @@
<ClInclude Include="..\Src\Util\BMPFile.h"> <ClInclude Include="..\Src\Util\BMPFile.h">
<Filter>Header Files\Util</Filter> <Filter>Header Files\Util</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Plane.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DFloat.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Pkgs\tinyxml2.h"> <ClInclude Include="..\Src\Pkgs\tinyxml2.h">
<Filter>Header Files\Pkgs</Filter> <Filter>Header Files\Pkgs</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DScrollFog.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Util\NewConfig.h"> <ClInclude Include="..\Src\Util\NewConfig.h">
<Filter>Header Files\Util</Filter> <Filter>Header Files\Util</Filter>
</ClInclude> </ClInclude>
@ -790,30 +742,12 @@
<ClInclude Include="..\Src\Debugger\DebuggerIO.h"> <ClInclude Include="..\Src\Debugger\DebuggerIO.h">
<Filter>Header Files\Debugger</Filter> <Filter>Header Files\Debugger</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DFrameBuffers.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\GLSLShader.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderQuads.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderTriangles.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Sound\MPEG\MpegAudio.h"> <ClInclude Include="..\Src\Sound\MPEG\MpegAudio.h">
<Filter>Header Files\Sound\MPEG</Filter> <Filter>Header Files\Sound\MPEG</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Src\Pkgs\minimp3.h"> <ClInclude Include="..\Src\Pkgs\minimp3.h">
<Filter>Header Files\Pkgs</Filter> <Filter>Header Files\Pkgs</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Src\Network\TCPSend.h">
<Filter>Source Files\Network</Filter>
</ClInclude>
<ClInclude Include="..\Src\Network\TCPReceive.h">
<Filter>Source Files\Network</Filter>
</ClInclude>
<ClInclude Include="..\Src\Model3\DriveBoard\BillBoard.h"> <ClInclude Include="..\Src\Model3\DriveBoard\BillBoard.h">
<Filter>Header Files\Model3\DriveBoard</Filter> <Filter>Header Files\Model3\DriveBoard</Filter>
</ClInclude> </ClInclude>
@ -829,6 +763,90 @@
<ClInclude Include="..\Src\Model3\DriveBoard\WheelBoard.h"> <ClInclude Include="..\Src\Model3\DriveBoard\WheelBoard.h">
<Filter>Header Files\Model3\DriveBoard</Filter> <Filter>Header Files\Model3\DriveBoard</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Src\Network\INetBoard.h">
<Filter>Header Files\Network</Filter>
</ClInclude>
<ClInclude Include="..\Src\Network\SimNetBoard.h">
<Filter>Header Files\Network</Filter>
</ClInclude>
<ClInclude Include="..\Src\Network\TCPReceive.h">
<Filter>Header Files\Network</Filter>
</ClInclude>
<ClInclude Include="..\Src\Network\TCPSend.h">
<Filter>Header Files\Network</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\IRender3D.h">
<Filter>Header Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Render2D.h">
<Filter>Header Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Shader.h">
<Filter>Header Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Shaders2D.h">
<Filter>Header Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Legacy3D\Legacy3D.h">
<Filter>Header Files\Graphics\Legacy</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Legacy3D\Shaders3D.h">
<Filter>Header Files\Graphics\Legacy</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\Legacy3D\TextureRefs.h">
<Filter>Header Files\Graphics\Legacy</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\GLSLShader.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Mat4.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Model.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\New3D.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Plane.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\PolyHeader.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DData.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DFloat.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DFrameBuffers.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DScrollFog.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DShader.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderQuads.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderTriangles.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Texture.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\TextureSheet.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\VBO.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Vec.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="..\Src\Debugger\ReadMe.txt"> <CustomBuild Include="..\Src\Debugger\ReadMe.txt">