Commit 442f2ba3 authored by NTAuthority's avatar NTAuthority

game window, event system changes and a rendering test

parent add4f1f5
Pipeline #58 skipped
......@@ -31,7 +31,19 @@
#include <utils/StringConvert.h>
#include <utils/LockUtil.h>
#include <rw.h>
// manually include RW stuff as we don't want D3D lingering in our global namespace
//#include <rw.h>
#include "src/rwbase.h"
#include "src/rwplugin.h"
#include "src/rwpipeline.h"
#include "src/rwobjects.h"
#include "src/rwps2.h"
//#include "src/rwxbox.h"
//#include "src/rwd3d.h"
//#include "src/rwd3d8.h"
//#include "src/rwd3d9.h"
//#include "src/rwogl.h"
#include <RwHelpers.h>
#include <Console.Base.h>
\ No newline at end of file
#pragma once
namespace krt
{
class EventSystem;
class GameWindow abstract
{
public:
virtual ~GameWindow() = default;
virtual void* CreateGraphicsContext() = 0;
virtual void Close() = 0;
virtual void ProcessEvents() = 0;
public:
static std::unique_ptr<GameWindow> Create(const std::string& title, int defaultWidth, int defaultHeight, EventSystem* eventSystem);
};
}
\ No newline at end of file
#include <StdInc.h>
#include <windows.h>
#include <d3d9.h>
#define RW_D3D9
#include "src/rwd3d.h"
#include "src/rwd3d9.h"
#include <wrl.h>
#pragma comment(lib, "d3d9.lib")
using Microsoft::WRL::ComPtr;
namespace krt
{
void* InitializeD3D(HWND hWnd, int width, int height)
{
// initialize the D3D9 factory
ComPtr<IDirect3D9> d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
// create presentation parameters
D3DPRESENT_PARAMETERS pp = { 0 };
pp.BackBufferWidth = width;
pp.BackBufferHeight = height;
pp.BackBufferCount = 1;
pp.BackBufferFormat = D3DFMT_A8R8G8B8;
pp.MultiSampleQuality = 0;
pp.MultiSampleType = D3DMULTISAMPLE_NONE;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.hDeviceWindow = hWnd;
pp.Windowed = TRUE;
pp.EnableAutoDepthStencil = TRUE;
pp.AutoDepthStencilFormat = D3DFMT_D24S8;
pp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// create device
IDirect3DDevice9* devicePtr = nullptr;
check(SUCCEEDED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, &pp, &devicePtr)));
// store device
rw::d3d::device = devicePtr;
return devicePtr;
}
}
\ No newline at end of file
#include <StdInc.h>
#include <GameWindow.h>
#include <Console.VariableHelpers.h>
#include <EventSystem.h>
#include <windows.h>
namespace krt
{
const static KeyCode g_scancodeMapping[] = {
KeyCode::None, KeyCode::Escape, KeyCode::D1, KeyCode::D2, KeyCode::D3, KeyCode::D4, KeyCode::D5, KeyCode::D6,
KeyCode::D7, KeyCode::D8, KeyCode::D9, KeyCode::D0, KeyCode::OemMinus, KeyCode::Oemplus, KeyCode::Back, KeyCode::Tab,
KeyCode::Q, KeyCode::W, KeyCode::E, KeyCode::R, KeyCode::T, KeyCode::Y, KeyCode::U, KeyCode::I,
KeyCode::O, KeyCode::P, KeyCode::OemOpenBrackets, KeyCode::OemCloseBrackets, KeyCode::Return, KeyCode::ControlKey, KeyCode::A, KeyCode::S,
KeyCode::D, KeyCode::F, KeyCode::G, KeyCode::H, KeyCode::J, KeyCode::K, KeyCode::L, KeyCode::OemSemicolon,
KeyCode::OemQuotes, KeyCode::Oemtilde, KeyCode::LShiftKey, KeyCode::OemBackslash, KeyCode::Z, KeyCode::X, KeyCode::C, KeyCode::V,
KeyCode::B, KeyCode::N, KeyCode::M, KeyCode::Oemcomma, KeyCode::OemPeriod, KeyCode::OemQuestion, KeyCode::RShiftKey, KeyCode::Multiply,
KeyCode::Menu, KeyCode::Space, KeyCode::CapsLock, KeyCode::F1, KeyCode::F2, KeyCode::F3, KeyCode::F4, KeyCode::F5,
KeyCode::F6, KeyCode::F7, KeyCode::F8, KeyCode::F9, KeyCode::F10, KeyCode::Pause, KeyCode::None, KeyCode::Home,
KeyCode::Up, KeyCode::PageUp, KeyCode::Subtract, KeyCode::Left, KeyCode::NumPad5, KeyCode::Right, KeyCode::Add, KeyCode::End,
KeyCode::Down, KeyCode::PageDown, KeyCode::Insert, KeyCode::Delete, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::F11,
KeyCode::F12, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None,
KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None,
KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None,
KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None,
KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None, KeyCode::None};
inline static KeyCode MapKeyCode(LPARAM lParam)
{
// 16..23: scan code
int scanCode = (lParam >> 16) & 0xFF;
if (scanCode > 127)
{
return KeyCode::None;
}
// 24: is extended scan code?
bool isExtendedKey = (lParam >> 24) & 1;
KeyCode keyCode = g_scancodeMapping[scanCode];
// extended mappings
if (isExtendedKey)
{
switch (keyCode)
{
case KeyCode::OemQuestion:
keyCode = KeyCode::Divide;
break;
case KeyCode::Pause:
keyCode = KeyCode::NumLock;
break;
}
}
return keyCode;
}
void* InitializeD3D(HWND hWnd, int width, int height);
class Win32GameWindow : public GameWindow
{
public:
Win32GameWindow(const std::string& title, int defaultWidth, int defaultHeight, EventSystem* eventSystem)
: m_widthVar("r_width", ConVar_Archive, defaultWidth, &m_width),
m_heightVar("r_height", ConVar_Archive, defaultHeight, &m_height),
m_fullscreenVar("r_fullscreen", ConVar_Archive, false, &m_fullscreen),
m_eventSystem(eventSystem)
{
// prepare resolution
HMONITOR hMonitor = MonitorFromPoint(POINT{0, 0}, 0);
MONITORINFO monitorInfo = {sizeof(MONITORINFO)};
GetMonitorInfo(hMonitor, &monitorInfo);
int x = 0;
int y = 0;
if (!m_fullscreen)
{
console::Printf("Creating %dx%d game window...\n", m_width, m_height);
x = ((monitorInfo.rcWork.right - m_width) / 2);
y = ((monitorInfo.rcWork.bottom - m_height) / 2);
}
else
{
m_widthVar.GetHelper()->SetRawValue(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
m_heightVar.GetHelper()->SetRawValue(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top);
console::Printf("Creating fullscreen (%dx%d) game window...\n", m_width, m_height);
}
// create the actual game window - well, the class
{
// TODO: icon resource
WNDCLASS windowClass = {0};
windowClass.lpfnWndProc = WindowProcedureWrapper;
windowClass.hInstance = GetModuleHandle(nullptr);
windowClass.hCursor = LoadCursor(0, IDC_ARROW);
windowClass.lpszClassName = L"Win32GameWindow";
check(RegisterClass(&windowClass));
}
DWORD windowStyle = WS_VISIBLE;
if (m_fullscreen)
{
windowStyle |= WS_POPUP;
}
else
{
windowStyle |= WS_SYSMENU | WS_CAPTION;
}
// adjust the rectangle to fit a possible client area
RECT windowRect;
windowRect.left = x;
windowRect.right = m_width + x;
windowRect.top = y;
windowRect.bottom = m_height + y;
AdjustWindowRect(&windowRect, windowStyle, FALSE);
// create the window
m_windowHandle = CreateWindowEx(0, L"Win32GameWindow", ToWide(title).c_str(),
windowStyle, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top,
nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
check(m_windowHandle != nullptr);
ms_windowMapping.insert({m_windowHandle, this});
}
virtual ~Win32GameWindow() override
{
Close();
}
virtual void* CreateGraphicsContext() override
{
return InitializeD3D(m_windowHandle, m_width, m_height);
}
virtual void Close() override
{
DestroyWindow(m_windowHandle);
UnregisterClass(L"Win32GameWindow", GetModuleHandle(nullptr));
}
virtual void ProcessEvents() override
{
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
private:
LRESULT WindowProcedure(UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
m_eventSystem->QueueEvent(std::make_unique<KeyEvent>(true, MapKeyCode(lParam)));
break;
case WM_KEYUP:
case WM_SYSKEYUP:
m_eventSystem->QueueEvent(std::make_unique<KeyEvent>(false, MapKeyCode(lParam)));
break;
case WM_CHAR:
{
wchar_t charParam = static_cast<wchar_t>(wParam);
// WM_CHAR events are expected to be wchar_t, at least...
m_eventSystem->QueueEvent(std::make_unique<CharEvent>(ToNarrow(std::wstring(&charParam, 1))));
break;
}
case WM_CLOSE:
PostQuitMessage(0);
break;
}
return DefWindowProc(m_windowHandle, msg, wParam, lParam);
}
private:
static std::map<HWND, Win32GameWindow*> ms_windowMapping;
static LRESULT CALLBACK WindowProcedureWrapper(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
auto it = ms_windowMapping.find(window);
if (it != ms_windowMapping.end())
{
return it->second->WindowProcedure(msg, wParam, lParam);
}
return DefWindowProc(window, msg, wParam, lParam);
}
private:
ConVar<int> m_widthVar;
ConVar<int> m_heightVar;
ConVar<bool> m_fullscreenVar;
private:
EventSystem* m_eventSystem;
private:
HWND m_windowHandle;
int m_width;
int m_height;
bool m_fullscreen;
};
std::map<HWND, Win32GameWindow*> Win32GameWindow::ms_windowMapping;
std::unique_ptr<GameWindow> GameWindow::Create(const std::string& title, int defaultWidth, int defaultHeight, EventSystem* eventSystem)
{
return std::make_unique<Win32GameWindow>(title, defaultWidth, defaultHeight, eventSystem);
}
}
\ No newline at end of file
......@@ -18,6 +18,230 @@ class Event abstract
uint64_t m_time;
};
enum class KeyCode
{
None = 0x00000000,
LButton = 0x00000001,
RButton = 0x00000002,
Cancel = 0x00000003,
MButton = 0x00000004,
XButton1 = 0x00000005,
XButton2 = 0x00000006,
Back = 0x00000008,
Tab = 0x00000009,
LineFeed = 0x0000000A,
Clear = 0x0000000C,
Return = 0x0000000D,
Enter = 0x0000000D,
ShiftKey = 0x00000010,
ControlKey = 0x00000011,
Menu = 0x00000012,
Pause = 0x00000013,
CapsLock = 0x00000014,
Capital = 0x00000014,
KanaMode = 0x00000015,
HanguelMode = 0x00000015,
HangulMode = 0x00000015,
JunjaMode = 0x00000017,
FinalMode = 0x00000018,
KanjiMode = 0x00000019,
HanjaMode = 0x00000019,
Escape = 0x0000001B,
IMEConvert = 0x0000001C,
IMENonconvert = 0x0000001D,
IMEAceept = 0x0000001E,
IMEModeChange = 0x0000001F,
Space = 0x00000020,
PageUp = 0x00000021,
Prior = 0x00000021,
PageDown = 0x00000022,
Next = 0x00000022,
End = 0x00000023,
Home = 0x00000024,
Left = 0x00000025,
Up = 0x00000026,
Right = 0x00000027,
Down = 0x00000028,
Select = 0x00000029,
Print = 0x0000002A,
Execute = 0x0000002B,
PrintScreen = 0x0000002C,
Snapshot = 0x0000002C,
Insert = 0x0000002D,
Delete = 0x0000002E,
Help = 0x0000002F,
D0 = 0x00000030,
D1 = 0x00000031,
D2 = 0x00000032,
D3 = 0x00000033,
D4 = 0x00000034,
D5 = 0x00000035,
D6 = 0x00000036,
D7 = 0x00000037,
D8 = 0x00000038,
D9 = 0x00000039,
A = 0x00000041,
B = 0x00000042,
C = 0x00000043,
D = 0x00000044,
E = 0x00000045,
F = 0x00000046,
G = 0x00000047,
H = 0x00000048,
I = 0x00000049,
J = 0x0000004A,
K = 0x0000004B,
L = 0x0000004C,
M = 0x0000004D,
N = 0x0000004E,
O = 0x0000004F,
P = 0x00000050,
Q = 0x00000051,
R = 0x00000052,
S = 0x00000053,
T = 0x00000054,
U = 0x00000055,
V = 0x00000056,
W = 0x00000057,
X = 0x00000058,
Y = 0x00000059,
Z = 0x0000005A,
LWin = 0x0000005B,
RWin = 0x0000005C,
Apps = 0x0000005D,
NumPad0 = 0x00000060,
NumPad1 = 0x00000061,
NumPad2 = 0x00000062,
NumPad3 = 0x00000063,
NumPad4 = 0x00000064,
NumPad5 = 0x00000065,
NumPad6 = 0x00000066,
NumPad7 = 0x00000067,
NumPad8 = 0x00000068,
NumPad9 = 0x00000069,
Multiply = 0x0000006A,
Add = 0x0000006B,
Separator = 0x0000006C,
Subtract = 0x0000006D,
Decimal = 0x0000006E,
Divide = 0x0000006F,
F1 = 0x00000070,
F2 = 0x00000071,
F3 = 0x00000072,
F4 = 0x00000073,
F5 = 0x00000074,
F6 = 0x00000075,
F7 = 0x00000076,
F8 = 0x00000077,
F9 = 0x00000078,
F10 = 0x00000079,
F11 = 0x0000007A,
F12 = 0x0000007B,
F13 = 0x0000007C,
F14 = 0x0000007D,
F15 = 0x0000007E,
F16 = 0x0000007F,
F17 = 0x00000080,
F18 = 0x00000081,
F19 = 0x00000082,
F20 = 0x00000083,
F21 = 0x00000084,
F22 = 0x00000085,
F23 = 0x00000086,
F24 = 0x00000087,
NumLock = 0x00000090,
Scroll = 0x00000091,
LShiftKey = 0x000000A0,
RShiftKey = 0x000000A1,
LControlKey = 0x000000A2,
RControlKey = 0x000000A3,
LMenu = 0x000000A4,
RMenu = 0x000000A5,
BrowserBack = 0x000000A6,
BrowserForward = 0x000000A7,
BrowserRefresh = 0x000000A8,
BrowserStop = 0x000000A9,
BrowserSearch = 0x000000AA,
BrowserFavorites = 0x000000AB,
BrowserHome = 0x000000AC,
VolumeMute = 0x000000AD,
VolumeDown = 0x000000AE,
VolumeUp = 0x000000AF,
MediaNextTrack = 0x000000B0,
MediaPreviousTrack = 0x000000B1,
MediaStop = 0x000000B2,
MediaPlayPause = 0x000000B3,
LaunchMail = 0x000000B4,
SelectMedia = 0x000000B5,
LaunchApplication1 = 0x000000B6,
LaunchApplication2 = 0x000000B7,
OemSemicolon = 0x000000BA,
Oemplus = 0x000000BB,
Oemcomma = 0x000000BC,
OemMinus = 0x000000BD,
OemPeriod = 0x000000BE,
OemQuestion = 0x000000BF,
Oemtilde = 0x000000C0,
OemOpenBrackets = 0x000000DB,
OemPipe = 0x000000DC,
OemCloseBrackets = 0x000000DD,
OemQuotes = 0x000000DE,
Oem8 = 0x000000DF,
OemBackslash = 0x000000E2,
ProcessKey = 0x000000E5,
Attn = 0x000000F6,
Crsel = 0x000000F7,
Exsel = 0x000000F8,
EraseEof = 0x000000F9,
Play = 0x000000FA,
Zoom = 0x000000FB,
NoName = 0x000000FC,
Pa1 = 0x000000FD,
OemClear = 0x000000FE,
IMEAccept = 0x0000001E,
Oem1 = 0x000000BA,
Oem102 = 0x000000E2,
Oem2 = 0x000000BF,
Oem3 = 0x000000C0,
Oem4 = 0x000000DB,
Oem5 = 0x000000DC,
Oem6 = 0x000000DD,
Oem7 = 0x000000DE,
Packet = 0x000000E7,
Sleep = 0x0000005F
};
class KeyEvent : public Event
{
public:
inline KeyEvent(bool isDown, KeyCode keyCode)
: m_isDown(isDown), m_keyCode(keyCode)
{
}
virtual void Handle() override;
private:
bool m_isDown;
KeyCode m_keyCode;
};
// actually [arbitrary UTF8 sequence] event, thanks input methods!
class CharEvent : public Event
{
public:
inline CharEvent(const std::string& ch)
: m_character(ch)
{
}
virtual void Handle() override;
private:
std::string m_character;
};
class EventSystem
{
public:
......@@ -25,10 +249,14 @@ class EventSystem
void QueueEvent(std::unique_ptr<Event>&& ev);
void RegisterEventSourceFunction(const std::function<void()>& function);
private:
std::unique_ptr<Event> GetEvent();
private:
std::vector<std::function<void()>> m_eventSources;
std::queue<std::unique_ptr<Event>> m_events;
std::mutex m_mutex;
......
......@@ -78,6 +78,8 @@ struct ModelManager : public streaming::StreamingTypeInterface
ModelResource* GetModelByID( streaming::ident_t id );
ModelResource* GetModelByName( const std::string& name );
void LoadAllModels( void );
void LoadResource( streaming::ident_t localID, const void *dataBuf, size_t memSize ) override;
......
......@@ -34,6 +34,16 @@ public:
}
};
void KeyEvent::Handle()
{
}
void CharEvent::Handle()
{
}
static void ProcessConsoleInput(EventSystem* eventSystem)
{
const char* consoleBuffer = sys::GetConsoleInput();
......@@ -48,8 +58,15 @@ uint64_t EventSystem::HandleEvents()
{
while (true)
{
// try to get events from the event sources
ProcessConsoleInput(this);
for (const auto& eventSource : m_eventSources)
{
eventSource();
}
// loop through the event queue
std::unique_ptr<Event> event = GetEvent();
if (dynamic_cast<NullEvent*>(event.get()) != nullptr)
......@@ -82,6 +99,11 @@ std::unique_ptr<Event> EventSystem::GetEvent()
}
}
void EventSystem::RegisterEventSourceFunction(const std::function<void()>& function)
{
m_eventSources.push_back(function);
}
void EventSystem::QueueEvent(std::unique_ptr<Event>&& ev)
{
m_events.push(std::move(ev));
......
......@@ -5,6 +5,8 @@
#include <fstream>
#include <iostream>
#include "GameWindow.h"
#include "Console.CommandHelpers.h"
#include "Console.h"
......@@ -43,7 +45,7 @@ Game::Game(const std::vector<std::pair<std::string, std::string>>& setList) : st
// Initialize RW.
rw::platform = rw::PLATFORM_D3D9;
rw::loadTextures = false;
rw::loadTextures = true;
gta::attachPlugins();
......@@ -83,12 +85,22 @@ Game::~Game(void)
theGame = NULL;
}
void RenderingTest(void* gfxDevice);
void Game::Run()
{
sys::TimerContext timerContext;
EventSystem eventSystem;
std::unique_ptr<GameWindow> gameWindow = GameWindow::Create("ATG: TheGame", 1280, 720, &eventSystem);
void* gfxContext = gameWindow->CreateGraphicsContext();
eventSystem.RegisterEventSourceFunction([&] ()
{
gameWindow->ProcessEvents();
});
// run the main game loop
bool wantsToExit = false;
uint64_t lastTime = 0;
......@@ -151,6 +163,9 @@ void Game::Run()
// load the game universe if variables are valid
LoadUniverseIfAvailable();
// rendering test
RenderingTest(gfxContext);
// whatever else might come to mind
}
}
......@@ -207,6 +222,7 @@ void Game::LoadUniverseIfAvailable()
configuration.gameName = gameName;
configuration.rootPath = gameDir;
configuration.imageFiles.push_back("models/txd.img");
configuration.imageFiles.push_back("models/gta3.img");
configuration.imageFiles.push_back("models/gta_int.img");
......
......@@ -205,6 +205,18 @@ ModelManager::ModelResource* ModelManager::GetModelByID( streaming::ident_t id )
return this->models[ id ];
}
ModelManager::ModelResource* ModelManager::GetModelByName( const std::string& name )
{
auto findIter = this->modelByName.find(name);
if (findIter != this->modelByName.end())
{
return findIter->second;
}
return NULL;
}
void ModelManager::LoadAllModels( void )
{
// Request all models and wait for them to load.
......
#include <StdInc.h>
#include <Game.h>
#include <Streaming.h>
#include <windows.h>
#include <d3d9.h>
namespace krt
{
void RenderingTest(void* gfxDevice)
{
static bool modelChanged = false;
static std::string modelName = "ind_maindrag2";