Compare commits

..

32 Commits

Author SHA1 Message Date
Till Wübbers
d6e0cbf41c more tutorial text 2025-06-26 11:12:10 +02:00
Asuro
f95d9dee91 final build ig 2025-06-21 12:31:46 +02:00
Asuro
3c0af71470 puzzle 2025-06-21 12:21:14 +02:00
Asuro
7e89d93a7d bridge 2025-06-21 12:10:53 +02:00
Asuro
05cf88d986 fixes 2025-06-21 11:06:05 +02:00
Asuro
d6bec9e870 rotation fix 2025-06-21 10:57:36 +02:00
Asuro
3ccbbf493f walls 2025-06-21 03:27:25 +02:00
Asuro
b47a0cf841 test puzzles 2025-06-21 00:26:44 +02:00
Asuro
db47297ea4 less sticky movement 2025-06-21 00:26:37 +02:00
Asuro
6461b442de (kinda) fix ui offset 2025-06-21 00:13:51 +02:00
Asuro
146bf4aa22 color changes 2025-06-21 00:04:33 +02:00
Asuro
42c5b55f95 fix texture rotation, add tutorial popup 2025-06-20 23:34:32 +02:00
Asuro
d7fc6b781e ui hack 2025-06-20 15:42:05 +02:00
Asuro
e15cd79e04 fix collision 2025-06-20 15:41:52 +02:00
Asuro
4e00355dbe working collision! 2025-06-20 05:15:35 +02:00
Asuro
ffcc5bd134 fix heightmaps 2025-06-20 03:00:42 +02:00
Till Wübbers
67c1489da0 heightmap wip 2025-06-18 00:28:40 +02:00
Till Wübbers
59b8eea3a7 heightmap previews 2025-06-13 13:10:31 +02:00
Till Wübbers
a936222711 new debug message 2025-06-01 14:26:13 +02:00
Asuro
3af10d120b landscape 2025-06-01 03:17:29 +02:00
Asuro
6c8bead6ab new dithering 2025-06-01 03:17:21 +02:00
Asuro
faa36dd679 fix dithergen 2025-06-01 02:06:32 +02:00
Asuro
196d119338 slight entity rework (todo: memory corruption >.<) 2025-05-31 01:39:34 +02:00
Asuro
383c6f975b fix asset upgrade for arrays 2025-05-31 00:20:23 +02:00
Till Wübbers
4b230be2a8 half assed bugfixing 2025-05-29 17:33:14 +02:00
Till W
87ce032833 wip 2025-05-26 18:04:51 +02:00
Till W
cac2ef3330 new puzzle tool 2025-05-25 13:19:50 +02:00
Till W
410f401aef flags enum stuff 2025-05-25 13:07:11 +02:00
Till W
0c2d10d631 fix upgrading native type changes 2025-05-25 10:34:28 +02:00
Till W
18e7085aeb build notes 2025-05-23 01:57:32 +02:00
Asuro
bd2962fc38 refactor 2025-05-21 02:48:36 +02:00
Asuro
15dc65530d reset 2025-05-19 18:41:10 +02:00
69 changed files with 2287 additions and 950 deletions

Binary file not shown.

Binary file not shown.

BIN
assets/textures/reset.png LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
src/buildnotes.txt Normal file
View File

@@ -0,0 +1 @@
https://github.com/mstorsjo/llvm-mingw/releases

2
src/debug.ps1 Normal file
View File

@@ -0,0 +1,2 @@
.\build.ps1
& raddbg.exe --project:../tools/radsession.rad --auto_run -q

View File

@@ -55,6 +55,9 @@ namespace Gen
constexpr char EnumField1[] =
R"END( %s,
)END";
constexpr char EnumFieldNumbered2[] =
R"END( %s = %s,
)END";
constexpr char EnumNamesStart2[] =
R"END( };
@@ -71,6 +74,25 @@ namespace Gen
};
)END";
constexpr char EnumFlagOperators12[] =
R"END( inline %s::Enum operator| (const %s::Enum& a, const %s::Enum& b)
{
return a | b;
}
inline %s::Enum operator& (const %s::Enum& a, const %s::Enum& b)
{
return a & b;
}
inline %s::Enum operator|= (%s::Enum& a, const %s::Enum& b)
{
return a |= b;
}
inline %s::Enum operator&= (%s::Enum& a, const %s::Enum& b)
{
return a &= b;
}
)END";
constexpr char FileEnd[] =
R"END(}
)END";
@@ -124,6 +146,7 @@ namespace Gen
}
// Failed to resolve hash, the type definition chaned since the file was saved! try to match by name.
*obj = {};
int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName);
if (nameMatchIdx < 0)
{
@@ -175,7 +198,10 @@ namespace Gen
constexpr char LoadFuncBodyTypeUpgradeMember3[] = R"END( if (bx::strCmp(memberName, "%s") == 0)
{
auto* fieldPtr = reinterpret_cast<%s*>(objBasePtr + WriteDestinations[j]);
isOk = Load(fieldPtr, %u, serializer) && isOk;
uint16_t wantedCount = %u;
uint16_t existingCount = matchedDef.ChildArraySizes[j];
isOk = Load(fieldPtr, bx::min(wantedCount, existingCount), serializer) && isOk;
if (existingCount > wantedCount) serializer.Skip((existingCount - wantedCount) * childDef.Size);
continue;
}
)END";
@@ -293,7 +319,7 @@ void CppFileWriter::WriteInternal(WriteBuffer& buf, const char* templateStr, va_
}
void CppFileWriter::PrintTypeName(
char* buf, int32_t bufSize, Def::TypeRef type, const Def::DefinitionFile& definitions, bool printActualEnumType)
char* buf, int32_t bufSize, Def::TypeRef type, const Def::DefinitionFile& definitions, PrintFlags flags)
{
if (buf == nullptr || bufSize == 0 || !IsValid(type))
{
@@ -303,7 +329,8 @@ void CppFileWriter::PrintTypeName(
if (type.FieldKind == Def::EFieldType::DefinedClass)
{
auto& t = definitions.Types[type.TypeIdx];
if ((uint32_t)t.TypeFlags & (uint32_t)Def::ETypeFlags::IsNative)
if (((uint32_t)t.TypeFlags & (uint32_t)Def::ETypeFlags::IsNative) &&
((uint32_t)flags & (uint32_t)PrintFlags::PrintNativeTypeName))
{
bx::strCopy(buf, bufSize, t.NativeCName);
}
@@ -315,7 +342,7 @@ void CppFileWriter::PrintTypeName(
else if (type.FieldKind == Def::EFieldType::DefinedEnum)
{
bx::strCopy(buf, bufSize, definitions.Enums[type.TypeIdx].Name);
if (printActualEnumType)
if ((int32_t)flags & (int32_t)PrintFlags::PrintFullEnumName)
{
bx::strCat(buf, bufSize, "::Enum");
}
@@ -327,6 +354,7 @@ void CppFileWriter::WriteEnums(const Def::DefinitionFile& definitions)
for (int32_t enumIdx = 0; enumIdx < definitions.EnumCount; ++enumIdx)
{
const Def::Enum& e = definitions.Enums[enumIdx];
bool isFlagsEnum = (uint32_t)e.EnumFlags & (uint32_t)Def::EEnumFlags::FlagsEnum;
if (!IsValid(e.EnumType))
{
@@ -334,12 +362,24 @@ void CppFileWriter::WriteEnums(const Def::DefinitionFile& definitions)
continue;
}
char Buf[Def::MaxNameLength]{0};
PrintTypeName(Buf, sizeof(Buf), e.EnumType, definitions);
Write(WriteTemplates::EnumHeader4, e.Name, definitions.TypeCount + enumIdx, e.EntryCount, Buf);
char enumTypeNameBuf[Def::MaxNameLength]{0};
PrintTypeName(enumTypeNameBuf, sizeof(enumTypeNameBuf), e.EnumType, definitions);
Write(WriteTemplates::EnumHeader4, e.Name, definitions.TypeCount + enumIdx, e.EntryCount, enumTypeNameBuf);
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx)
{
Write(WriteTemplates::EnumField1, e.EntryNames[entryIdx]);
if (isFlagsEnum)
{
char numBuf[64] = "0";
if (entryIdx > 0)
{
bx::snprintf(numBuf, sizeof(numBuf), "1 << %u", entryIdx - 1);
}
Write(WriteTemplates::EnumFieldNumbered2, e.EntryNames[entryIdx], numBuf);
}
else
{
Write(WriteTemplates::EnumField1, e.EntryNames[entryIdx]);
}
}
Write(WriteTemplates::EnumNamesStart2, "EntryNames", Def::MaxNameLength);
@@ -358,6 +398,23 @@ void CppFileWriter::WriteEnums(const Def::DefinitionFile& definitions)
}
Write(WriteTemplates::EnumNamesEnd);
if (isFlagsEnum)
{
Write(WriteTemplates::EnumFlagOperators12,
e.Name,
e.Name,
e.Name,
e.Name,
e.Name,
e.Name,
e.Name,
e.Name,
e.Name,
e.Name,
e.Name,
e.Name);
}
}
}
void CppFileWriter::WriteTypes(const Def::DefinitionFile& definitions)
@@ -454,7 +511,10 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions)
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
{
const char* fieldName = t.FieldNames[fieldIdx];
PrintTypeName(fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions, false);
// This prints native type name, seems wrong??
// Havent i already fixed this???
PrintTypeName(
fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions, PrintFlags::None);
WriteCpp(WriteTemplates::LoadFuncBodyMemberCheck4, fieldName, fieldTypeName, typeName, fieldName);
}
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeStart);

View File

@@ -10,6 +10,13 @@ struct WriteBuffer
uint64_t WrittenBytes = 0;
};
enum class PrintFlags : uint32_t
{
None = 0,
PrintFullEnumName = 1 << 0,
PrintNativeTypeName = 1 << 1,
};
struct CppFileWriter
{
private:
@@ -25,7 +32,8 @@ struct CppFileWriter
int32_t bufSize,
Def::TypeRef type,
const Def::DefinitionFile& definitions,
bool printActualEnumType = true);
PrintFlags flags = (PrintFlags)((uint32_t)PrintFlags::PrintFullEnumName |
(uint32_t)PrintFlags::PrintNativeTypeName));
void WriteEnums(const Def::DefinitionFile& definitions);
void WriteTypes(const Def::DefinitionFile& definitions);
void WriteSaveLoadMethods(const Def::DefinitionFile& definitions);

View File

@@ -283,6 +283,12 @@ Parser::Result Parser::HandleEnum()
e.EnumType = {(uint16_t)Gen::KnownType::i32, Def::EFieldType::DefinedClass};
}
if (CmpAdvance("Flags", Res) && Res == OK)
{
e.EnumFlags = (Def::EEnumFlags)((uint32_t)e.EnumFlags | (uint32_t)Def::EEnumFlags::FlagsEnum);
CHECK(SkipWhitespace());
}
CHECK(ExpectChar("{"));
CHECK(SkipWhitespace());
while (!CmpAdvance("}", Res))

View File

@@ -25,6 +25,12 @@ namespace Def
DynamicArray = 1 << 0,
};
enum class EEnumFlags : uint32_t
{
None = 0,
FlagsEnum = 1,
};
struct TypeRef
{
uint16_t TypeIdx = UINT16_MAX;
@@ -58,6 +64,7 @@ namespace Def
char ExtraStringFieldNames[MaxExtraEnumFields][MaxNameLength];
char ExtraStringFields[MaxFields][MaxExtraEnumFields][MaxNameLength];
char Name[MaxNameLength]{0};
EEnumFlags EnumFlags = EEnumFlags::None;
uint32_t Hash = 0;
};

158
src/game/Entity.h Normal file
View File

@@ -0,0 +1,158 @@
#pragma once
#include "../gen/Generated.h"
#include "Log.h"
#include "Puzzle.h" // TODO: remove
#include "bgfx/bgfx.h"
#include "rendering/Rendering.h"
#include <cstdint>
#include <typeinfo>
#define ENTITY_HANDLE(X) \
struct X \
{ \
uint16_t Idx = UINT16_MAX; \
}; \
inline bool IsValid(X h) \
{ \
return h.Idx != UINT16_MAX; \
}
namespace Game
{
int32_t GetNextRenderID();
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;
int32_t RenderID = 0;
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] = {};
Data[Count].EData.RenderID = GetNextRenderID();
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;
bgfx::setMarker(typeid(T).name());
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

View File

@@ -393,6 +393,37 @@ namespace Gen
return true;
}
bool RayTriangleIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out)
{
const float EPSILON = 1e-6f;
Vec3 dir = l2 - l1; // Ray direction
Vec3 edge1 = p2 - p1;
Vec3 edge2 = p3 - p1;
Vec3 h = CrossProduct(dir, edge2);
float a = DotProduct(edge1, h);
if (bx::abs(a) < EPSILON) return false; // Ray is parallel to the triangle
float f = 1.0f / a;
Vec3 s = l1 - p1;
float u = f * DotProduct(s, h);
if (u < 0.0f || u > 1.0f) return false;
Vec3 q = CrossProduct(s, edge1);
float v = f * DotProduct(dir, q);
if (v < 0.0f || u + v > 1.0f) return false;
float t = f * DotProduct(edge2, q);
if (t > EPSILON)
{
out = l1 + dir * t;
return true;
}
return false;
}
void Translate(Transform& trans, Vec3 offset)
{
trans.Position += Vec3{offset.x, offset.y, offset.z};

View File

@@ -81,6 +81,7 @@ namespace Gen
Vec3 CrossProduct(Vec3 a, Vec3 b);
Vec3 CrossProductFromPlane(Vec3 a, Vec3 b, Vec3 c);
bool RayPlaneIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out);
bool RayTriangleIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out);
void Translate(Transform& trans, Vec3 offset);
void TranslateLocal(Transform& trans, Vec3 offset);

View File

@@ -52,18 +52,19 @@ namespace Game
struct InstanceDebugData
{
uint16_t SelectedDebugLevel = UINT16_MAX;
static constexpr uint32_t MaxAssets = 128;
uint16_t SelectedDebugLevel = 0;
uint64_t ImguiIniSize = 0;
char ImguiIni[4096]{0};
static constexpr uint32_t MaxAssets = 128;
uint32_t AssetCount = 0;
Gen::AssetHandle AssetHandles[MaxAssets]{0};
char AssetHandlePaths[MaxAssets][128];
bool ShowImguiDemo = false;
bool DebugBreakIDEnabled = false;
int DebugBreakID = -1;
uint8_t DebugCardRotation = 0;
bool ShortenLogFileNames = true;
bool ShowStats = true;
bool ShowArenaUsage = false;
};
struct GameInstance

