textures almost work?

This commit is contained in:
Asuro
2025-02-15 04:13:03 +01:00
parent ab326d3624
commit f93c40f3b6
19 changed files with 643 additions and 456 deletions

4
src/dependency/.ignore Normal file
View File

@@ -0,0 +1,4 @@
SDL/*
# !SDL/src
# bgfx.cmake/*
tinygltf/*

View File

@@ -6,7 +6,10 @@ struct SharedWindowData
void* Handle = nullptr; void* Handle = nullptr;
int32_t WindowWidth = 1920; int32_t WindowWidth = 1920;
int32_t WindowHeight = 1080; int32_t WindowHeight = 1080;
bool HeldScanCodes[512]{0}; bool HeldScanCodes[512]{false};
bool LastHeldScanCodes[512]{false};
bool HeldMouseButtons[8]{false};
bool LastHeldMouseButtons[8]{false};
float MouseDeltaX = 0.0f; float MouseDeltaX = 0.0f;
float MouseDeltaY = 0.0f; float MouseDeltaY = 0.0f;
}; };
@@ -29,6 +32,9 @@ struct GameData
void* EntityStorage = nullptr; void* EntityStorage = nullptr;
uint64_t EntityStorageSize = 0; uint64_t EntityStorageSize = 0;
void* TransientStorage = nullptr;
uint64_t TransientStorageSize = 0;
}; };
struct SharedData struct SharedData

View File

@@ -61,6 +61,16 @@ void EngineWindow::Update(SharedWindowData& shared)
shared.MouseDeltaY += evt.motion.yrel; shared.MouseDeltaY += evt.motion.yrel;
break; break;
} }
case SDL_EVENT_MOUSE_BUTTON_DOWN:
{
shared.HeldMouseButtons[evt.button.button] = true;
break;
}
case SDL_EVENT_MOUSE_BUTTON_UP:
{
shared.HeldMouseButtons[evt.button.button] = false;
break;
}
default: default:
break; break;
} }

View File

@@ -8,15 +8,15 @@
#undef min #undef min
#undef max #undef max
#include <cstdio>
#include <bx/string.h>
#include <bx/mpscqueue.h>
#include <bx/allocator.h> #include <bx/allocator.h>
#include <bx/mpscqueue.h>
#include <bx/string.h>
#include <cstdio>
#include "Shared.h" #include "Shared.h"
#include "Window.h" #include "Window.h"
//#define VISUAL_STUDIO // #define VISUAL_STUDIO
#ifdef VISUAL_STUDIO #ifdef VISUAL_STUDIO
constexpr const char* DLLPath = "PuzGame.dll"; constexpr const char* DLLPath = "PuzGame.dll";
@@ -28,285 +28,307 @@ constexpr const wchar_t* DLLWatch = L"libPuzGame2.dll";
namespace namespace
{ {
bx::AllocatorI* defaultAllocator = new bx::DefaultAllocator{}; bx::AllocatorI* defaultAllocator = new bx::DefaultAllocator{};
} }
enum class FileChangeType enum class FileChangeType
{ {
DLL, DLL,
Shader, Shader,
CompiledShader, CompiledShader,
}; };
struct FileWatcherStartup struct FileWatcherStartup
{ {
char DirPath[512]{0}; char DirPath[512]{0};
wchar_t CompName[512]{0}; wchar_t CompName[512]{0};
FileChangeType ChangeType = FileChangeType::Shader; FileChangeType ChangeType = FileChangeType::Shader;
bool Shutdown = false; bool Shutdown = false;
}; };
struct FileWatcherData struct FileWatcherData
{ {
FileWatcherStartup DLLWatcher; FileWatcherStartup DLLWatcher;
FileWatcherStartup ShaderWatcher; FileWatcherStartup ShaderWatcher;
FileWatcherStartup CompiledShaderWatcher; FileWatcherStartup CompiledShaderWatcher;
bx::MpScUnboundedQueueT<FileChangeNotification> ShaderQueue{defaultAllocator}; bx::MpScUnboundedQueueT<FileChangeNotification> ShaderQueue{defaultAllocator};
bx::MpScUnboundedQueueT<FileChangeNotification> DLLQueue{defaultAllocator}; bx::MpScUnboundedQueueT<FileChangeNotification> DLLQueue{defaultAllocator};
}; };
struct DevelopmentData struct DevelopmentData
{ {
HMODULE GameLib = NULL; HMODULE GameLib = NULL;
FileWatcherData FileWatcher; FileWatcherData FileWatcher;
}; };
struct EngineData struct EngineData
{ {
EngineWindow Window; EngineWindow Window;
}; };
namespace namespace
{ {
DevelopmentData DevData; DevelopmentData DevData;
EngineData Engine; EngineData Engine;
SharedData Shared; SharedData Shared;
Startup StartupFunc; Startup StartupFunc;
Update UpdateFunc; Update UpdateFunc;
Shutdown ShutdownFunc; Shutdown ShutdownFunc;
} } // namespace
void FileChangeCheck(HANDLE dirHandle, FileChangeType changeType, const wchar_t* compName = nullptr) void FileChangeCheck(HANDLE dirHandle, FileChangeType changeType, const wchar_t* compName = nullptr)
{ {
if (dirHandle == NULL) return; if (dirHandle == NULL) return;
uint8_t fileChangeBuffer[1024]{ 0 }; uint8_t fileChangeBuffer[1024]{0};
bx::memSet(fileChangeBuffer, 0, sizeof(fileChangeBuffer)); bx::memSet(fileChangeBuffer, 0, sizeof(fileChangeBuffer));
DWORD bytesReturned = 0; DWORD bytesReturned = 0;
if (ReadDirectoryChangesW(dirHandle, fileChangeBuffer, sizeof(fileChangeBuffer), true, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE, &bytesReturned, NULL, NULL)) if (ReadDirectoryChangesW(dirHandle,
{ fileChangeBuffer,
uint32_t offset = 0; sizeof(fileChangeBuffer),
while (true) true,
{ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE,
FILE_NOTIFY_INFORMATION* notifyData = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(&fileChangeBuffer[offset]); &bytesReturned,
if (notifyData->Action == FILE_ACTION_ADDED || notifyData->Action == FILE_ACTION_MODIFIED || notifyData->Action == FILE_ACTION_RENAMED_NEW_NAME) NULL,
{ NULL))
if (compName == nullptr || compName[0] == 0 || wcscmp(notifyData->FileName, compName) == 0) {
{ uint32_t offset = 0;
FileChangeNotification notif; while (true)
wcscpy(notif.FileName, notifyData->FileName); {
if (changeType == FileChangeType::DLL) FILE_NOTIFY_INFORMATION* notifyData = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(&fileChangeBuffer[offset]);
{ if (notifyData->Action == FILE_ACTION_ADDED || notifyData->Action == FILE_ACTION_MODIFIED ||
DevData.FileWatcher.DLLQueue.push(&notif); notifyData->Action == FILE_ACTION_RENAMED_NEW_NAME)
} {
else if (changeType == FileChangeType::Shader) if (compName == nullptr || compName[0] == 0 || wcscmp(notifyData->FileName, compName) == 0)
{ {
std::system("shadercompile.bat"); FileChangeNotification notif;
} wcscpy(notif.FileName, notifyData->FileName);
else if (changeType == FileChangeType::CompiledShader) if (changeType == FileChangeType::DLL)
{ {
DevData.FileWatcher.ShaderQueue.push(&notif); DevData.FileWatcher.DLLQueue.push(&notif);
} }
printf("detected file change of type %u!\n", changeType); else if (changeType == FileChangeType::Shader)
} {
} std::system("shadercompile.bat");
}
else if (changeType == FileChangeType::CompiledShader)
{
DevData.FileWatcher.ShaderQueue.push(&notif);
}
printf("detected file change of type %u!\n", changeType);
}
}
if (notifyData->NextEntryOffset == 0) break; if (notifyData->NextEntryOffset == 0) break;
offset += notifyData->NextEntryOffset; offset += notifyData->NextEntryOffset;
} }
} }
} }
HANDLE LoadDirHandle(const char* name) HANDLE LoadDirHandle(const char* name)
{ {
HANDLE h = CreateFileA(name, HANDLE h = CreateFileA(name,
FILE_LIST_DIRECTORY, FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, NULL,
OPEN_EXISTING, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL); NULL);
if (h == NULL) if (h == NULL)
{ {
printf("Failed to load dir handle for %s", name); printf("Failed to load dir handle for %s", name);
} }
return h; return h;
} }
unsigned long FileWatcherThread(void* data) unsigned long FileWatcherThread(void* data)
{ {
FileWatcherStartup* startupData = reinterpret_cast<FileWatcherStartup*>(data); FileWatcherStartup* startupData = reinterpret_cast<FileWatcherStartup*>(data);
printf("Starting file watcher of type %u\n", startupData->ChangeType); printf("Starting file watcher of type %u\n", startupData->ChangeType);
if (startupData->DirPath[0] == 0) if (startupData->DirPath[0] == 0)
{ {
printf("Invalid file watcher path!\n"); printf("Invalid file watcher path!\n");
return 1; return 1;
} }
HANDLE dirHandle = LoadDirHandle(startupData->DirPath); HANDLE dirHandle = LoadDirHandle(startupData->DirPath);
if (dirHandle == NULL) if (dirHandle == NULL)
{ {
printf("Failed to load dir %s for file watcher!\n", startupData->DirPath); printf("Failed to load dir %s for file watcher!\n", startupData->DirPath);
return 1; return 1;
} }
while (!startupData->Shutdown) while (!startupData->Shutdown)
{ {
FileChangeCheck(dirHandle, startupData->ChangeType, startupData->CompName); FileChangeCheck(dirHandle, startupData->ChangeType, startupData->CompName);
} }
printf("File watcher thread ended!\n"); printf("File watcher thread ended!\n");
return 0; return 0;
} }
bool ReloadDLL() bool ReloadDLL()
{ {
if (DevData.GameLib != NULL) if (DevData.GameLib != NULL)
{ {
FreeLibrary(DevData.GameLib); FreeLibrary(DevData.GameLib);
} }
#ifdef VISUAL_STUDIO #ifdef VISUAL_STUDIO
if (!CopyFile("PuzGame2.dll", "PuzGame.dll", false)) if (!CopyFile("PuzGame2.dll", "PuzGame.dll", false))
{ {
printf("Failed to copy game DLL!\n"); printf("Failed to copy game DLL!\n");
return false; return false;
} }
#else #else
if (!CopyFile("cmake-build\\libPuzGame2.dll", "cmake-build\\libPuzGame.dll", false)) if (!CopyFile("cmake-build\\libPuzGame2.dll", "cmake-build\\libPuzGame.dll", false))
{ {
printf("Failed to copy game DLL!\n"); printf("Failed to copy game DLL!\n");
return false; return false;
} }
#endif #endif
HMODULE gameLibReloaded = LoadLibraryEx(DLLPath, NULL, 0); HMODULE gameLibReloaded = LoadLibraryEx(DLLPath, NULL, 0);
if (gameLibReloaded == NULL) if (gameLibReloaded == NULL)
{ {
printf("Failed to load game DLL from %s!\n", DLLPath); printf("Failed to load game DLL from %s!\n", DLLPath);
return false; return false;
} }
DevData.GameLib = gameLibReloaded; DevData.GameLib = gameLibReloaded;
#ifdef VISUAL_STUDIO #ifdef VISUAL_STUDIO
Startup StartupReloaded = (Startup)GetProcAddress(DevData.GameLib, "?Setup@Game@@YAXPEAX@Z"); Startup StartupReloaded = (Startup)GetProcAddress(DevData.GameLib, "?Setup@Game@@YAXPEAX@Z");
#else #else
Startup StartupReloaded = (Startup)GetProcAddress(DevData.GameLib, "_ZN4Game5SetupER10SharedData"); Startup StartupReloaded = (Startup)GetProcAddress(DevData.GameLib, "_ZN4Game5SetupER10SharedData");
#endif #endif
if (StartupReloaded == NULL) if (StartupReloaded == NULL)
{ {
printf("Failed to load startup function from game DLL!\n"); printf("Failed to load startup function from game DLL!\n");
return false; return false;
} }
#ifdef VISUAL_STUDIO #ifdef VISUAL_STUDIO
Update UpdateReloaded = (Update)GetProcAddress(DevData.GameLib, "?Update@Game@@YAXXZ"); Update UpdateReloaded = (Update)GetProcAddress(DevData.GameLib, "?Update@Game@@YAXXZ");
#else #else
Update UpdateReloaded = (Update)GetProcAddress(DevData.GameLib, "_ZN4Game6UpdateEv"); Update UpdateReloaded = (Update)GetProcAddress(DevData.GameLib, "_ZN4Game6UpdateEv");
#endif #endif
if (UpdateReloaded == NULL) if (UpdateReloaded == NULL)
{ {
printf("Failed to load update function from game DLL!\n"); printf("Failed to load update function from game DLL!\n");
return false; return false;
} }
#ifdef VISUAL_STUDIO #ifdef VISUAL_STUDIO
Shutdown ShutdownReloaded = (Shutdown)GetProcAddress(DevData.GameLib, "?Shutdown@Game@@YAXXZ"); Shutdown ShutdownReloaded = (Shutdown)GetProcAddress(DevData.GameLib, "?Shutdown@Game@@YAXXZ");
#else #else
Shutdown ShutdownReloaded = (Shutdown)GetProcAddress(DevData.GameLib, "_ZN4Game8ShutdownEv"); Shutdown ShutdownReloaded = (Shutdown)GetProcAddress(DevData.GameLib, "_ZN4Game8ShutdownEv");
#endif #endif
if (ShutdownReloaded == NULL) if (ShutdownReloaded == NULL)
{ {
printf("Failed to load shutdown function from game DLL\n"); printf("Failed to load shutdown function from game DLL\n");
return false; return false;
} }
StartupFunc = StartupReloaded; StartupFunc = StartupReloaded;
UpdateFunc = UpdateReloaded; UpdateFunc = UpdateReloaded;
ShutdownFunc = ShutdownReloaded; ShutdownFunc = ShutdownReloaded;
printf("Loaded Game DLL successfully!\n"); printf("Loaded Game DLL successfully!\n");
return true; return true;
} }
int main() int main()
{ {
char PathBuf[512]{ 0 }; char PathBuf[512]{0};
GetCurrentDirectory(sizeof(PathBuf), PathBuf); GetCurrentDirectory(sizeof(PathBuf), PathBuf);
printf("Current path: %s\n", PathBuf); printf("Current path: %s\n", PathBuf);
if (!ReloadDLL()) return 1; if (!ReloadDLL()) return 1;
Engine.Window.Startup(Shared.Window); Engine.Window.Startup(Shared.Window);
if (Shared.Window.Handle == nullptr) if (Shared.Window.Handle == nullptr)
{ {
printf("Failed to set up window!\n"); printf("Failed to set up window!\n");
return 1; return 1;
} }
DevData.FileWatcher.DLLWatcher.ChangeType = FileChangeType::DLL; DevData.FileWatcher.DLLWatcher.ChangeType = FileChangeType::DLL;
DevData.FileWatcher.ShaderWatcher.ChangeType = FileChangeType::Shader; DevData.FileWatcher.ShaderWatcher.ChangeType = FileChangeType::Shader;
DevData.FileWatcher.CompiledShaderWatcher.ChangeType = FileChangeType::CompiledShader; DevData.FileWatcher.CompiledShaderWatcher.ChangeType = FileChangeType::CompiledShader;
bx::strCopy(DevData.FileWatcher.DLLWatcher.DirPath, sizeof(DevData.FileWatcher.DLLWatcher.DirPath), "cmake-build"); bx::strCopy(DevData.FileWatcher.DLLWatcher.DirPath, sizeof(DevData.FileWatcher.DLLWatcher.DirPath), "cmake-build");
bx::strCopy(DevData.FileWatcher.ShaderWatcher.DirPath, sizeof(DevData.FileWatcher.ShaderWatcher.DirPath), "game/shaders"); bx::strCopy(
bx::strCopy(DevData.FileWatcher.CompiledShaderWatcher.DirPath, sizeof(DevData.FileWatcher.CompiledShaderWatcher.DirPath), "game/compiled-shaders/dx11"); DevData.FileWatcher.ShaderWatcher.DirPath, sizeof(DevData.FileWatcher.ShaderWatcher.DirPath), "game/shaders");
bx::strCopy(DevData.FileWatcher.CompiledShaderWatcher.DirPath,
sizeof(DevData.FileWatcher.CompiledShaderWatcher.DirPath),
"game/compiled-shaders/dx11");
wcscpy(DevData.FileWatcher.DLLWatcher.CompName, DLLWatch); wcscpy(DevData.FileWatcher.DLLWatcher.CompName, DLLWatch);
DWORD fileWatcherThreadId = 0; DWORD fileWatcherThreadId = 0;
HANDLE dllThread = CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.DLLWatcher, 0, &fileWatcherThreadId); HANDLE dllThread =
HANDLE shaderThread = CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.ShaderWatcher, 0, &fileWatcherThreadId); CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.DLLWatcher, 0, &fileWatcherThreadId);
HANDLE compiledShaderThread = CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.CompiledShaderWatcher, 0, &fileWatcherThreadId); HANDLE shaderThread =
CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.ShaderWatcher, 0, &fileWatcherThreadId);
HANDLE compiledShaderThread =
CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.CompiledShaderWatcher, 0, &fileWatcherThreadId);
Shared.Game.PermanentStorageSize = 1024*1024; Shared.Game.PermanentStorageSize = 1024 * 1024;
Shared.Game.PermanentStorage = VirtualAllocEx(GetCurrentProcess(), NULL, Shared.Game.PermanentStorageSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); Shared.Game.PermanentStorage = VirtualAllocEx(
Shared.Game.EntityStorageSize = 1024*1024; GetCurrentProcess(), NULL, Shared.Game.PermanentStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Shared.Game.EntityStorage = VirtualAllocEx(GetCurrentProcess(), NULL, Shared.Game.EntityStorageSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); Shared.Game.EntityStorageSize = 1024 * 1024;
StartupFunc(Shared); Shared.Game.EntityStorage = VirtualAllocEx(
GetCurrentProcess(), NULL, Shared.Game.EntityStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Shared.Game.TransientStorageSize = 1024 * 1024 * 100;
Shared.Game.TransientStorage = VirtualAllocEx(
GetCurrentProcess(), NULL, Shared.Game.TransientStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
StartupFunc(Shared);
bool isRunning = true; bool isRunning = true;
while (isRunning) while (isRunning)
{ {
Engine.Window.Update(Shared.Window); Engine.Window.Update(Shared.Window);
if (Engine.Window.CloseRequested) if (Engine.Window.CloseRequested)
{ {
isRunning = false; isRunning = false;
} }
FileChangeNotification* DLLChange = nullptr; FileChangeNotification* DLLChange = nullptr;
if (DevData.FileWatcher.DLLQueue.pop()) if (DevData.FileWatcher.DLLQueue.pop())
{ {
// Empty queue to avoid multiple reloads // Empty queue to avoid multiple reloads
while (DevData.FileWatcher.DLLQueue.pop()) {} while (DevData.FileWatcher.DLLQueue.pop())
ShutdownFunc(); {
ReloadDLL(); }
StartupFunc(Shared); ShutdownFunc();
} ReloadDLL();
StartupFunc(Shared);
}
FileChangeNotification* CompiledShaderChange = nullptr; FileChangeNotification* CompiledShaderChange = nullptr;
while ((CompiledShaderChange = DevData.FileWatcher.ShaderQueue.pop())) while ((CompiledShaderChange = DevData.FileWatcher.ShaderQueue.pop()))
{ {
if (Shared.Dev.ChangedShaderCount < BX_COUNTOF(Shared.Dev.ChangedShaders)) if (Shared.Dev.ChangedShaderCount < BX_COUNTOF(Shared.Dev.ChangedShaders))
{ {
wcscpy(Shared.Dev.ChangedShaders[Shared.Dev.ChangedShaderCount].FileName, CompiledShaderChange->FileName); wcscpy(Shared.Dev.ChangedShaders[Shared.Dev.ChangedShaderCount].FileName,
++Shared.Dev.ChangedShaderCount; CompiledShaderChange->FileName);
} ++Shared.Dev.ChangedShaderCount;
else }
{ else
printf("Ran out of shader change buffer!\n"); {
} printf("Ran out of shader change buffer!\n");
} }
}
UpdateFunc(); UpdateFunc();
} }
ShutdownFunc(); ShutdownFunc();
Engine.Window.Shutdown(); Engine.Window.Shutdown();
DevData.FileWatcher.DLLWatcher.Shutdown = true; DevData.FileWatcher.DLLWatcher.Shutdown = true;
DevData.FileWatcher.ShaderWatcher.Shutdown = true; DevData.FileWatcher.ShaderWatcher.Shutdown = true;
DevData.FileWatcher.CompiledShaderWatcher.Shutdown = true; DevData.FileWatcher.CompiledShaderWatcher.Shutdown = true;
WaitForSingleObject(dllThread, 100); WaitForSingleObject(dllThread, 100);
WaitForSingleObject(shaderThread, 100); WaitForSingleObject(shaderThread, 100);
WaitForSingleObject(compiledShaderThread, 100); WaitForSingleObject(compiledShaderThread, 100);
return 0; return 0;
} }

View File

@@ -1,7 +1,10 @@
#include "../engine/Shared.h"
#include "Global.h" #include "Global.h"
#include "Instance.h"
#include "bx/bx.h" #include "bx/bx.h"
#include "bx/math.h" #include "bx/math.h"
#include <cassert> #include <cassert>
#include <cstdint>
namespace namespace
{ {
@@ -105,4 +108,15 @@ namespace Game
{ {
GameInst = &instance; GameInst = &instance;
} }
void* AllocateScratch(size_t byteCount, size_t align = 16)
{
size_t offset = GetInstance().UsedScratchAmount;
uint8_t* base = static_cast<uint8_t*>(GetShared().Game.TransientStorage);
uint8_t* current = base + offset;
uintptr_t ptrAligned = ((reinterpret_cast<uintptr_t>(current) + align - 1) / align) * align;
uintptr_t newOffset = ptrAligned - reinterpret_cast<uintptr_t>(base) + byteCount;
if (newOffset > GetShared().Game.TransientStorageSize) return nullptr;
return reinterpret_cast<void*>(ptrAligned);
}
} // namespace Game } // namespace Game

View File

@@ -2,26 +2,48 @@
#include "bx/math.h" #include "bx/math.h"
struct Vec2
{
float x = 0.0f;
float y = 0.0f;
};
struct Vec3
{
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
};
struct Vec4
{
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
float w = 0.0f;
};
struct Mat3
{
// clang-format off
float M[9]{
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
};
// clang-format on
};
struct Mat4 struct Mat4
{ {
// clang-format off
float M[16]{ float M[16]{
1.0, 1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 0.0, 1.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
}; };
// clang-format on
}; };
struct Transform struct Transform
@@ -54,4 +76,5 @@ namespace Game
void SetShared(SharedData& instance); void SetShared(SharedData& instance);
GameInstance& GetInstance(); GameInstance& GetInstance();
void SetInstance(GameInstance& instance); void SetInstance(GameInstance& instance);
void* AllocateScratch(size_t byteCount);
} // namespace Game } // namespace Game

View File

@@ -8,4 +8,32 @@ namespace Game
{ {
return GetShared().Window.HeldScanCodes[(int32_t)key]; return GetShared().Window.HeldScanCodes[(int32_t)key];
} }
bool GetKeyPressedNow(ScanCode key)
{
auto& win = GetShared().Window;
return win.HeldScanCodes[(int32_t)key] && !win.LastHeldScanCodes[(int32_t)key];
}
bool GetKeyReleasedNow(ScanCode key)
{
auto& win = GetShared().Window;
return !win.HeldScanCodes[(int32_t)key] && win.LastHeldScanCodes[(int32_t)key];
}
bool GetMouseButton(MouseButton button)
{
return GetShared().Window.HeldMouseButtons[(int32_t)button];
}
bool GetMouseButtonPressedNow(MouseButton button)
{
auto& win = GetShared().Window;
return win.HeldMouseButtons[(int32_t)button] && !win.LastHeldMouseButtons[(int32_t)button];
}
bool GetMouseButtonReleasedNow(MouseButton button)
{
auto& win = GetShared().Window;
return !win.HeldMouseButtons[(int32_t)button] && win.LastHeldMouseButtons[(int32_t)button];
}
Vec2 GetMouseMovement()
{
return {GetShared().Window.MouseDeltaX, GetShared().Window.MouseDeltaY};
}
} // namespace Game } // namespace Game

View File

@@ -1,4 +1,14 @@
#pragma once #pragma once
#include "Global.h"
enum class MouseButton
{
Left = 1,
Middle = 2,
Right = 3,
Four = 4,
Five = 5,
};
enum class ScanCode enum class ScanCode
{ {
@@ -60,50 +70,50 @@ enum class ScanCode
LEFTBRACKET = 47, LEFTBRACKET = 47,
RIGHTBRACKET = 48, RIGHTBRACKET = 48,
BACKSLASH = 49, /**< Located at the lower left of the return BACKSLASH = 49, /**< Located at the lower left of the return
* key on ISO keyboards and at the right end * key on ISO keyboards and at the right end
* of the QWERTY row on ANSI keyboards. * of the QWERTY row on ANSI keyboards.
* Produces REVERSE SOLIDUS (backslash) and * Produces REVERSE SOLIDUS (backslash) and
* VERTICAL LINE in a US layout, REVERSE * VERTICAL LINE in a US layout, REVERSE
* SOLIDUS and VERTICAL LINE in a UK Mac * SOLIDUS and VERTICAL LINE in a UK Mac
* layout, NUMBER SIGN and TILDE in a UK * layout, NUMBER SIGN and TILDE in a UK
* Windows layout, DOLLAR SIGN and POUND SIGN * Windows layout, DOLLAR SIGN and POUND SIGN
* in a Swiss German layout, NUMBER SIGN and * in a Swiss German layout, NUMBER SIGN and
* APOSTROPHE in a German layout, GRAVE * APOSTROPHE in a German layout, GRAVE
* ACCENT and POUND SIGN in a French Mac * ACCENT and POUND SIGN in a French Mac
* layout, and ASTERISK and MICRO SIGN in a * layout, and ASTERISK and MICRO SIGN in a
* French Windows layout. * French Windows layout.
*/ */
NONUSHASH = 50, /**< ISO USB keyboards actually use this code NONUSHASH = 50, /**< ISO USB keyboards actually use this code
* instead of 49 for the same key, but all * instead of 49 for the same key, but all
* OSes I've seen treat the two codes * OSes I've seen treat the two codes
* identically. So, as an implementor, unless * identically. So, as an implementor, unless
* your keyboard generates both of those * your keyboard generates both of those
* codes and your OS treats them differently, * codes and your OS treats them differently,
* you should generate BACKSLASH * you should generate BACKSLASH
* instead of this code. As a user, you * instead of this code. As a user, you
* should not rely on this code because SDL * should not rely on this code because SDL
* will never generate it with most (all?) * will never generate it with most (all?)
* keyboards. * keyboards.
*/ */
SEMICOLON = 51, SEMICOLON = 51,
APOSTROPHE = 52, APOSTROPHE = 52,
GRAVE = 53, /**< Located in the top left corner (on both ANSI GRAVE = 53, /**< Located in the top left corner (on both ANSI
* and ISO keyboards). Produces GRAVE ACCENT and * and ISO keyboards). Produces GRAVE ACCENT and
* TILDE in a US Windows layout and in US and UK * TILDE in a US Windows layout and in US and UK
* Mac layouts on ANSI keyboards, GRAVE ACCENT * Mac layouts on ANSI keyboards, GRAVE ACCENT
* and NOT SIGN in a UK Windows layout, SECTION * and NOT SIGN in a UK Windows layout, SECTION
* SIGN and PLUS-MINUS SIGN in US and UK Mac * SIGN and PLUS-MINUS SIGN in US and UK Mac
* layouts on ISO keyboards, SECTION SIGN and * layouts on ISO keyboards, SECTION SIGN and
* DEGREE SIGN in a Swiss German layout (Mac: * DEGREE SIGN in a Swiss German layout (Mac:
* only on ISO keyboards), CIRCUMFLEX ACCENT and * only on ISO keyboards), CIRCUMFLEX ACCENT and
* DEGREE SIGN in a German layout (Mac: only on * DEGREE SIGN in a German layout (Mac: only on
* ISO keyboards), SUPERSCRIPT TWO and TILDE in a * ISO keyboards), SUPERSCRIPT TWO and TILDE in a
* French Windows layout, COMMERCIAL AT and * French Windows layout, COMMERCIAL AT and
* NUMBER SIGN in a French Mac layout on ISO * NUMBER SIGN in a French Mac layout on ISO
* keyboards, and LESS-THAN SIGN and GREATER-THAN * keyboards, and LESS-THAN SIGN and GREATER-THAN
* SIGN in a Swiss German, German, or French Mac * SIGN in a Swiss German, German, or French Mac
* layout on ANSI keyboards. * layout on ANSI keyboards.
*/ */
COMMA = 54, COMMA = 54,
PERIOD = 55, PERIOD = 55,
SLASH = 56, SLASH = 56,
@@ -139,7 +149,7 @@ enum class ScanCode
UP = 82, UP = 82,
NUMLOCKCLEAR = 83, /**< num lock on PC, clear on Mac keyboards NUMLOCKCLEAR = 83, /**< num lock on PC, clear on Mac keyboards
*/ */
KP_DIVIDE = 84, KP_DIVIDE = 84,
KP_MULTIPLY = 85, KP_MULTIPLY = 85,
KP_MINUS = 86, KP_MINUS = 86,
@@ -158,19 +168,19 @@ enum class ScanCode
KP_PERIOD = 99, KP_PERIOD = 99,
NONUSBACKSLASH = 100, /**< This is the additional key that ISO NONUSBACKSLASH = 100, /**< This is the additional key that ISO
* keyboards have over ANSI ones, * keyboards have over ANSI ones,
* located between left shift and Y. * located between left shift and Y.
* Produces GRAVE ACCENT and TILDE in a * Produces GRAVE ACCENT and TILDE in a
* US or UK Mac layout, REVERSE SOLIDUS * US or UK Mac layout, REVERSE SOLIDUS
* (backslash) and VERTICAL LINE in a * (backslash) and VERTICAL LINE in a
* US or UK Windows layout, and * US or UK Windows layout, and
* LESS-THAN SIGN and GREATER-THAN SIGN * LESS-THAN SIGN and GREATER-THAN SIGN
* in a Swiss German, German, or French * in a Swiss German, German, or French
* layout. */ * layout. */
APPLICATION = 101, /**< windows contextual menu, compose */ APPLICATION = 101, /**< windows contextual menu, compose */
POWER = 102, /**< The USB document says this is a status flag, POWER = 102, /**< The USB document says this is a status flag,
* not a physical key - but some Mac keyboards * not a physical key - but some Mac keyboards
* do have a power key. */ * do have a power key. */
KP_EQUALS = 103, KP_EQUALS = 103,
F13 = 104, F13 = 104,
F14 = 105, F14 = 105,
@@ -295,9 +305,9 @@ enum class ScanCode
RGUI = 231, /**< windows, command (apple), meta */ RGUI = 231, /**< windows, command (apple), meta */
MODE = 257, /**< I'm not sure if this is really not covered MODE = 257, /**< I'm not sure if this is really not covered
* by any of the above, but since there's a * by any of the above, but since there's a
* special SDL_KMOD_MODE for it I'm adding it here * special SDL_KMOD_MODE for it I'm adding it here
*/ */
/* @} */ /* Usage page 0x07 */ /* @} */ /* Usage page 0x07 */
@@ -378,4 +388,10 @@ enum class ScanCode
namespace Game namespace Game
{ {
bool GetKey(ScanCode key); bool GetKey(ScanCode key);
} bool GetKeyPressedNow(ScanCode key);
bool GetKeyReleasedNow(ScanCode key);
bool GetMouseButton(MouseButton button);
bool GetMouseButtonPressedNow(MouseButton button);
bool GetMouseButtonReleasedNow(MouseButton button);
Vec2 GetMouseMovement();
} // namespace Game

