refactor
This commit is contained in:
151
src/game/Entity.h
Normal file
151
src/game/Entity.h
Normal file
@@ -0,0 +1,151 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gen/Generated.h"
|
||||
#include "Log.h"
|
||||
#include "Puzzle.h" // TODO: remove
|
||||
#include "rendering/Rendering.h"
|
||||
#include <cstdint>
|
||||
|
||||
#define ENTITY_HANDLE(X) \
|
||||
struct X \
|
||||
{ \
|
||||
uint16_t Idx = UINT16_MAX; \
|
||||
}; \
|
||||
inline bool IsValid(X h) \
|
||||
{ \
|
||||
return h.Idx != UINT16_MAX; \
|
||||
}
|
||||
|
||||
namespace Game
|
||||
{
|
||||
struct EntityRenderData
|
||||
{
|
||||
Gen::Vec4 DotColor{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
Gen::Vec4 BaseColor{0.0f, 0.0f, 0.0f, 1.0f};
|
||||
Gen::Transform Transform;
|
||||
Gen::EMaterial::Enum MaterialHandle = Gen::EMaterial::UI;
|
||||
Gen::TextureHandle TextureHandle;
|
||||
Gen::ModelHandle ModelH;
|
||||
bool Visible = true;
|
||||
|
||||
void Render(const Model* models, const Material* materials, const Texture* textures);
|
||||
void LoadFromSaved(const Gen::SavedEntityRenderData& saved);
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(CubeHandle);
|
||||
struct Cube
|
||||
{
|
||||
int32_t TestX = -1;
|
||||
int32_t TestY = -1;
|
||||
EntityRenderData EData;
|
||||
|
||||
void Setup();
|
||||
void Update();
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(TestEntityHandle);
|
||||
struct TestEntity
|
||||
{
|
||||
EntityRenderData EData;
|
||||
|
||||
void Setup();
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(PuzzleTileEntityHandle);
|
||||
struct PuzzleTileEntity
|
||||
{
|
||||
EntityRenderData EData;
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(PuzzleTileCoverHandle);
|
||||
struct PuzzleTileCover
|
||||
{
|
||||
EntityRenderData EData;
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(UIQuadEntityHandle);
|
||||
struct UIQuadEntity
|
||||
{
|
||||
EntityRenderData EData;
|
||||
Gen::Vec3 UIPos;
|
||||
float UIRot = 0.0f;
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(LevelEntityHandle);
|
||||
struct LevelEntity
|
||||
{
|
||||
EntityRenderData EData;
|
||||
};
|
||||
|
||||
class IEntityManager
|
||||
{
|
||||
public:
|
||||
virtual bool Setup(uint8_t*& ptr, bool forceReset) = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename HandleT, uint32_t C> class EntityManager : public IEntityManager
|
||||
{
|
||||
public:
|
||||
uint16_t Count = 0;
|
||||
T* Data = nullptr;
|
||||
uint32_t EntitySize = 0;
|
||||
T InvalidObject{};
|
||||
bool IsEnabled = true;
|
||||
|
||||
public:
|
||||
// Returns true if size changed
|
||||
bool Setup(uint8_t*& ptr, bool forceReset)
|
||||
{
|
||||
bool changed = false;
|
||||
if (EntitySize != sizeof(T) || forceReset)
|
||||
{
|
||||
Count = 0;
|
||||
changed = true;
|
||||
}
|
||||
EntitySize = sizeof(T);
|
||||
Data = reinterpret_cast<T*>(ptr);
|
||||
ptr += C * EntitySize;
|
||||
return changed;
|
||||
}
|
||||
|
||||
HandleT New()
|
||||
{
|
||||
if (Data == nullptr)
|
||||
{
|
||||
ERROR_ONCE("Accessed EntityManager before setup!");
|
||||
return {};
|
||||
}
|
||||
if (Count >= C)
|
||||
{
|
||||
ERROR_ONCE("Too many entities!");
|
||||
return {};
|
||||
}
|
||||
Data[Count] = {};
|
||||
HandleT H;
|
||||
H.Idx = Count;
|
||||
++Count;
|
||||
return H;
|
||||
}
|
||||
|
||||
T& Get(HandleT handle)
|
||||
{
|
||||
if (handle.Idx >= Count)
|
||||
{
|
||||
ERROR_ONCE("OOB Access!");
|
||||
return InvalidObject;
|
||||
}
|
||||
return Data[handle.Idx];
|
||||
}
|
||||
|
||||
void Render(const Model* models, const Material* materials, const Texture* textures)
|
||||
{
|
||||
if (!IsEnabled) return;
|
||||
for (uint16_t i = 0; i < Count; ++i)
|
||||
{
|
||||
Get({i}).EData.Render(models, materials, textures);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef EntityManager<UIQuadEntity, UIQuadEntityHandle, Puzzle::Config::MaxTilesInPuzzle * 2> UIQuadEntityManager;
|
||||
} // namespace Game
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Level.h"
|
||||
#include "Log.h"
|
||||
#include "Puzzle.h"
|
||||
#include "UI.h"
|
||||
#include "bx/bx.h"
|
||||
#include "rendering/Rendering.h"
|
||||
|
||||
@@ -189,6 +190,7 @@ namespace Game
|
||||
Puzzles[i].Setup();
|
||||
}
|
||||
}
|
||||
PuzzleUI.Setup();
|
||||
TabletHandle = UIQuads.New();
|
||||
UpdatePlayerInputMode();
|
||||
|
||||
@@ -286,12 +288,17 @@ namespace Game
|
||||
}
|
||||
|
||||
// Puzzle tiles
|
||||
uint16_t activeIdx = GetInstance().DebugData.SelectedDebugLevel;
|
||||
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
|
||||
{
|
||||
Puzzles[i].IsActive = GetInstance().DebugData.SelectedDebugLevel == i;
|
||||
Puzzles[i].IsActive = activeIdx == i;
|
||||
Puzzles[i].Update();
|
||||
}
|
||||
|
||||
Puzzle::PuzzleSolver solver;
|
||||
bool isPuzzleSolved = solver.IsPuzzleSolved(Puzzles[activeIdx].Data);
|
||||
PuzzleUI.Update(Puzzles[activeIdx].Data, isPuzzleSolved);
|
||||
|
||||
END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter);
|
||||
}
|
||||
|
||||
@@ -369,187 +376,18 @@ namespace Game
|
||||
auto& cover = level.PuzzleTileCovers.Get(CoverHandles[idx]);
|
||||
cover.EData.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
UIPlacedCards[i] = level.UIQuads.New();
|
||||
auto& quad = level.UIQuads.Get(UIPlacedCards[i]);
|
||||
quad.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/plane.glb");
|
||||
quad.EData.MaterialHandle = EMaterial::UI;
|
||||
}
|
||||
for (int32_t i = 0; i < Puzzle::Config::MaxAvailableStacks * WorldPuzzle::UIAvailableCardMaxStackPreview; ++i)
|
||||
{
|
||||
UIAvailableCards[i] = level.UIQuads.New();
|
||||
auto& quad = level.UIQuads.Get(UIAvailableCards[i]);
|
||||
quad.EData.MaterialHandle = EMaterial::UI;
|
||||
quad.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/plane.glb");
|
||||
}
|
||||
SolvedQuad = level.UIQuads.New();
|
||||
ResetQuad = level.UIQuads.New();
|
||||
IsSetup = true;
|
||||
LOG("finished setup!");
|
||||
}
|
||||
|
||||
Vec3 GetMousePosWorld()
|
||||
{
|
||||
auto& window = GetShared().Window;
|
||||
Vec2 mousePos = GetMousePos();
|
||||
mousePos.x = mousePos.x / window.WindowWidth;
|
||||
mousePos.y = mousePos.y / window.WindowHeight;
|
||||
mousePos *= 2.0f;
|
||||
mousePos -= 1.0f;
|
||||
Vec4 mousePosView = {mousePos.x, -mousePos.y, 0.0f, 1.0f};
|
||||
Vec4 mousePosCam4 = Mul(GetInstance().Player.ProjectionInverse, mousePosView);
|
||||
Vec3 mousePosCam = Vec3{
|
||||
mousePosCam4.x /= mousePosCam4.w,
|
||||
mousePosCam4.y /= mousePosCam4.w,
|
||||
mousePosCam4.z /= mousePosCam4.w,
|
||||
};
|
||||
|
||||
return LocalToGlobalPoint(GetInstance().Player.PlayerCamTransform, mousePosCam);
|
||||
}
|
||||
|
||||
bool IsQuadHovered(Transform& quadTransform, Vec3 mousePosWorld, Vec3& outQuadPlaneIntersectPos)
|
||||
{
|
||||
Vec3 quadPosWorld = quadTransform.Position;
|
||||
Vec3 quadXWorld = LocalToGlobalPoint(quadTransform, {1, 0, 0});
|
||||
Vec3 quadZWorld = LocalToGlobalPoint(quadTransform, {0, 0, 1});
|
||||
if (RayPlaneIntersect(GetInstance().Player.PlayerCamTransform.Position,
|
||||
mousePosWorld,
|
||||
quadPosWorld,
|
||||
quadXWorld,
|
||||
quadZWorld,
|
||||
outQuadPlaneIntersectPos))
|
||||
{
|
||||
Vec3 quadSpaceIntersect = GlobalToLocalPoint(quadTransform, outQuadPlaneIntersectPos);
|
||||
if (quadSpaceIntersect.x >= -1.0f && quadSpaceIntersect.x <= 1.0f && quadSpaceIntersect.z >= -1.0f &&
|
||||
quadSpaceIntersect.z <= 1.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WorldPuzzle::Update()
|
||||
{
|
||||
Level& level = GetInstance().GameLevel;
|
||||
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
|
||||
auto& visuals = Puzzle::GetStaticPuzzleData().Visuals;
|
||||
|
||||
Transform& camTransform = GetInstance().Player.PlayerCamTransform;
|
||||
UpdateMatrix(camTransform);
|
||||
Vec3 cameraPos = camTransform.Position;
|
||||
|
||||
// TODO: disable warning & check if parentheses make sense like this
|
||||
Vec2 uiOffset = Vec2{static_cast<float>(Data.WidthTiles / Puzzle::Config::CardSize) - 1,
|
||||
static_cast<float>(Data.HeightTiles / Puzzle::Config::CardSize) - 1};
|
||||
uiOffset *= -UICardOffset * 0.5f;
|
||||
|
||||
Transform& boardTransform = level.UIQuads.Get(level.TabletHandle).EData.Transform;
|
||||
Transform tileOriginTransform = boardTransform;
|
||||
tileOriginTransform.Position += AxisForward(camTransform.M) * -0.01f;
|
||||
TranslateLocal(tileOriginTransform, Vec3{uiOffset.x, 0.0f, uiOffset.y} * 1.0f);
|
||||
UpdateMatrix(tileOriginTransform);
|
||||
|
||||
Vec3 mousePosWorld = GetMousePosWorld();
|
||||
Vec3 quadPlaneIntersectPos;
|
||||
|
||||
Puzzle::PuzzleSolver solver;
|
||||
EntityRenderData solvedData;
|
||||
solvedData.LoadFromSaved(GetInstance().Player.Config.TabletStatusRenderData);
|
||||
auto& solvedQuad = level.UIQuads.Get(SolvedQuad);
|
||||
solvedQuad.EData = solvedData;
|
||||
solvedQuad.EData.Visible = IsActive;
|
||||
solvedQuad.EData.TextureHandle = solver.IsPuzzleSolved(Data)
|
||||
? GetInstance().Player.Config.TabletStatusSolvedTexture
|
||||
: solvedData.TextureHandle;
|
||||
solvedQuad.EData.Transform.Position = tileOriginTransform.Position;
|
||||
solvedQuad.EData.Transform.Rotation = camTransform.Rotation;
|
||||
TranslateLocal(solvedQuad.EData.Transform, solvedData.Transform.Position);
|
||||
Rotate(solvedQuad.EData.Transform, Vec3{bx::kPi * 0.5f, 0.0f, (1.0f - 0 * 0.5f) * bx::kPi});
|
||||
|
||||
EntityRenderData resetData;
|
||||
resetData.LoadFromSaved(GetInstance().Player.Config.TabletResetRenderData);
|
||||
auto& resetQuad = level.UIQuads.Get(ResetQuad);
|
||||
resetQuad.EData = resetData;
|
||||
resetQuad.EData.Visible = IsActive;
|
||||
resetQuad.EData.Transform.Position = tileOriginTransform.Position;
|
||||
resetQuad.EData.Transform.Rotation = camTransform.Rotation;
|
||||
TranslateLocal(resetQuad.EData.Transform, resetData.Transform.Position);
|
||||
Rotate(resetQuad.EData.Transform, Vec3{bx::kPi * 0.5f, 0.0f, (1.0f - 0 * 0.5f) * bx::kPi});
|
||||
if (GetMouseButtonPressedNow(MouseButton::Left) &&
|
||||
IsQuadHovered(resetQuad.EData.Transform, mousePosWorld, quadPlaneIntersectPos))
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
// Available Cards
|
||||
for (int32_t i = 0; i < Puzzle::Config::MaxAvailableStacks; ++i)
|
||||
{
|
||||
auto& card = Data.AvailableCards[i];
|
||||
for (int32_t j = 0; j < UIAvailableCardMaxStackPreview; j++)
|
||||
{
|
||||
auto& quad = level.UIQuads.Get(UIAvailableCards[i * UIAvailableCardMaxStackPreview + j]);
|
||||
int32_t remaining = (int32_t)card.MaxAvailableCount - (int32_t)card.UsedCount;
|
||||
if (i < Data.AvailableCardCount && j < remaining)
|
||||
{
|
||||
quad.EData.Visible = IsActive;
|
||||
quad.EData.TextureHandle = Puzzle::IsValid(Data.AvailableCards[i].RefCard)
|
||||
? staticCards[Data.AvailableCards[i].RefCard.Idx].BoardTextureHandle
|
||||
: Gen::TextureHandle{};
|
||||
quad.EData.Transform.Position = tileOriginTransform.Position;
|
||||
quad.EData.Transform.Rotation = camTransform.Rotation;
|
||||
TranslateLocal(quad.EData.Transform,
|
||||
Vec3{j * 0.05f + i * 1.2f, 6.0f + (j % 2 == 0 ? 0.02f : 0.0f), j * 0.001f} *
|
||||
UICardOffset * UICardScale);
|
||||
Rotate(quad.EData.Transform, Vec3{bx::kPi * 0.5f, 0.0f, (1.0f - 0 * 0.5f) * bx::kPi});
|
||||
quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale};
|
||||
quad.EData.DotColor = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
quad.EData.BaseColor = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
if (IsQuadHovered(quad.EData.Transform, mousePosWorld, quadPlaneIntersectPos) &&
|
||||
DraggedAvailableCardIdx == UINT16_MAX && DraggedCard.X == -1 &&
|
||||
GetMouseButtonPressedNow(MouseButton::Left))
|
||||
{
|
||||
DraggedAvailableCardIdx = i;
|
||||
}
|
||||
if (DraggedAvailableCardIdx == i)
|
||||
{
|
||||
Vec3 dragPos = quadPlaneIntersectPos;
|
||||
dragPos -= AxisForward(camTransform.M) * 0.01f;
|
||||
quad.EData.Transform.Position = dragPos;
|
||||
|
||||
Vec3 boardPos = GlobalToLocalPoint(tileOriginTransform, quadPlaneIntersectPos);
|
||||
Vec3 boardTilePos = boardPos / UICardOffset;
|
||||
int32_t xPos = (int32_t)bx::round(boardTilePos.x);
|
||||
int32_t yPos = (int32_t)bx::round(boardTilePos.z);
|
||||
|
||||
if (!GetMouseButton(MouseButton::Left))
|
||||
{
|
||||
if (xPos >= 0 && xPos < Data.WidthTiles / Puzzle::Config::CardSize && yPos >= 0 &&
|
||||
yPos < Data.HeightTiles / Puzzle::Config::CardSize)
|
||||
{
|
||||
Gen::PuzPos targetCardPos = {(int8_t)xPos, (int8_t)yPos};
|
||||
Gen::PlacedPuzzleCard& targetCard =
|
||||
Data.PlacedCards[yPos * Puzzle::Config::MaxPuzzleSizeCards + xPos];
|
||||
if (!Puzzle::IsValid(targetCard.RefCard) || targetCard.RefCard.Idx == 0)
|
||||
{
|
||||
Puzzle::DragAvailableCardTo(Data, targetCardPos, DraggedAvailableCardIdx, 0);
|
||||
}
|
||||
}
|
||||
DraggedAvailableCardIdx = UINT16_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
quad.EData.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Board
|
||||
for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y)
|
||||
{
|
||||
@@ -558,7 +396,6 @@ namespace Game
|
||||
int32_t cardIdx = y * Puzzle::Config::MaxPuzzleSizeCards + x;
|
||||
Gen::PlacedPuzzleCard& card = Data.PlacedCards[cardIdx];
|
||||
auto& tile = level.PuzzleTiles.Get(TileHandles[cardIdx]);
|
||||
auto& quad = level.UIQuads.Get(UIPlacedCards[cardIdx]);
|
||||
|
||||
bool isValid = Puzzle::IsValid(card.RefCard);
|
||||
auto& staticCard = isValid ? staticCards[card.RefCard.Idx] : staticCards[0];
|
||||
@@ -597,96 +434,6 @@ namespace Game
|
||||
Gen::RotateLocal(cover.EData.Transform, Gen::EulerFromRotation(model.Sockets[i].Rot));
|
||||
}
|
||||
}
|
||||
|
||||
// UI Quad
|
||||
quad.EData.Visible = isValid && IsActive;
|
||||
quad.EData.TextureHandle =
|
||||
isValid ? staticCards[card.RefCard.Idx].BoardTextureHandle : Gen::TextureHandle{};
|
||||
quad.EData.DotColor = card.IsLocked ? Puzzle::GetStaticPuzzleData().Visuals.DisabledCardTint
|
||||
: Vec4{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
quad.EData.Transform.Position = tileOriginTransform.Position;
|
||||
quad.EData.Transform.Rotation = camTransform.Rotation;
|
||||
TranslateLocal(quad.EData.Transform,
|
||||
Vec3{(float)card.Position.X, (float)card.Position.Y, 0.0f} * UICardOffset * UICardScale);
|
||||
Rotate(quad.EData.Transform, Vec3{bx::kPi * 0.5f, 0.0f, (1.0f - card.Rotation * 0.5f) * bx::kPi});
|
||||
quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale};
|
||||
|
||||
Vec3 quadPlaneIntersectPos;
|
||||
if (isValid && IsQuadHovered(quad.EData.Transform, mousePosWorld, quadPlaneIntersectPos))
|
||||
{
|
||||
if (!card.IsLocked && DraggedCard.X == -1 && DraggedAvailableCardIdx == UINT16_MAX)
|
||||
{
|
||||
if (GetMouseButtonPressedNow(MouseButton::Left))
|
||||
{
|
||||
DraggedCard.X = x;
|
||||
DraggedCard.Y = y;
|
||||
}
|
||||
if (GetMouseButtonPressedNow(MouseButton::Right))
|
||||
{
|
||||
Puzzle::RotateCard(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DraggedCard.X == x && DraggedCard.Y == y)
|
||||
{
|
||||
Vec3 dragPos = quadPlaneIntersectPos;
|
||||
dragPos -= AxisForward(camTransform.M) * 0.01f;
|
||||
quad.EData.Transform.Position = dragPos;
|
||||
|
||||
Vec3 boardPos = GlobalToLocalPoint(tileOriginTransform, quadPlaneIntersectPos);
|
||||
Vec3 boardTilePos = boardPos / UICardOffset;
|
||||
int32_t xPos = (int32_t)bx::round(boardTilePos.x);
|
||||
int32_t yPos = (int32_t)bx::round(boardTilePos.z);
|
||||
Gen::PuzPos srcCardPos = {(int8_t)DraggedCard.X, (int8_t)DraggedCard.Y};
|
||||
Gen::PlacedPuzzleCard& srcCard =
|
||||
Data.PlacedCards[srcCardPos.Y * Puzzle::Config::MaxPuzzleSizeCards + srcCardPos.X];
|
||||
|
||||
if (GetMouseButtonPressedNow(MouseButton::Right))
|
||||
{
|
||||
Puzzle::RotateCard(srcCard);
|
||||
}
|
||||
|
||||
if (!GetMouseButton(MouseButton::Left))
|
||||
{
|
||||
Gen::PuzPos targetCardPos = {(int8_t)xPos, (int8_t)yPos};
|
||||
if (xPos >= 0 && xPos < Data.WidthTiles / Puzzle::Config::CardSize && yPos >= 0 &&
|
||||
yPos < Data.HeightTiles / Puzzle::Config::CardSize)
|
||||
{
|
||||
PlacedPuzzleCard srcCardCopy = srcCard;
|
||||
Gen::PlacedPuzzleCard& targetCard =
|
||||
Data.PlacedCards[yPos * Puzzle::Config::MaxPuzzleSizeCards + xPos];
|
||||
bool canBeReplaced = !Puzzle::IsValid(targetCard.RefCard) || targetCard.RefCard.Idx == 0;
|
||||
if (canBeReplaced && Puzzle::ReturnPlacedCard(Data, srcCardPos))
|
||||
{
|
||||
int32_t foundIdx = -1;
|
||||
for (int32_t availCardIdx = 0; availCardIdx < Data.AvailableCardCount; ++availCardIdx)
|
||||
{
|
||||
LOG("CHECK: %u", Data.AvailableCards[availCardIdx].RefCard.Idx);
|
||||
if (Data.AvailableCards[availCardIdx].RefCard.Idx == srcCardCopy.RefCard.Idx)
|
||||
{
|
||||
foundIdx = availCardIdx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundIdx >= 0)
|
||||
{
|
||||
Puzzle::DragAvailableCardTo(Data, targetCardPos, foundIdx, srcCard.Rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("NOTFOUND: %u", srcCardCopy.RefCard.Idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Puzzle::ReturnPlacedCard(Data, srcCardPos);
|
||||
}
|
||||
DraggedCard.X = -1;
|
||||
DraggedCard.Y = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
152
src/game/Level.h
152
src/game/Level.h
@@ -1,166 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "../engine/Shared.h"
|
||||
#include "Log.h"
|
||||
#include "Puzzle.h"
|
||||
#include "UI.h"
|
||||
#include "rendering/Rendering.h"
|
||||
#include <bgfx/bgfx.h>
|
||||
#include <cstdint>
|
||||
|
||||
#define ENTITY_HANDLE(X) \
|
||||
struct X \
|
||||
{ \
|
||||
uint16_t Idx = UINT16_MAX; \
|
||||
}; \
|
||||
inline bool IsValid(X h) \
|
||||
{ \
|
||||
return h.Idx != UINT16_MAX; \
|
||||
}
|
||||
|
||||
namespace Game
|
||||
{
|
||||
struct EntityRenderData
|
||||
{
|
||||
Gen::Vec4 DotColor{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
Gen::Vec4 BaseColor{0.0f, 0.0f, 0.0f, 1.0f};
|
||||
Gen::Transform Transform;
|
||||
Gen::EMaterial::Enum MaterialHandle = Gen::EMaterial::UI;
|
||||
Gen::TextureHandle TextureHandle;
|
||||
Gen::ModelHandle ModelH;
|
||||
bool Visible = true;
|
||||
|
||||
void Render(const Model* models, const Material* materials, const Texture* textures);
|
||||
void LoadFromSaved(const Gen::SavedEntityRenderData& saved);
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(CubeHandle);
|
||||
struct Cube
|
||||
{
|
||||
int32_t TestX = -1;
|
||||
int32_t TestY = -1;
|
||||
EntityRenderData EData;
|
||||
|
||||
void Setup();
|
||||
void Update();
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(TestEntityHandle);
|
||||
struct TestEntity
|
||||
{
|
||||
EntityRenderData EData;
|
||||
|
||||
void Setup();
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(PuzzleTileEntityHandle);
|
||||
struct PuzzleTileEntity
|
||||
{
|
||||
EntityRenderData EData;
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(PuzzleTileCoverHandle);
|
||||
struct PuzzleTileCover
|
||||
{
|
||||
EntityRenderData EData;
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(UIQuadEntityHandle);
|
||||
struct UIQuadEntity
|
||||
{
|
||||
EntityRenderData EData;
|
||||
};
|
||||
|
||||
ENTITY_HANDLE(LevelEntityHandle);
|
||||
struct LevelEntity
|
||||
{
|
||||
EntityRenderData EData;
|
||||
};
|
||||
|
||||
class IEntityManager
|
||||
{
|
||||
public:
|
||||
virtual bool Setup(uint8_t*& ptr, bool forceReset) = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename HandleT, uint32_t C> class EntityManager : public IEntityManager
|
||||
{
|
||||
public:
|
||||
uint16_t Count = 0;
|
||||
T* Data = nullptr;
|
||||
uint32_t EntitySize = 0;
|
||||
T InvalidObject{};
|
||||
bool IsEnabled = true;
|
||||
|
||||
public:
|
||||
// Returns true if size changed
|
||||
bool Setup(uint8_t*& ptr, bool forceReset)
|
||||
{
|
||||
bool changed = false;
|
||||
if (EntitySize != sizeof(T) || forceReset)
|
||||
{
|
||||
Count = 0;
|
||||
changed = true;
|
||||
}
|
||||
EntitySize = sizeof(T);
|
||||
Data = reinterpret_cast<T*>(ptr);
|
||||
ptr += C * EntitySize;
|
||||
return changed;
|
||||
}
|
||||
|
||||
HandleT New()
|
||||
{
|
||||
if (Data == nullptr)
|
||||
{
|
||||
ERROR_ONCE("Accessed EntityManager before setup!");
|
||||
return {};
|
||||
}
|
||||
if (Count >= C)
|
||||
{
|
||||
ERROR_ONCE("Too many entities!");
|
||||
return {};
|
||||
}
|
||||
Data[Count] = {};
|
||||
HandleT H;
|
||||
H.Idx = Count;
|
||||
++Count;
|
||||
return H;
|
||||
}
|
||||
|
||||
T& Get(HandleT handle)
|
||||
{
|
||||
if (handle.Idx >= Count)
|
||||
{
|
||||
ERROR_ONCE("OOB Access!");
|
||||
return InvalidObject;
|
||||
}
|
||||
return Data[handle.Idx];
|
||||
}
|
||||
|
||||
void Render(const Model* models, const Material* materials, const Texture* textures)
|
||||
{
|
||||
if (!IsEnabled) return;
|
||||
for (uint16_t i = 0; i < Count; ++i)
|
||||
{
|
||||
Get({i}).EData.Render(models, materials, textures);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct WorldPuzzle
|
||||
{
|
||||
static constexpr Gen::Vec2 WorldCardSize{10.0f, 10.0f};
|
||||
static constexpr float UICardScale = 0.05f;
|
||||
static constexpr float UICardOffset = 2.1f * UICardScale;
|
||||
static constexpr int32_t UIAvailableCardMaxStackPreview = 3;
|
||||
Gen::PuzzleData Data;
|
||||
Gen::Vec3 WorldPosition;
|
||||
PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle];
|
||||
PuzzleTileCoverHandle CoverHandles[Puzzle::Config::MaxCardsInPuzzle * Puzzle::Config::MaxCoversInTile];
|
||||
UIQuadEntityHandle UIPlacedCards[Puzzle::Config::MaxCardsInPuzzle];
|
||||
UIQuadEntityHandle UIAvailableCards[Puzzle::Config::MaxAvailableStacks * UIAvailableCardMaxStackPreview];
|
||||
UIQuadEntityHandle SolvedQuad;
|
||||
UIQuadEntityHandle ResetQuad;
|
||||
Gen::PuzPos DraggedCard{-1, -1};
|
||||
uint16_t DraggedAvailableCardIdx = UINT16_MAX;
|
||||
bool IsSetup = false;
|
||||
bool IsActive = false;
|
||||
|
||||
@@ -176,7 +31,7 @@ namespace Game
|
||||
EntityManager<TestEntity, TestEntityHandle, 32> Tests;
|
||||
EntityManager<PuzzleTileEntity, PuzzleTileEntityHandle, Puzzle::Config::MaxTilesTotal> PuzzleTiles;
|
||||
EntityManager<PuzzleTileCover, PuzzleTileCoverHandle, Puzzle::Config::MaxCoversTotal> PuzzleTileCovers;
|
||||
EntityManager<UIQuadEntity, UIQuadEntityHandle, Puzzle::Config::MaxTilesInPuzzle * 2> UIQuads;
|
||||
UIQuadEntityManager UIQuads;
|
||||
EntityManager<LevelEntity, LevelEntityHandle, 64> LevelEntities;
|
||||
|
||||
CubeHandle PlayerOutsideViewCube;
|
||||
@@ -185,6 +40,7 @@ namespace Game
|
||||
public:
|
||||
Gen::StaticPuzzleData PuzzleData;
|
||||
WorldPuzzle Puzzles[Puzzle::Config::MaxVisiblePuzzles];
|
||||
WorldPuzzleUI PuzzleUI;
|
||||
|
||||
public:
|
||||
void Setup(GameData& data);
|
||||
|
||||
@@ -306,6 +306,8 @@ namespace Tools
|
||||
ImGui::Text("Status");
|
||||
bTabletChanged |= Tools::EntityDataSettings(player.Config.TabletStatusRenderData);
|
||||
bTabletChanged |= Tools::TextureDropdown(player.Config.TabletStatusSolvedTexture, "Solved Texture");
|
||||
bTabletChanged |=
|
||||
Tools::TextureDropdown(player.Config.TabletStatusNotSolvedTexture, "Not Solved Texture");
|
||||
ImGui::Text("Reset");
|
||||
bTabletChanged |= Tools::EntityDataSettings(player.Config.TabletResetRenderData);
|
||||
if (bTabletChanged)
|
||||
@@ -314,6 +316,7 @@ namespace Tools
|
||||
s.Init("game/data/static/uiconfig.dat", "UICO");
|
||||
s.WriteT(player.Config);
|
||||
s.Finish();
|
||||
level.PuzzleUI.Reset();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
333
src/game/UI.cpp
Normal file
333
src/game/UI.cpp
Normal file
@@ -0,0 +1,333 @@
|
||||
#include "UI.h"
|
||||
|
||||
#include "Gen.h"
|
||||
#include "Global.h"
|
||||
#include "Input.h"
|
||||
#include "Instance.h"
|
||||
#include "Level.h"
|
||||
|
||||
#include "bx/math.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
namespace
|
||||
{
|
||||
Game::StaticUIData StaticData;
|
||||
}
|
||||
|
||||
namespace Game
|
||||
{
|
||||
UIQuadEntityHandle NewQuad(UIQuadEntityManager& manager, const Gen::SavedEntityRenderData& loadData)
|
||||
{
|
||||
UIQuadEntityHandle h = manager.New();
|
||||
if (!IsValid(h)) return h;
|
||||
|
||||
UIQuadEntity& entity = manager.Get(h);
|
||||
entity.EData.LoadFromSaved(loadData);
|
||||
entity.UIPos = entity.EData.Transform.Position;
|
||||
return h;
|
||||
}
|
||||
|
||||
void UpdateQuad(UIQuadEntityManager& manager, UIQuadEntityHandle handle)
|
||||
{
|
||||
if (!IsValid(handle)) return;
|
||||
|
||||
UIQuadEntity& entity = manager.Get(handle);
|
||||
entity.EData.Transform.Position = StaticData.UITransform.Position;
|
||||
entity.EData.Transform.Rotation = StaticData.UITransform.Rotation;
|
||||
TranslateLocal(entity.EData.Transform, entity.UIPos);
|
||||
Rotate(entity.EData.Transform, Vec3{bx::kPi * 0.5f, 0.0f, (1.0f - 0 * 0.5f) * bx::kPi});
|
||||
Rotate(entity.EData.Transform, {0.0f, entity.UIRot, 0.0f});
|
||||
}
|
||||
|
||||
Vec3 GetMousePosWorld()
|
||||
{
|
||||
auto& window = GetShared().Window;
|
||||
Vec2 mousePos = GetMousePos();
|
||||
mousePos.x = mousePos.x / window.WindowWidth;
|
||||
mousePos.y = mousePos.y / window.WindowHeight;
|
||||
mousePos *= 2.0f;
|
||||
mousePos -= 1.0f;
|
||||
Vec4 mousePosView = {mousePos.x, -mousePos.y, 0.0f, 1.0f};
|
||||
Vec4 mousePosCam4 = Mul(GetInstance().Player.ProjectionInverse, mousePosView);
|
||||
Vec3 mousePosCam = Vec3{
|
||||
mousePosCam4.x /= mousePosCam4.w,
|
||||
mousePosCam4.y /= mousePosCam4.w,
|
||||
mousePosCam4.z /= mousePosCam4.w,
|
||||
};
|
||||
|
||||
return LocalToGlobalPoint(GetInstance().Player.PlayerCamTransform, mousePosCam);
|
||||
}
|
||||
|
||||
bool IsQuadHovered(Transform& quadTransform, Vec3 mousePosWorld, Vec3& outQuadPlaneIntersectPos)
|
||||
{
|
||||
Vec3 quadPosWorld = quadTransform.Position;
|
||||
Vec3 quadXWorld = LocalToGlobalPoint(quadTransform, {1, 0, 0});
|
||||
Vec3 quadZWorld = LocalToGlobalPoint(quadTransform, {0, 0, 1});
|
||||
if (RayPlaneIntersect(GetInstance().Player.PlayerCamTransform.Position,
|
||||
mousePosWorld,
|
||||
quadPosWorld,
|
||||
quadXWorld,
|
||||
quadZWorld,
|
||||
outQuadPlaneIntersectPos))
|
||||
{
|
||||
Vec3 quadSpaceIntersect = GlobalToLocalPoint(quadTransform, outQuadPlaneIntersectPos);
|
||||
if (quadSpaceIntersect.x >= -1.0f && quadSpaceIntersect.x <= 1.0f && quadSpaceIntersect.z >= -1.0f &&
|
||||
quadSpaceIntersect.z <= 1.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WorldPuzzleUI::Setup()
|
||||
{
|
||||
auto& level = GetInstance().GameLevel;
|
||||
SolvedQuad = NewQuad(level.UIQuads, GetInstance().Player.Config.TabletStatusRenderData);
|
||||
ResetQuad = NewQuad(level.UIQuads, GetInstance().Player.Config.TabletResetRenderData);
|
||||
|
||||
for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i)
|
||||
{
|
||||
UIPlacedCards[i] = level.UIQuads.New();
|
||||
auto& quad = level.UIQuads.Get(UIPlacedCards[i]);
|
||||
quad.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/plane.glb");
|
||||
quad.EData.MaterialHandle = EMaterial::UI;
|
||||
}
|
||||
for (int32_t i = 0; i < Puzzle::Config::MaxAvailableStacks * UIAvailableCardMaxStackPreview; ++i)
|
||||
{
|
||||
UIAvailableCards[i] = level.UIQuads.New();
|
||||
auto& quad = level.UIQuads.Get(UIAvailableCards[i]);
|
||||
quad.EData.MaterialHandle = EMaterial::UI;
|
||||
quad.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/plane.glb");
|
||||
}
|
||||
}
|
||||
|
||||
void WorldPuzzleUI::UpdateAvailableCards(Gen::PuzzleData& Data)
|
||||
{
|
||||
auto& level = GetInstance().GameLevel;
|
||||
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
|
||||
|
||||
Vec3 quadPlaneIntersectPos;
|
||||
Vec3 mousePosWorld = GetMousePosWorld();
|
||||
|
||||
for (int32_t i = 0; i < Puzzle::Config::MaxAvailableStacks; ++i)
|
||||
{
|
||||
auto& card = Data.AvailableCards[i];
|
||||
for (int32_t j = 0; j < UIAvailableCardMaxStackPreview; j++)
|
||||
{
|
||||
auto h = UIAvailableCards[i * UIAvailableCardMaxStackPreview + j];
|
||||
auto& quad = level.UIQuads.Get(h);
|
||||
int32_t remaining = (int32_t)card.MaxAvailableCount - (int32_t)card.UsedCount;
|
||||
if (i < Data.AvailableCardCount && j < remaining)
|
||||
{
|
||||
quad.UIPos = Vec3{j * 0.05f + i * 1.2f, 4.2f + (j % 2 == 0 ? 0.02f : 0.0f), j * 0.001f} *
|
||||
UICardOffset * UICardScale;
|
||||
UpdateQuad(level.UIQuads, h);
|
||||
quad.EData.Visible = true;
|
||||
quad.EData.TextureHandle = Puzzle::IsValid(Data.AvailableCards[i].RefCard)
|
||||
? staticCards[Data.AvailableCards[i].RefCard.Idx].BoardTextureHandle
|
||||
: Gen::TextureHandle{};
|
||||
quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale};
|
||||
quad.EData.DotColor = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
quad.EData.BaseColor = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
if (IsQuadHovered(quad.EData.Transform, mousePosWorld, quadPlaneIntersectPos) &&
|
||||
DraggedAvailableCardIdx == UINT16_MAX && DraggedCard.X == -1 &&
|
||||
GetMouseButtonPressedNow(MouseButton::Left))
|
||||
{
|
||||
DraggedAvailableCardIdx = i;
|
||||
}
|
||||
if (DraggedAvailableCardIdx == i)
|
||||
{
|
||||
Vec3 dragPos = quadPlaneIntersectPos;
|
||||
dragPos += StaticData.ZAxis * -0.01f;
|
||||
quad.EData.Transform.Position = dragPos;
|
||||
|
||||
Vec3 boardPos = GlobalToLocalPoint(StaticData.UITransform, quadPlaneIntersectPos);
|
||||
Vec3 boardTilePos = boardPos / UICardOffset;
|
||||
int32_t xPos = (int32_t)bx::round(boardTilePos.x);
|
||||
int32_t yPos = (int32_t)bx::round(boardTilePos.y);
|
||||
|
||||
if (!GetMouseButton(MouseButton::Left))
|
||||
{
|
||||
if (xPos >= 0 && xPos < Data.WidthTiles / Puzzle::Config::CardSize && yPos >= 0 &&
|
||||
yPos < Data.HeightTiles / Puzzle::Config::CardSize)
|
||||
{
|
||||
Gen::PuzPos targetCardPos = {(int8_t)xPos, (int8_t)yPos};
|
||||
Gen::PlacedPuzzleCard& targetCard =
|
||||
Data.PlacedCards[yPos * Puzzle::Config::MaxPuzzleSizeCards + xPos];
|
||||
if (!Puzzle::IsValid(targetCard.RefCard) || targetCard.RefCard.Idx == 0)
|
||||
{
|
||||
Puzzle::DragAvailableCardTo(Data, targetCardPos, DraggedAvailableCardIdx, 0);
|
||||
}
|
||||
}
|
||||
DraggedAvailableCardIdx = UINT16_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
quad.EData.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldPuzzleUI::UpdateBoardCards(Gen::PuzzleData& Data)
|
||||
{
|
||||
auto& level = GetInstance().GameLevel;
|
||||
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
|
||||
Vec3 quadPlaneIntersectPos;
|
||||
|
||||
for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y)
|
||||
{
|
||||
for (int8_t x = 0; x < Data.WidthTiles / Puzzle::Config::CardSize; ++x)
|
||||
{
|
||||
// UI Quad
|
||||
int32_t cardIdx = y * Puzzle::Config::MaxPuzzleSizeCards + x;
|
||||
PlacedPuzzleCard& card = Data.PlacedCards[cardIdx];
|
||||
bool isValid = Puzzle::IsValid(card.RefCard);
|
||||
|
||||
auto& quad = level.UIQuads.Get(UIPlacedCards[cardIdx]);
|
||||
quad.UIPos = Vec3{(float)card.Position.X, (float)card.Position.Y, 0.0f} * UICardOffset * UICardScale;
|
||||
quad.UIRot = card.Rotation * bx::kPi * 0.5f;
|
||||
UpdateQuad(level.UIQuads, UIPlacedCards[cardIdx]);
|
||||
|
||||
quad.EData.Visible = isValid;
|
||||
quad.EData.TextureHandle =
|
||||
isValid ? staticCards[card.RefCard.Idx].BoardTextureHandle : Gen::TextureHandle{};
|
||||
quad.EData.DotColor = card.IsLocked ? Puzzle::GetStaticPuzzleData().Visuals.DisabledCardTint
|
||||
: Vec4{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale};
|
||||
|
||||
if (isValid && IsQuadHovered(quad.EData.Transform, StaticData.MousePosWorld, quadPlaneIntersectPos))
|
||||
{
|
||||
if (!card.IsLocked && DraggedCard.X == -1 && DraggedAvailableCardIdx == UINT16_MAX)
|
||||
{
|
||||
if (GetMouseButtonPressedNow(MouseButton::Left))
|
||||
{
|
||||
DraggedCard.X = x;
|
||||
DraggedCard.Y = y;
|
||||
}
|
||||
if (GetMouseButtonPressedNow(MouseButton::Right))
|
||||
{
|
||||
Puzzle::RotateCard(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DraggedCard.X == x && DraggedCard.Y == y)
|
||||
{
|
||||
Vec3 dragPos = quadPlaneIntersectPos;
|
||||
dragPos += StaticData.ZAxis * -0.01f;
|
||||
quad.EData.Transform.Position = dragPos;
|
||||
|
||||
Vec3 boardPos = GlobalToLocalPoint(StaticData.UITransform, quadPlaneIntersectPos);
|
||||
Vec3 boardTilePos = boardPos / UICardOffset;
|
||||
int32_t xPos = (int32_t)bx::round(boardTilePos.x);
|
||||
int32_t yPos = (int32_t)bx::round(boardTilePos.y);
|
||||
Gen::PuzPos srcCardPos = {(int8_t)DraggedCard.X, (int8_t)DraggedCard.Y};
|
||||
Gen::PlacedPuzzleCard& srcCard =
|
||||
Data.PlacedCards[srcCardPos.Y * Puzzle::Config::MaxPuzzleSizeCards + srcCardPos.X];
|
||||
|
||||
if (GetMouseButtonPressedNow(MouseButton::Right))
|
||||
{
|
||||
Puzzle::RotateCard(srcCard);
|
||||
}
|
||||
|
||||
if (!GetMouseButton(MouseButton::Left))
|
||||
{
|
||||
Gen::PuzPos targetCardPos = {(int8_t)xPos, (int8_t)yPos};
|
||||
if (xPos >= 0 && xPos < Data.WidthTiles / Puzzle::Config::CardSize && yPos >= 0 &&
|
||||
yPos < Data.HeightTiles / Puzzle::Config::CardSize)
|
||||
{
|
||||
PlacedPuzzleCard srcCardCopy = srcCard;
|
||||
Gen::PlacedPuzzleCard& targetCard =
|
||||
Data.PlacedCards[yPos * Puzzle::Config::MaxPuzzleSizeCards + xPos];
|
||||
bool canBeReplaced = !Puzzle::IsValid(targetCard.RefCard) || targetCard.RefCard.Idx == 0;
|
||||
if (canBeReplaced && Puzzle::ReturnPlacedCard(Data, srcCardPos))
|
||||
{
|
||||
int32_t foundIdx = -1;
|
||||
for (int32_t availCardIdx = 0; availCardIdx < Data.AvailableCardCount; ++availCardIdx)
|
||||
{
|
||||
if (Data.AvailableCards[availCardIdx].RefCard.Idx == srcCardCopy.RefCard.Idx)
|
||||
{
|
||||
foundIdx = availCardIdx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundIdx >= 0)
|
||||
{
|
||||
Puzzle::DragAvailableCardTo(Data, targetCardPos, foundIdx, srcCard.Rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("NOTFOUND: %u", srcCardCopy.RefCard.Idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Puzzle::ReturnPlacedCard(Data, srcCardPos);
|
||||
}
|
||||
DraggedCard.X = -1;
|
||||
DraggedCard.Y = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldPuzzleUI::Update(Gen::PuzzleData& Data, bool IsPuzzleSolved)
|
||||
{
|
||||
auto& level = GetInstance().GameLevel;
|
||||
|
||||
Transform& camTransform = GetInstance().Player.PlayerCamTransform;
|
||||
UpdateMatrix(camTransform);
|
||||
|
||||
StaticData.UITransform = level.UIQuads.Get(level.TabletHandle).EData.Transform;
|
||||
StaticData.UITransform.Rotation = camTransform.Rotation;
|
||||
StaticData.ZAxis = AxisForward(StaticData.UITransform.M);
|
||||
StaticData.UITransform.Position += StaticData.ZAxis * -0.01f;
|
||||
StaticData.MousePosWorld = GetMousePosWorld();
|
||||
|
||||
// TODO: disable warning & check if parentheses make sense like this
|
||||
Vec2 uiOffset = Vec2{static_cast<float>(Data.WidthTiles / Puzzle::Config::CardSize) - 1,
|
||||
static_cast<float>(Data.HeightTiles / Puzzle::Config::CardSize) - 1};
|
||||
uiOffset *= -UICardOffset * 0.5f;
|
||||
|
||||
Transform tileOriginTransform = StaticData.UITransform;
|
||||
tileOriginTransform.Position += AxisForward(StaticData.UITransform.M) * -1.0f;
|
||||
TranslateLocal(tileOriginTransform, Vec3{uiOffset.x, 0.0f, uiOffset.y} * 1.0f);
|
||||
UpdateMatrix(tileOriginTransform);
|
||||
|
||||
auto& solvedQuad = level.UIQuads.Get(SolvedQuad);
|
||||
solvedQuad.EData.Visible = true;
|
||||
solvedQuad.EData.TextureHandle = IsPuzzleSolved ? GetInstance().Player.Config.TabletStatusSolvedTexture
|
||||
: GetInstance().Player.Config.TabletStatusNotSolvedTexture;
|
||||
UpdateQuad(level.UIQuads, SolvedQuad);
|
||||
auto& resetQuad = level.UIQuads.Get(ResetQuad);
|
||||
resetQuad.EData.Visible = true;
|
||||
UpdateQuad(level.UIQuads, ResetQuad);
|
||||
|
||||
Vec3 hoverPosWorld;
|
||||
if (GetMouseButtonPressedNow(MouseButton::Left) &&
|
||||
IsQuadHovered(resetQuad.EData.Transform, StaticData.MousePosWorld, hoverPosWorld))
|
||||
{
|
||||
LOG_WARN("TODO!");
|
||||
// TODO
|
||||
}
|
||||
|
||||
UpdateAvailableCards(Data);
|
||||
UpdateBoardCards(Data);
|
||||
}
|
||||
|
||||
void WorldPuzzleUI::Reset()
|
||||
{
|
||||
auto& level = GetInstance().GameLevel;
|
||||
}
|
||||
} // namespace Game
|
||||
41
src/game/UI.h
Normal file
41
src/game/UI.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gen/Generated.h"
|
||||
#include "Entity.h"
|
||||
#include "Puzzle.h"
|
||||
|
||||
namespace Game
|
||||
{
|
||||
struct StaticUIData
|
||||
{
|
||||
Gen::Transform UITransform;
|
||||
Gen::Vec3 ZAxis;
|
||||
Gen::Vec3 MousePosWorld;
|
||||
};
|
||||
|
||||
struct WorldPuzzleUI
|
||||
{
|
||||
static constexpr float UICardScale = 0.05f;
|
||||
static constexpr float UICardOffset = 2.1f * UICardScale;
|
||||
static constexpr int32_t UIAvailableCardMaxStackPreview = 3;
|
||||
|
||||
UIQuadEntityHandle SolvedQuad;
|
||||
UIQuadEntityHandle ResetQuad;
|
||||
|
||||
UIQuadEntityHandle UIPlacedCards[Puzzle::Config::MaxCardsInPuzzle];
|
||||
UIQuadEntityHandle UIAvailableCards[Puzzle::Config::MaxAvailableStacks * UIAvailableCardMaxStackPreview];
|
||||
Gen::PuzPos DraggedCard{-1, -1};
|
||||
uint16_t DraggedAvailableCardIdx = UINT16_MAX;
|
||||
|
||||
void Setup();
|
||||
void UpdateAvailableCards(Gen::PuzzleData& Data);
|
||||
void UpdateBoardCards(Gen::PuzzleData& Data);
|
||||
void Update(Gen::PuzzleData& Data, bool IsPuzzleSolved);
|
||||
void Reset();
|
||||
};
|
||||
|
||||
UIQuadEntityHandle NewQuad(UIQuadEntityManager& manager, const Gen::SavedEntityRenderData& loadData);
|
||||
void UpdateQuad(UIQuadEntityManager& manager, UIQuadEntityHandle handle);
|
||||
Gen::Vec3 GetMousePosWorld();
|
||||
bool IsQuadHovered(Gen::Transform& quadTransform, Gen::Vec3 mousePosWorld, Gen::Vec3& outQuadPlaneIntersectPos);
|
||||
} // namespace Game
|
||||
Binary file not shown.
@@ -170,6 +170,7 @@ type SavedPlayerConfig
|
||||
{
|
||||
SavedEntityRenderData TabletBackgroundRenderData
|
||||
SavedEntityRenderData TabletStatusRenderData
|
||||
TextureHandle TabletStatusNotSolvedTexture
|
||||
TextureHandle TabletStatusSolvedTexture
|
||||
SavedEntityRenderData TabletResetRenderData
|
||||
}
|
||||
|
||||
@@ -2452,6 +2452,7 @@ namespace Gen
|
||||
{
|
||||
isOk = Save(&obj[i].TabletBackgroundRenderData, 1, serializer) && isOk;
|
||||
isOk = Save(&obj[i].TabletStatusRenderData, 1, serializer) && isOk;
|
||||
isOk = Save(&obj[i].TabletStatusNotSolvedTexture, 1, serializer) && isOk;
|
||||
isOk = Save(&obj[i].TabletStatusSolvedTexture, 1, serializer) && isOk;
|
||||
isOk = Save(&obj[i].TabletResetRenderData, 1, serializer) && isOk;
|
||||
}
|
||||
@@ -2472,6 +2473,7 @@ namespace Gen
|
||||
{
|
||||
isOk = Load(&obj[i].TabletBackgroundRenderData, 1, serializer) && isOk;
|
||||
isOk = Load(&obj[i].TabletStatusRenderData, 1, serializer) && isOk;
|
||||
isOk = Load(&obj[i].TabletStatusNotSolvedTexture, 1, serializer) && isOk;
|
||||
isOk = Load(&obj[i].TabletStatusSolvedTexture, 1, serializer) && isOk;
|
||||
isOk = Load(&obj[i].TabletResetRenderData, 1, serializer) && isOk;
|
||||
}
|
||||
@@ -2509,6 +2511,10 @@ namespace Gen
|
||||
{
|
||||
WriteDestinations[i] = offsetof(SavedPlayerConfig, TabletStatusRenderData);
|
||||
}
|
||||
if (bx::strCmp(memberName, "TabletStatusNotSolvedTexture") == 0 && bx::strCmp(memberTypeName, "TextureHandle") == 0)
|
||||
{
|
||||
WriteDestinations[i] = offsetof(SavedPlayerConfig, TabletStatusNotSolvedTexture);
|
||||
}
|
||||
if (bx::strCmp(memberName, "TabletStatusSolvedTexture") == 0 && bx::strCmp(memberTypeName, "TextureHandle") == 0)
|
||||
{
|
||||
WriteDestinations[i] = offsetof(SavedPlayerConfig, TabletStatusSolvedTexture);
|
||||
@@ -2549,6 +2555,12 @@ namespace Gen
|
||||
isOk = Load(fieldPtr, 1, serializer) && isOk;
|
||||
continue;
|
||||
}
|
||||
if (bx::strCmp(memberName, "TabletStatusNotSolvedTexture") == 0)
|
||||
{
|
||||
auto* fieldPtr = reinterpret_cast<TextureHandle*>(objBasePtr + WriteDestinations[j]);
|
||||
isOk = Load(fieldPtr, 1, serializer) && isOk;
|
||||
continue;
|
||||
}
|
||||
if (bx::strCmp(memberName, "TabletStatusSolvedTexture") == 0)
|
||||
{
|
||||
auto* fieldPtr = reinterpret_cast<TextureHandle*>(objBasePtr + WriteDestinations[j]);
|
||||
|
||||
@@ -224,6 +224,7 @@ namespace Gen
|
||||
static constexpr uint16_t TypeIdx = 31;
|
||||
SavedEntityRenderData TabletBackgroundRenderData = {};
|
||||
SavedEntityRenderData TabletStatusRenderData = {};
|
||||
TextureHandle TabletStatusNotSolvedTexture = {};
|
||||
TextureHandle TabletStatusSolvedTexture = {};
|
||||
SavedEntityRenderData TabletResetRenderData = {};
|
||||
};
|
||||
@@ -351,11 +352,11 @@ namespace Gen
|
||||
TypeDef{sizeof(PlacedPuzzleCard), 3555575973, "PlacedPuzzleCard", 4, {24, 21, 4, 8}, {0, 0, 0, 0}, {{313, 7}, {320, 8}, {328, 8}, {336, 8}}},
|
||||
TypeDef{sizeof(PuzzleData), 3349686056, "PuzzleData", 10, {5, 11, 4, 4, 6, 27, 28, 32, 6, 21}, {0, 64, 0, 0, 0, 16, 256, 1024, 0, 16}, {{344, 2}, {346, 10}, {356, 10}, {366, 11}, {377, 18}, {395, 14}, {409, 11}, {420, 15}, {435, 17}, {452, 13}}},
|
||||
TypeDef{sizeof(SavedEntityRenderData), 3172756855, "SavedEntityRenderData", 7, {14, 14, 17, 33, 20, 19, 8}, {0, 0, 0, 0, 0, 0, 0}, {{465, 9}, {474, 14}, {488, 2}, {490, 8}, {498, 7}, {505, 5}, {510, 7}}},
|
||||
TypeDef{sizeof(SavedPlayerConfig), 2457294139, "SavedPlayerConfig", 4, {30, 30, 20, 30}, {0, 0, 0, 0}, {{517, 26}, {543, 22}, {565, 25}, {590, 21}}},
|
||||
TypeDef{sizeof(SavedPlayerConfig), 3685229621, "SavedPlayerConfig", 5, {30, 30, 20, 20, 30}, {0, 0, 0, 0, 0}, {{517, 26}, {543, 22}, {565, 28}, {593, 25}, {618, 21}}},
|
||||
TypeDef{sizeof(PuzzleElementType::Enum), 2983807453, "PuzzleElementType", 0, {}, {}, {}},
|
||||
TypeDef{sizeof(EMaterial::Enum), 2024002654, "EMaterial", 0, {}, {}, {}},
|
||||
};
|
||||
char MemberNameBuffer[64*64*64]{"xyxyzxyzwMMMMIPositionRotationScaleIdxModelIdxAssetTextureIdxAssetXYModelConnectionDirectionElementsBaseModelHandleNorthCoverHandleEastCoverHandleSouthCoverHandleWestCoverHandleSocketsModelTextureHandleBoardTextureHandleIdxTileBaseColorTileDotColorTestDisabledCardTintCardsVisualsRefCardMaxAvailableCountUsedCountRefCardPositionRotationIsLockedIDPuzzleNameWidthTilesHeightTilesAvailableCardCountAvailableCardsPlacedCardsBackgroundTilesGoalPositionCountGoalPositionsBaseColorHighlightColorTFMaterialTextureModelVisibleTabletBackgroundRenderDataTabletStatusRenderDataTabletStatusSolvedTextureTabletResetRenderData"};
|
||||
char MemberNameBuffer[64*64*64]{"xyxyzxyzwMMMMIPositionRotationScaleIdxModelIdxAssetTextureIdxAssetXYModelConnectionDirectionElementsBaseModelHandleNorthCoverHandleEastCoverHandleSouthCoverHandleWestCoverHandleSocketsModelTextureHandleBoardTextureHandleIdxTileBaseColorTileDotColorTestDisabledCardTintCardsVisualsRefCardMaxAvailableCountUsedCountRefCardPositionRotationIsLockedIDPuzzleNameWidthTilesHeightTilesAvailableCardCountAvailableCardsPlacedCardsBackgroundTilesGoalPositionCountGoalPositionsBaseColorHighlightColorTFMaterialTextureModelVisibleTabletBackgroundRenderDataTabletStatusRenderDataTabletStatusNotSolvedTextureTabletStatusSolvedTextureTabletResetRenderData"};
|
||||
};
|
||||
|
||||
constexpr MetadataTable Metadata;
|
||||
|
||||
Reference in New Issue
Block a user