View File

@@ -6,7 +6,9 @@
#include "Level.h"
#include "Log.h"
#include "Puzzle.h"
#include "UI.h"
#include "bx/bx.h"
#include "bx/debug.h"
#include "rendering/Rendering.h"
#include "SDL3/SDL_mouse.h"
@@ -27,6 +29,13 @@ namespace Game
{
void EntityRenderData::Render(const Model* models, const Material* materials, const Texture* textures)
{
auto& debug = GetInstance().DebugData;
if ((int32_t)debug.DebugBreakID == RenderID && debug.DebugBreakIDEnabled)
{
bx::debugBreak();
debug.DebugBreakIDEnabled = false;
}
if (models == nullptr || materials == nullptr || textures == nullptr) return;
if (!Gen::IsValid(ModelH) || MaterialHandle >= EMaterial::EntryCount) return;
if (!Visible) return;
@@ -100,7 +109,7 @@ namespace Game
{
auto& IO = ImGui::GetIO();
IO.ConfigFlags =
FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, IsGaming);
FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, captureMouse);
}
rendering.UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug;
}
@@ -179,6 +188,13 @@ namespace Game
Cubes.Get(PlayerOutsideViewCube).Setup();
}
{
Deserializer d;
d.Init("game/data/static/uiconfig.dat", "UICO");
d.ReadT(GetInstance().Player.Config);
d.Finish();
}
UIQuads.Count = 0;
PuzzleTiles.Count = 0;
PuzzleTileCovers.Count = 0;
@@ -189,17 +205,92 @@ namespace Game
Puzzles[i].Setup();
}
}
TabletHandle = UIQuads.New();
PuzzleUI.Setup();
ReloadLevelEntities();
UpdatePlayerInputMode();
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
{
Deserializer d;
d.Init("game/data/static/uiconfig.dat", "UICO");
d.ReadT(GetInstance().Player.Config);
d.Finish();
Puzzles[i].WorldPosition = {0.0f, 0.0f, i * 50.0f};
}
}
bool IsInPuzzle(WorldPuzzle& puz, Vec3 worldPos)
{
Vec3 offsetToPuzzle = worldPos - puz.WorldPosition + (Vec3{0.5f, 0.0f, 0.5f} * Puzzle::Config::CardScaleWorld);
Vec3 scaledOffset = offsetToPuzzle / Puzzle::Config::CardScaleWorld;
int32_t offsetX = (int32_t)bx::floor(scaledOffset.x);
int32_t offsetY = (int32_t)bx::floor(scaledOffset.z);
return (offsetX >= 0 && offsetX < puz.Data.WidthTiles / 2 && offsetY >= -1 &&
offsetY < puz.Data.HeightTiles / 2);
}
bool IsOnGround(Level& level, Vec3 worldPos)
{
for (auto& puz : level.Puzzles)
{
Vec3 offsetToPuzzle =
worldPos - puz.WorldPosition + (Vec3{0.5f, 0.0f, 0.5f} * Puzzle::Config::CardScaleWorld);
Vec3 scaledOffset = offsetToPuzzle / Puzzle::Config::CardScaleWorld;
int32_t offsetX = (int32_t)bx::floor(scaledOffset.x);
int32_t offsetY = puz.Data.HeightTiles / 2 - (int32_t)bx::floor(scaledOffset.z) - 1;
float fracOffsetX = scaledOffset.x - offsetX;
float fracOffsetY = scaledOffset.z - bx::floor(scaledOffset.z);
if (offsetX >= 0 && offsetX < puz.Data.WidthTiles / 2 && offsetY >= 0 && offsetY < puz.Data.HeightTiles / 2)
{
auto& card = puz.Data.PlacedCards[offsetY * Puzzle::Config::MaxPuzzleSizeCards + offsetX];
if (card.RefCard.Idx == UINT16_MAX)
{
return true;
}
auto& refCard = Puzzle::GetStaticPuzzleData().Cards[card.RefCard.Idx];
if (!IsValid(refCard.BaseModelHandle))
{
LOG_WARN("missing base model! @ %i %i", offsetX, offsetY);
return true;
}
auto& heightmap = GameRendering::Get().Models[refCard.BaseModelHandle.ModelIdx].Height;
int32_t xPos = (int32_t)(fracOffsetX * heightmap.Width);
int32_t yPos = (int32_t)(fracOffsetY * heightmap.Height);
uint8_t height = 0;
switch (card.Rotation)
{
case 0:
height = heightmap.Values[yPos * heightmap.Width + xPos];
break;
case 1:
height = heightmap.Values[xPos * heightmap.Width + (heightmap.Height - yPos - 1)];
break;
case 2:
height =
heightmap
.Values[(heightmap.Height - yPos - 1) * heightmap.Width + (heightmap.Width - xPos - 1)];
break;
default:
height = heightmap.Values[(heightmap.Height - xPos - 1) * heightmap.Width + yPos];
break;
}
return height >= 110 && height <= 125;
}
if (offsetX == 1 && offsetY == puz.Data.HeightTiles / Puzzle::Config::CardSize)
{
if (puz.IsSolved)
{
return true;
}
return true; // TODO!
}
}
return false;
}
void Level::Update()
{
ZoneScopedN("Level update");
@@ -251,9 +342,38 @@ namespace Game
}
else if (player.CameraM == CameraMode::Walk)
{
TranslateLocal(player.PlayerCamTransform, {0.0f, 0.0f, inputVec.z});
TranslateLocal(player.PlayerCamTransform, {inputVec.x, 0.0f, 0.0f});
player.PlayerCamTransform.Position.y = 3.0f;
auto newTransform = player.PlayerCamTransform;
// Global and local are inverted because camera
Vec3 globalInput = GlobalToLocalDirection(newTransform, {inputVec.x, 0.0f, inputVec.z});
Translate(newTransform, globalInput);
newTransform.Position.y = 3.0f;
if (IsOnGround(*this, newTransform.Position))
{
player.PlayerCamTransform = newTransform;
}
else
{
auto newTransform = player.PlayerCamTransform;
Translate(newTransform, {globalInput.x, 0.0f, 0.0f});
newTransform.Position.y = 3.0f;
if (IsOnGround(*this, newTransform.Position))
{
player.PlayerCamTransform = newTransform;
}
else
{
auto newTransform = player.PlayerCamTransform;
Translate(newTransform, {0.0f, 0.0f, globalInput.z});
newTransform.Position.y = 3.0f;
if (IsOnGround(*this, newTransform.Position))
{
player.PlayerCamTransform = newTransform;
}
}
}
player.WalkXRot += rotInput.x;
player.WalkYRot += rotInput.y;
@@ -267,18 +387,6 @@ namespace Game
UpdatePlayerInputMode();
}
// UI Tablet
if (IsValid(TabletHandle))
{
auto& tablet = UIQuads.Get(TabletHandle);
tablet.EData.LoadFromSaved(player.Config.TabletBackgroundRenderData);
UpdateMatrix(player.PlayerCamTransform);
tablet.EData.Transform.Rotation = player.PlayerCamTransform.Rotation;
Rotate(tablet.EData.Transform, {0.5f * bx::kPi, 0.0f, 0.0f});
tablet.EData.Transform.Position =
player.PlayerCamTransform.Position + AxisForward(player.PlayerCamTransform.M) * 1.0f;
}
// Cubes
for (uint16_t i = 0; i < Cubes.Count; ++i)
{
@@ -286,12 +394,21 @@ namespace Game
}
// Puzzle tiles
Puzzle::PuzzleSolver solver;
uint16_t activeIdx = GetInstance().DebugData.SelectedDebugLevel;
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
{
Puzzles[i].IsActive = GetInstance().DebugData.SelectedDebugLevel == i;
if (IsInPuzzle(Puzzles[i], player.PlayerCamTransform.Position))
{
activeIdx = i;
}
Puzzles[i].IsActive = activeIdx == i;
Puzzles[i].Update();
Puzzles[i].IsSolved = solver.IsPuzzleSolved(Puzzles[i].Data);
}
PuzzleUI.Update(Puzzles[activeIdx].Data, Puzzles[activeIdx].IsSolved);
END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter);
}
@@ -332,6 +449,7 @@ namespace Game
{
UIQuads.Render(models, materials, textures);
}
LevelEntities.Render(models, materials, textures);
}
void Cube::Setup()
@@ -355,77 +473,50 @@ namespace Game
void WorldPuzzle::Setup()
{
auto& level = GetInstance().GameLevel;
Level& level = GetInstance().GameLevel;
for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i)
{
TileHandles[i] = level.PuzzleTiles.New();
auto& tile = level.PuzzleTiles.Get(TileHandles[i]);
PuzzleTileEntity& tile = level.PuzzleTiles.Get(TileHandles[i]);
tile.EData.MaterialHandle = EMaterial::Default;
for (int32_t j = 0; j < Puzzle::Config::MaxCoversInTile; ++j)
{
int32_t idx = i * Puzzle::Config::MaxCoversInTile + j;
CoverHandles[idx] = level.PuzzleTileCovers.New();
auto& cover = level.PuzzleTileCovers.Get(CoverHandles[idx]);
PuzzleTileCover& 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)
for (int32_t i = 0; i < BX_COUNTOF(EndHandles); ++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");
EndHandles[i] = level.PuzzleTiles.New();
PuzzleTileEntity& tile = level.PuzzleTiles.Get(EndHandles[i]);
tile.EData.MaterialHandle = EMaterial::Default;
}
SolvedQuad = level.UIQuads.New();
WallHandle = level.PuzzleTiles.New();
PuzzleTileEntity& wHandle = level.PuzzleTiles.Get(WallHandle);
wHandle.EData.MaterialHandle = EMaterial::Default;
wHandle.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/GateWall.glb");
DoorHandle = level.PuzzleTiles.New();
PuzzleTileEntity& dHandle = level.PuzzleTiles.Get(DoorHandle);
dHandle.EData.MaterialHandle = EMaterial::Default;
dHandle.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/GateDoor.glb");
IsSetup = true;
LOG("finished setup!");
}
Vec3 GetMousePosWorld()
Vec3 PuzPosToWorldPos(const PuzzleData& data, int32_t x, int32_t y)
{
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 {
(float)x * Puzzle::Config::CardScaleWorld,
-5.0f,
(float)(data.HeightTiles / 2 - y - 1) * Puzzle::Config::CardScaleWorld,
};
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()
@@ -434,107 +525,6 @@ namespace Game
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();
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;
solvedQuad.EData.Transform.Scale = solvedData.Transform.Scale;
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});
// 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)
{
Vec3 quadPlaneIntersectPos;
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)
{
@@ -543,29 +533,25 @@ 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];
// World Tile
tile.EData.Visible = IsActive;
tile.EData.Visible = true;
tile.EData.ModelH = staticCard.BaseModelHandle;
tile.EData.TextureHandle = staticCard.ModelTextureHandle;
tile.EData.DotColor = visuals.TileDotColor;
tile.EData.BaseColor = visuals.TileBaseColor;
Vec3 cardPos = {
(float)card.Position.X * Puzzle::Config::CardScaleWorld,
-5.0f,
(float)card.Position.Y * Puzzle::Config::CardScaleWorld,
};
Vec3 cardPos = PuzPosToWorldPos(Data, card.Position.X, card.Position.Y);
if (!isValid)
{
cardPos = {x * Puzzle::Config::CardScaleWorld, -5.0f, y * Puzzle::Config::CardScaleWorld};
cardPos = PuzPosToWorldPos(Data, x, y);
}
tile.EData.Transform.Position = cardPos;
bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * 0.5f);
tile.EData.Transform.Position = cardPos + WorldPosition;
bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * -0.5f);
// Covers
if (IsValid(staticCard.BaseModelHandle))
@@ -578,101 +564,65 @@ namespace Game
cover.EData.Visible = IsActive;
cover.EData.ModelH = staticCard.Sockets[i].Model;
cover.EData.Transform = tile.EData.Transform;
cover.EData.MaterialHandle = EMaterial::Default;
cover.EData.BaseColor = {0.2f, 0.1f, 0.7f, 1.0f};
cover.EData.DotColor = {0.2f, 0.2f, 0.8f, 1.0f};
Gen::TranslateLocal(cover.EData.Transform, model.Sockets[i].Pos);
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;
}
}
}
}
// End
for (int32_t i = 0; i < BX_COUNTOF(EndHandles); ++i)
{
auto& tile = level.PuzzleTiles.Get(EndHandles[i]);
if (i < Data.WidthTiles / 2)
{
tile.EData.Visible = true;
tile.EData.ModelH = staticCards[0].BaseModelHandle;
tile.EData.TextureHandle = staticCards[0].ModelTextureHandle;
tile.EData.DotColor = visuals.TileDotColor;
tile.EData.BaseColor = visuals.TileBaseColor + Vec4{0.1f, 0.1f, 0.1f, 0.0f};
tile.EData.Transform.Position = WorldPosition + Vec3{
i * Puzzle::Config::CardScaleWorld,
-5.0f,
(float)Data.HeightTiles / Puzzle::Config::CardSize *
Puzzle::Config::CardScaleWorld,
};
}
else
{
tile.EData.Visible = false;
}
}
auto& wall = level.PuzzleTiles.Get(WallHandle);
wall.EData.Visible = true;
wall.EData.Transform.Position =
WorldPosition + Vec3{0.0f, 0.0f, Data.HeightTiles * 5.0f} + Vec3{30.0f, -5.0f, 0.2f};
auto& door = level.PuzzleTiles.Get(DoorHandle);
door.EData.Visible = !IsSolved;
door.EData.Transform.Position =
WorldPosition + Vec3{0.0f, 0.0f, Data.HeightTiles * 5.0f} + Vec3{30.0f, -5.0f, 0.2f};
}
void Level::ReloadLevelEntities()
{
LevelEntities.Count = 0;
for (int32_t i = 0; i < BX_COUNTOF(BackgroundEntityHandles); ++i)
{
BackgroundEntityHandles[i] = LevelEntities.New();
auto& levelBgEntity = LevelEntities.Get(BackgroundEntityHandles[i]);
levelBgEntity.EData.LoadFromSaved(GetInstance().Player.Config.BackgroundLevelRenderData[i]);
}
}
int32_t GetNextRenderID()
{
static int32_t RenderIDCounter = 0;
RenderIDCounter++;
return RenderIDCounter;
}
} // namespace Game