View File

@@ -5,14 +5,37 @@
namespace Game namespace Game
{ {
enum class PlayerMode
{
Walk,
Freefly,
};
struct Time
{
double Now = 0.0;
double Delta = 0.0;
uint32_t FrameCounter = 0;
int64_t StartTime = 0;
};
struct PlayerData
{
Transform FreeflyCamTransform;
float FreeflyXRot = 0.0f;
float FreeflyYRot = 0.0f;
Transform PlayerTransform;
Transform PlayerCamTransform;
PlayerMode Mode = PlayerMode::Freefly;
};
struct GameInstance struct GameInstance
{ {
bool IsInitialized = false; bool IsInitialized = false;
uint64_t Size = sizeof(GameInstance); uint64_t Size = sizeof(GameInstance);
uint32_t FrameCounter = 0; uint8_t UsedScratchAmount = 0;
int64_t StartTime = 0; Time Time;
double Now = 0.0; PlayerData Player;
double Delta = 0.0;
Level GameLevel; Level GameLevel;
}; };
} // namespace Game } // namespace Game

View File

@@ -27,7 +27,8 @@ namespace Game
bgfx::setState(currentMaterial.State); bgfx::setState(currentMaterial.State);
float TimeValues[4]{0.0f}; float TimeValues[4]{0.0f};
TimeValues[0] = GetInstance().Now; TimeValues[0] = GetInstance().Time.Now;
bgfx::setTexture(0, currentMaterial.Textures[0].SamplerHandle, currentMaterial.Textures[0].Handle);
bgfx::setUniform(currentMaterial.Uniforms[Material::UTime], TimeValues); bgfx::setUniform(currentMaterial.Uniforms[Material::UTime], TimeValues);
bgfx::setUniform(currentMaterial.Uniforms[Material::UDotColor], TestColor); bgfx::setUniform(currentMaterial.Uniforms[Material::UDotColor], TestColor);
@@ -66,13 +67,40 @@ namespace Game
void Level::Update() void Level::Update()
{ {
if (GetKey(ScanCode::R)) PlayerData& player = GetInstance().Player;
if (GetKeyPressedNow(ScanCode::R))
{ {
Cubes.Count = 0; Cubes.Count = 0;
Tests.Count = 0; Tests.Count = 0;
Setup(GetShared().Game); Setup(GetShared().Game);
} }
float delta = GetInstance().Time.Delta;
constexpr float moveSpeed = 10.0f;
constexpr float rotSpeed = 0.6f;
float forwardInput = (GetKey(ScanCode::W) ? 1.0f : 0.0f) + (GetKey(ScanCode::S) ? -1.0f : 0.0f);
float rightInput = (GetKey(ScanCode::D) ? 1.0f : 0.0f) + (GetKey(ScanCode::A) ? -1.0f : 0.0f);
bx::Vec3 moveInput = bx::Vec3{rightInput, forwardInput, 0.0f};
moveInput = bx::normalize(moveInput);
bx::Vec3 inputVec = {moveInput.x * delta * moveSpeed, 0.0f, moveInput.y * delta * moveSpeed};
bx::Vec3 camForward = player.FreeflyCamTransform.Forward();
bx::Vec3 camRight = player.FreeflyCamTransform.Right();
if (GetMouseButton(MouseButton::Left))
{
Vec2 mouseMovement = GetMouseMovement();
bx::Vec3 rotInput = {mouseMovement.y * delta * rotSpeed, mouseMovement.x * delta * rotSpeed, 0.0f};
player.FreeflyXRot += rotInput.x;
player.FreeflyYRot += rotInput.y;
bx::mtxRotateY(player.FreeflyCamTransform.Rotation.M, player.FreeflyYRot);
player.FreeflyCamTransform.RotateLocal({player.FreeflyXRot, 0.0f, 0.0f});
}
player.FreeflyCamTransform.TranslateLocal({0.0f, 0.0f, -inputVec.z});
player.FreeflyCamTransform.TranslateLocal({-inputVec.x, 0.0f, 0.0f});
Cubes.Update(); Cubes.Update();
Tests.Update(); Tests.Update();
} }
@@ -87,7 +115,7 @@ namespace Game
{ {
if (TestX >= 0 && TestY >= 0) if (TestX >= 0 && TestY >= 0)
{ {
double globalTime = GetInstance().Now; double globalTime = GetInstance().Time.Now;
double time = TestY <= 5 ? globalTime * 1.0f : 0.0f; double time = TestY <= 5 ? globalTime * 1.0f : 0.0f;
float scale = 1.0f + TestX * 0.4f; float scale = 1.0f + TestX * 0.4f;
EData.Transform.Position = bx::Vec3{TestX * 2.0f, TestY * 2.0f, 0.0f}; EData.Transform.Position = bx::Vec3{TestX * 2.0f, TestY * 2.0f, 0.0f};

View File

@@ -2,6 +2,7 @@
#include "Instance.h" #include "Instance.h"
#include "Log.h" #include "Log.h"
#include "Setup.h" #include "Setup.h"
#include "bx/bx.h"
#include "bx/timer.h" #include "bx/timer.h"
#include "rendering/Rendering.h" #include "rendering/Rendering.h"
@@ -52,13 +53,18 @@ namespace Game
void Update() void Update()
{ {
++GetInstance().FrameCounter; ++GetInstance().Time.FrameCounter;
double newNow = (bx::getHPCounter() - GetInstance().StartTime) / (double)(bx::getHPFrequency()); double newNow = (bx::getHPCounter() - GetInstance().Time.StartTime) / (double)(bx::getHPFrequency());
GetInstance().Delta = newNow - GetInstance().Now; GetInstance().Time.Delta = newNow - GetInstance().Time.Now;
GetInstance().Now = newNow; GetInstance().Time.Now = newNow;
SetupInstance.Rendering.Update(); SetupInstance.Rendering.Update();
GetShared().Window.MouseDeltaX = 0.0f;
GetShared().Window.MouseDeltaY = 0.0f; auto& win = GetShared().Window;
win.MouseDeltaX = 0.0f;
win.MouseDeltaY = 0.0f;
bx::memCopy(win.LastHeldScanCodes, win.HeldScanCodes, sizeof(win.HeldScanCodes));
bx::memCopy(win.LastHeldMouseButtons, win.HeldMouseButtons, sizeof(win.HeldMouseButtons));
} }
void Shutdown() void Shutdown()

View File

@@ -1,15 +1,18 @@
#include "../../engine/Shared.h" #include "../../engine/Shared.h"
#include "../Global.h" #include "../Global.h"
#include "../Input.h"
#include "../Instance.h" #include "../Instance.h"
#include "../Log.h" #include "../Log.h"
#include "../Mesh.h" #include "../Mesh.h"
#include "Rendering.h" #include "Rendering.h"
#include "bgfx/defines.h" #include "bgfx/defines.h"
#include "bx/filepath.h"
#include "bx/math.h" #include "bx/math.h"
#include "bx/timer.h" #include "bx/timer.h"
#include <bgfx/bgfx.h> #include <bgfx/bgfx.h>
#include <bimg/bimg.h>
#include <bx/file.h> #include <bx/file.h>
#include <cstdio>
#include <thread> #include <thread>
using namespace std::chrono_literals; using namespace std::chrono_literals;
@@ -18,20 +21,34 @@ namespace Game
{ {
namespace namespace
{ {
static const bgfx::Memory* loadMem(bx::FileReaderI* _reader, const bx::FilePath& _filePath) const bgfx::Memory* loadFile(const char* path, bool appendZero = false, int32_t retryCount = 1)
{ {
if (bx::open(_reader, _filePath)) FILE* file;
for (int32_t i = 0; i < retryCount; ++i)
{ {
uint32_t size = (uint32_t)bx::getSize(_reader); file = fopen(path, "rb");
const bgfx::Memory* mem = bgfx::alloc(size + 1); if (file == nullptr && i < retryCount - 1)
bx::read(_reader, mem->data, size, bx::ErrorAssert{}); {
bx::close(_reader); std::this_thread::sleep_for(100ms);
mem->data[mem->size - 1] = '\0'; break;
}
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
const bgfx::Memory* mem = bgfx::alloc(fileSize + 1);
fread(mem->data, 1, fileSize, file);
if (appendZero)
{
mem->data[mem->size - 1] = '\0';
}
fclose(file);
return mem; return mem;
} }
Log("Failed to load %s.", _filePath.getCPtr()); return nullptr;
return NULL;
} }
bgfx::ShaderHandle loadShader(const char* FILENAME) bgfx::ShaderHandle loadShader(const char* FILENAME)
@@ -72,31 +89,98 @@ namespace Game
bx::strCat(buffer, sizeof(buffer), ".bin"); bx::strCat(buffer, sizeof(buffer), ".bin");
Log("Loading shader at %s", buffer); Log("Loading shader at %s", buffer);
const bgfx::Memory* mem = loadFile(buffer, true, 3);
FILE* file; if (mem == nullptr)
for (int32_t i = 0; i < 3; ++i)
{ {
file = fopen(buffer, "rb"); Log("Failed to load shader %s", FILENAME);
if (file == nullptr) return {};
{ }
std::this_thread::sleep_for(100ms); return bgfx::createShader(mem);
break; }
}
fseek(file, 0, SEEK_END); bgfx::TextureHandle loadTexture(const bx::FilePath& _filePath,
long fileSize = ftell(file); uint64_t _flags,
fseek(file, 0, SEEK_SET); uint8_t _skip,
bgfx::TextureInfo* _info,
bimg::Orientation::Enum* _orientation)
{
BX_UNUSED(_skip);
bgfx::TextureHandle handle = BGFX_INVALID_HANDLE;
bx::Error err;
const bgfx::Memory* mem = bgfx::alloc(fileSize + 1); const bgfx::Memory* data = loadFile(_filePath.getCPtr());
fread(mem->data, 1, fileSize, file); if (data == nullptr)
mem->data[mem->size - 1] = '\0'; {
fclose(file); Log("Failed to find image %s", _filePath.getCPtr());
return handle;
return bgfx::createShader(mem); }
bimg::ImageContainer imageContainer;
if (!bimg::imageParse(imageContainer, data->data, data->size, &err))
{
Log("Failed to load image %s", _filePath.getCPtr());
return handle;
}
if (NULL != _orientation)
{
*_orientation = imageContainer.m_orientation;
} }
Log("Failed to load shader %s", FILENAME); const bgfx::Memory* mem = bgfx::makeRef(imageContainer.m_data, imageContainer.m_size);
return {};
if (NULL != _info)
{
bgfx::calcTextureSize(*_info,
uint16_t(imageContainer.m_width),
uint16_t(imageContainer.m_height),
uint16_t(imageContainer.m_depth),
imageContainer.m_cubeMap,
1 < imageContainer.m_numMips,
imageContainer.m_numLayers,
bgfx::TextureFormat::Enum(imageContainer.m_format));
}
if (imageContainer.m_cubeMap)
{
handle = bgfx::createTextureCube(uint16_t(imageContainer.m_width),
1 < imageContainer.m_numMips,
imageContainer.m_numLayers,
bgfx::TextureFormat::Enum(imageContainer.m_format),
_flags,
mem);
}
else if (1 < imageContainer.m_depth)
{
handle = bgfx::createTexture3D(uint16_t(imageContainer.m_width),
uint16_t(imageContainer.m_height),
uint16_t(imageContainer.m_depth),
1 < imageContainer.m_numMips,
bgfx::TextureFormat::Enum(imageContainer.m_format),
_flags,
mem);
}
else if (bgfx::isTextureValid(0,
false,
imageContainer.m_numLayers,
bgfx::TextureFormat::Enum(imageContainer.m_format),
_flags))
{
handle = bgfx::createTexture2D(uint16_t(imageContainer.m_width),
uint16_t(imageContainer.m_height),
1 < imageContainer.m_numMips,
imageContainer.m_numLayers,
bgfx::TextureFormat::Enum(imageContainer.m_format),
_flags,
mem);
}
if (bgfx::isValid(handle))
{
const bx::StringView name(_filePath);
bgfx::setName(handle, name.getPtr(), name.getLength());
}
return handle;
} }
} // namespace } // namespace
@@ -108,7 +192,6 @@ namespace Game
bgfx::Init init; bgfx::Init init;
init.type = bgfx::RendererType::Direct3D12; init.type = bgfx::RendererType::Direct3D12;
init.debug = true; init.debug = true;
init.callback = &Callback;
init.platformData.nwh = shared.Window.Handle; init.platformData.nwh = shared.Window.Handle;
init.platformData.ndt = nullptr; init.platformData.ndt = nullptr;
init.platformData.type = bgfx::NativeWindowHandleType::Default; init.platformData.type = bgfx::NativeWindowHandleType::Default;
@@ -129,14 +212,18 @@ namespace Game
bgfx::setDebug(BGFX_DEBUG_TEXT); bgfx::setDebug(BGFX_DEBUG_TEXT);
bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x303030ff, 1.0f, 0); bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x303030ff, 1.0f, 0);
DefaultSampler = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler);
Textures[0].Handle =
loadTexture(bx::FilePath{"models/body.dds"}, BGFX_TEXTURE_NONE | BGFX_SAMPLER_NONE, 0, nullptr, nullptr);
Textures[0].SamplerHandle = DefaultSampler;
LoadMesh(Models[0], "models/cube.gltf"); LoadMesh(Models[0], "models/cube.gltf");
LoadMesh(Models[1], "models/zurg.gltf"); LoadMesh(Models[1], "models/zurg.gltf");
Materials[0] = Material::LoadFromShader("vert", "frag"); Materials[0] = Material::LoadFromShader("vert", "frag", Textures[0].Handle, Textures[0].SamplerHandle);
if (!GetInstance().IsInitialized) if (!GetInstance().IsInitialized)
{ {
GetInstance().StartTime = bx::getHPCounter(); GetInstance().Time.StartTime = bx::getHPCounter();
} }
} }
@@ -170,30 +257,6 @@ namespace Game
{ {
GetInstance().GameLevel.Update(); GetInstance().GameLevel.Update();
float delta = GetInstance().Delta;
constexpr float moveSpeed = 10.0f;
constexpr float rotSpeed = 0.6f;
float forwardInput = (GetKey(ScanCode::W) ? 1.0f : 0.0f) + (GetKey(ScanCode::S) ? -1.0f : 0.0f);
float rightInput = (GetKey(ScanCode::D) ? 1.0f : 0.0f) + (GetKey(ScanCode::A) ? -1.0f : 0.0f);
bx::Vec3 moveInput = bx::Vec3{rightInput, forwardInput, 0.0f};
moveInput = bx::normalize(moveInput);
bx::Vec3 inputVec = {moveInput.x * delta * moveSpeed, 0.0f, moveInput.y * delta * moveSpeed};
bx::Vec3 camForward = Cam.Transform.Forward();
bx::Vec3 camRight = Cam.Transform.Right();
bx::Vec3 rotInput = {
shared.Window.MouseDeltaY * delta * rotSpeed, shared.Window.MouseDeltaX * delta * rotSpeed, 0.0f};
Cam.FreelookXRot += rotInput.x;
Cam.FreelookYRot += rotInput.y;
bx::mtxRotateY(Cam.Transform.Rotation.M, Cam.FreelookYRot);
Cam.Transform.RotateLocal({Cam.FreelookXRot, 0.0f, 0.0f});
Cam.Transform.TranslateLocal({0.0f, 0.0f, -inputVec.z});
Cam.Transform.TranslateLocal({-inputVec.x, 0.0f, 0.0f});
bgfx::dbgTextPrintf(1, 4, 0x0f, "Cam forward: %.2f %.2f %.2f", camForward.x, camForward.y, camForward.z);
} }
// Set view and projection matrix for view 0. // Set view and projection matrix for view 0.
@@ -205,8 +268,17 @@ namespace Game
0.1f, 0.1f,
1000.0f, 1000.0f,
bgfx::getCaps()->homogeneousDepth); bgfx::getCaps()->homogeneousDepth);
Cam.Transform.UpdateMatrix();
bgfx::setViewTransform(0, Cam.Transform.M.M, proj); auto& player = GetInstance().Player;
if (player.Mode == PlayerMode::Freefly)
{
player.FreeflyCamTransform.UpdateMatrix();
bgfx::setViewTransform(0, player.FreeflyCamTransform.M.M, proj);
}
else
{
// TODO
}
// Set view 0 default viewport. // Set view 0 default viewport.
bgfx::setViewRect(0, 0, 0, shared.Window.WindowWidth, shared.Window.WindowHeight); bgfx::setViewRect(0, 0, 0, shared.Window.WindowWidth, shared.Window.WindowHeight);
@@ -215,9 +287,10 @@ namespace Game
GetInstance().GameLevel.Cubes.Render(Models, Materials); GetInstance().GameLevel.Cubes.Render(Models, Materials);
GetInstance().GameLevel.Tests.Render(Models, Materials); GetInstance().GameLevel.Tests.Render(Models, Materials);
bgfx::dbgTextPrintf(1, 1, 0x0F, "Time: %.1f", GetInstance().Now); bgfx::dbgTextPrintf(1, 1, 0x0F, "Time: %.1f", GetInstance().Time.Now);
bgfx::dbgTextPrintf(1, 2, 0x0F, "Frame: %u", GetInstance().FrameCounter); bgfx::dbgTextPrintf(1, 2, 0x0F, "Frame: %u", GetInstance().Time.FrameCounter);
bgfx::dbgTextPrintf(1, 3, 0x0F, "Delta: %.3fms / %.0ffps", GetInstance().Delta, 1.0 / GetInstance().Delta); bgfx::dbgTextPrintf(
1, 3, 0x0F, "Delta: %.3fms / %.0ffps", GetInstance().Time.Delta, 1.0 / GetInstance().Time.Delta);
bgfx::frame(); bgfx::frame();
} }
@@ -227,10 +300,14 @@ namespace Game
bgfx::shutdown(); bgfx::shutdown();
} }
Material Material::LoadFromShader(const char* vertPath, const char* fragPath) Material Material::LoadFromShader(const char* vertPath,
const char* fragPath,
bgfx::TextureHandle tex,
bgfx::UniformHandle sampler)
{ {
bgfx::ShaderHandle vertexShader = loadShader("vert"); BX_ASSERT(vertPath != nullptr && fragPath != nullptr, "Invalid shader path!");
bgfx::ShaderHandle fragmentShader = loadShader("frag"); bgfx::ShaderHandle vertexShader = loadShader(vertPath);
bgfx::ShaderHandle fragmentShader = loadShader(fragPath);
Material mat; Material mat;
mat.Shader = bgfx::createProgram(vertexShader, fragmentShader, true); mat.Shader = bgfx::createProgram(vertexShader, fragmentShader, true);
@@ -238,6 +315,8 @@ namespace Game
BGFX_STATE_CULL_CCW | BGFX_STATE_MSAA; BGFX_STATE_CULL_CCW | BGFX_STATE_MSAA;
mat.Uniforms[Material::UTime] = bgfx::createUniform("u_time", bgfx::UniformType::Vec4); mat.Uniforms[Material::UTime] = bgfx::createUniform("u_time", bgfx::UniformType::Vec4);
mat.Uniforms[Material::UDotColor] = bgfx::createUniform("u_testColor", bgfx::UniformType::Vec4); mat.Uniforms[Material::UDotColor] = bgfx::createUniform("u_testColor", bgfx::UniformType::Vec4);
mat.Textures[0].Handle = tex;
mat.Textures[0].SamplerHandle = sampler;
return mat; return mat;
} }
} // namespace Game } // namespace Game

