Compare commits

...

3 Commits

Author SHA1 Message Date
Asuro 60f1e72144 meshes! 2025-02-25 04:03:48 +01:00
Asuro d3dcec1458 more stuff 2025-02-24 05:29:24 +01:00
Asuro 369b994755 handles 2025-02-23 02:07:26 +01:00
20 changed files with 379 additions and 49 deletions
+1
View File
@@ -0,0 +1 @@
*.glb filter=lfs diff=lfs merge=lfs -text
+2
View File
@@ -46,5 +46,7 @@ namespace Game
Time Time;
PlayerData Player;
Level GameLevel;
uint64_t ImguiIniSize = 0;
char ImguiIni[4096]{0};
};
} // namespace Game
+76 -13
View File
@@ -3,9 +3,12 @@
#include "Instance.h"
#include "Level.h"
#include "Log.h"
#include "Mesh.h"
#include "Puzzle.h"
#include "SDL3/SDL_mouse.h"
#include "bgfx/bgfx.h"
#include "imgui.h"
#include "rendering/Rendering.h"
#include <SDL3/SDL.h>
#include <bx/math.h>
#include <cstdint>
@@ -15,7 +18,9 @@ namespace Game
void EntityRenderData::Render(const Model* models, const Material* materials)
{
if (ModelHandle == UINT16_MAX || MaterialHandle == UINT16_MAX) return;
if (!Visible) return;
// Log("%u", ModelHandle);
Transform.UpdateMatrix();
bgfx::setTransform(Transform.M.M);
@@ -42,6 +47,7 @@ namespace Game
SDL_SetWindowRelativeMouseMode(GetShared().Window.SDLWindow, IsGaming);
auto& IO = ImGui::GetIO();
IO.ConfigFlags = FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, IsGaming);
GameRendering::Get().UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug;
}
} // namespace
@@ -52,26 +58,37 @@ namespace Game
bool needReset = false;
needReset |= Cubes.Setup(storagePtr, needReset);
needReset |= Tests.Setup(storagePtr, needReset);
needReset |= PuzzleTiles.Setup(storagePtr, needReset);
PuzzleData.Setup();
if (Cubes.Count == 0)
{
for (uint32_t yy = 0; yy < 11; ++yy)
{
for (uint32_t xx = 0; xx < 11; ++xx)
{
Cube* c = Cubes.New();
Cube* c = Cubes.Get(Cubes.New());
if (c)
{
c->TestX = xx;
c->TestY = yy;
c->Setup();
}
}
}
Cube* floor = Cubes.New();
Cubes.New(); // Floor
}
if (Tests.Count == 0)
{
Tests.New();
Tests.Get(Tests.New())->Setup();
}
if (PuzzleTiles.Count == 0)
{
for (uint32_t puzI = 0; puzI < BX_COUNTOF(Puzzles); ++puzI)
{
Puzzles[puzI].Setup();
}
}
UpdatePlayerInputMode();
@@ -82,6 +99,7 @@ namespace Game
START_PERF();
PlayerData& player = GetInstance().Player;
// Input
float delta = GetInstance().Time.Delta;
delta = 1.0f / 144.0f;
constexpr float moveSpeed = 10.0f;
@@ -138,8 +156,18 @@ namespace Game
player.PlayerCamTransform.RotateLocal({player.WalkXRot, 0.0f, 0.0f});
}
Cubes.Update();
Tests.Update();
// Cubes
for (uint16_t i = 0; i < Cubes.Count; ++i)
{
Cubes.Get({i})->Update();
}
// Puzzle tiles
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
{
Puzzles[i].Update();
}
END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter);
}
@@ -160,21 +188,24 @@ namespace Game
{
player.FreeflyCamTransform.UpdateMatrix();
bgfx::setViewTransform(viewId, player.FreeflyCamTransform.M.M, proj);
bgfx::dbgTextPrintf(1, 0, 0b1100, "NOCLIP");
}
else
{
player.PlayerCamTransform.UpdateMatrix();
bgfx::setViewTransform(viewId, player.PlayerCamTransform.M.M, proj);
bgfx::dbgTextPrintf(1, 0, 0b1100, " ");
}
Cubes.Render(models, materials);
// Cubes.Render(models, materials);
Tests.Render(models, materials);
PuzzleTiles.Render(models, materials);
}
void Cube::Setup()
{
EData.MaterialHandle = 0;
EData.ModelHandle = 0;
EData.ModelHandle = GameRendering::Get().GetModelHandleFromPath("models/cube.gltf");
}
void Cube::Update()
@@ -200,13 +231,45 @@ namespace Game
void TestEntity::Setup()
{
EData.MaterialHandle = 0;
EData.ModelHandle = 1;
EData.ModelHandle = GameRendering::Get().GetModelHandleFromPath("models/zurg.gltf");
EData.Transform.Position = {0.0f, 0.0f, 10.0f};
}
void TestEntity::Update()
{
EData.TestColor[0] = 0.0f;
}
void WorldPuzzle::Setup()
{
Data.PlacedCardCount = 16;
for (int32_t i = 0; i < 16; ++i)
{
Data.PlacedCards[i].RefCard = {0};
Data.PlacedCards[i].Position = {int8_t(i % 4), int8_t(i / 4)};
}
for (uint32_t cardI = 0; cardI < Data.PlacedCardCount; ++cardI)
{
const Puzzle::PlacedPuzzleCard& card = Data.PlacedCards[cardI];
auto& tiles = GetInstance().GameLevel.PuzzleTiles;
TileHandles[cardI] = tiles.New();
bx::Vec3 Pos = {
WorldPosition.x + card.Position.X * WorldCardSize.x,
WorldPosition.y,
WorldPosition.z + card.Position.Y * WorldCardSize.y,
};
auto& tile = *tiles.Get(TileHandles[cardI]);
tile.EData.Transform.Position = Pos;
tile.EData.MaterialHandle = 0;
}
}
void WorldPuzzle::Update()
{
for (int32_t cardI = 0; cardI < Data.PlacedCardCount; ++cardI)
{
Puzzle::PlacedPuzzleCard& card = Data.PlacedCards[cardI];
if (!card.RefCard.IsValid()) continue;
const Puzzle::StaticPuzzleCard& cData = Puzzle::StaticPuzzleData::Get().GetCard(card.RefCard);
GetInstance().GameLevel.PuzzleTiles.Get(TileHandles[cardI])->EData.ModelHandle = cData.ModelHandle;
}
}
} // namespace Game
+46 -23
View File
@@ -2,10 +2,17 @@
#include "../engine/Shared.h"
#include "Global.h"
#include "Log.h"
#include "Puzzle.h"
#include "rendering/Rendering.h"
#include <bgfx/bgfx.h>
#include <cstdint>
#define ENTITY_HANDLE(X) \
struct X \
{ \
uint16_t Idx = UINT16_MAX; \
};
namespace Game
{
struct EntityRenderData
@@ -14,10 +21,12 @@ namespace Game
Transform Transform;
uint16_t MaterialHandle = UINT16_MAX;
uint16_t ModelHandle = UINT16_MAX;
bool Visible = true;
void Render(const Model* models, const Material* materials);
};
ENTITY_HANDLE(CubeHandle);
struct Cube
{
int32_t TestX = -1;
@@ -28,15 +37,21 @@ namespace Game
void Update();
};
ENTITY_HANDLE(TestEntityHandle);
struct TestEntity
{
EntityRenderData EData;
void Setup();
void Update();
};
template <typename T, uint32_t C> class EntityManager
ENTITY_HANDLE(PuzzleTileEntityHandle);
struct PuzzleTileEntity
{
EntityRenderData EData;
};
template <typename T, typename HandleT, uint32_t C> class EntityManager
{
public:
uint16_t Count = 0;
@@ -59,58 +74,66 @@ namespace Game
return changed;
}
T* New()
HandleT New()
{
if (Data == nullptr)
{
Log("Accessed EntityManager before setup!");
return nullptr;
return {};
}
if (Count >= C)
{
Log("Too many entities!");
return nullptr;
return {};
}
Data[Count] = {};
Data[Count].Setup();
T* result = &Data[Count];
HandleT H;
H.Idx = Count;
++Count;
return result;
return H;
}
T* Get(uint16_t idx)
T* Get(HandleT handle)
{
if (idx > Count)
if (handle.Idx > Count)
{
Log("OOB Access!");
return nullptr;
}
return &Data[idx];
}
void Update()
{
for (uint32_t i = 0; i < Count; ++i)
{
Data[i].Update();
}
return &Data[handle.Idx];
}
void Render(const Model* models, const Material* materials)
{
for (int32_t i = 0; i < Count; ++i)
for (uint16_t i = 0; i < Count; ++i)
{
T* c = Get(i);
T* c = Get({i});
if (c) c->EData.Render(models, materials);
}
}
};
struct WorldPuzzle
{
static constexpr Vec2 WorldCardSize{10.0f, 10.0f};
Puzzle::PuzzleData Data;
Vec3 WorldPosition;
PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle];
void Setup();
void Update();
};
class Level
{
public:
EntityManager<Cube, 1024> Cubes;
EntityManager<TestEntity, 32> Tests;
EntityManager<Cube, CubeHandle, 1024> Cubes;
EntityManager<TestEntity, TestEntityHandle, 32> Tests;
EntityManager<PuzzleTileEntity, PuzzleTileEntityHandle, 1024> PuzzleTiles;
public:
Puzzle::StaticPuzzleData PuzzleData;
WorldPuzzle Puzzles[1];
public:
void Setup(GameData& data);
+84 -3
View File
@@ -1,6 +1,12 @@
#include "Log.h"
#include "Mesh.h"
#include "bx/bx.h"
#include "bx/error.h"
#include "bx/file.h"
#include "bx/filepath.h"
#include "bx/hash.h"
#include "bx/string.h"
#include "rendering/Rendering.h"
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
@@ -9,7 +15,7 @@
namespace Game
{
void LoadMesh(Model& mesh, const char* path)
bool LoadMesh(Model& mesh, const char* path, bool isBinary)
{
mesh.VertLayout.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
@@ -22,14 +28,23 @@ namespace Game
tinygltf::TinyGLTF loader;
std::string warn;
std::string err;
bool loadSuccess = loader.LoadASCIIFromFile(&model, &err, &warn, path);
bool loadSuccess;
if (isBinary)
{
loadSuccess = loader.LoadBinaryFromFile(&model, &err, &warn, path);
}
else
{
loadSuccess = loader.LoadASCIIFromFile(&model, &err, &warn, path);
}
if (!warn.empty()) Log("WARN: %s", warn.c_str());
if (!err.empty()) Log("ERR: %s", err.c_str());
if (!loadSuccess)
{
Log("Model load failed!");
return;
return false;
}
tinygltf::Primitive primitive = model.meshes[0].primitives[0];
@@ -69,5 +84,71 @@ namespace Game
}
mesh.VertexBuffer = bgfx::createVertexBuffer(vbMem, mesh.VertLayout);
}
return true;
}
void LoadModels(Model* models, uint32_t& outCount)
{
bx::Error err;
bx::DirectoryReader reader{};
if (!reader.open("models", &err) || !err.isOk())
{
Log("Failed to read models dir: %s", err.getMessage());
}
bx::FileInfo info;
int32_t modelFilePathCount = 0;
bx::FilePath modelFilePaths[GameRendering::MaxModels];
bool modelFileIsBinary[GameRendering::MaxModels]{false};
while (err.isOk())
{
int32_t res = reader.read(&info, sizeof(info), &err);
if (res == 0) break; // EOF
if (res != sizeof(info))
{
Log("Dir iter error: %s", err.getMessage());
break;
}
const bx::StringView ext = info.filePath.getExt();
bool isBinary = bx::strCmp(ext, ".glb") == 0;
bool isText = bx::strCmp(ext, ".gltf") == 0;
if ((isBinary || isText) && !ext.isEmpty() && info.type == bx::FileType::File)
{
if (modelFilePathCount >= GameRendering::MaxModels)
{
Log("Model limit reached!");
break;
}
modelFilePaths[modelFilePathCount] = info.filePath;
modelFileIsBinary[modelFilePathCount] = isBinary;
modelFilePathCount++;
}
}
Log("Found %u models!", modelFilePathCount);
int32_t writeI = 0;
for (int32_t i = 0; i < modelFilePathCount; ++i)
{
bx::FilePath fullPath = bx::FilePath{"models"};
fullPath.join(modelFilePaths[i].getCPtr());
Model& mod = models[writeI];
if (LoadMesh(mod, fullPath.getCPtr(), modelFileIsBinary[i]))
{
mod.AssetHandle = CrcPath(fullPath.getCPtr());
++writeI;
}
else
{
Log("Failed to load model: %s", fullPath.getCPtr());
}
}
outCount = writeI;
}
uint32_t CrcPath(const char* path)
{
bx::HashCrc32 hash;
hash.begin();
hash.add(path);
return hash.end();
}
} // namespace Game
+4 -2
View File
@@ -4,5 +4,7 @@
namespace Game
{
void LoadMesh(Model& mesh, const char* path);
}
bool LoadMesh(Model& mesh, const char* path, bool isBinary);
void LoadModels(Model* models, uint32_t& outCount);
uint32_t CrcPath(const char* path);
} // namespace Game
+46 -1
View File
@@ -1,4 +1,8 @@
#include "Log.h"
#include "Puzzle.h"
#include "rendering/Rendering.h"
#include "bx/bx.h"
#include <cassert>
namespace
@@ -9,10 +13,33 @@ namespace
{0, 1},
{1, 0},
};
}
Puzzle::StaticPuzzleData* StaticDataInstance = nullptr;
} // namespace
namespace Puzzle
{
void StaticPuzzleData::Setup()
{
StaticDataInstance = this;
Log("Setting up static puzzle data");
for (int32_t i = 0; i < BX_COUNTOF(Cards); ++i)
{
Cards[i].ModelHandle = Game::GameRendering::Get().GetModelHandleFromPath("models/w straight.glb");
}
}
StaticPuzzleData& StaticPuzzleData::Get()
{
assert(StaticDataInstance != nullptr);
return *StaticDataInstance;
}
const StaticPuzzleCard& StaticPuzzleData::GetCard(StaticPuzzleCardHandle H) const
{
assert(H.IsValid());
return Cards[H.Idx];
}
bool PuzzleNode::HasElement(PuzzleElementType search) const
{
for (int32_t i = 0; i < Config::MaxElementsPerTile; ++i)
@@ -37,11 +64,29 @@ namespace Puzzle
return MaxAvailableCount - UsedCount;
}
const PuzzleNode& PuzzleData::GetNodeAt(PuzPos pos) const
{
assert(pos.X < Config::MaxPuzzleSizeCards && pos.Y < Config::MaxPuzzleSizeCards && pos.X >= 0 && pos.Y >= 0);
return PlacedNodes[pos.Y * Config::MaxPuzzleSizeCards + pos.X];
}
PuzzleElementType PuzzleData::GetElementAt(ElemPos pos) const
{
assert(pos.ElemIdx < Config::MaxElementsPerTile);
const PuzzleNode& node = GetNodeAt(pos.Position);
return node.PlacedTypes[pos.ElemIdx];
}
bool PuzzleSolver::IsPuzzleSolved(const PuzzleData& puzzle)
{
bool IsSolved = true;
for (uint32_t i = 0; i < puzzle.GoalPositionCount; ++i)
{
if (!IsExitSatisfied(puzzle, puzzle.GoalPositions[i]))
{
IsSolved = false;
break;
}
}
return IsSolved;
}
+14
View File
@@ -64,11 +64,25 @@ namespace Puzzle
struct StaticPuzzleCard
{
PuzzleNode Nodes[Config::NodesPerCard];
uint16_t ModelHandle = 0;
};
struct StaticPuzzleCardHandle
{
uint16_t Idx = UINT16_MAX;
bool IsValid()
{
return Idx != UINT16_MAX;
}
};
struct StaticPuzzleData
{
StaticPuzzleCard Cards[64];
void Setup();
static StaticPuzzleData& Get();
const StaticPuzzleCard& GetCard(StaticPuzzleCardHandle H) const;
};
struct PlacedPuzzleCard
+58 -6
View File
@@ -8,8 +8,8 @@
#include "SDL3/SDL_events.h"
#include "backends/imgui_impl_sdl3.h"
#include "bgfx/defines.h"
#include "bx/bx.h"
#include "bx/filepath.h"
#include "bx/math.h"
#include "bx/timer.h"
#include <bgfx/bgfx.h>
#include <bimg/bimg.h>
@@ -190,11 +190,21 @@ namespace Game
return handle;
}
GameRendering* Instance = nullptr;
} // namespace
GameRendering& GameRendering::Get()
{
assert(Instance != nullptr);
return *Instance;
}
void GameRendering::Setup()
{
Log("--- RENDERING STARTUP ---");
if (Instance != nullptr) Log("Warning, old rendering wasn't destroyed!");
Instance = this;
SharedData& shared = GetShared();
bgfx::Init init;
@@ -228,8 +238,7 @@ namespace Game
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[1], "models/zurg.gltf");
LoadModels(Models, ModelCount);
Materials[0] =
Material::LoadFromShader("vert", "frag", MainViewID, Textures[0].Handle, Textures[0].SamplerHandle);
@@ -250,9 +259,15 @@ namespace Game
// platIO.Platform_SetWindowSize = TODO;
// platIO.Platform_RenderWindow = TODO;
if (!GetInstance().IsInitialized)
GameInstance& inst = GetInstance();
if (!inst.IsInitialized)
{
GetInstance().Time.StartTime = bx::getHPCounter();
inst.Time.StartTime = bx::getHPCounter();
}
if (inst.ImguiIniSize > 0)
{
ImGui::LoadIniSettingsFromMemory(inst.ImguiIni, inst.ImguiIniSize);
}
}
@@ -305,7 +320,24 @@ namespace Game
imguiBeginFrame(20);
ImGui_ImplSDL3_NewFrame();
ImGui::DockSpaceOverViewport(0, 0, ImGuiDockNodeFlags_PassthruCentralNode);
ImGui::ShowDemoWindow();
if (UIVisible == UIVisibilityState::Debug)
{
if (ImGui::Begin("Rendering"))
{
if (ImGui::Button("Reload Meshes"))
{
LoadModels(Models, ModelCount);
}
if (ImGui::Button("Reload Level"))
{
auto& lvl = GetInstance().GameLevel;
lvl = {};
lvl.Setup(shared.Game);
}
}
ImGui::End();
}
GetInstance().GameLevel.Update();
GetInstance().GameLevel.Render(MainViewID, Models, Materials);
@@ -333,9 +365,15 @@ namespace Game
void GameRendering::Shutdown()
{
Log("--- RENDERING_SHUTDOWN ---");
const char* iniData = ImGui::SaveIniSettingsToMemory(reinterpret_cast<uint64_t*>(&GetInstance().ImguiIniSize));
assert(GetInstance().ImguiIniSize <= BX_COUNTOF(GameInstance::ImguiIni));
bx::memCopy(
GetInstance().ImguiIni, iniData, bx::min(GetInstance().ImguiIniSize, BX_COUNTOF(GameInstance::ImguiIni)));
ImGui_ImplSDL3_Shutdown();
imguiDestroy();
bgfx::shutdown();
Instance = nullptr;
}
Material Material::LoadFromShader(
@@ -356,4 +394,18 @@ namespace Game
mat.ViewID = view;
return mat;
}
uint16_t GameRendering::GetModelHandleFromPath(const char* path)
{
uint32_t AssetHandle = CrcPath(path);
for (int32_t i = 0; i < ModelCount; ++i)
{
if (Models[i].AssetHandle == AssetHandle)
{
return i;
}
}
return 0;
}
} // namespace Game
+18 -1
View File
@@ -32,6 +32,7 @@ namespace Game
bgfx::VertexBufferHandle VertexBuffer;
bgfx::IndexBufferHandle IndexBuffer;
bgfx::VertexLayout VertLayout;
uint32_t AssetHandle = UINT16_MAX;
};
struct Material
@@ -54,13 +55,28 @@ namespace Game
bgfx::UniformHandle sampler = BGFX_INVALID_HANDLE);
};
enum class UIVisibilityState
{
None,
Game,
Debug,
};
class GameRendering
{
public:
static constexpr uint32_t MaxModels = 64;
static GameRendering& Get();
public:
UIVisibilityState UIVisible = UIVisibilityState::Game;
private:
bgfx::UniformHandle DefaultSampler;
Texture Textures[8];
Material Materials[8];
Model Models[8];
uint32_t ModelCount = 0;
Model Models[MaxModels];
int32_t LastWidth = 0;
int32_t LastHeight = 0;
uint32_t ResetFlags = BGFX_RESET_VSYNC;
@@ -70,5 +86,6 @@ namespace Game
void Setup();
void Update();
void Shutdown();
uint16_t GetModelHandleFromPath(const char* path);
};
} // namespace Game
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.