View File

@@ -1,167 +1,29 @@
#pragma once
#include "../engine/Shared.h"
#include "Log.h"
#include "Entity.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;
Gen::PuzPos DraggedCard{-1, -1};
uint16_t DraggedAvailableCardIdx = UINT16_MAX;
PuzzleTileEntityHandle EndHandles[Puzzle::Config::MaxPuzzleSizeCards];
PuzzleTileEntityHandle WallHandle;
PuzzleTileEntityHandle DoorHandle;
bool IsSetup = false;
bool IsActive = false;
bool IsSolved = false;
void Setup();
void Update();
@@ -174,19 +36,21 @@ 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;
UIQuadEntityHandle TabletHandle;
LevelEntityHandle BackgroundEntityHandles[16];
public:
Gen::StaticPuzzleData PuzzleData;
WorldPuzzle Puzzles[Puzzle::Config::MaxVisiblePuzzles];
WorldPuzzleUI PuzzleUI;
public:
void Setup(GameData& data);
void Update();
void Render(uint16_t ViewID, const Model* models, const Material* materials, const Texture* textures);
void ReloadLevelEntities();
};
} // namespace Game

View File

@@ -2,15 +2,18 @@
#include "Global.h"
#include "Log.h"
#include "Mesh.h"
#include "bgfx/bgfx.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 "bx/timer.h"
#include "rendering/Rendering.h"
#include "Instance.h"
#include <cstdint>
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
@@ -21,6 +24,7 @@ namespace Game
{
bool LoadMesh(Model& mesh, const char* path, bool isBinary)
{
bx::strCopy(mesh.Name, sizeof(mesh.Name), path);
mesh.VertLayout.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float)
@@ -58,23 +62,23 @@ namespace Game
tinygltf::Primitive primitive = model.meshes[0].primitives[0];
{
tinygltf::Accessor accessor = model.accessors.at(primitive.indices);
tinygltf::BufferView bufferView = model.bufferViews.at(accessor.bufferView);
tinygltf::Buffer buffer = model.buffers[bufferView.buffer];
const bgfx::Memory* ibMem = bgfx::alloc(bufferView.byteLength);
bx::memCopy(ibMem->data, &buffer.data.at(bufferView.byteOffset), bufferView.byteLength);
tinygltf::Accessor indexAccessor = model.accessors.at(primitive.indices);
tinygltf::BufferView indexBufferView = model.bufferViews.at(indexAccessor.bufferView);
int32_t indexStride = sizeof(uint16_t);
tinygltf::Buffer indexBuffer = model.buffers[indexBufferView.buffer];
const bgfx::Memory* ibMem = bgfx::alloc(indexBufferView.byteLength);
bx::memCopy(ibMem->data, &indexBuffer.data.at(indexBufferView.byteOffset), indexBufferView.byteLength);
mesh.IndexBuffer = bgfx::createIndexBuffer(ibMem);
}
{
tinygltf::Accessor posAccessor = model.accessors.at(primitive.attributes.at("POSITION"));
tinygltf::Accessor normalAccessor = model.accessors.at(primitive.attributes.at("NORMAL"));
tinygltf::Accessor uvAccessor = model.accessors.at(primitive.attributes.at("TEXCOORD_0"));
tinygltf::BufferView posBufferView = model.bufferViews[posAccessor.bufferView];
tinygltf::BufferView normalBufferView = model.bufferViews[normalAccessor.bufferView];
tinygltf::BufferView uvBufferView = model.bufferViews[uvAccessor.bufferView];
int posStride = posAccessor.ByteStride(posBufferView);
int normalStride = normalAccessor.ByteStride(normalBufferView);
int uvStride = uvAccessor.ByteStride(uvBufferView);
int32_t posStride = posAccessor.ByteStride(posBufferView);
int32_t normalStride = normalAccessor.ByteStride(normalBufferView);
int32_t uvStride = uvAccessor.ByteStride(uvBufferView);
tinygltf::Buffer posBuffer = model.buffers[posBufferView.buffer];
tinygltf::Buffer normalBuffer = model.buffers[normalBufferView.buffer];
tinygltf::Buffer uvBuffer = model.buffers[uvBufferView.buffer];
@@ -92,8 +96,81 @@ namespace Game
bx::memCopy(&v.uv_x, &uvBuffer.data.at(uvBufferView.byteOffset + i * uvStride), uvStride);
}
mesh.VertexBuffer = bgfx::createVertexBuffer(vbMem, mesh.VertLayout);
constexpr float SIZE_LIMIT = 1000.0f;
mesh.MinPos = {SIZE_LIMIT, SIZE_LIMIT, SIZE_LIMIT};
mesh.MaxPos = {-SIZE_LIMIT, -SIZE_LIMIT, -SIZE_LIMIT};
bx::memSet(mesh.Height.Values, 0, BX_COUNTOF(mesh.Height.Values));
int64_t startTime = bx::getHPCounter();
for (int32_t i = 0; i < vertexCount; ++i)
{
Gen::Vec3* pos =
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + i * posStride]);
if (pos->x < mesh.MinPos.x) mesh.MinPos.x = pos->x;
if (pos->y < mesh.MinPos.y) mesh.MinPos.y = pos->y;
if (pos->z < mesh.MinPos.z) mesh.MinPos.z = pos->z;
if (pos->x > mesh.MaxPos.x) mesh.MaxPos.x = pos->x;
if (pos->y > mesh.MaxPos.y) mesh.MaxPos.y = pos->y;
if (pos->z > mesh.MaxPos.z) mesh.MaxPos.z = pos->z;
}
LOG("min/max: %lli", bx::getHPCounter() - startTime);
mesh.MinPos = {-5.0f, -5.0f, -5.0f};
mesh.MaxPos = {5.0f, 5.0f, 5.0f};
mesh.Size = mesh.MaxPos - mesh.MinPos;
startTime = bx::getHPCounter();
for (uint32_t v = 0; v < HeightMap::Height; ++v)
{
float vPos = mesh.MinPos.z + (float)v / HeightMap::Height * mesh.Size.z;
for (uint32_t u = 0; u < HeightMap::Width; ++u)
{
float uPos = mesh.MinPos.x + (float)u / HeightMap::Width * mesh.Size.x;
Gen::Vec3 rayStart = {uPos, -100.0f, vPos};
Gen::Vec3 rayEnd = {uPos, 100.0f, vPos};
Gen::Vec3 ptOut;
for (int16_t i = 0; i < indexBufferView.byteLength; i += indexStride * 3)
{
uint16_t* idxA = reinterpret_cast<uint16_t*>(&indexBuffer.data[indexBufferView.byteOffset + i]);
uint16_t* idxB = reinterpret_cast<uint16_t*>(
&indexBuffer.data[indexBufferView.byteOffset + i + 1 * indexStride]);
uint16_t* idxC = reinterpret_cast<uint16_t*>(
&indexBuffer.data[indexBufferView.byteOffset + i + 2 * indexStride]);
Gen::Vec3* triA =
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + *idxA * posStride]);
Gen::Vec3* triB =
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + *idxB * posStride]);
Gen::Vec3* triC =
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + *idxC * posStride]);
if (Gen::RayTriangleIntersect(rayStart, rayEnd, *triA, *triB, *triC, ptOut))
{
float len = ptOut.y - rayStart.y;
uint8_t val = (uint8_t)(len / mesh.Size.y * UINT8_MAX);
int32_t idx = v * HeightMap::Width + u;
if (mesh.Height.Values[idx] < val)
{
mesh.Height.Values[idx] = val;
}
if (len < 0.0f)
{
LOG_ONCE("%f / %f = %u", len, mesh.Size.y, val);
}
}
}
}
}
LOG("heightmap: %lli", bx::getHPCounter() - startTime);
}
const bgfx::Memory* mem = bgfx::makeRef(&mesh.Height.Values[0], sizeof(mesh.Height.Values));
mesh.HeightMapTexture =
bgfx::createTexture2D(HeightMap::Width, HeightMap::Height, false, 1, bgfx::TextureFormat::R8, 0, mem);
for (auto& node : model.nodes)
{
if (bx::strFindI(node.name.c_str(), "_slot_").getLength() > 0)

View File

@@ -1,7 +1,6 @@
#include "../gen/Def.h"
#include "Gen.h"
#include "Global.h"
#include "Instance.h"
#include "Log.h"
#include "Puzzle.h"
@@ -22,6 +21,7 @@ namespace
StaticPuzzleData StaticData;
StaticPuzzleCard InvalidCard;
PlacedPuzzleCard InvalidPlacedCard;
} // namespace
namespace Puzzle
@@ -104,6 +104,24 @@ namespace Puzzle
return puz.BackgroundTiles[pos.Y * Puzzle::Config::MaxPuzzleSizeTiles + pos.X];
}
PuzzleElementType::Enum GetInitialNodeAt(const PuzzleData& puz, PuzPos pos)
{
assert(pos.X < Puzzle::Config::MaxPuzzleSizeTiles && pos.Y < Puzzle::Config::MaxPuzzleSizeTiles && pos.X >= 0 &&
pos.Y >= 0);
int32_t cardIdxX = pos.X / Puzzle::Config::CardSize;
int32_t cardIdxY = pos.Y / Puzzle::Config::CardSize;
auto& card = puz.InitialPlacedCards[cardIdxY * Puzzle::Config::MaxPuzzleSizeCards + cardIdxX];
int32_t offsetX = pos.X - (cardIdxX * Config::CardSize);
int32_t offsetY = pos.Y - (cardIdxY * Config::CardSize);
if (offsetX >= 0 && offsetX < Puzzle::Config::CardSize && offsetY >= 0 && offsetY < Puzzle::Config::CardSize &&
IsValid(card.RefCard))
{
PuzzleElementType::Enum cardVal = GetCardNodeAt(GetCard(card.RefCard), card.Rotation, offsetX, offsetY);
if (cardVal != PuzzleElementType::None) return cardVal;
}
return puz.BackgroundTiles[pos.Y * Puzzle::Config::MaxPuzzleSizeTiles + pos.X];
}
PuzzleElementType::Enum GetCardNodeAt(const StaticPuzzleCard& card, uint8_t rotation, int8_t x, int8_t y)
{
assert(x >= 0 && x < Puzzle::Config::CardSize);
@@ -288,12 +306,32 @@ namespace Puzzle
bx::snprintf(buf, bufSize, "%s/%u.pzl", Puzzle::PuzzleFileDir, puzID);
}
PlacedPuzzleCard& GetCardAt(PuzzleData& obj, PuzPos pos)
{
if (pos.X < 0 || pos.X >= Config::MaxPuzzleSizeCards || pos.Y < 0 || pos.Y >= Config::MaxPuzzleSizeCards)
{
LOG_ERROR("Invalid card access at %i %i!!", pos.X, pos.Y);
return InvalidPlacedCard;
}
return obj.PlacedCards[pos.Y * Config::MaxPuzzleSizeCards + pos.X];
}
PlacedPuzzleCard& GetInitialCardAt(PuzzleData& obj, PuzPos pos)
{
if (pos.X < 0 || pos.X >= Config::MaxPuzzleSizeCards || pos.Y < 0 || pos.Y >= Config::MaxPuzzleSizeCards)
{
LOG_ERROR("Invalid card access at %i %i!!", pos.X, pos.Y);
return InvalidPlacedCard;
}
return obj.InitialPlacedCards[pos.Y * Config::MaxPuzzleSizeCards + pos.X];
}
bool ReturnPlacedCard(PuzzleData& obj, PuzPos targetPos)
{
auto& placedCard = obj.PlacedCards[targetPos.Y * Config::MaxPuzzleSizeCards + targetPos.X];
PlacedPuzzleCard& placedCard = GetCardAt(obj, targetPos);
if (IsValid(placedCard.RefCard))
{
if (placedCard.IsLocked)
if (GetFlag(placedCard.Flags, PlacedPuzzleCardFlags::Locked))
{
LOG_WARN("Card at %i %i is locked!", targetPos.X, targetPos.Y);
return false;
@@ -330,19 +368,55 @@ namespace Puzzle
auto& draggedCard = obj.AvailableCards[availIdx];
draggedCard.UsedCount++;
auto& placedCard = obj.PlacedCards[targetPos.Y * Config::MaxPuzzleSizeCards + targetPos.X];
PlacedPuzzleCard& placedCard = GetCardAt(obj, targetPos);
placedCard.RefCard = draggedCard.RefCard;
placedCard.IsLocked = false;
placedCard.Flags = (PlacedPuzzleCardFlags::Enum)ClearFlags(placedCard.Flags, PlacedPuzzleCardFlags::Locked);
placedCard.Position = targetPos;
placedCard.Rotation = rotation;
return true;
}
void RecalculateInitialAvailable(PuzzleData& obj)
{
for (int32_t i = 0; i < obj.AvailableCardCount; ++i)
{
obj.AvailableCards[i].UsedCount = obj.AvailableCards[i].MaxAvailableCount;
}
for (int32_t y = 0; y < obj.HeightTiles; ++y)
{
for (int32_t x = 0; x < obj.WidthTiles; ++x)
{
auto& placedCard = obj.PlacedCards[y * Puzzle::Config::MaxPuzzleSizeCards + x];
if (Puzzle::IsValid(placedCard.RefCard))
{
bool found = false;
for (int32_t i = 0; i < obj.AvailableCardCount; ++i)
{
if (obj.AvailableCards[i].RefCard.Idx == placedCard.RefCard.Idx)
{
found = true;
obj.AvailableCards[i].MaxAvailableCount++;
}
}
if (!found)
{
if (obj.AvailableCardCount == Puzzle::Config::MaxAvailableStacks)
{
LOG_ERROR("Read limit of available card stacks!");
break;
}
obj.AvailableCards[obj.AvailableCardCount] = {};
obj.AvailableCards[obj.AvailableCardCount].RefCard = placedCard.RefCard;
obj.AvailableCards[obj.AvailableCardCount].MaxAvailableCount = 1;
}
}
}
}
}
bool RenderDebugUI(PuzzleData& obj)
{
bool dataChanged = false;
uint8_t debugRot = Game::GetInstance().DebugData.DebugCardRotation;
bool isVisible = true;
if (ImGui::Begin("Puzzle", &isVisible))
{
@@ -356,17 +430,34 @@ namespace Puzzle
return false;
}
ImGui::SameLine();
if (ImGui::Button("Reload"))
if (ImGui::Button("Reset"))
{
// TODO
ResetPuzzle(obj);
}
ImGui::SameLine();
if (ImGui::Button("Save"))
{
ResetPuzzle(obj);
char path[128]{0};
WritePuzzleFilePath(path, sizeof(path), obj.ID);
Serializer ser;
if (ser.Init(path, "PZZL") && ser.WriteT(obj))
{
LOG("Saved to %s", path);
}
else
{
LOG_ERROR("Failed to save to %s", path);
}
ser.Finish();
}
int32_t val = obj.ID;
if (ImGui::InputInt("ID", &val))
{
obj.ID = val;
dataChanged = true;
}
dataChanged = ImGui::InputText("Name", obj.PuzzleName, sizeof(obj.PuzzleName)) || dataChanged;
ImGui::InputText("Name", obj.PuzzleName, sizeof(obj.PuzzleName));
int32_t W = obj.WidthTiles;
int32_t H = obj.HeightTiles;
@@ -375,7 +466,6 @@ namespace Puzzle
if (ImGui::DragInt("", &W, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
{
obj.WidthTiles = uint8_t(W);
dataChanged = true;
}
ImGui::PopID();
ImGui::SameLine();
@@ -386,7 +476,6 @@ namespace Puzzle
if (ImGui::DragInt("", &H, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
{
obj.HeightTiles = uint8_t(H);
dataChanged = true;
}
ImGui::PopID();
@@ -401,7 +490,7 @@ namespace Puzzle
{
ImGui::PushID(x);
PuzPos nodePos = {int8_t(x), int8_t(y)};
auto node = GetNodeAt(obj, nodePos);
auto node = GetInitialNodeAt(obj, nodePos);
if (node == PuzzleElementType::WaterGoal)
{
obj.GoalPositions[obj.GoalPositionCount] = nodePos;
@@ -414,36 +503,30 @@ namespace Puzzle
ImGui::SetCursorScreenPos(pos);
if (x % Puzzle::Config::CardSize == 0 && y % Puzzle::Config::CardSize == 0)
{
int32_t cardX = x / Config::CardSize;
int32_t cardY = y / Config::CardSize;
PuzPos cardPos = {int8_t(cardX), int8_t(cardY)};
auto& placedCard = obj.PlacedCards[cardY * Config::MaxPuzzleSizeCards + cardX];
PuzPos cardPos = {int8_t(x / Config::CardSize), int8_t(y / Config::CardSize)};
PlacedPuzzleCard& placedCard = GetInitialCardAt(obj, cardPos);
bool isLocked = GetFlag(placedCard.Flags, PlacedPuzzleCardFlags::Locked);
ImGui::InvisibleButton("bn", {UIPuzBoxSize * 2, UIPuzBoxSize * 2});
if (ImGui::IsItemClicked(ImGuiMouseButton_Right))
{
placedCard.Rotation += 1;
if (placedCard.Rotation >= 4) placedCard.Rotation = 0;
dataChanged = true;
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Middle) && IsValid(placedCard.RefCard))
if (ImGui::IsItemClicked(ImGuiMouseButton_Middle))
{
if (placedCard.IsLocked)
if (ImGui::IsKeyDown(ImGuiKey_LeftShift))
{
placedCard.IsLocked = false;
placedCard.RefCard = {};
dataChanged = true;
placedCard = {};
}
else
{
if (!ReturnPlacedCard(obj, cardPos))
{
placedCard.IsLocked = false;
placedCard.RefCard = {};
dataChanged = true;
}
placedCard.Flags =
(PlacedPuzzleCardFlags::Enum)(placedCard.Flags ^ PlacedPuzzleCardFlags::Locked);
RecalculateInitialAvailable(obj);
}
}
if (!placedCard.IsLocked && IsValid(placedCard.RefCard))
if (!isLocked && IsValid(placedCard.RefCard))
{
ImVec2 s = {puzCursorStart.x + x * UIPuzBoxSize, puzCursorStart.y + y * UIPuzBoxSize};
drawList.AddRectFilled(s,
@@ -458,17 +541,11 @@ namespace Puzzle
uint32_t CardIdx = *reinterpret_cast<uint32_t*>(payload->Data);
placedCard = {};
placedCard.RefCard = {(uint16_t)CardIdx};
placedCard.Rotation = debugRot;
placedCard.Rotation = 0;
placedCard.Position = cardPos;
placedCard.IsLocked = true;
dataChanged = true;
}
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("availcard", 0))
{
DragAvailableCardTo(obj,
cardPos,
*(int32_t*)payload->Data,
Game::GetInstance().DebugData.DebugCardRotation);
placedCard.Flags = (PlacedPuzzleCardFlags::Enum)SetFlags(placedCard.Flags,
PlacedPuzzleCardFlags::Locked);
RecalculateInitialAvailable(obj);
}
ImGui::EndDragDropTarget();
}
@@ -534,7 +611,6 @@ namespace Puzzle
obj.AvailableCardCount++;
}
}
dataChanged = true;
}
ImGui::EndDragDropTarget();
}
@@ -547,14 +623,8 @@ namespace Puzzle
ImGui::SetCursorScreenPos(localPos);
ImGui::PushID(i);
auto& card = obj.AvailableCards[i];
DrawCard(GetCard(card.RefCard), debugRot, ImGui::GetCursorScreenPos());
DrawCard(GetCard(card.RefCard), 0, ImGui::GetCursorScreenPos());
int displayCount = card.MaxAvailableCount - card.UsedCount;
if (displayCount > 0 && ImGui::BeginDragDropSource())
{
ImGui::SetDragDropPayload("availcard", &i, sizeof(i));
DrawCard(GetCard(card.RefCard), debugRot, ImGui::GetCursorScreenPos());
ImGui::EndDragDropSource();
}
ImGui::SetCursorScreenPos({localPos.x, localPos.y + 55.0f});
ImGui::SetNextItemWidth(35);
@@ -563,7 +633,6 @@ namespace Puzzle
{
int diff = displayCount - (card.MaxAvailableCount - card.UsedCount);
card.MaxAvailableCount = bx::max(0, card.MaxAvailableCount + diff);
dataChanged = true;
}
ImGui::PopID();
ImGui::SameLine(0, 3);
@@ -582,22 +651,17 @@ namespace Puzzle
}
ImGui::End();
if (dataChanged)
{
char path[128]{0};
WritePuzzleFilePath(path, sizeof(path), obj.ID);
Serializer ser;
if (ser.Init(path, "PZZL") && ser.WriteT(obj))
{
LOG("Saved to %s", path);
}
else
{
LOG_ERROR("Failed to save to %s", path);
}
ser.Finish();
}
return isVisible;
}
void ResetPuzzle(PuzzleData& puz)
{
for (int32_t i = 0; i < puz.AvailableCardCount; ++i)
{
puz.AvailableCards[i].UsedCount = 0;
}
for (int32_t i = 0; i < BX_COUNTOF(puz.PlacedCards); ++i)
{
puz.PlacedCards[i] = puz.InitialPlacedCards[i];
}
}
} // namespace Puzzle

View File

@@ -19,7 +19,8 @@ namespace Puzzle
static constexpr uint32_t MaxCardsInPuzzle = MaxPuzzleSizeCards * MaxPuzzleSizeCards;
static constexpr uint32_t MaxPuzzleSizeTiles = 16 * CardSize;
static constexpr uint32_t MaxTilesInPuzzle = MaxPuzzleSizeTiles * MaxPuzzleSizeTiles;
static constexpr uint32_t MaxTilesTotal = MaxTilesInPuzzle * MaxVisiblePuzzles;
static constexpr uint32_t MaxTilesTotal =
MaxTilesInPuzzle * MaxVisiblePuzzles + MaxPuzzleSizeCards * MaxVisiblePuzzles + 64;
static constexpr uint32_t MaxAvailableStacks = 16;
static constexpr uint32_t MaxGoalPositions = 16;
static constexpr float CardScaleWorld = 10.0f;
@@ -35,15 +36,19 @@ namespace Puzzle
bool IsValid(StaticPuzzleCardHandle h);
uint8_t GetRemainingCount(const PuzzleCardStack& stack);
PuzzleElementType::Enum GetNodeAt(const PuzzleData& puz, PuzPos pos);
PuzzleElementType::Enum GetInitialNodeAt(const PuzzleData& puz, PuzPos pos);
PuzzleElementType::Enum GetCardNodeAt(const StaticPuzzleCard& card, uint8_t rotation, int8_t x, int8_t y);
PuzzleElementType::Enum& EditCardNodeAt(StaticPuzzleCard& card, uint8_t rotation, int8_t x, int8_t y);
void DrawCard(const StaticPuzzleCard& card, uint8_t rotation, ImVec2 pos);
void RotateCard(PlacedPuzzleCard& card);
PlacedPuzzleCard& GetCardAt(PuzzleData& obj, PuzPos pos);
PlacedPuzzleCard& GetInitialCardAt(PuzzleData& obj, PuzPos pos);
// TODO: targetPos is of type CardPos
bool ReturnPlacedCard(PuzzleData& obj, PuzPos targetPos);
// TODO: targetPos is of type CardPos
bool DragAvailableCardTo(PuzzleData& obj, PuzPos targetPos, int32_t availIdx, uint8_t rotation);
void ResetPuzzle(PuzzleData& puz);
struct PuzzleSolver
{

View File

@@ -7,9 +7,11 @@
#include "Puzzle.h"
#include "Tools.h"
#include "bgfx/bgfx.h"
#include "bx/filepath.h"
#include "bx/string.h"
#include "bx/timer.h"
#include "rendering/Rendering.h"
#include <imgui.h>
#include <tracy/Tracy.hpp>
@@ -52,12 +54,12 @@ namespace Tools
return changed;
}
bool ModelDropdown(Gen::ModelHandle& modelHandle, const char* name)
bool ModelDropdown(Gen::ModelHandle& modelHandle, const char* title)
{
bool changed = false;
auto& R = Game::GameRendering::Get();
const char* assetName = GetAssetPath(modelHandle.Asset);
if (ImGui::BeginCombo(name, assetName))
if (ImGui::BeginCombo(title, assetName))
{
for (int32_t i = 0; i < R.ModelCount; ++i)
{
@@ -72,12 +74,12 @@ namespace Tools
return changed;
}
bool TextureDropdown(Gen::TextureHandle& texHandle)
bool TextureDropdown(Gen::TextureHandle& texHandle, const char* title)
{
bool changed = false;
auto& R = Game::GameRendering::Get();
const char* name = GetAssetPath(texHandle.Asset);
if (ImGui::BeginCombo("Texture", name))
if (ImGui::BeginCombo(title, name))
{
for (int32_t i = 0; i < R.MaxTextures; ++i)
{
@@ -182,140 +184,159 @@ namespace Tools
return changed;
}
void RenderDebugUI(Game::GameRendering& rendering)
void RenderLogUI()
{
if (!rendering.SetupData.UseImgui) return;
auto& time = Game::GetInstance().Time;
auto& debug = Game::GetInstance().DebugData;
if (ImGui::Begin("Log"))
{
ImGui::Checkbox("Shorten File Names", &debug.ShortenLogFileNames);
ImGui::BeginTable("tbl",
4,
ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_SizingFixedFit |
ImGuiTableFlags_RowBg);
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_NoResize);
ImGui::TableSetupColumn("Log");
ImGui::TableSetupColumn("Line", ImGuiTableColumnFlags_NoResize);
ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_NoResize);
ImGui::TableHeadersRow();
auto& logs = GetLogHistory();
int32_t lineCount = bx::min(100, LogInternal::LogHistorySize);
for (int32_t i = 0; i < lineCount; ++i)
{
int32_t idx = logs.WriteIdx - i - 1;
if (idx < 0) idx += LogInternal::LogHistorySize;
const char* line = &logs.LogBuffer[idx * LogInternal::MaxLineSize];
if (line[0] != 0)
{
int64_t timeOffset = logs.WriteTime[idx] - time.StartTime;
double writeTime = (double)timeOffset / bx::getHPFrequency();
uint32_t fileLine = logs.LineBuffer[idx];
const char* filePath = &logs.FileBuffer[idx * LogInternal::MaxLineSize];
const char* filePathRes =
debug.ShortenLogFileNames ? bx::FilePath{filePath}.getFileName().getPtr() : filePath;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%.01f", writeTime);
ImGui::TableNextColumn();
ImGui::Text("%s", line);
ImGui::SetItemTooltip("%f\n%s%s:%u", writeTime, line, filePath, fileLine);
ImGui::TableNextColumn();
ImGui::Text("%u", fileLine);
ImGui::TableNextColumn();
ImGui::Text("%s", filePathRes);
if (i > 0) ImGui::PopStyleColor(2);
ImVec4 bgCol = {0.0f, 0.0f, 0.0f, 1.0f};
if (logs.WriteType[idx] == ELogType::Warn)
bgCol = {0.2f, 0.2f, 0.0f, 1.0f};
else if (logs.WriteType[idx] == ELogType::Error)
bgCol = {0.2f, 0.0f, 0.0f, 1.0f};
ImGui::PushStyleColor(ImGuiCol_TableRowBg, bgCol);
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, bgCol);
}
}
ImGui::EndTable();
if (lineCount > 0) ImGui::PopStyleColor(2);
}
ImGui::End();
}
void RenderRenderSettingsUI(Game::GameRendering& rendering)
{
auto& time = Game::GetInstance().Time;
auto& shared = Game::GetShared();
auto& debug = Game::GetInstance().DebugData;
auto& level = Game::GetInstance().GameLevel;
auto& player = Game::GetInstance().Player;
if (rendering.UIVisible == Game::UIVisibilityState::Debug)
if (ImGui::Begin("Rendering"))
{
ZoneScopedN("DebugUI");
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right))
if (rendering.LastShaderLoadTime >= 0.0f)
{
debug.DebugCardRotation++;
if (debug.DebugCardRotation >= 4) debug.DebugCardRotation = 0;
ImGui::TextColored({0.2f, 0.9f, 0.2f, 1.0f},
"Shader loaded %.0f seconds ago",
time.Now - rendering.LastShaderLoadTime);
}
if (ImGui::Begin("Log"))
else
{
ImGui::Checkbox("Shorten File Names", &debug.ShortenLogFileNames);
ImGui::BeginTable("tbl",
4,
ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable |
ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg);
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_NoResize);
ImGui::TableSetupColumn("Log");
ImGui::TableSetupColumn("Line", ImGuiTableColumnFlags_NoResize);
ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_NoResize);
ImGui::TableHeadersRow();
auto& logs = GetLogHistory();
int32_t lineCount = bx::min(100, LogInternal::LogHistorySize);
for (int32_t i = 0; i < lineCount; ++i)
{
int32_t idx = logs.WriteIdx - i - 1;
if (idx < 0) idx += LogInternal::LogHistorySize;
const char* line = &logs.LogBuffer[idx * LogInternal::MaxLineSize];
if (line[0] != 0)
{
int64_t timeOffset = logs.WriteTime[idx] - time.StartTime;
double writeTime = (double)timeOffset / bx::getHPFrequency();
uint32_t fileLine = logs.LineBuffer[idx];
const char* filePath = &logs.FileBuffer[idx * LogInternal::MaxLineSize];
const char* filePathRes =
debug.ShortenLogFileNames ? bx::FilePath{filePath}.getFileName().getPtr() : filePath;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%.01f", writeTime);
ImGui::TableNextColumn();
ImGui::Text("%s", line);
ImGui::SetItemTooltip("%f\n%s%s:%u", writeTime, line, filePath, fileLine);
ImGui::TableNextColumn();
ImGui::Text("%u", fileLine);
ImGui::TableNextColumn();
ImGui::Text("%s", filePathRes);
if (i > 0) ImGui::PopStyleColor(2);
ImVec4 bgCol = {0.0f, 0.0f, 0.0f, 1.0f};
if (logs.WriteType[idx] == ELogType::Warn)
bgCol = {0.2f, 0.2f, 0.0f, 1.0f};
else if (logs.WriteType[idx] == ELogType::Error)
bgCol = {0.2f, 0.0f, 0.0f, 1.0f};
ImGui::PushStyleColor(ImGuiCol_TableRowBg, bgCol);
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, bgCol);
}
}
ImGui::EndTable();
if (lineCount > 0) ImGui::PopStyleColor(2);
ImGui::TextColored({0.9f, 0.2f, 0.2f, 1.0f}, "Shader load Failiure!");
}
ImGui::End();
if (ImGui::Begin("Rendering"))
ImGui::SameLine();
if (ImGui::Button("Reload Level"))
{
if (rendering.LastShaderLoadTime >= 0.0f)
{
ImGui::TextColored({0.2f, 0.9f, 0.2f, 1.0f},
"Shader loaded %.0f seconds ago",
time.Now - rendering.LastShaderLoadTime);
}
else
{
ImGui::TextColored({0.9f, 0.2f, 0.2f, 1.0f}, "Shader load Failiure!");
}
if (ImGui::Button("Reload Meshes"))
{
LoadModels(rendering.Models, rendering.ModelCount);
}
ImGui::SameLine();
if (ImGui::Button("Reload Level"))
{
level = {};
level.Setup(shared.Game);
}
level = {};
level.Setup(shared.Game);
}
ImGui::SliderFloat("Mouse Sensitivity", &player.MouseSensitivity, 0.1f, 5.0f);
ImGui::SliderFloat("Player Speed", &player.MovementSpeed, 1.0f, 30.0f);
ImGui::DragFloat3("Player Pos", &player.PlayerCamTransform.Position.x);
ImGui::DragFloat3("Puz0 Pos", &level.Puzzles[0].WorldPosition.x);
ImGui::SliderFloat("Mouse Sensitivity", &player.MouseSensitivity, 0.1f, 5.0f);
ImGui::SliderFloat("Player Speed", &player.MovementSpeed, 1.0f, 30.0f);
ImGui::Checkbox("Show ImGui Demo", &debug.ShowImguiDemo);
ImGui::Checkbox("Show Stats", &debug.ShowStats);
if (debug.ShowImguiDemo) ImGui::ShowDemoWindow(&debug.ShowImguiDemo);
ImGui::Checkbox("Show ImGui Demo", &debug.ShowImguiDemo);
ImGui::Checkbox("Show Stats", &debug.ShowStats);
if (debug.ShowImguiDemo) ImGui::ShowDemoWindow(&debug.ShowImguiDemo);
ImGui::Separator();
ImGui::Separator();
ImGui::Text("Entity Groups");
if (ImGui::TreeNodeEx("Entity Groups"))
{
ImGui::Checkbox("Cubes", &level.Cubes.IsEnabled);
ImGui::Checkbox("Tests", &level.Tests.IsEnabled);
ImGui::Checkbox("PuzzleTiles", &level.PuzzleTiles.IsEnabled);
ImGui::Checkbox("UIQuads", &level.UIQuads.IsEnabled);
ImGui::Checkbox("Level", &level.LevelEntities.IsEnabled);
ImGui::TreePop();
}
bool uiconfigChanged = false;
if (ImGui::TreeNodeEx("Game Tablet"))
{
uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletBackgroundRenderData);
ImGui::Separator();
ImGui::Text("Game Tablet");
bool bTabletChanged = false;
bTabletChanged |= Tools::EntityDataSettings(player.Config.TabletBackgroundRenderData);
ImGui::Text("Status");
bTabletChanged |= Tools::EntityDataSettings(player.Config.TabletStatusRenderData);
bTabletChanged |= Tools::TextureDropdown(player.Config.TabletStatusSolvedTexture);
if (bTabletChanged)
{
Serializer s;
s.Init("game/data/static/uiconfig.dat", "UICO");
s.WriteT(player.Config);
s.Finish();
}
uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletStatusRenderData);
uiconfigChanged |= Tools::TextureDropdown(player.Config.TabletStatusSolvedTexture, "Solved Texture");
uiconfigChanged |=
Tools::TextureDropdown(player.Config.TabletStatusNotSolvedTexture, "Not Solved Texture");
ImGui::Separator();
ImGui::Text("Reset");
uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletResetRenderData);
ImGui::TreePop();
}
if (ImGui::TreeNodeEx("Background Level"))
{
for (int32_t i = 0; i < BX_COUNTOF(player.Config.BackgroundLevelRenderData); ++i)
{
if (i > 0) ImGui::Separator();
uiconfigChanged |= Tools::EntityDataSettings(player.Config.BackgroundLevelRenderData[i]);
}
ImGui::TreePop();
}
if (uiconfigChanged)
{
Serializer s;
s.Init("game/data/static/uiconfig.dat", "UICO");
s.WriteT(player.Config);
s.Finish();
level.PuzzleUI.Reset();
level.ReloadLevelEntities();
}
if (ImGui::TreeNodeEx("Dithering"))
{
if (ImGui::Button("Dithergen"))
{
DitherGen(rendering.DitherTextures, rendering.DitherRecursion);
@@ -342,156 +363,247 @@ namespace Tools
ImGui::Image(rendering.DitherTextures.RampTex.idx,
{BX_COUNTOF(rendering.DitherTextures.BrightnessRamp), 8});
}
Vec3 quadPos = level.UIQuads.Get({0}).EData.Transform.Position;
ImGui::Text("%f %f %f", quadPos.x, quadPos.y, quadPos.z);
ImGui::TreePop();
}
ImGui::Text("Shader log:");
if (ImGui::TreeNodeEx("Shader log"))
{
ImGui::TextWrapped("%s", Game::GetShared().Dev.ShaderLog);
ImGui::TreePop();
}
ImGui::End();
if (ImGui::Begin("Textures"))
{
if (ImGui::Button("Reload"))
{
rendering.LoadTextures();
}
for (int32_t i = 0; i < rendering.MaxTextures; ++i)
{
if (!isValid(rendering.Textures[i].RenderHandle)) continue;
ImGui::Text("%i", i);
float width = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.width);
float height = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.height);
ImGui::Image(rendering.Textures[i].RenderHandle.idx, {width, height});
}
}
ImGui::End();
if (ImGui::Begin("Puzzles"))
{
char nameBuf[64]{0};
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
{
auto& puzzleData = level.Puzzles[i].Data;
}
ImGui::End();
}
bool isSelected = debug.SelectedDebugLevel == i;
ImGui::PushID("selectable");
bx::snprintf(nameBuf, sizeof(nameBuf), "%u: %s", i, puzzleData.PuzzleName);
if (ImGui::Selectable(nameBuf, isSelected))
{
debug.SelectedDebugLevel = isSelected ? UINT16_MAX : i;
}
ImGui::PopID();
}
}
ImGui::End();
if (debug.SelectedDebugLevel < BX_COUNTOF(level.Puzzles))
void RenderTexturesUI(Game::GameRendering& rendering)
{
if (ImGui::Begin("Textures"))
{
if (ImGui::Button("Reload"))
{
if (!Puzzle::RenderDebugUI(level.Puzzles[debug.SelectedDebugLevel].Data))
{
debug.SelectedDebugLevel = UINT16_MAX;
}
rendering.LoadTextures();
}
if (ImGui::Begin("Cards"))
for (int32_t i = 0; i < rendering.MaxTextures; ++i)
{
Gen::StaticPuzzleData& staticData = Puzzle::GetStaticPuzzleData();
if (!isValid(rendering.Textures[i].RenderHandle)) continue;
ImGui::Text("%i", i);
float width = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.width);
float height = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.height);
ImGui::Image(rendering.Textures[i].RenderHandle.idx, {width, height});
}
}
ImGui::End();
}
if (ImGui::Button("Save"))
void RenderModelsUI(Game::GameRendering& rendering)
{
if (ImGui::Begin("Models"))
{
if (ImGui::Button("Reload"))
{
LoadModels(rendering.Models, rendering.ModelCount);
}
for (int32_t i = 0; i < rendering.ModelCount; ++i)
{
auto& mdl = rendering.Models[i];
if (bgfx::isValid(mdl.HeightMapTexture))
{
Puzzle::SaveStaticPuzzleData();
ImGui::Text("%s", mdl.Name);
ImGui::Image(mdl.HeightMapTexture.idx,
ImVec2{(float)Game::HeightMap::Height, (float)Game::HeightMap::Width});
}
ImGui::SameLine();
if (ImGui::Button("Reload"))
else
{
Puzzle::LoadStaticPuzzleData();
ImGui::Text("Invalid Handle!");
}
ImGui::Spacing();
}
}
ImGui::End();
}
void RenderPuzzlesUI()
{
auto& debug = Game::GetInstance().DebugData;
auto& level = Game::GetInstance().GameLevel;
if (ImGui::Begin("Puzzles"))
{
char nameBuf[64]{0};
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
{
ImGui::PushID(i);
auto& puzzleData = level.Puzzles[i].Data;
bool isSelected = debug.SelectedDebugLevel == i;
ImGui::PushID("selectable");
bx::snprintf(nameBuf, sizeof(nameBuf), "%u: %s", i, puzzleData.PuzzleName);
if (ImGui::Selectable(nameBuf, isSelected))
{
debug.SelectedDebugLevel = isSelected ? UINT16_MAX : i;
}
ImGui::DragFloat3("Pos", &level.Puzzles[i].WorldPosition.x);
ImGui::PopID();
ImGui::PopID();
}
}
ImGui::End();
if (debug.SelectedDebugLevel < BX_COUNTOF(level.Puzzles))
{
if (!Puzzle::RenderDebugUI(level.Puzzles[debug.SelectedDebugLevel].Data))
{
debug.SelectedDebugLevel = UINT16_MAX;
}
}
}
void RenderCardsUI(Game::GameRendering& rendering)
{
auto& debug = Game::GetInstance().DebugData;
if (ImGui::Begin("Cards"))
{
Gen::StaticPuzzleData& staticData = Puzzle::GetStaticPuzzleData();
if (ImGui::Button("Save"))
{
Puzzle::SaveStaticPuzzleData();
}
ImGui::SameLine();
if (ImGui::Button("Reload"))
{
Puzzle::LoadStaticPuzzleData();
}
ImGui::Separator();
ImGui::ColorEdit3("Disabled Tint", &staticData.Visuals.DisabledCardTint.x);
ImGui::ColorEdit3("Tile Base Color", &staticData.Visuals.TileBaseColor.x);
ImGui::ColorEdit3("Tile Dot Color", &staticData.Visuals.TileDotColor.x);
for (int32_t i = 0; i < BX_COUNTOF(staticData.Cards); ++i)
{
ImGui::Separator();
ImGui::ColorEdit3("Disabled Tint", &staticData.Visuals.DisabledCardTint.x);
ImGui::ColorEdit3("Tile Base Color", &staticData.Visuals.TileBaseColor.x);
ImGui::ColorEdit3("Tile Dot Color", &staticData.Visuals.TileDotColor.x);
for (int32_t i = 0; i < BX_COUNTOF(staticData.Cards); ++i)
Gen::StaticPuzzleCard& card = staticData.Cards[i];
ImGui::PushID(i);
char cardName[64]{0};
bx::snprintf(cardName, sizeof(cardName), "%i", i);
ImGui::Selectable(cardName);
if (ImGui::BeginDragDropSource())
{
ImGui::Separator();
Puzzle::DrawCard(card, debug.DebugCardRotation, ImGui::GetCursorScreenPos());
ImGui::SetDragDropPayload("cardtype", &i, sizeof(i));
ImGui::EndDragDropSource();
}
Gen::StaticPuzzleCard& card = staticData.Cards[i];
ImGui::PushID(i);
char cardName[64]{0};
bx::snprintf(cardName, sizeof(cardName), "%i", i);
ImGui::Selectable(cardName);
if (ImGui::BeginDragDropSource())
Tools::ModelDropdown(card.BaseModelHandle);
Tools::TextureDropdown(card.ModelTextureHandle, "World Texture");
Tools::TextureDropdown(card.BoardTextureHandle, "UI Texture");
if (IsValid(card.BaseModelHandle))
{
auto& mdl = rendering.Models[card.BaseModelHandle.ModelIdx];
if (mdl.SocketCount > 0 && ImGui::TreeNodeEx("Slots"))
{
Puzzle::DrawCard(card, debug.DebugCardRotation, ImGui::GetCursorScreenPos());
ImGui::SetDragDropPayload("cardtype", &i, sizeof(i));
ImGui::EndDragDropSource();
}
Tools::ModelDropdown(card.BaseModelHandle);
Tools::TextureDropdown(card.BoardTextureHandle);
if (IsValid(card.BaseModelHandle))
{
auto& mdl = rendering.Models[card.BaseModelHandle.ModelIdx];
if (mdl.SocketCount > 0 && ImGui::TreeNodeEx("Slots"))
for (int32_t sIdx = 0; sIdx < mdl.SocketCount; ++sIdx)
{
for (int32_t sIdx = 0; sIdx < mdl.SocketCount; ++sIdx)
Tools::ModelDropdown(card.Sockets[sIdx].Model, mdl.Sockets[sIdx].Name);
int val = card.Sockets[sIdx].ConnectionDirection;
ImGui::PushID(sIdx);
if (ImGui::Combo("Connection Direction", &val, "North\0East\0South\0West\0"))
{
Tools::ModelDropdown(card.Sockets[sIdx].Model, mdl.Sockets[sIdx].Name);
int val = card.Sockets[sIdx].ConnectionDirection;
ImGui::PushID(sIdx);
if (ImGui::Combo("Connection Direction", &val, "North\0East\0South\0West\0"))
{
card.Sockets[sIdx].ConnectionDirection = val;
}
ImGui::PopID();
}
ImGui::TreePop();
}
}
ImGui::Text("Card");
for (int8_t y = 0; y < Puzzle::Config::CardSize; ++y)
{
ImGui::PushID(y);
for (int8_t x = 0; x < Puzzle::Config::CardSize; ++x)
{
if (x > 0) ImGui::SameLine();
ImGui::PushID(x);
auto& node = Puzzle::EditCardNodeAt(card, 0, x, y);
if (ImGui::Button(Gen::PuzzleElementType::ShortName[node], {26, 24}))
{
int32_t newVal = int32_t(node) + 1;
if (newVal >= Gen::PuzzleElementType::EntryCount)
{
newVal = 0;
}
node = Gen::PuzzleElementType::Enum(newVal);
card.Sockets[sIdx].ConnectionDirection = val;
}
ImGui::PopID();
}
ImGui::TreePop();
}
}
ImGui::Text("Card");
for (int8_t y = 0; y < Puzzle::Config::CardSize; ++y)
{
ImGui::PushID(y);
for (int8_t x = 0; x < Puzzle::Config::CardSize; ++x)
{
if (x > 0) ImGui::SameLine();
ImGui::PushID(x);
auto& node = Puzzle::EditCardNodeAt(card, 0, x, y);
if (ImGui::Button(Gen::PuzzleElementType::ShortName[node], {26, 24}))
{
int32_t newVal = int32_t(node) + 1;
if (newVal >= Gen::PuzzleElementType::EntryCount)
{
newVal = 0;
}
node = Gen::PuzzleElementType::Enum(newVal);
}
ImGui::PopID();
}
ImGui::PopID();
}
}
ImGui::End();
if (ImGui::Begin("Debug"))
{
ImGui::Checkbox("Arenas", &debug.ShowArenaUsage);
ImGui::Checkbox("ImGui Demo", &debug.ShowImguiDemo);
}
ImGui::End();
if (debug.ShowArenaUsage)
{
if (ImGui::Begin("Arenas", &debug.ShowArenaUsage))
{
ProgressBar("Permanent", shared.Game.PermanentArena.Used, shared.Game.PermanentArena.MaxSize);
ProgressBar("Entity", shared.Game.EntityArena.Used, shared.Game.EntityArena.MaxSize);
ProgressBar("Transient", shared.Game.TransientArena.Used, shared.Game.TransientArena.MaxSize);
}
ImGui::End();
ImGui::PopID();
}
}
ImGui::End();
}
void RenderEntitiesUI()
{
auto& level = Game::GetInstance().GameLevel;
if (ImGui::Begin("Entities"))
{
if (ImGui::TreeNodeEx("UIQuads"))
{
ImGui::Text("Count: %u", level.UIQuads.Count);
for (uint16_t i = 0; i < level.UIQuads.Count; ++i)
{
ImGui::Separator();
ImGui::PushID(i);
ImGui::Text("%u", i);
ImGui::SameLine();
auto& quad = level.UIQuads.Get({i});
ImGui::Checkbox("Visible", &quad.EData.Visible);
TextureDropdown(quad.EData.TextureHandle);
MaterialDropdown(quad.EData.MaterialHandle);
ImGui::DragFloat3("Pos", &quad.EData.Transform.Position.x);
ImGui::DragFloat3("UI Pos", &quad.UIPos.x);
ImGui::Text("RenderID: %i", quad.EData.RenderID);
ImGui::PopID();
}
ImGui::TreePop();
}
if (ImGui::TreeNodeEx("Level"))
{
ImGui::Text("Count: %u", level.LevelEntities.Count);
for (uint16_t i = 0; i < level.LevelEntities.Count; ++i)
{
ImGui::Separator();
ImGui::PushID(i);
ImGui::Text("%u", i);
ImGui::SameLine();
auto& levelEnt = level.LevelEntities.Get({i});
ImGui::Checkbox("Visible", &levelEnt.EData.Visible);
TextureDropdown(levelEnt.EData.TextureHandle);
MaterialDropdown(levelEnt.EData.MaterialHandle);
ImGui::DragFloat3("Pos", &levelEnt.EData.Transform.Position.x);
ImGui::Text("RenderID: %i", levelEnt.EData.RenderID);
ImGui::PopID();
}
ImGui::TreePop();
}
}
ImGui::End();
}
void RenderStatsUI()
{
auto& time = Game::GetInstance().Time;
auto& debug = Game::GetInstance().DebugData;
if (debug.ShowStats)
{
ImGui::SetNextWindowPos({0, 0});
@@ -510,7 +622,7 @@ namespace Tools
ImGui::Text("FPS: %.0f", 1.0 / time.Delta);
constexpr ImVec2 FpsPlotSize{200, 60};
if (ImGui::BeginChild("FpsPlot", FpsPlotSize))
if (ImGui::BeginChild("FpsPlot", FpsPlotSize, 0, ImGuiWindowFlags_NoInputs))
{
auto& drawList = *ImGui::GetWindowDrawList();
ImVec2 pos = ImGui::GetWindowPos();
@@ -540,6 +652,105 @@ namespace Tools
ImGui::End();
}
}
void RenderDebugUI(Game::GameRendering& rendering)
{
if (!rendering.SetupData.UseImgui) return;
ZoneScopedN("DebugUI");
auto& time = Game::GetInstance().Time;
auto& shared = Game::GetShared();
auto& debug = Game::GetInstance().DebugData;
auto& level = Game::GetInstance().GameLevel;
auto& player = Game::GetInstance().Player;
if (ImGui::Begin("Hilfe"))
{
if (ImGui::Button("Spiel Neustarten"))
{
player.PlayerCamTransform.Position = {0.0f, 3.0f, 0.0f};
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
{
Puzzle::ResetPuzzle(level.Puzzles[i].Data);
}
}
ImGui::SameLine();
if (ImGui::Button("Zurück zum Anfang"))
{
player.PlayerCamTransform.Position = {0.0f, 3.0f, 0.0f};
}
ImGui::Separator();
ImGui::Text("Anleitung:");
ImGui::Text("Bewege dich mit");
ImGui::SameLine();
ImGui::TextColored({1.0f, 0.6f, 0.6f, 1.0f}, "W, A, S, D");
ImGui::SameLine();
ImGui::Text("und schau dich um mit der");
ImGui::SameLine();
ImGui::TextColored({1.0f, 0.6f, 0.6f, 1.0f}, "Maus.");
ImGui::Text("Drücke");
ImGui::SameLine();
ImGui::TextColored({1.0f, 0.6f, 0.6f, 1.0f}, "Leertaste");
ImGui::SameLine();
ImGui::Text("um den Spielplan zu öffnen.");
ImGui::Text("Auf dem Spielplan kannst du Karten verschieben.");
ImGui::Text("Mit");
ImGui::SameLine();
ImGui::TextColored({1.0f, 0.6f, 0.6f, 1.0f}, "Rechter Maustaste");
ImGui::SameLine();
ImGui::Text("kannst du Karten drehen.");
ImGui::Text("");
ImGui::Text("Dein Ziel: Verbinde die Pumpe mit dem Abfluss, um das");
ImGui::Text("Tor zum nächsten Level zu öffnen!");
ImGui::Text("");
auto& inflowTexture = rendering.Textures[10];
auto& outflowTexture = rendering.Textures[9];
auto& connectionTexture = rendering.Textures[8];
ImGui::Text("Pumpe (Wasserquelle):");
ImGui::Image(inflowTexture.RenderHandle.idx, {64.0f, 64.0f});
ImGui::Text("Abfluss (Ziel):");
ImGui::Image(outflowTexture.RenderHandle.idx, {64.0f, 64.0f});
ImGui::Text("Verbindung:");
ImGui::Image(connectionTexture.RenderHandle.idx, {64.0f, 64.0f});
}
ImGui::End();
if (rendering.UIVisible == Game::UIVisibilityState::Debug)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right))
{
debug.DebugCardRotation++;
if (debug.DebugCardRotation >= 4) debug.DebugCardRotation = 0;
}
if (ImGui::Begin("Debug"))
{
ImGui::Checkbox("ImGui Demo", &debug.ShowImguiDemo);
ImGui::SliderFloat("Font Scale", &ImGui::GetIO().FontGlobalScale, 0.5f, 4.0f);
ImGui::Checkbox("Break on ID", &debug.DebugBreakIDEnabled);
ImGui::SameLine();
ImGui::PushID("@#$");
ImGui::InputInt("", &debug.DebugBreakID);
ImGui::PopID();
ImGui::Separator();
ImGui::Text("Arenas");
ProgressBar("Permanent", shared.Game.PermanentArena.Used, shared.Game.PermanentArena.MaxSize);
ProgressBar("Entity", shared.Game.EntityArena.Used, shared.Game.EntityArena.MaxSize);
ProgressBar("Transient", shared.Game.TransientArena.Used, shared.Game.TransientArena.MaxSize);
}
ImGui::End();
RenderLogUI();
RenderRenderSettingsUI(rendering);
RenderTexturesUI(rendering);
RenderModelsUI(rendering);
RenderPuzzlesUI();
RenderCardsUI(rendering);
RenderEntitiesUI();
}
RenderStatsUI();
}
void MeasureFrameEnd()
{
FrameTimes[FrameTimeIdx] = bx::getHPCounter();

View File

@@ -5,8 +5,8 @@
namespace Tools
{
bool EntityDataSettings(Gen::SavedEntityRenderData& data);
bool ModelDropdown(Gen::ModelHandle& modelHandle, const char* name = "Model");
bool TextureDropdown(Gen::TextureHandle& texHandle);
bool ModelDropdown(Gen::ModelHandle& modelHandle, const char* title = "Model");
bool TextureDropdown(Gen::TextureHandle& texHandle, const char* title = "Texture");
bool MaterialDropdown(Gen::EMaterial::Enum& material);
bool TransformUI(Gen::Transform& transform);
void RenderDebugUI(Game::GameRendering& rendering);

382
src/game/UI.cpp Normal file
View File

@@ -0,0 +1,382 @@
#include "UI.h"
#include "Entity.h"
#include "Gen.h"
#include "Global.h"
#include "Input.h"
#include "Instance.h"
#include "Level.h"
#include "Puzzle.h"
#include "bx/math.h"
using namespace Gen;
namespace
{
Game::StaticUIData StaticData;
}
namespace Game
{
UIQuadEntityHandle NewQuad(UIQuadEntityManager& manager,
const Gen::SavedEntityRenderData& loadData,
UIQuadEntityHandle oldHandle)
{
UIQuadEntityHandle h = oldHandle;
if (!IsValid(h))
{
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;
auto& player = GetInstance().Player;
TabletHandle = NewQuad(level.UIQuads, player.Config.TabletBackgroundRenderData);
SolvedQuad = NewQuad(level.UIQuads, player.Config.TabletStatusRenderData);
ResetQuad = NewQuad(level.UIQuads, 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");
}
}
Vec3 CalcBoardOffset(const Gen::PuzzleData& puzData)
{
return Vec3{
(float)(puzData.WidthTiles) / 2.0f - 0.5f,
(float)(puzData.HeightTiles) / 2.0f - 0.5f,
0.0f,
} *
WorldPuzzleUI::UICardScale * WorldPuzzleUI::UICardScale;
}
Vec3 CardPosToUIPos(const Gen::PuzzleData& data, int32_t cardX, int32_t cardY)
{
return Vec3{(float)cardX, (float)(data.HeightTiles / 2 - cardY - 1), -0.3f} * WorldPuzzleUI::UICardOffset *
WorldPuzzleUI::UICardScale -
CalcBoardOffset(data);
}
void UIPosToCardPos(const Gen::PuzzleData& data, Vec3 uiPos, int32_t& cardXOut, int32_t& cardYOut)
{
Vec3 boardOffset = CalcBoardOffset(data) / WorldPuzzleUI::UICardScale;
Vec3 boardPos = GlobalToLocalPoint(StaticData.UITransform, uiPos);
Vec3 boardTilePos = (boardPos + boardOffset) / WorldPuzzleUI::UICardOffset;
cardXOut = (int32_t)bx::round(boardTilePos.x);
cardYOut = data.HeightTiles / 2 - (int32_t)bx::round(boardTilePos.y) - 1;
}
void WorldPuzzleUI::UpdateAvailableCards(Gen::PuzzleData& Data)
{
auto& level = GetInstance().GameLevel;
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
Vec3 quadPlaneIntersectPos;
Vec3 mousePosWorld = GetMousePosWorld();
for (int32_t stackIdx = 0; stackIdx < Puzzle::Config::MaxAvailableStacks; ++stackIdx)
{
auto& card = Data.AvailableCards[stackIdx];
for (int32_t cardIdx = 0; cardIdx < UIAvailableCardMaxStackPreview; cardIdx++)
{
auto h = UIAvailableCards[stackIdx * UIAvailableCardMaxStackPreview + cardIdx];
auto& quad = level.UIQuads.Get(h);
int32_t remaining = (int32_t)card.MaxAvailableCount - (int32_t)card.UsedCount;
if (stackIdx < Data.AvailableCardCount && cardIdx < remaining)
{
quad.UIPos = Vec3{cardIdx * 0.05f + stackIdx * 1.2f,
4.2f + (cardIdx % 2 == 0 ? 0.02f : 0.0f),
cardIdx * 0.001f - 0.3f} *
UICardOffset * UICardScale;
UpdateQuad(level.UIQuads, h);
quad.EData.Visible = true;
quad.EData.TextureHandle = Puzzle::IsValid(card.RefCard)
? staticCards[card.RefCard.Idx].BoardTextureHandle
: Gen::TextureHandle{0};
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 (cardIdx == 0)
{
if (IsQuadHovered(quad.EData.Transform, mousePosWorld, quadPlaneIntersectPos) &&
DraggedAvailableCardIdx == UINT16_MAX && DraggedCard.X == -1 &&
GetMouseButtonPressedNow(MouseButton::Left))
{
DraggedAvailableCardIdx = stackIdx;
}
if (DraggedAvailableCardIdx == stackIdx)
{
Vec3 dragPos = quadPlaneIntersectPos;
dragPos += StaticData.ZAxis * -0.01f;
quad.EData.Transform.Position = dragPos;
int32_t xPos;
int32_t yPos;
UIPosToCardPos(Data, quadPlaneIntersectPos, xPos, yPos);
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;
Vec3 boardOffset = CalcBoardOffset(Data);
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);
bool isLocked = GetFlag(card.Flags, PlacedPuzzleCardFlags::Locked);
auto& quad = level.UIQuads.Get(UIPlacedCards[cardIdx]);
quad.UIPos = CardPosToUIPos(Data, card.Position.X, card.Position.Y);
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 =
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 (!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;
int32_t xPos;
int32_t yPos;
UIPosToCardPos(Data, quadPlaneIntersectPos, xPos, yPos);
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;
auto& player = GetInstance().Player;
Transform& camTransform = player.PlayerCamTransform;
UpdateMatrix(camTransform);
// UI Tablet
if (IsValid(TabletHandle))
{
auto& tablet = level.UIQuads.Get(TabletHandle);
tablet.EData.Transform.Rotation = camTransform.Rotation;
Rotate(tablet.EData.Transform, {0.5f * bx::kPi, 0.0f, 0.0f});
tablet.EData.Transform.Position = camTransform.Position + AxisForward(camTransform.M) * 1.0f;
StaticData.UITransform = tablet.EData.Transform;
tablet.EData.Transform.Position += {0.0f, 0.0f, 0.01f};
}
StaticData.UITransform.Rotation = camTransform.Rotation;
StaticData.ZAxis = AxisForward(StaticData.UITransform.M);
StaticData.UITransform.Position += StaticData.ZAxis * -0.01f;
StaticData.MousePosWorld = GetMousePosWorld();
// NOLINTBEGIN
Vec2 uiOffset = Vec2{static_cast<float>(Data.WidthTiles / Puzzle::Config::CardSize - 1),
static_cast<float>(Data.HeightTiles / Puzzle::Config::CardSize - 1)};
// NOLINTEND
uiOffset *= -UICardOffset * 0.5f;
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))
{
Puzzle::ResetPuzzle(Data);
}
UpdateAvailableCards(Data);
UpdateBoardCards(Data);
}
void WorldPuzzleUI::Reset()
{
auto& level = GetInstance().GameLevel;
auto& config = GetInstance().Player.Config;
TabletHandle = NewQuad(level.UIQuads, config.TabletBackgroundRenderData, TabletHandle);
SolvedQuad = NewQuad(level.UIQuads, config.TabletStatusRenderData, SolvedQuad);
ResetQuad = NewQuad(level.UIQuads, config.TabletResetRenderData, ResetQuad);
}
} // namespace Game

44
src/game/UI.h Normal file
View File

@@ -0,0 +1,44 @@
#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 TabletHandle;
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,
UIQuadEntityHandle oldHandle = {});
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.

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.

Binary file not shown.

View File

@@ -127,12 +127,18 @@ type PuzzleCardStack
u8 UsedCount
}
enum PlacedPuzzleCardFlags(u8) Flags
{
None
Locked
}
type PlacedPuzzleCard
{
StaticPuzzleCardHandle RefCard
PuzPos Position
u8 Rotation
b IsLocked
PlacedPuzzleCardFlags Flags
}
type PuzzleData
@@ -144,6 +150,7 @@ type PuzzleData
u32 AvailableCardCount
PuzzleCardStack AvailableCards Arr(16)
PlacedPuzzleCard PlacedCards Arr(256)
PlacedPuzzleCard InitialPlacedCards Arr(256)
PuzzleElementType BackgroundTiles Arr(1024)
u32 GoalPositionCount
PuzPos GoalPositions Arr(16)
@@ -170,5 +177,8 @@ type SavedPlayerConfig
{
SavedEntityRenderData TabletBackgroundRenderData
SavedEntityRenderData TabletStatusRenderData
TextureHandle TabletStatusNotSolvedTexture
TextureHandle TabletStatusSolvedTexture
SavedEntityRenderData TabletResetRenderData
SavedEntityRenderData BackgroundLevelRenderData Arr(16)
}

View File

@@ -16,11 +16,12 @@ void DitherGen(DitherData& data, int32_t recursion)
for (int32_t i = 0; i < data.BrightnessBucketCount; ++i)
data.BrightnessBuckets[i] = 0;
for (int32_t recursionLevel = 0; recursionLevel < recursion; ++recursionLevel)
// add "subdivided" beyer matrix layers
for (int32_t recursionLevel = 0; recursionLevel < recursion - 1; ++recursionLevel)
{
int32_t startCount = data.PointCount;
float offset = bx::pow(0.5f, recursionLevel + 1);
for (int32_t i = 0; i < 4; ++i)
for (int32_t i = 1; i < 4; ++i)
{
for (int32_t j = 0; j < startCount; ++j)
{
@@ -30,6 +31,7 @@ void DitherGen(DitherData& data, int32_t recursion)
}
}
// Texture info setup
uint64_t dotsPerSide = bx::round(bx::pow(2, recursion));
data.DitherTexDepth = dotsPerSide * dotsPerSide;
data.DitherTexWH = 16 * dotsPerSide;
@@ -41,6 +43,7 @@ void DitherGen(DitherData& data, int32_t recursion)
return;
}
// What does this do?
float invRes = 1.0f / data.DitherTexWH;
for (int32_t z = 0; z < data.DitherTexDepth; ++z)
{
@@ -48,7 +51,7 @@ void DitherGen(DitherData& data, int32_t recursion)
float dotArea = 0.5f / dotCount;
float dotRadius = bx::sqrt(dotArea / bx::kPi);
int zOffset = z * data.DitherTexWH * data.DitherTexWH;
int32_t zOffset = z * data.DitherTexWH * data.DitherTexWH;
for (int32_t y = 0; y < data.DitherTexWH; ++y)
{
int32_t yOffset = y * data.DitherTexWH;
@@ -59,7 +62,9 @@ void DitherGen(DitherData& data, int32_t recursion)
for (int32_t i = 0; i < dotCount; ++i)
{
Vec2 vec = point - data.Points[i];
Vec2 wrappedVec{bx::mod(vec.x + 0.5f, 1.0f) - 0.5f, bx::mod(vec.y + 0.5f, 1.0f) - 0.5f};
float wrapX = bx::wrap(vec.x + 0.5f, 1.0f) - 0.5f;
float wrapY = bx::wrap(vec.y + 0.5f, 1.0f) - 0.5f;
Vec2 wrappedVec = {wrapX, wrapY};
float curDist = Magnitude(wrappedVec);
dist = bx::min(dist, curDist);
}
@@ -67,7 +72,6 @@ void DitherGen(DitherData& data, int32_t recursion)
dist = dist / (dotRadius * 2.4f);
float val = bx::clamp(1.0f - dist, 0.0f, 1.0f);
data.DitherTex[x + yOffset + zOffset] = Vec4{val, val, val, 1.0f};
// data.DitherTex[x + yOffset + zOffset] = Vec4{1.0, 0.0f, 0.0f, 1.0f};
int32_t bucket = bx::clamp(
uint32_t(val * DitherData::BrightnessBucketCount), 0, DitherData::BrightnessBucketCount - 1);
data.BrightnessBuckets[bucket] += 1;

View File

@@ -325,7 +325,7 @@ namespace Game
SharedData& shared = GetShared();
bgfx::Init init;
init.type = bgfx::RendererType::Direct3D12;
init.type = bgfx::RendererType::Direct3D11;
#ifdef _DEBUG
init.debug = true;
// init.debug = false;

View File

@@ -40,6 +40,13 @@ namespace Game
char Name[MaxSocketNameLength]{};
};
struct HeightMap
{
static constexpr uint32_t Width = 64;
static constexpr uint32_t Height = 64;
uint8_t Values[Width * Height]{0};
};
struct Model
{
static constexpr uint16_t MaxSocketCount = 16;
@@ -49,6 +56,12 @@ namespace Game
Gen::ModelHandle Handle;
uint16_t SocketCount = 0;
ModelSocket Sockets[MaxSocketCount];
HeightMap Height;
bgfx::TextureHandle HeightMapTexture = {bgfx::kInvalidHandle};
Gen::Vec3 MinPos;
Gen::Vec3 MaxPos;
Gen::Vec3 Size;
char Name[128]{0};
};
struct Material

View File

@@ -32,7 +32,7 @@ vec3 desaturate(vec3 color)
float dither(float brightness, vec2 inputUv)
{
float globalScale = 8;
float globalScale = 6;
// constants
float xRes = u_texInfo.z;
@@ -42,31 +42,30 @@ float dither(float brightness, vec2 inputUv)
float zRes = dotsTotal;
float invZRes = 1 / zRes;
float2 rampLookupUv = vec2((0.5 * invXRes + (1 - invXRes) * brightness), 0.5);
vec2 rampLookupUv = vec2((0.5 * invXRes + (1 - invXRes) * brightness), 0.5);
float brightnessCurve = texture2D(s_rampSampler, rampLookupUv).r;
// Magic dot frequency calculation
float2 dx = ddx(inputUv);
float2 dy = ddy(inputUv);
float2x2 mat = float2x2(dx, dy);
float4 vectorized = float4(dx, dy);
vec2 dx = dFdx(inputUv);
vec2 dy = dFdy(inputUv);
mat2 mat = mat2(dx, dy);
vec4 vectorized = vec4(dx, dy);
float qq = dot(vectorized, vectorized);
float rr = determinant(mat);
float discriminantSqr = max(0.0, qq*qq - 4.0*rr*rr);
float discriminant = sqrt(discriminantSqr);
float2 freq = sqrt(float2(qq + discriminant, qq - discriminant) / 2.0);
vec2 freq = sqrt(vec2(qq + discriminant, qq - discriminant) / 2.0);
// Figuring out how many dots we want
float scaleExp = exp2(globalScale);
float spacing = freq.y * scaleExp;
spacing *= dotsPerSide * 0.125;
spacing *= dotsPerSide * (1 / globalScale); // todo: just guessed that globalScale is the right variable here
float brightnessSpacingMultiplier = pow(brightnessCurve * 2 + 0.001, -(1 - 0.5));
// float brightnessSpacingMultiplier = 1;
spacing *= brightnessSpacingMultiplier;
float spacingLog = log2(spacing);
int patternScaleLevel = floor(spacingLog);
int patternScaleLevel = int(floor(spacingLog));
float patternFractional = spacingLog - patternScaleLevel;
vec2 uv = inputUv / exp2(patternScaleLevel);
@@ -77,35 +76,72 @@ float dither(float brightness, vec2 inputUv)
float pattern = texture3D(s_ditherSampler, vec3(uv, subLayer)).r;
float contrast = 2 * scaleExp * brightnessSpacingMultiplier * 0.1;
float contrast = 0.5 * scaleExp * brightnessSpacingMultiplier * 0.1;
contrast *= pow(freq.y / freq.x, 1.0);
float baseVal = lerp(0.5, brightness, saturate(1.05 / (1 + contrast)));
float threshold = 1 - brightnessCurve + 0.6;
float threshold = 1 - brightnessCurve;
return saturate((pattern - threshold) * contrast + baseVal);
}
vec4 rgbToCmyk(vec3 rgb)
{
float k = min(1.0 - rgb.r, min(1.0 - rgb.g, 1.0 - rgb.b));
vec3 cmy = vec3(0.0, 0.0, 0.0);
float invK = 1.0 - k;
if (invK != 0.0)
{
cmy.x = 1.0 - rgb.r - k;
cmy.y = 1.0 - rgb.g - k;
cmy.z = 1.0 - rgb.b - k;
cmy /= invK;
}
return saturate(vec4(cmy, k));
}
vec3 cmykToRgb(vec4 cmyk)
{
float invK = 1.0 - cmyk.w;
float r = 1.0 - min(1.0, cmyk.x * invK + cmyk.w);
float g = 1.0 - min(1.0, cmyk.y * invK + cmyk.w);
float b = 1.0 - min(1.0, cmyk.z * invK + cmyk.w);
return saturate(vec3(r,g,b));
}
vec2 rotateUV(vec2 uv, vec2 angle)
{
return uv;
}
void main()
{
// setup
bool isTextured = u_dotColor.x < 0.02;
float testRadius = 30.0;
float testSpeed = 1.0;
vec3 testOffset = vec3(0.0, 0.0, 50.0);
float3 lightPos = vec3(sin(u_time.x * testSpeed) * testRadius, 5.0, cos(u_time.x * testSpeed) * testRadius);
vec3 texColor = u_dotColor.x > 0.1 ? u_dotColor.xyz : texture2D(s_texColor, v_uv0).xyz;
vec3 lightPos = vec3(sin(u_time.x * testSpeed) * testRadius, 5.0, cos(u_time.x * testSpeed) * testRadius);
vec3 baseColor = u_baseColor.xyz;
vec3 texColor = isTextured ? texture2D(s_texColor, v_uv0).xyz : u_dotColor.xyz;
// lighting
// float brightness = calcBrightness(lightPos, v_wpos, v_normal);
float brightness = lerp(0.5, 0.9, calcBrightnessDirectional(vec3(0.5, 0.3, 1.0), v_normal));
// float brightness = 0.5;
// brightness = lerp(0.2, 1.0, sin(u_time.x) * 0.5 + 0.5);
float brightness = lerp(0.2, 0.8, calcBrightnessDirectional(vec3(0.5, 0.3, 1.0), v_normal));
float r = dither(brightness * texColor.r, v_uv0);
float g = dither(brightness * texColor.g, v_uv0);
float b = dither(brightness * texColor.b, v_uv0);
// float3 finalColor = vec3(r, g, b);
float3 ditheredColor = dither(brightness, v_uv0);
float3 finalColor = mix(u_baseColor, texColor, ditheredColor);
gl_FragColor = vec4(finalColor, 1.0);
// dither
float r = dither(texColor.r * brightness, v_uv0);
float g = dither(texColor.g * brightness, v_uv0);
float b = dither(texColor.b * brightness, v_uv0);
// vec3 ditheredColor = vec3(r,g,b);
vec4 cmyk = rgbToCmyk(texColor * brightness);
cmyk.x = dither(cmyk.x, rotateUV(v_uv0, float2(0.966, 0.259)));
cmyk.y = dither(cmyk.y, rotateUV(v_uv0, float2(0.259, 0.966)));
cmyk.z = dither(cmyk.z, rotateUV(v_uv0, float2(1.000, 0.000)));
cmyk.w = dither(cmyk.w, rotateUV(v_uv0, float2(0.707, 0.707)));
vec3 ditheredColor = cmykToRgb(cmyk);
// finalize
vec3 finalColor = mix(baseColor, ditheredColor, ditheredColor);
gl_FragColor = vec4(finalColor.rg, finalColor.b * 0.99, 1.0);
// gl_FragColor = vec4(ditheredColor, 1.0);
}

View File

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

View File

@@ -42,19 +42,19 @@ float dither(float brightness, vec2 inputUv)
float zRes = dotsTotal;
float invZRes = 1 / zRes;
float2 rampLookupUv = vec2((0.5 * invXRes + (1 - invXRes) * brightness), 0.5);
vec2 rampLookupUv = vec2((0.5 * invXRes + (1 - invXRes) * brightness), 0.5);
float brightnessCurve = texture2D(s_rampSampler, rampLookupUv).r;
// Magic dot frequency calculation
float2 dx = ddx(inputUv);
float2 dy = ddy(inputUv);
float2x2 mat = float2x2(dx, dy);
float4 vectorized = float4(dx, dy);
vec2 dx = dFdx(inputUv);
vec2 dy = dFdy(inputUv);
mat2 mat = mat2(dx, dy);
vec4 vectorized = vec4(dx, dy);
float qq = dot(vectorized, vectorized);
float rr = determinant(mat);
float discriminantSqr = max(0.0, qq*qq - 4.0*rr*rr);
float discriminant = sqrt(discriminantSqr);
float2 freq = sqrt(float2(qq + discriminant, qq - discriminant) / 2.0);
vec2 freq = sqrt(vec2(qq + discriminant, qq - discriminant) / 2.0);
// Figuring out how many dots we want
float scaleExp = exp2(globalScale);
@@ -66,7 +66,7 @@ float dither(float brightness, vec2 inputUv)
spacing *= brightnessSpacingMultiplier;
float spacingLog = log2(spacing);
int patternScaleLevel = floor(spacingLog);
int patternScaleLevel = int(floor(spacingLog));
float patternFractional = spacingLog - patternScaleLevel;
vec2 uv = inputUv / exp2(patternScaleLevel);

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -54,10 +54,41 @@ namespace Gen
"#",
};
};
struct EMaterial
struct PlacedPuzzleCardFlags
{
static constexpr uint16_t TypeIdx = 33;
static constexpr int32_t EntryCount = 2;
enum Enum : uint8_t
{
None = 0,
Locked = 1 << 0,
};
static constexpr char EntryNames[EntryCount][64]
{
"None",
"Locked",
};
};
inline PlacedPuzzleCardFlags::Enum operator| (const PlacedPuzzleCardFlags::Enum& a, const PlacedPuzzleCardFlags::Enum& b)
{
return a | b;
}
inline PlacedPuzzleCardFlags::Enum operator& (const PlacedPuzzleCardFlags::Enum& a, const PlacedPuzzleCardFlags::Enum& b)
{
return a & b;
}
inline PlacedPuzzleCardFlags::Enum operator|= (PlacedPuzzleCardFlags::Enum& a, const PlacedPuzzleCardFlags::Enum& b)
{
return a |= b;
}
inline PlacedPuzzleCardFlags::Enum operator&= (PlacedPuzzleCardFlags::Enum& a, const PlacedPuzzleCardFlags::Enum& b)
{
return a &= b;
}
struct EMaterial
{
static constexpr uint16_t TypeIdx = 34;
static constexpr int32_t EntryCount = 2;
enum Enum : int32_t
{
Default,
@@ -192,7 +223,7 @@ namespace Gen
StaticPuzzleCardHandle RefCard = {};
PuzPos Position = {};
uint8_t Rotation = {};
bool IsLocked = {};
PlacedPuzzleCardFlags::Enum Flags = {};
};
struct PuzzleData
{
@@ -204,6 +235,7 @@ namespace Gen
uint32_t AvailableCardCount = {};
PuzzleCardStack AvailableCards[16] = {};
PlacedPuzzleCard PlacedCards[256] = {};
PlacedPuzzleCard InitialPlacedCards[256] = {};
PuzzleElementType::Enum BackgroundTiles[1024] = {};
uint32_t GoalPositionCount = {};
PuzPos GoalPositions[16] = {};
@@ -224,10 +256,15 @@ namespace Gen
static constexpr uint16_t TypeIdx = 31;
SavedEntityRenderData TabletBackgroundRenderData = {};
SavedEntityRenderData TabletStatusRenderData = {};
TextureHandle TabletStatusNotSolvedTexture = {};
TextureHandle TabletStatusSolvedTexture = {};
SavedEntityRenderData TabletResetRenderData = {};
SavedEntityRenderData BackgroundLevelRenderData[16] = {};
};
bool Save(const PuzzleElementType::Enum* obj, uint32_t count, Serializer& serializer);
bool Load(PuzzleElementType::Enum* obj, uint32_t count, Deserializer& serializer);
bool Save(const PlacedPuzzleCardFlags::Enum* obj, uint32_t count, Serializer& serializer);
bool Load(PlacedPuzzleCardFlags::Enum* obj, uint32_t count, Deserializer& serializer);
bool Save(const EMaterial::Enum* obj, uint32_t count, Serializer& serializer);
bool Load(EMaterial::Enum* obj, uint32_t count, Deserializer& serializer);
bool Save(const int8_t* obj, uint32_t count, Serializer& serializer);
@@ -317,7 +354,7 @@ namespace Gen
struct MetadataTable
{
TypeDef TypeDefinitions[34]
TypeDef TypeDefinitions[35]
{
TypeDef{sizeof(int8_t), 0, "i8", 0, {}, {}, {}},
TypeDef{sizeof(int16_t), 1, "i16", 0, {}, {}, {}},
@@ -347,14 +384,15 @@ namespace Gen
TypeDef{sizeof(PuzzleVisualSettings), 2302077481, "PuzzleVisualSettings", 4, {14, 14, 13, 14}, {0, 0, 0, 0}, {{223, 13}, {236, 12}, {248, 4}, {252, 16}}},
TypeDef{sizeof(StaticPuzzleData), 2637647137, "StaticPuzzleData", 2, {23, 25}, {64, 0}, {{268, 5}, {273, 7}}},
TypeDef{sizeof(PuzzleCardStack), 53538532, "PuzzleCardStack", 3, {24, 4, 4}, {0, 0, 0}, {{280, 7}, {287, 17}, {304, 9}}},
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), 692059165, "SavedPlayerConfig", 3, {30, 30, 20}, {0, 0, 0}, {{517, 26}, {543, 22}, {565, 25}}},
TypeDef{sizeof(PlacedPuzzleCard), 838818025, "PlacedPuzzleCard", 4, {24, 21, 4, 33}, {0, 0, 0, 0}, {{313, 7}, {320, 8}, {328, 8}, {336, 5}}},
TypeDef{sizeof(PuzzleData), 1562434765, "PuzzleData", 11, {5, 11, 4, 4, 6, 27, 28, 28, 32, 6, 21}, {0, 64, 0, 0, 0, 16, 256, 256, 1024, 0, 16}, {{341, 2}, {343, 10}, {353, 10}, {363, 11}, {374, 18}, {392, 14}, {406, 11}, {417, 18}, {435, 15}, {450, 17}, {467, 13}}},
TypeDef{sizeof(SavedEntityRenderData), 3172756855, "SavedEntityRenderData", 7, {14, 14, 17, 34, 20, 19, 8}, {0, 0, 0, 0, 0, 0, 0}, {{480, 9}, {489, 14}, {503, 2}, {505, 8}, {513, 7}, {520, 5}, {525, 7}}},
TypeDef{sizeof(SavedPlayerConfig), 1710757245, "SavedPlayerConfig", 6, {30, 30, 20, 20, 30, 30}, {0, 0, 0, 0, 0, 16}, {{532, 26}, {558, 22}, {580, 28}, {608, 25}, {633, 21}, {654, 25}}},
TypeDef{sizeof(PuzzleElementType::Enum), 2983807453, "PuzzleElementType", 0, {}, {}, {}},
TypeDef{sizeof(PlacedPuzzleCardFlags::Enum), 2983807453, "PlacedPuzzleCardFlags", 0, {}, {}, {}},
TypeDef{sizeof(EMaterial::Enum), 2024002654, "EMaterial", 0, {}, {}, {}},
};
char MemberNameBuffer[64*64*64]{"xyxyzxyzwMMMMIPositionRotationScaleIdxModelIdxAssetTextureIdxAssetXYModelConnectionDirectionElementsBaseModelHandleNorthCoverHandleEastCoverHandleSouthCoverHandleWestCoverHandleSocketsModelTextureHandleBoardTextureHandleIdxTileBaseColorTileDotColorTestDisabledCardTintCardsVisualsRefCardMaxAvailableCountUsedCountRefCardPositionRotationIsLockedIDPuzzleNameWidthTilesHeightTilesAvailableCardCountAvailableCardsPlacedCardsBackgroundTilesGoalPositionCountGoalPositionsBaseColorHighlightColorTFMaterialTextureModelVisibleTabletBackgroundRenderDataTabletStatusRenderDataTabletStatusSolvedTexture"};
char MemberNameBuffer[64*64*64]{"xyxyzxyzwMMMMIPositionRotationScaleIdxModelIdxAssetTextureIdxAssetXYModelConnectionDirectionElementsBaseModelHandleNorthCoverHandleEastCoverHandleSouthCoverHandleWestCoverHandleSocketsModelTextureHandleBoardTextureHandleIdxTileBaseColorTileDotColorTestDisabledCardTintCardsVisualsRefCardMaxAvailableCountUsedCountRefCardPositionRotationFlagsIDPuzzleNameWidthTilesHeightTilesAvailableCardCountAvailableCardsPlacedCardsInitialPlacedCardsBackgroundTilesGoalPositionCountGoalPositionsBaseColorHighlightColorTFMaterialTextureModelVisibleTabletBackgroundRenderDataTabletStatusRenderDataTabletStatusNotSolvedTextureTabletStatusSolvedTextureTabletResetRenderDataBackgroundLevelRenderData"};
};
constexpr MetadataTable Metadata;

Binary file not shown.

BIN
src/models/GateDoor.glb LFS Normal file

Binary file not shown.

BIN
src/models/GateWall.glb LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/models/river.glb LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/models/z_water_cover.glb LFS Normal file

Binary file not shown.

View File

@@ -3,15 +3,21 @@ $shadersDir = ".\game\shaders"
$outputBaseDir = ".\game\compiled-shaders"
$includeDir = ".\dependency\bgfx.cmake\bgfx\src"
function CompileForAPI {
param ([string]$API, [string]$ShaderProfile)
$outDir = "$outputBaseDir\$API\$DirectoryName"
New-Item -ItemType Directory -Path $outDir -Force -ErrorAction Stop | Out-Null
Write-Host "Frag: $API $ShaderProfile"
& $shadercPath -f "$DirectoryFull\vert.sc" -o "$outDir\vert.bin" -i $includeDir --type v --platform windows --profile $ShaderProfile
Write-Host "Vert: $API $ShaderProfile"
& $shadercPath -f "$DirectoryFull\frag.sc" -o "$outDir\frag.bin" -i $includeDir --type f --platform windows --profile $ShaderProfile
}
function Process-Directory {
param ([string]$DirectoryFull, [string]$DirectoryName)
Write-Host "Dir: $DirectoryName"
$outDir = "$outputBaseDir\dx11\$DirectoryName"
New-Item -ItemType Directory -Path $outDir -Force -ErrorAction Stop | Out-Null
Write-Host "Frag"
& $shadercPath -f "$DirectoryFull\vert.sc" -o "$outDir\vert.bin" -i $includeDir --type v --platform windows --profile s_5_0
Write-Host "Vert"
& $shadercPath -f "$DirectoryFull\frag.sc" -o "$outDir\frag.bin" -i $includeDir --type f --platform windows --profile s_5_0
CompileForAPI -API "dx11" -ShaderProfile "s_5_0"
CompileForAPI -API "glsl" -ShaderProfile "430"
}
$subdirectories = Get-ChildItem -Path $shadersDir -Directory -Recurse -ErrorAction Stop

BIN
src/textures/reset.ktx LFS Normal 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.

24
tools/radsession.rad Normal file
View File

@@ -0,0 +1,24 @@
// raddbg 0.9.19 project file
recent_file: path: "../src/game/level.cpp"
recent_file: path: "../src/game/puzzle.cpp"
recent_file: path: "../src/dependency/bgfx.cmake/bx/src/debug.cpp"
recent_file: path: "../src/game/entity.h"
recent_file: path: "../src/game/ui.cpp"
recent_file: path: "../src/game/Log.cpp"
recent_file: path: "../src/game/rendering/dither.cpp"
recent_file: path: "../src/game/rendering/rendering.cpp"
recent_file: path: "../src/gen/generated.cpp"
recent_file: path: "../src/engine/main.cpp"
recent_file: path: "../src/game/setup.cpp"
recent_file: path: "../src/dependency/imgui/imgui_widgets.cpp"
recent_file: path: "../src/game/tools.cpp"
recent_file: path: "../src/gen/def.h"
recent_file: path: "../src/game/global.cpp"
target:
{
executable: "../src/cmake-build/PuzGameEngine.exe"
working_directory: "../src"
enabled: 1
debug_subprocesses: 0
}

Binary file not shown.

Binary file not shown.