View File

@@ -1,8 +1,7 @@
#pragma once #pragma once
#include "../Global.h"
#include <bgfx/bgfx.h> #include <bgfx/bgfx.h>
#include <bx/string.h> #include <bx/string.h>
#include <cstdio> #include <cstdint>
namespace Game namespace Game
{ {
@@ -19,84 +18,10 @@ namespace Game
float uv_y; float uv_y;
}; };
struct BgfxCallback : public bgfx::CallbackI struct Texture
{ {
virtual ~BgfxCallback() bgfx::UniformHandle SamplerHandle;
{ bgfx::TextureHandle Handle;
}
virtual void fatal(const char* _filePath, uint16_t _line, bgfx::Fatal::Enum _code, const char* _str) override
{
// Something unexpected happened, inform user and bail out.
printf("Fatal error: 0x%08x: %s", _code, _str);
// Must terminate, continuing will cause crash anyway.
abort();
}
virtual void traceVargs(const char* _filePath, uint16_t _line, const char* _format, va_list _argList) override
{
printf("%s (%d): ", _filePath, _line);
vprintf(_format, _argList);
}
virtual void profilerBegin(const char* /*_name*/,
uint32_t /*_abgr*/,
const char* /*_filePath*/,
uint16_t /*_line*/) override
{
}
virtual void profilerBeginLiteral(const char* /*_name*/,
uint32_t /*_abgr*/,
const char* /*_filePath*/,
uint16_t /*_line*/) override
{
}
virtual void profilerEnd() override
{
}
virtual uint32_t cacheReadSize(uint64_t _id) override
{
return 0;
}
virtual bool cacheRead(uint64_t _id, void* _data, uint32_t _size) override
{
return false;
}
virtual void cacheWrite(uint64_t _id, const void* _data, uint32_t _size) override
{
}
virtual void screenShot(const char* _filePath,
uint32_t _width,
uint32_t _height,
uint32_t _pitch,
const void* _data,
uint32_t /*_size*/,
bool _yflip) override
{
}
virtual void captureBegin(uint32_t _width,
uint32_t _height,
uint32_t /*_pitch*/,
bgfx::TextureFormat::Enum /*_format*/,
bool _yflip) override
{
}
virtual void captureEnd() override
{
}
virtual void captureFrame(const void* _data, uint32_t /*_size*/) override
{
}
}; };
struct Model struct Model
@@ -116,24 +41,21 @@ namespace Game
bgfx::ProgramHandle Shader; bgfx::ProgramHandle Shader;
bgfx::UniformHandle Uniforms[8]; bgfx::UniformHandle Uniforms[8];
Texture Textures[4];
uint64_t State = 0; uint64_t State = 0;
static Material LoadFromShader(const char* vertPath, const char* fragPath); static Material LoadFromShader(const char* vertPath,
}; const char* fragPath,
bgfx::TextureHandle = BGFX_INVALID_HANDLE,
struct Camera bgfx::UniformHandle sampler = BGFX_INVALID_HANDLE);
{
float FreelookXRot = 0.0f;
float FreelookYRot = 0.0f;
Transform Transform;
}; };
class GameRendering class GameRendering
{ {
private: private:
bgfx::UniformHandle DefaultSampler;
Texture Textures[8];
Material Materials[8]; Material Materials[8];
Model Models[8]; Model Models[8];
BgfxCallback Callback;
Camera Cam;
public: public:
void Setup(); void Setup();

View File

@@ -3,11 +3,12 @@ $input v_normal
$input v_uv0 $input v_uv0
$input v_wpos $input v_wpos
#include "common.sh"
SAMPLER2D(s_texColor, 0);
uniform vec4 u_time; uniform vec4 u_time;
uniform vec4 u_testColor; uniform vec4 u_testColor;
#include "common.sh"
float circle(vec2 uv, float radius) float circle(vec2 uv, float radius)
{ {
float distSq = uv.x * uv.x + uv.y * uv.y; float distSq = uv.x * uv.x + uv.y * uv.y;
@@ -86,4 +87,5 @@ void main()
// gl_FragColor = brightness; // gl_FragColor = brightness;
// gl_FragColor = dither; // gl_FragColor = dither;
// gl_FragColor = u_testColor; // gl_FragColor = u_testColor;
gl_FragColor = texture2D(s_texColor, v_uv0);
} }

View File

@@ -10,5 +10,5 @@ void main()
v_uv0 = a_texcoord0; v_uv0 = a_texcoord0;
v_wpos = mul(u_model[0], vec4(a_position, 1.0)).xyz; v_wpos = mul(u_model[0], vec4(a_position, 1.0)).xyz;
v_normal = normalize(mul((mat3)u_model[0], a_normal)); v_normal = normalize(mul(mat3(u_model[0]), a_normal));
} }

4
src/setup-release.bat Normal file
View File

@@ -0,0 +1,4 @@
cd dependency/bgfx.cmake
cmake -G "Ninja" -S . -B cmake-build-release -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DBGFX_BUILD_TOOLS=OFF -DBGFX_BUILD_EXAMPLES=OFF
cd ..\..
cmake -G "Ninja" -S . -B cmake-build-release -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON