Compare commits

...

28 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
64 changed files with 1744 additions and 604 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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[] = constexpr char EnumField1[] =
R"END( %s, R"END( %s,
)END"; )END";
constexpr char EnumFieldNumbered2[] =
R"END( %s = %s,
)END";
constexpr char EnumNamesStart2[] = constexpr char EnumNamesStart2[] =
R"END( }; R"END( };
@@ -71,6 +74,25 @@ namespace Gen
}; };
)END"; )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[] = constexpr char FileEnd[] =
R"END(} R"END(}
)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. // 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); int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName);
if (nameMatchIdx < 0) if (nameMatchIdx < 0)
{ {
@@ -175,7 +198,10 @@ namespace Gen
constexpr char LoadFuncBodyTypeUpgradeMember3[] = R"END( if (bx::strCmp(memberName, "%s") == 0) constexpr char LoadFuncBodyTypeUpgradeMember3[] = R"END( if (bx::strCmp(memberName, "%s") == 0)
{ {
auto* fieldPtr = reinterpret_cast<%s*>(objBasePtr + WriteDestinations[j]); 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; continue;
} }
)END"; )END";
@@ -328,6 +354,7 @@ void CppFileWriter::WriteEnums(const Def::DefinitionFile& definitions)
for (int32_t enumIdx = 0; enumIdx < definitions.EnumCount; ++enumIdx) for (int32_t enumIdx = 0; enumIdx < definitions.EnumCount; ++enumIdx)
{ {
const Def::Enum& e = definitions.Enums[enumIdx]; const Def::Enum& e = definitions.Enums[enumIdx];
bool isFlagsEnum = (uint32_t)e.EnumFlags & (uint32_t)Def::EEnumFlags::FlagsEnum;
if (!IsValid(e.EnumType)) if (!IsValid(e.EnumType))
{ {
@@ -335,13 +362,25 @@ void CppFileWriter::WriteEnums(const Def::DefinitionFile& definitions)
continue; continue;
} }
char Buf[Def::MaxNameLength]{0}; char enumTypeNameBuf[Def::MaxNameLength]{0};
PrintTypeName(Buf, sizeof(Buf), e.EnumType, definitions); PrintTypeName(enumTypeNameBuf, sizeof(enumTypeNameBuf), e.EnumType, definitions);
Write(WriteTemplates::EnumHeader4, e.Name, definitions.TypeCount + enumIdx, e.EntryCount, Buf); Write(WriteTemplates::EnumHeader4, e.Name, definitions.TypeCount + enumIdx, e.EntryCount, enumTypeNameBuf);
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx) for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++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::EnumField1, e.EntryNames[entryIdx]);
} }
}
Write(WriteTemplates::EnumNamesStart2, "EntryNames", Def::MaxNameLength); Write(WriteTemplates::EnumNamesStart2, "EntryNames", Def::MaxNameLength);
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx) for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx)
@@ -359,6 +398,23 @@ void CppFileWriter::WriteEnums(const Def::DefinitionFile& definitions)
} }
Write(WriteTemplates::EnumNamesEnd); 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) void CppFileWriter::WriteTypes(const Def::DefinitionFile& definitions)

View File

@@ -283,6 +283,12 @@ Parser::Result Parser::HandleEnum()
e.EnumType = {(uint16_t)Gen::KnownType::i32, Def::EFieldType::DefinedClass}; 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(ExpectChar("{"));
CHECK(SkipWhitespace()); CHECK(SkipWhitespace());
while (!CmpAdvance("}", Res)) while (!CmpAdvance("}", Res))

View File

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

View File

@@ -3,8 +3,10 @@
#include "../gen/Generated.h" #include "../gen/Generated.h"
#include "Log.h" #include "Log.h"
#include "Puzzle.h" // TODO: remove #include "Puzzle.h" // TODO: remove
#include "bgfx/bgfx.h"
#include "rendering/Rendering.h" #include "rendering/Rendering.h"
#include <cstdint> #include <cstdint>
#include <typeinfo>
#define ENTITY_HANDLE(X) \ #define ENTITY_HANDLE(X) \
struct X \ struct X \
@@ -18,6 +20,8 @@
namespace Game namespace Game
{ {
int32_t GetNextRenderID();
struct EntityRenderData struct EntityRenderData
{ {
Gen::Vec4 DotColor{1.0f, 1.0f, 1.0f, 1.0f}; Gen::Vec4 DotColor{1.0f, 1.0f, 1.0f, 1.0f};
@@ -27,6 +31,7 @@ namespace Game
Gen::TextureHandle TextureHandle; Gen::TextureHandle TextureHandle;
Gen::ModelHandle ModelH; Gen::ModelHandle ModelH;
bool Visible = true; bool Visible = true;
int32_t RenderID = 0;
void Render(const Model* models, const Material* materials, const Texture* textures); void Render(const Model* models, const Material* materials, const Texture* textures);
void LoadFromSaved(const Gen::SavedEntityRenderData& saved); void LoadFromSaved(const Gen::SavedEntityRenderData& saved);
@@ -121,6 +126,7 @@ namespace Game
return {}; return {};
} }
Data[Count] = {}; Data[Count] = {};
Data[Count].EData.RenderID = GetNextRenderID();
HandleT H; HandleT H;
H.Idx = Count; H.Idx = Count;
++Count; ++Count;
@@ -140,6 +146,7 @@ namespace Game
void Render(const Model* models, const Material* materials, const Texture* textures) void Render(const Model* models, const Material* materials, const Texture* textures)
{ {
if (!IsEnabled) return; if (!IsEnabled) return;
bgfx::setMarker(typeid(T).name());
for (uint16_t i = 0; i < Count; ++i) for (uint16_t i = 0; i < Count; ++i)
{ {
Get({i}).EData.Render(models, materials, textures); Get({i}).EData.Render(models, materials, textures);

View File

@@ -393,6 +393,37 @@ namespace Gen
return true; 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) void Translate(Transform& trans, Vec3 offset)
{ {
trans.Position += Vec3{offset.x, offset.y, offset.z}; trans.Position += Vec3{offset.x, offset.y, offset.z};

View File

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

View File

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

View File

@@ -8,6 +8,7 @@
#include "Puzzle.h" #include "Puzzle.h"
#include "UI.h" #include "UI.h"
#include "bx/bx.h" #include "bx/bx.h"
#include "bx/debug.h"
#include "rendering/Rendering.h" #include "rendering/Rendering.h"
#include "SDL3/SDL_mouse.h" #include "SDL3/SDL_mouse.h"
@@ -28,6 +29,13 @@ namespace Game
{ {
void EntityRenderData::Render(const Model* models, const Material* materials, const Texture* textures) 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 (models == nullptr || materials == nullptr || textures == nullptr) return;
if (!Gen::IsValid(ModelH) || MaterialHandle >= EMaterial::EntryCount) return; if (!Gen::IsValid(ModelH) || MaterialHandle >= EMaterial::EntryCount) return;
if (!Visible) return; if (!Visible) return;
@@ -101,7 +109,7 @@ namespace Game
{ {
auto& IO = ImGui::GetIO(); auto& IO = ImGui::GetIO();
IO.ConfigFlags = 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; rendering.UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug;
} }
@@ -180,6 +188,13 @@ namespace Game
Cubes.Get(PlayerOutsideViewCube).Setup(); Cubes.Get(PlayerOutsideViewCube).Setup();
} }
{
Deserializer d;
d.Init("game/data/static/uiconfig.dat", "UICO");
d.ReadT(GetInstance().Player.Config);
d.Finish();
}
UIQuads.Count = 0; UIQuads.Count = 0;
PuzzleTiles.Count = 0; PuzzleTiles.Count = 0;
PuzzleTileCovers.Count = 0; PuzzleTileCovers.Count = 0;
@@ -190,18 +205,92 @@ namespace Game
Puzzles[i].Setup(); Puzzles[i].Setup();
} }
} }
PuzzleUI.Setup(); PuzzleUI.Setup();
TabletHandle = UIQuads.New();
ReloadLevelEntities();
UpdatePlayerInputMode(); UpdatePlayerInputMode();
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
{ {
Deserializer d; Puzzles[i].WorldPosition = {0.0f, 0.0f, i * 50.0f};
d.Init("game/data/static/uiconfig.dat", "UICO");
d.ReadT(GetInstance().Player.Config);
d.Finish();
} }
} }
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() void Level::Update()
{ {
ZoneScopedN("Level update"); ZoneScopedN("Level update");
@@ -253,9 +342,38 @@ namespace Game
} }
else if (player.CameraM == CameraMode::Walk) else if (player.CameraM == CameraMode::Walk)
{ {
TranslateLocal(player.PlayerCamTransform, {0.0f, 0.0f, inputVec.z}); auto newTransform = player.PlayerCamTransform;
TranslateLocal(player.PlayerCamTransform, {inputVec.x, 0.0f, 0.0f}); // Global and local are inverted because camera
player.PlayerCamTransform.Position.y = 3.0f; 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.WalkXRot += rotInput.x;
player.WalkYRot += rotInput.y; player.WalkYRot += rotInput.y;
@@ -269,18 +387,6 @@ namespace Game
UpdatePlayerInputMode(); 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 // Cubes
for (uint16_t i = 0; i < Cubes.Count; ++i) for (uint16_t i = 0; i < Cubes.Count; ++i)
{ {
@@ -288,16 +394,20 @@ namespace Game
} }
// Puzzle tiles // Puzzle tiles
Puzzle::PuzzleSolver solver;
uint16_t activeIdx = GetInstance().DebugData.SelectedDebugLevel; uint16_t activeIdx = GetInstance().DebugData.SelectedDebugLevel;
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i) for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
{ {
if (IsInPuzzle(Puzzles[i], player.PlayerCamTransform.Position))
{
activeIdx = i;
}
Puzzles[i].IsActive = activeIdx == i; Puzzles[i].IsActive = activeIdx == i;
Puzzles[i].Update(); Puzzles[i].Update();
Puzzles[i].IsSolved = solver.IsPuzzleSolved(Puzzles[i].Data);
} }
Puzzle::PuzzleSolver solver; PuzzleUI.Update(Puzzles[activeIdx].Data, Puzzles[activeIdx].IsSolved);
bool isPuzzleSolved = solver.IsPuzzleSolved(Puzzles[activeIdx].Data);
PuzzleUI.Update(Puzzles[activeIdx].Data, isPuzzleSolved);
END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter); END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter);
} }
@@ -339,6 +449,7 @@ namespace Game
{ {
UIQuads.Render(models, materials, textures); UIQuads.Render(models, materials, textures);
} }
LevelEntities.Render(models, materials, textures);
} }
void Cube::Setup() void Cube::Setup()
@@ -362,26 +473,52 @@ namespace Game
void WorldPuzzle::Setup() void WorldPuzzle::Setup()
{ {
auto& level = GetInstance().GameLevel; Level& level = GetInstance().GameLevel;
for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i) for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i)
{ {
TileHandles[i] = level.PuzzleTiles.New(); TileHandles[i] = level.PuzzleTiles.New();
auto& tile = level.PuzzleTiles.Get(TileHandles[i]); PuzzleTileEntity& tile = level.PuzzleTiles.Get(TileHandles[i]);
tile.EData.MaterialHandle = EMaterial::Default; tile.EData.MaterialHandle = EMaterial::Default;
for (int32_t j = 0; j < Puzzle::Config::MaxCoversInTile; ++j) for (int32_t j = 0; j < Puzzle::Config::MaxCoversInTile; ++j)
{ {
int32_t idx = i * Puzzle::Config::MaxCoversInTile + j; int32_t idx = i * Puzzle::Config::MaxCoversInTile + j;
CoverHandles[idx] = level.PuzzleTileCovers.New(); CoverHandles[idx] = level.PuzzleTileCovers.New();
auto& cover = level.PuzzleTileCovers.Get(CoverHandles[idx]); PuzzleTileCover& cover = level.PuzzleTileCovers.Get(CoverHandles[idx]);
cover.EData.Visible = false; cover.EData.Visible = false;
} }
} }
for (int32_t i = 0; i < BX_COUNTOF(EndHandles); ++i)
{
EndHandles[i] = level.PuzzleTiles.New();
PuzzleTileEntity& tile = level.PuzzleTiles.Get(EndHandles[i]);
tile.EData.MaterialHandle = EMaterial::Default;
}
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; IsSetup = true;
LOG("finished setup!"); LOG("finished setup!");
} }
Vec3 PuzPosToWorldPos(const PuzzleData& data, int32_t x, int32_t y)
{
return {
(float)x * Puzzle::Config::CardScaleWorld,
-5.0f,
(float)(data.HeightTiles / 2 - y - 1) * Puzzle::Config::CardScaleWorld,
};
}
void WorldPuzzle::Update() void WorldPuzzle::Update()
{ {
Level& level = GetInstance().GameLevel; Level& level = GetInstance().GameLevel;
@@ -401,23 +538,20 @@ namespace Game
auto& staticCard = isValid ? staticCards[card.RefCard.Idx] : staticCards[0]; auto& staticCard = isValid ? staticCards[card.RefCard.Idx] : staticCards[0];
// World Tile // World Tile
tile.EData.Visible = IsActive; tile.EData.Visible = true;
tile.EData.ModelH = staticCard.BaseModelHandle; tile.EData.ModelH = staticCard.BaseModelHandle;
tile.EData.TextureHandle = staticCard.ModelTextureHandle;
tile.EData.DotColor = visuals.TileDotColor; tile.EData.DotColor = visuals.TileDotColor;
tile.EData.BaseColor = visuals.TileBaseColor; tile.EData.BaseColor = visuals.TileBaseColor;
Vec3 cardPos = { Vec3 cardPos = PuzPosToWorldPos(Data, card.Position.X, card.Position.Y);
(float)card.Position.X * Puzzle::Config::CardScaleWorld,
-5.0f,
(float)card.Position.Y * Puzzle::Config::CardScaleWorld,
};
if (!isValid) if (!isValid)
{ {
cardPos = {x * Puzzle::Config::CardScaleWorld, -5.0f, y * Puzzle::Config::CardScaleWorld}; cardPos = PuzPosToWorldPos(Data, x, y);
} }
tile.EData.Transform.Position = cardPos; tile.EData.Transform.Position = cardPos + WorldPosition;
bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * 0.5f); bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * -0.5f);
// Covers // Covers
if (IsValid(staticCard.BaseModelHandle)) if (IsValid(staticCard.BaseModelHandle))
@@ -430,11 +564,65 @@ namespace Game
cover.EData.Visible = IsActive; cover.EData.Visible = IsActive;
cover.EData.ModelH = staticCard.Sockets[i].Model; cover.EData.ModelH = staticCard.Sockets[i].Model;
cover.EData.Transform = tile.EData.Transform; 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::TranslateLocal(cover.EData.Transform, model.Sockets[i].Pos);
Gen::RotateLocal(cover.EData.Transform, Gen::EulerFromRotation(model.Sockets[i].Rot)); Gen::RotateLocal(cover.EData.Transform, Gen::EulerFromRotation(model.Sockets[i].Rot));
} }
} }
} }
} }
// 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 } // namespace Game

View File

@@ -1,9 +1,11 @@
#pragma once #pragma once
#include "../engine/Shared.h" #include "../engine/Shared.h"
#include "Entity.h"
#include "Puzzle.h" #include "Puzzle.h"
#include "UI.h" #include "UI.h"
#include "rendering/Rendering.h" #include "rendering/Rendering.h"
#include <bgfx/bgfx.h> #include <bgfx/bgfx.h>
#include <cstdint> #include <cstdint>
namespace Game namespace Game
@@ -16,12 +18,15 @@ namespace Game
Gen::Vec3 WorldPosition; Gen::Vec3 WorldPosition;
PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle]; PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle];
PuzzleTileCoverHandle CoverHandles[Puzzle::Config::MaxCardsInPuzzle * Puzzle::Config::MaxCoversInTile]; PuzzleTileCoverHandle CoverHandles[Puzzle::Config::MaxCardsInPuzzle * Puzzle::Config::MaxCoversInTile];
PuzzleTileEntityHandle EndHandles[Puzzle::Config::MaxPuzzleSizeCards];
PuzzleTileEntityHandle WallHandle;
PuzzleTileEntityHandle DoorHandle;
bool IsSetup = false; bool IsSetup = false;
bool IsActive = false; bool IsActive = false;
bool IsSolved = false;
void Setup(); void Setup();
void Update(); void Update();
void Reset(); // TODO!
}; };
class Level class Level
@@ -35,7 +40,7 @@ namespace Game
EntityManager<LevelEntity, LevelEntityHandle, 64> LevelEntities; EntityManager<LevelEntity, LevelEntityHandle, 64> LevelEntities;
CubeHandle PlayerOutsideViewCube; CubeHandle PlayerOutsideViewCube;
UIQuadEntityHandle TabletHandle; LevelEntityHandle BackgroundEntityHandles[16];
public: public:
Gen::StaticPuzzleData PuzzleData; Gen::StaticPuzzleData PuzzleData;
@@ -46,5 +51,6 @@ namespace Game
void Setup(GameData& data); void Setup(GameData& data);
void Update(); void Update();
void Render(uint16_t ViewID, const Model* models, const Material* materials, const Texture* textures); void Render(uint16_t ViewID, const Model* models, const Material* materials, const Texture* textures);
void ReloadLevelEntities();
}; };
} // namespace Game } // namespace Game

View File

@@ -2,15 +2,18 @@
#include "Global.h" #include "Global.h"
#include "Log.h" #include "Log.h"
#include "Mesh.h" #include "Mesh.h"
#include "bgfx/bgfx.h"
#include "bx/bx.h" #include "bx/bx.h"
#include "bx/error.h" #include "bx/error.h"
#include "bx/file.h" #include "bx/file.h"
#include "bx/filepath.h" #include "bx/filepath.h"
#include "bx/hash.h" #include "bx/hash.h"
#include "bx/string.h" #include "bx/string.h"
#include "bx/timer.h"
#include "rendering/Rendering.h" #include "rendering/Rendering.h"
#include "Instance.h" #include "Instance.h"
#include <cstdint>
#define TINYGLTF_IMPLEMENTATION #define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
@@ -21,6 +24,7 @@ namespace Game
{ {
bool LoadMesh(Model& mesh, const char* path, bool isBinary) bool LoadMesh(Model& mesh, const char* path, bool isBinary)
{ {
bx::strCopy(mesh.Name, sizeof(mesh.Name), path);
mesh.VertLayout.begin() mesh.VertLayout.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.add(bgfx::Attrib::Normal, 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::Primitive primitive = model.meshes[0].primitives[0];
{ {
tinygltf::Accessor accessor = model.accessors.at(primitive.indices); tinygltf::Accessor indexAccessor = model.accessors.at(primitive.indices);
tinygltf::BufferView bufferView = model.bufferViews.at(accessor.bufferView); tinygltf::BufferView indexBufferView = model.bufferViews.at(indexAccessor.bufferView);
tinygltf::Buffer buffer = model.buffers[bufferView.buffer]; int32_t indexStride = sizeof(uint16_t);
const bgfx::Memory* ibMem = bgfx::alloc(bufferView.byteLength); tinygltf::Buffer indexBuffer = model.buffers[indexBufferView.buffer];
bx::memCopy(ibMem->data, &buffer.data.at(bufferView.byteOffset), bufferView.byteLength); const bgfx::Memory* ibMem = bgfx::alloc(indexBufferView.byteLength);
bx::memCopy(ibMem->data, &indexBuffer.data.at(indexBufferView.byteOffset), indexBufferView.byteLength);
mesh.IndexBuffer = bgfx::createIndexBuffer(ibMem); mesh.IndexBuffer = bgfx::createIndexBuffer(ibMem);
}
{
tinygltf::Accessor posAccessor = model.accessors.at(primitive.attributes.at("POSITION")); tinygltf::Accessor posAccessor = model.accessors.at(primitive.attributes.at("POSITION"));
tinygltf::Accessor normalAccessor = model.accessors.at(primitive.attributes.at("NORMAL")); tinygltf::Accessor normalAccessor = model.accessors.at(primitive.attributes.at("NORMAL"));
tinygltf::Accessor uvAccessor = model.accessors.at(primitive.attributes.at("TEXCOORD_0")); tinygltf::Accessor uvAccessor = model.accessors.at(primitive.attributes.at("TEXCOORD_0"));
tinygltf::BufferView posBufferView = model.bufferViews[posAccessor.bufferView]; tinygltf::BufferView posBufferView = model.bufferViews[posAccessor.bufferView];
tinygltf::BufferView normalBufferView = model.bufferViews[normalAccessor.bufferView]; tinygltf::BufferView normalBufferView = model.bufferViews[normalAccessor.bufferView];
tinygltf::BufferView uvBufferView = model.bufferViews[uvAccessor.bufferView]; tinygltf::BufferView uvBufferView = model.bufferViews[uvAccessor.bufferView];
int posStride = posAccessor.ByteStride(posBufferView); int32_t posStride = posAccessor.ByteStride(posBufferView);
int normalStride = normalAccessor.ByteStride(normalBufferView); int32_t normalStride = normalAccessor.ByteStride(normalBufferView);
int uvStride = uvAccessor.ByteStride(uvBufferView); int32_t uvStride = uvAccessor.ByteStride(uvBufferView);
tinygltf::Buffer posBuffer = model.buffers[posBufferView.buffer]; tinygltf::Buffer posBuffer = model.buffers[posBufferView.buffer];
tinygltf::Buffer normalBuffer = model.buffers[normalBufferView.buffer]; tinygltf::Buffer normalBuffer = model.buffers[normalBufferView.buffer];
tinygltf::Buffer uvBuffer = model.buffers[uvBufferView.buffer]; tinygltf::Buffer uvBuffer = model.buffers[uvBufferView.buffer];
@@ -92,7 +96,80 @@ namespace Game
bx::memCopy(&v.uv_x, &uvBuffer.data.at(uvBufferView.byteOffset + i * uvStride), uvStride); bx::memCopy(&v.uv_x, &uvBuffer.data.at(uvBufferView.byteOffset + i * uvStride), uvStride);
} }
mesh.VertexBuffer = bgfx::createVertexBuffer(vbMem, mesh.VertLayout); 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) for (auto& node : model.nodes)
{ {

View File

@@ -1,7 +1,6 @@
#include "../gen/Def.h" #include "../gen/Def.h"
#include "Gen.h" #include "Gen.h"
#include "Global.h" #include "Global.h"
#include "Instance.h"
#include "Log.h" #include "Log.h"
#include "Puzzle.h" #include "Puzzle.h"
@@ -22,6 +21,7 @@ namespace
StaticPuzzleData StaticData; StaticPuzzleData StaticData;
StaticPuzzleCard InvalidCard; StaticPuzzleCard InvalidCard;
PlacedPuzzleCard InvalidPlacedCard;
} // namespace } // namespace
namespace Puzzle namespace Puzzle
@@ -104,6 +104,24 @@ namespace Puzzle
return puz.BackgroundTiles[pos.Y * Puzzle::Config::MaxPuzzleSizeTiles + pos.X]; 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) PuzzleElementType::Enum GetCardNodeAt(const StaticPuzzleCard& card, uint8_t rotation, int8_t x, int8_t y)
{ {
assert(x >= 0 && x < Puzzle::Config::CardSize); assert(x >= 0 && x < Puzzle::Config::CardSize);
@@ -288,12 +306,32 @@ namespace Puzzle
bx::snprintf(buf, bufSize, "%s/%u.pzl", Puzzle::PuzzleFileDir, puzID); 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) 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 (IsValid(placedCard.RefCard))
{ {
if (placedCard.IsLocked) if (GetFlag(placedCard.Flags, PlacedPuzzleCardFlags::Locked))
{ {
LOG_WARN("Card at %i %i is locked!", targetPos.X, targetPos.Y); LOG_WARN("Card at %i %i is locked!", targetPos.X, targetPos.Y);
return false; return false;
@@ -330,19 +368,55 @@ namespace Puzzle
auto& draggedCard = obj.AvailableCards[availIdx]; auto& draggedCard = obj.AvailableCards[availIdx];
draggedCard.UsedCount++; draggedCard.UsedCount++;
auto& placedCard = obj.PlacedCards[targetPos.Y * Config::MaxPuzzleSizeCards + targetPos.X]; PlacedPuzzleCard& placedCard = GetCardAt(obj, targetPos);
placedCard.RefCard = draggedCard.RefCard; placedCard.RefCard = draggedCard.RefCard;
placedCard.IsLocked = false; placedCard.Flags = (PlacedPuzzleCardFlags::Enum)ClearFlags(placedCard.Flags, PlacedPuzzleCardFlags::Locked);
placedCard.Position = targetPos; placedCard.Position = targetPos;
placedCard.Rotation = rotation; placedCard.Rotation = rotation;
return true; 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 RenderDebugUI(PuzzleData& obj)
{ {
bool dataChanged = false;
uint8_t debugRot = Game::GetInstance().DebugData.DebugCardRotation;
bool isVisible = true; bool isVisible = true;
if (ImGui::Begin("Puzzle", &isVisible)) if (ImGui::Begin("Puzzle", &isVisible))
{ {
@@ -356,17 +430,34 @@ namespace Puzzle
return false; return false;
} }
ImGui::SameLine(); 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; int32_t val = obj.ID;
if (ImGui::InputInt("ID", &val)) if (ImGui::InputInt("ID", &val))
{ {
obj.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 W = obj.WidthTiles;
int32_t H = obj.HeightTiles; int32_t H = obj.HeightTiles;
@@ -375,7 +466,6 @@ namespace Puzzle
if (ImGui::DragInt("", &W, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles)) if (ImGui::DragInt("", &W, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
{ {
obj.WidthTiles = uint8_t(W); obj.WidthTiles = uint8_t(W);
dataChanged = true;
} }
ImGui::PopID(); ImGui::PopID();
ImGui::SameLine(); ImGui::SameLine();
@@ -386,7 +476,6 @@ namespace Puzzle
if (ImGui::DragInt("", &H, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles)) if (ImGui::DragInt("", &H, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
{ {
obj.HeightTiles = uint8_t(H); obj.HeightTiles = uint8_t(H);
dataChanged = true;
} }
ImGui::PopID(); ImGui::PopID();
@@ -401,7 +490,7 @@ namespace Puzzle
{ {
ImGui::PushID(x); ImGui::PushID(x);
PuzPos nodePos = {int8_t(x), int8_t(y)}; PuzPos nodePos = {int8_t(x), int8_t(y)};
auto node = GetNodeAt(obj, nodePos); auto node = GetInitialNodeAt(obj, nodePos);
if (node == PuzzleElementType::WaterGoal) if (node == PuzzleElementType::WaterGoal)
{ {
obj.GoalPositions[obj.GoalPositionCount] = nodePos; obj.GoalPositions[obj.GoalPositionCount] = nodePos;
@@ -414,36 +503,30 @@ namespace Puzzle
ImGui::SetCursorScreenPos(pos); ImGui::SetCursorScreenPos(pos);
if (x % Puzzle::Config::CardSize == 0 && y % Puzzle::Config::CardSize == 0) if (x % Puzzle::Config::CardSize == 0 && y % Puzzle::Config::CardSize == 0)
{ {
int32_t cardX = x / Config::CardSize; PuzPos cardPos = {int8_t(x / Config::CardSize), int8_t(y / Config::CardSize)};
int32_t cardY = y / Config::CardSize; PlacedPuzzleCard& placedCard = GetInitialCardAt(obj, cardPos);
PuzPos cardPos = {int8_t(cardX), int8_t(cardY)}; bool isLocked = GetFlag(placedCard.Flags, PlacedPuzzleCardFlags::Locked);
auto& placedCard = obj.PlacedCards[cardY * Config::MaxPuzzleSizeCards + cardX];
ImGui::InvisibleButton("bn", {UIPuzBoxSize * 2, UIPuzBoxSize * 2}); ImGui::InvisibleButton("bn", {UIPuzBoxSize * 2, UIPuzBoxSize * 2});
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) if (ImGui::IsItemClicked(ImGuiMouseButton_Right))
{ {
placedCard.Rotation += 1; placedCard.Rotation += 1;
if (placedCard.Rotation >= 4) placedCard.Rotation = 0; 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 = {};
placedCard.RefCard = {};
dataChanged = true;
} }
else else
{ {
if (!ReturnPlacedCard(obj, cardPos)) placedCard.Flags =
{ (PlacedPuzzleCardFlags::Enum)(placedCard.Flags ^ PlacedPuzzleCardFlags::Locked);
placedCard.IsLocked = false; RecalculateInitialAvailable(obj);
placedCard.RefCard = {};
dataChanged = true;
} }
} }
} if (!isLocked && IsValid(placedCard.RefCard))
if (!placedCard.IsLocked && IsValid(placedCard.RefCard))
{ {
ImVec2 s = {puzCursorStart.x + x * UIPuzBoxSize, puzCursorStart.y + y * UIPuzBoxSize}; ImVec2 s = {puzCursorStart.x + x * UIPuzBoxSize, puzCursorStart.y + y * UIPuzBoxSize};
drawList.AddRectFilled(s, drawList.AddRectFilled(s,
@@ -458,17 +541,11 @@ namespace Puzzle
uint32_t CardIdx = *reinterpret_cast<uint32_t*>(payload->Data); uint32_t CardIdx = *reinterpret_cast<uint32_t*>(payload->Data);
placedCard = {}; placedCard = {};
placedCard.RefCard = {(uint16_t)CardIdx}; placedCard.RefCard = {(uint16_t)CardIdx};
placedCard.Rotation = debugRot; placedCard.Rotation = 0;
placedCard.Position = cardPos; placedCard.Position = cardPos;
placedCard.IsLocked = true; placedCard.Flags = (PlacedPuzzleCardFlags::Enum)SetFlags(placedCard.Flags,
dataChanged = true; PlacedPuzzleCardFlags::Locked);
} RecalculateInitialAvailable(obj);
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("availcard", 0))
{
DragAvailableCardTo(obj,
cardPos,
*(int32_t*)payload->Data,
Game::GetInstance().DebugData.DebugCardRotation);
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
@@ -534,7 +611,6 @@ namespace Puzzle
obj.AvailableCardCount++; obj.AvailableCardCount++;
} }
} }
dataChanged = true;
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
@@ -547,14 +623,8 @@ namespace Puzzle
ImGui::SetCursorScreenPos(localPos); ImGui::SetCursorScreenPos(localPos);
ImGui::PushID(i); ImGui::PushID(i);
auto& card = obj.AvailableCards[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; 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::SetCursorScreenPos({localPos.x, localPos.y + 55.0f});
ImGui::SetNextItemWidth(35); ImGui::SetNextItemWidth(35);
@@ -563,7 +633,6 @@ namespace Puzzle
{ {
int diff = displayCount - (card.MaxAvailableCount - card.UsedCount); int diff = displayCount - (card.MaxAvailableCount - card.UsedCount);
card.MaxAvailableCount = bx::max(0, card.MaxAvailableCount + diff); card.MaxAvailableCount = bx::max(0, card.MaxAvailableCount + diff);
dataChanged = true;
} }
ImGui::PopID(); ImGui::PopID();
ImGui::SameLine(0, 3); ImGui::SameLine(0, 3);
@@ -582,22 +651,17 @@ namespace Puzzle
} }
ImGui::End(); 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; 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 } // namespace Puzzle

View File

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

View File

@@ -7,9 +7,11 @@
#include "Puzzle.h" #include "Puzzle.h"
#include "Tools.h" #include "Tools.h"
#include "bgfx/bgfx.h"
#include "bx/filepath.h" #include "bx/filepath.h"
#include "bx/string.h" #include "bx/string.h"
#include "bx/timer.h" #include "bx/timer.h"
#include "rendering/Rendering.h"
#include <imgui.h> #include <imgui.h>
#include <tracy/Tracy.hpp> #include <tracy/Tracy.hpp>
@@ -182,31 +184,18 @@ namespace Tools
return changed; return changed;
} }
void RenderDebugUI(Game::GameRendering& rendering) void RenderLogUI()
{ {
if (!rendering.SetupData.UseImgui) return;
auto& time = Game::GetInstance().Time; auto& time = Game::GetInstance().Time;
auto& shared = Game::GetShared();
auto& debug = Game::GetInstance().DebugData; auto& debug = Game::GetInstance().DebugData;
auto& level = Game::GetInstance().GameLevel;
auto& player = Game::GetInstance().Player;
if (rendering.UIVisible == Game::UIVisibilityState::Debug)
{
ZoneScopedN("DebugUI");
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right))
{
debug.DebugCardRotation++;
if (debug.DebugCardRotation >= 4) debug.DebugCardRotation = 0;
}
if (ImGui::Begin("Log")) if (ImGui::Begin("Log"))
{ {
ImGui::Checkbox("Shorten File Names", &debug.ShortenLogFileNames); ImGui::Checkbox("Shorten File Names", &debug.ShortenLogFileNames);
ImGui::BeginTable("tbl", ImGui::BeginTable("tbl",
4, 4,
ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_SizingFixedFit |
ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg); ImGuiTableFlags_RowBg);
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_NoResize); ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_NoResize);
ImGui::TableSetupColumn("Log"); ImGui::TableSetupColumn("Log");
ImGui::TableSetupColumn("Line", ImGuiTableColumnFlags_NoResize); ImGui::TableSetupColumn("Line", ImGuiTableColumnFlags_NoResize);
@@ -260,6 +249,16 @@ namespace Tools
if (lineCount > 0) ImGui::PopStyleColor(2); if (lineCount > 0) ImGui::PopStyleColor(2);
} }
ImGui::End(); 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 (ImGui::Begin("Rendering")) if (ImGui::Begin("Rendering"))
{ {
if (rendering.LastShaderLoadTime >= 0.0f) if (rendering.LastShaderLoadTime >= 0.0f)
@@ -272,10 +271,6 @@ namespace Tools
{ {
ImGui::TextColored({0.9f, 0.2f, 0.2f, 1.0f}, "Shader load Failiure!"); 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(); ImGui::SameLine();
if (ImGui::Button("Reload Level")) if (ImGui::Button("Reload Level"))
{ {
@@ -283,6 +278,8 @@ namespace Tools
level.Setup(shared.Game); level.Setup(shared.Game);
} }
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("Mouse Sensitivity", &player.MouseSensitivity, 0.1f, 5.0f);
ImGui::SliderFloat("Player Speed", &player.MovementSpeed, 1.0f, 30.0f); ImGui::SliderFloat("Player Speed", &player.MovementSpeed, 1.0f, 30.0f);
@@ -292,35 +289,54 @@ namespace Tools
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Entity Groups"); if (ImGui::TreeNodeEx("Entity Groups"))
{
ImGui::Checkbox("Cubes", &level.Cubes.IsEnabled); ImGui::Checkbox("Cubes", &level.Cubes.IsEnabled);
ImGui::Checkbox("Tests", &level.Tests.IsEnabled); ImGui::Checkbox("Tests", &level.Tests.IsEnabled);
ImGui::Checkbox("PuzzleTiles", &level.PuzzleTiles.IsEnabled); ImGui::Checkbox("PuzzleTiles", &level.PuzzleTiles.IsEnabled);
ImGui::Checkbox("UIQuads", &level.UIQuads.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::Separator();
ImGui::Text("Game Tablet");
bool bTabletChanged = false;
bTabletChanged |= Tools::EntityDataSettings(player.Config.TabletBackgroundRenderData);
ImGui::Text("Status"); ImGui::Text("Status");
bTabletChanged |= Tools::EntityDataSettings(player.Config.TabletStatusRenderData); uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletStatusRenderData);
bTabletChanged |= Tools::TextureDropdown(player.Config.TabletStatusSolvedTexture, "Solved Texture"); uiconfigChanged |= Tools::TextureDropdown(player.Config.TabletStatusSolvedTexture, "Solved Texture");
bTabletChanged |= uiconfigChanged |=
Tools::TextureDropdown(player.Config.TabletStatusNotSolvedTexture, "Not Solved Texture"); Tools::TextureDropdown(player.Config.TabletStatusNotSolvedTexture, "Not Solved Texture");
ImGui::Separator();
ImGui::Text("Reset"); ImGui::Text("Reset");
bTabletChanged |= Tools::EntityDataSettings(player.Config.TabletResetRenderData); uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletResetRenderData);
if (bTabletChanged) 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; Serializer s;
s.Init("game/data/static/uiconfig.dat", "UICO"); s.Init("game/data/static/uiconfig.dat", "UICO");
s.WriteT(player.Config); s.WriteT(player.Config);
s.Finish(); s.Finish();
level.PuzzleUI.Reset(); level.PuzzleUI.Reset();
level.ReloadLevelEntities();
} }
ImGui::Separator(); if (ImGui::TreeNodeEx("Dithering"))
{
if (ImGui::Button("Dithergen")) if (ImGui::Button("Dithergen"))
{ {
DitherGen(rendering.DitherTextures, rendering.DitherRecursion); DitherGen(rendering.DitherTextures, rendering.DitherRecursion);
@@ -347,13 +363,20 @@ namespace Tools
ImGui::Image(rendering.DitherTextures.RampTex.idx, ImGui::Image(rendering.DitherTextures.RampTex.idx,
{BX_COUNTOF(rendering.DitherTextures.BrightnessRamp), 8}); {BX_COUNTOF(rendering.DitherTextures.BrightnessRamp), 8});
} }
Vec3 quadPos = level.UIQuads.Get({0}).EData.Transform.Position; ImGui::TreePop();
ImGui::Text("%f %f %f", quadPos.x, quadPos.y, quadPos.z); }
ImGui::Text("Shader log:"); if (ImGui::TreeNodeEx("Shader log"))
{
ImGui::TextWrapped("%s", Game::GetShared().Dev.ShaderLog); ImGui::TextWrapped("%s", Game::GetShared().Dev.ShaderLog);
ImGui::TreePop();
}
} }
ImGui::End(); ImGui::End();
}
void RenderTexturesUI(Game::GameRendering& rendering)
{
if (ImGui::Begin("Textures")) if (ImGui::Begin("Textures"))
{ {
if (ImGui::Button("Reload")) if (ImGui::Button("Reload"))
@@ -370,11 +393,46 @@ namespace Tools
} }
} }
ImGui::End(); ImGui::End();
}
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))
{
ImGui::Text("%s", mdl.Name);
ImGui::Image(mdl.HeightMapTexture.idx,
ImVec2{(float)Game::HeightMap::Height, (float)Game::HeightMap::Width});
}
else
{
ImGui::Text("Invalid Handle!");
}
ImGui::Spacing();
}
}
ImGui::End();
}
void RenderPuzzlesUI()
{
auto& debug = Game::GetInstance().DebugData;
auto& level = Game::GetInstance().GameLevel;
if (ImGui::Begin("Puzzles")) if (ImGui::Begin("Puzzles"))
{ {
char nameBuf[64]{0}; char nameBuf[64]{0};
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i) for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
{ {
ImGui::PushID(i);
auto& puzzleData = level.Puzzles[i].Data; auto& puzzleData = level.Puzzles[i].Data;
bool isSelected = debug.SelectedDebugLevel == i; bool isSelected = debug.SelectedDebugLevel == i;
@@ -384,10 +442,14 @@ namespace Tools
{ {
debug.SelectedDebugLevel = isSelected ? UINT16_MAX : i; debug.SelectedDebugLevel = isSelected ? UINT16_MAX : i;
} }
ImGui::DragFloat3("Pos", &level.Puzzles[i].WorldPosition.x);
ImGui::PopID();
ImGui::PopID(); ImGui::PopID();
} }
} }
ImGui::End(); ImGui::End();
if (debug.SelectedDebugLevel < BX_COUNTOF(level.Puzzles)) if (debug.SelectedDebugLevel < BX_COUNTOF(level.Puzzles))
{ {
if (!Puzzle::RenderDebugUI(level.Puzzles[debug.SelectedDebugLevel].Data)) if (!Puzzle::RenderDebugUI(level.Puzzles[debug.SelectedDebugLevel].Data))
@@ -395,6 +457,12 @@ namespace Tools
debug.SelectedDebugLevel = UINT16_MAX; debug.SelectedDebugLevel = UINT16_MAX;
} }
} }
}
void RenderCardsUI(Game::GameRendering& rendering)
{
auto& debug = Game::GetInstance().DebugData;
if (ImGui::Begin("Cards")) if (ImGui::Begin("Cards"))
{ {
Gen::StaticPuzzleData& staticData = Puzzle::GetStaticPuzzleData(); Gen::StaticPuzzleData& staticData = Puzzle::GetStaticPuzzleData();
@@ -432,7 +500,8 @@ namespace Tools
} }
Tools::ModelDropdown(card.BaseModelHandle); Tools::ModelDropdown(card.BaseModelHandle);
Tools::TextureDropdown(card.BoardTextureHandle); Tools::TextureDropdown(card.ModelTextureHandle, "World Texture");
Tools::TextureDropdown(card.BoardTextureHandle, "UI Texture");
if (IsValid(card.BaseModelHandle)) if (IsValid(card.BaseModelHandle))
{ {
auto& mdl = rendering.Models[card.BaseModelHandle.ModelIdx]; auto& mdl = rendering.Models[card.BaseModelHandle.ModelIdx];
@@ -479,24 +548,62 @@ namespace Tools
} }
} }
ImGui::End(); ImGui::End();
if (ImGui::Begin("Debug"))
{
ImGui::Checkbox("Arenas", &debug.ShowArenaUsage);
ImGui::Checkbox("ImGui Demo", &debug.ShowImguiDemo);
} }
ImGui::End();
if (debug.ShowArenaUsage) void RenderEntitiesUI()
{ {
if (ImGui::Begin("Arenas", &debug.ShowArenaUsage)) auto& level = Game::GetInstance().GameLevel;
if (ImGui::Begin("Entities"))
{ {
ProgressBar("Permanent", shared.Game.PermanentArena.Used, shared.Game.PermanentArena.MaxSize); if (ImGui::TreeNodeEx("UIQuads"))
ProgressBar("Entity", shared.Game.EntityArena.Used, shared.Game.EntityArena.MaxSize); {
ProgressBar("Transient", shared.Game.TransientArena.Used, shared.Game.TransientArena.MaxSize); 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(); ImGui::End();
} }
}
void RenderStatsUI()
{
auto& time = Game::GetInstance().Time;
auto& debug = Game::GetInstance().DebugData;
if (debug.ShowStats) if (debug.ShowStats)
{ {
ImGui::SetNextWindowPos({0, 0}); ImGui::SetNextWindowPos({0, 0});
@@ -515,7 +622,7 @@ namespace Tools
ImGui::Text("FPS: %.0f", 1.0 / time.Delta); ImGui::Text("FPS: %.0f", 1.0 / time.Delta);
constexpr ImVec2 FpsPlotSize{200, 60}; constexpr ImVec2 FpsPlotSize{200, 60};
if (ImGui::BeginChild("FpsPlot", FpsPlotSize)) if (ImGui::BeginChild("FpsPlot", FpsPlotSize, 0, ImGuiWindowFlags_NoInputs))
{ {
auto& drawList = *ImGui::GetWindowDrawList(); auto& drawList = *ImGui::GetWindowDrawList();
ImVec2 pos = ImGui::GetWindowPos(); ImVec2 pos = ImGui::GetWindowPos();
@@ -545,6 +652,105 @@ namespace Tools
ImGui::End(); 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() void MeasureFrameEnd()
{ {
FrameTimes[FrameTimeIdx] = bx::getHPCounter(); FrameTimes[FrameTimeIdx] = bx::getHPCounter();

View File

@@ -1,11 +1,13 @@
#include "UI.h" #include "UI.h"
#include "Entity.h"
#include "Gen.h" #include "Gen.h"
#include "Global.h" #include "Global.h"
#include "Input.h" #include "Input.h"
#include "Instance.h" #include "Instance.h"
#include "Level.h" #include "Level.h"
#include "Puzzle.h"
#include "bx/math.h" #include "bx/math.h"
using namespace Gen; using namespace Gen;
@@ -17,10 +19,16 @@ namespace
namespace Game namespace Game
{ {
UIQuadEntityHandle NewQuad(UIQuadEntityManager& manager, const Gen::SavedEntityRenderData& loadData) UIQuadEntityHandle NewQuad(UIQuadEntityManager& manager,
const Gen::SavedEntityRenderData& loadData,
UIQuadEntityHandle oldHandle)
{ {
UIQuadEntityHandle h = manager.New(); UIQuadEntityHandle h = oldHandle;
if (!IsValid(h))
{
h = manager.New();
if (!IsValid(h)) return h; if (!IsValid(h)) return h;
}
UIQuadEntity& entity = manager.Get(h); UIQuadEntity& entity = manager.Get(h);
entity.EData.LoadFromSaved(loadData); entity.EData.LoadFromSaved(loadData);
@@ -84,8 +92,11 @@ namespace Game
void WorldPuzzleUI::Setup() void WorldPuzzleUI::Setup()
{ {
auto& level = GetInstance().GameLevel; auto& level = GetInstance().GameLevel;
SolvedQuad = NewQuad(level.UIQuads, GetInstance().Player.Config.TabletStatusRenderData); auto& player = GetInstance().Player;
ResetQuad = NewQuad(level.UIQuads, GetInstance().Player.Config.TabletResetRenderData);
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) for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i)
{ {
@@ -103,6 +114,32 @@ namespace Game
} }
} }
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) void WorldPuzzleUI::UpdateAvailableCards(Gen::PuzzleData& Data)
{ {
auto& level = GetInstance().GameLevel; auto& level = GetInstance().GameLevel;
@@ -111,45 +148,46 @@ namespace Game
Vec3 quadPlaneIntersectPos; Vec3 quadPlaneIntersectPos;
Vec3 mousePosWorld = GetMousePosWorld(); Vec3 mousePosWorld = GetMousePosWorld();
for (int32_t i = 0; i < Puzzle::Config::MaxAvailableStacks; ++i) for (int32_t stackIdx = 0; stackIdx < Puzzle::Config::MaxAvailableStacks; ++stackIdx)
{ {
auto& card = Data.AvailableCards[i]; auto& card = Data.AvailableCards[stackIdx];
for (int32_t j = 0; j < UIAvailableCardMaxStackPreview; j++) for (int32_t cardIdx = 0; cardIdx < UIAvailableCardMaxStackPreview; cardIdx++)
{ {
auto h = UIAvailableCards[i * UIAvailableCardMaxStackPreview + j]; auto h = UIAvailableCards[stackIdx * UIAvailableCardMaxStackPreview + cardIdx];
auto& quad = level.UIQuads.Get(h); auto& quad = level.UIQuads.Get(h);
int32_t remaining = (int32_t)card.MaxAvailableCount - (int32_t)card.UsedCount; int32_t remaining = (int32_t)card.MaxAvailableCount - (int32_t)card.UsedCount;
if (i < Data.AvailableCardCount && j < remaining) if (stackIdx < Data.AvailableCardCount && cardIdx < remaining)
{ {
quad.UIPos = Vec3{j * 0.05f + i * 1.2f, 4.2f + (j % 2 == 0 ? 0.02f : 0.0f), j * 0.001f} * 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; UICardOffset * UICardScale;
UpdateQuad(level.UIQuads, h); UpdateQuad(level.UIQuads, h);
quad.EData.Visible = true; quad.EData.Visible = true;
quad.EData.TextureHandle = Puzzle::IsValid(Data.AvailableCards[i].RefCard) quad.EData.TextureHandle = Puzzle::IsValid(card.RefCard)
? staticCards[Data.AvailableCards[i].RefCard.Idx].BoardTextureHandle ? staticCards[card.RefCard.Idx].BoardTextureHandle
: Gen::TextureHandle{}; : Gen::TextureHandle{0};
quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale}; quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale};
quad.EData.DotColor = {1.0f, 1.0f, 1.0f, 1.0f}; quad.EData.DotColor = {1.0f, 1.0f, 1.0f, 1.0f};
quad.EData.BaseColor = {1.0f, 1.0f, 1.0f, 1.0f}; quad.EData.BaseColor = {1.0f, 1.0f, 1.0f, 1.0f};
if (j == 0) if (cardIdx == 0)
{ {
if (IsQuadHovered(quad.EData.Transform, mousePosWorld, quadPlaneIntersectPos) && if (IsQuadHovered(quad.EData.Transform, mousePosWorld, quadPlaneIntersectPos) &&
DraggedAvailableCardIdx == UINT16_MAX && DraggedCard.X == -1 && DraggedAvailableCardIdx == UINT16_MAX && DraggedCard.X == -1 &&
GetMouseButtonPressedNow(MouseButton::Left)) GetMouseButtonPressedNow(MouseButton::Left))
{ {
DraggedAvailableCardIdx = i; DraggedAvailableCardIdx = stackIdx;
} }
if (DraggedAvailableCardIdx == i) if (DraggedAvailableCardIdx == stackIdx)
{ {
Vec3 dragPos = quadPlaneIntersectPos; Vec3 dragPos = quadPlaneIntersectPos;
dragPos += StaticData.ZAxis * -0.01f; dragPos += StaticData.ZAxis * -0.01f;
quad.EData.Transform.Position = dragPos; quad.EData.Transform.Position = dragPos;
Vec3 boardPos = GlobalToLocalPoint(StaticData.UITransform, quadPlaneIntersectPos); int32_t xPos;
Vec3 boardTilePos = boardPos / UICardOffset; int32_t yPos;
int32_t xPos = (int32_t)bx::round(boardTilePos.x); UIPosToCardPos(Data, quadPlaneIntersectPos, xPos, yPos);
int32_t yPos = (int32_t)bx::round(boardTilePos.y);
if (!GetMouseButton(MouseButton::Left)) if (!GetMouseButton(MouseButton::Left))
{ {
@@ -182,6 +220,7 @@ namespace Game
auto& level = GetInstance().GameLevel; auto& level = GetInstance().GameLevel;
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards; auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
Vec3 quadPlaneIntersectPos; Vec3 quadPlaneIntersectPos;
Vec3 boardOffset = CalcBoardOffset(Data);
for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y) for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y)
{ {
@@ -191,22 +230,23 @@ namespace Game
int32_t cardIdx = y * Puzzle::Config::MaxPuzzleSizeCards + x; int32_t cardIdx = y * Puzzle::Config::MaxPuzzleSizeCards + x;
PlacedPuzzleCard& card = Data.PlacedCards[cardIdx]; PlacedPuzzleCard& card = Data.PlacedCards[cardIdx];
bool isValid = Puzzle::IsValid(card.RefCard); bool isValid = Puzzle::IsValid(card.RefCard);
bool isLocked = GetFlag(card.Flags, PlacedPuzzleCardFlags::Locked);
auto& quad = level.UIQuads.Get(UIPlacedCards[cardIdx]); auto& quad = level.UIQuads.Get(UIPlacedCards[cardIdx]);
quad.UIPos = Vec3{(float)card.Position.X, (float)card.Position.Y, 0.0f} * UICardOffset * UICardScale; quad.UIPos = CardPosToUIPos(Data, card.Position.X, card.Position.Y);
quad.UIRot = card.Rotation * bx::kPi * 0.5f; quad.UIRot = card.Rotation * bx::kPi * -0.5f;
UpdateQuad(level.UIQuads, UIPlacedCards[cardIdx]); UpdateQuad(level.UIQuads, UIPlacedCards[cardIdx]);
quad.EData.Visible = isValid; quad.EData.Visible = isValid;
quad.EData.TextureHandle = quad.EData.TextureHandle =
isValid ? staticCards[card.RefCard.Idx].BoardTextureHandle : Gen::TextureHandle{}; isValid ? staticCards[card.RefCard.Idx].BoardTextureHandle : Gen::TextureHandle{};
quad.EData.DotColor = card.IsLocked ? Puzzle::GetStaticPuzzleData().Visuals.DisabledCardTint quad.EData.DotColor =
: Vec4{1.0f, 1.0f, 1.0f, 1.0f}; isLocked ? Puzzle::GetStaticPuzzleData().Visuals.DisabledCardTint : Vec4{1.0f, 1.0f, 1.0f, 1.0f};
quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale}; quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale};
if (isValid && IsQuadHovered(quad.EData.Transform, StaticData.MousePosWorld, quadPlaneIntersectPos)) if (isValid && IsQuadHovered(quad.EData.Transform, StaticData.MousePosWorld, quadPlaneIntersectPos))
{ {
if (!card.IsLocked && DraggedCard.X == -1 && DraggedAvailableCardIdx == UINT16_MAX) if (!isLocked && DraggedCard.X == -1 && DraggedAvailableCardIdx == UINT16_MAX)
{ {
if (GetMouseButtonPressedNow(MouseButton::Left)) if (GetMouseButtonPressedNow(MouseButton::Left))
{ {
@@ -226,10 +266,9 @@ namespace Game
dragPos += StaticData.ZAxis * -0.01f; dragPos += StaticData.ZAxis * -0.01f;
quad.EData.Transform.Position = dragPos; quad.EData.Transform.Position = dragPos;
Vec3 boardPos = GlobalToLocalPoint(StaticData.UITransform, quadPlaneIntersectPos); int32_t xPos;
Vec3 boardTilePos = boardPos / UICardOffset; int32_t yPos;
int32_t xPos = (int32_t)bx::round(boardTilePos.x); UIPosToCardPos(Data, quadPlaneIntersectPos, xPos, yPos);
int32_t yPos = (int32_t)bx::round(boardTilePos.y);
Gen::PuzPos srcCardPos = {(int8_t)DraggedCard.X, (int8_t)DraggedCard.Y}; Gen::PuzPos srcCardPos = {(int8_t)DraggedCard.X, (int8_t)DraggedCard.Y};
Gen::PlacedPuzzleCard& srcCard = Gen::PlacedPuzzleCard& srcCard =
Data.PlacedCards[srcCardPos.Y * Puzzle::Config::MaxPuzzleSizeCards + srcCardPos.X]; Data.PlacedCards[srcCardPos.Y * Puzzle::Config::MaxPuzzleSizeCards + srcCardPos.X];
@@ -285,26 +324,33 @@ namespace Game
void WorldPuzzleUI::Update(Gen::PuzzleData& Data, bool IsPuzzleSolved) void WorldPuzzleUI::Update(Gen::PuzzleData& Data, bool IsPuzzleSolved)
{ {
auto& level = GetInstance().GameLevel; auto& level = GetInstance().GameLevel;
auto& player = GetInstance().Player;
Transform& camTransform = GetInstance().Player.PlayerCamTransform; Transform& camTransform = player.PlayerCamTransform;
UpdateMatrix(camTransform); UpdateMatrix(camTransform);
StaticData.UITransform = level.UIQuads.Get(level.TabletHandle).EData.Transform; // 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.UITransform.Rotation = camTransform.Rotation;
StaticData.ZAxis = AxisForward(StaticData.UITransform.M); StaticData.ZAxis = AxisForward(StaticData.UITransform.M);
StaticData.UITransform.Position += StaticData.ZAxis * -0.01f; StaticData.UITransform.Position += StaticData.ZAxis * -0.01f;
StaticData.MousePosWorld = GetMousePosWorld(); StaticData.MousePosWorld = GetMousePosWorld();
// TODO: disable warning & check if parentheses make sense like this // NOLINTBEGIN
Vec2 uiOffset = Vec2{static_cast<float>(Data.WidthTiles / Puzzle::Config::CardSize) - 1, Vec2 uiOffset = Vec2{static_cast<float>(Data.WidthTiles / Puzzle::Config::CardSize - 1),
static_cast<float>(Data.HeightTiles / Puzzle::Config::CardSize) - 1}; static_cast<float>(Data.HeightTiles / Puzzle::Config::CardSize - 1)};
// NOLINTEND
uiOffset *= -UICardOffset * 0.5f; uiOffset *= -UICardOffset * 0.5f;
Transform tileOriginTransform = StaticData.UITransform;
tileOriginTransform.Position += AxisForward(StaticData.UITransform.M) * -1.0f;
TranslateLocal(tileOriginTransform, Vec3{uiOffset.x, 0.0f, uiOffset.y} * 1.0f);
UpdateMatrix(tileOriginTransform);
auto& solvedQuad = level.UIQuads.Get(SolvedQuad); auto& solvedQuad = level.UIQuads.Get(SolvedQuad);
solvedQuad.EData.Visible = true; solvedQuad.EData.Visible = true;
solvedQuad.EData.TextureHandle = IsPuzzleSolved ? GetInstance().Player.Config.TabletStatusSolvedTexture solvedQuad.EData.TextureHandle = IsPuzzleSolved ? GetInstance().Player.Config.TabletStatusSolvedTexture
@@ -318,8 +364,7 @@ namespace Game
if (GetMouseButtonPressedNow(MouseButton::Left) && if (GetMouseButtonPressedNow(MouseButton::Left) &&
IsQuadHovered(resetQuad.EData.Transform, StaticData.MousePosWorld, hoverPosWorld)) IsQuadHovered(resetQuad.EData.Transform, StaticData.MousePosWorld, hoverPosWorld))
{ {
LOG_WARN("TODO!"); Puzzle::ResetPuzzle(Data);
// TODO
} }
UpdateAvailableCards(Data); UpdateAvailableCards(Data);
@@ -329,5 +374,9 @@ namespace Game
void WorldPuzzleUI::Reset() void WorldPuzzleUI::Reset()
{ {
auto& level = GetInstance().GameLevel; 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 } // namespace Game

View File

@@ -19,6 +19,7 @@ namespace Game
static constexpr float UICardOffset = 2.1f * UICardScale; static constexpr float UICardOffset = 2.1f * UICardScale;
static constexpr int32_t UIAvailableCardMaxStackPreview = 3; static constexpr int32_t UIAvailableCardMaxStackPreview = 3;
UIQuadEntityHandle TabletHandle;
UIQuadEntityHandle SolvedQuad; UIQuadEntityHandle SolvedQuad;
UIQuadEntityHandle ResetQuad; UIQuadEntityHandle ResetQuad;
@@ -34,7 +35,9 @@ namespace Game
void Reset(); void Reset();
}; };
UIQuadEntityHandle NewQuad(UIQuadEntityManager& manager, const Gen::SavedEntityRenderData& loadData); UIQuadEntityHandle NewQuad(UIQuadEntityManager& manager,
const Gen::SavedEntityRenderData& loadData,
UIQuadEntityHandle oldHandle = {});
void UpdateQuad(UIQuadEntityManager& manager, UIQuadEntityHandle handle); void UpdateQuad(UIQuadEntityManager& manager, UIQuadEntityHandle handle);
Gen::Vec3 GetMousePosWorld(); Gen::Vec3 GetMousePosWorld();
bool IsQuadHovered(Gen::Transform& quadTransform, Gen::Vec3 mousePosWorld, Gen::Vec3& outQuadPlaneIntersectPos); bool IsQuadHovered(Gen::Transform& quadTransform, Gen::Vec3 mousePosWorld, Gen::Vec3& outQuadPlaneIntersectPos);

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 u8 UsedCount
} }
enum PlacedPuzzleCardFlags(u8) Flags
{
None
Locked
}
type PlacedPuzzleCard type PlacedPuzzleCard
{ {
StaticPuzzleCardHandle RefCard StaticPuzzleCardHandle RefCard
PuzPos Position PuzPos Position
u8 Rotation u8 Rotation
b IsLocked PlacedPuzzleCardFlags Flags
} }
type PuzzleData type PuzzleData
@@ -144,6 +150,7 @@ type PuzzleData
u32 AvailableCardCount u32 AvailableCardCount
PuzzleCardStack AvailableCards Arr(16) PuzzleCardStack AvailableCards Arr(16)
PlacedPuzzleCard PlacedCards Arr(256) PlacedPuzzleCard PlacedCards Arr(256)
PlacedPuzzleCard InitialPlacedCards Arr(256)
PuzzleElementType BackgroundTiles Arr(1024) PuzzleElementType BackgroundTiles Arr(1024)
u32 GoalPositionCount u32 GoalPositionCount
PuzPos GoalPositions Arr(16) PuzPos GoalPositions Arr(16)
@@ -173,4 +180,5 @@ type SavedPlayerConfig
TextureHandle TabletStatusNotSolvedTexture TextureHandle TabletStatusNotSolvedTexture
TextureHandle TabletStatusSolvedTexture TextureHandle TabletStatusSolvedTexture
SavedEntityRenderData TabletResetRenderData 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) for (int32_t i = 0; i < data.BrightnessBucketCount; ++i)
data.BrightnessBuckets[i] = 0; 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; int32_t startCount = data.PointCount;
float offset = bx::pow(0.5f, recursionLevel + 1); 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) 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)); uint64_t dotsPerSide = bx::round(bx::pow(2, recursion));
data.DitherTexDepth = dotsPerSide * dotsPerSide; data.DitherTexDepth = dotsPerSide * dotsPerSide;
data.DitherTexWH = 16 * dotsPerSide; data.DitherTexWH = 16 * dotsPerSide;
@@ -41,6 +43,7 @@ void DitherGen(DitherData& data, int32_t recursion)
return; return;
} }
// What does this do?
float invRes = 1.0f / data.DitherTexWH; float invRes = 1.0f / data.DitherTexWH;
for (int32_t z = 0; z < data.DitherTexDepth; ++z) 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 dotArea = 0.5f / dotCount;
float dotRadius = bx::sqrt(dotArea / bx::kPi); 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) for (int32_t y = 0; y < data.DitherTexWH; ++y)
{ {
int32_t yOffset = y * data.DitherTexWH; 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) for (int32_t i = 0; i < dotCount; ++i)
{ {
Vec2 vec = point - data.Points[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); float curDist = Magnitude(wrappedVec);
dist = bx::min(dist, curDist); dist = bx::min(dist, curDist);
} }
@@ -67,7 +72,6 @@ void DitherGen(DitherData& data, int32_t recursion)
dist = dist / (dotRadius * 2.4f); dist = dist / (dotRadius * 2.4f);
float val = bx::clamp(1.0f - dist, 0.0f, 1.0f); 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{val, val, val, 1.0f};
// data.DitherTex[x + yOffset + zOffset] = Vec4{1.0, 0.0f, 0.0f, 1.0f};
int32_t bucket = bx::clamp( int32_t bucket = bx::clamp(
uint32_t(val * DitherData::BrightnessBucketCount), 0, DitherData::BrightnessBucketCount - 1); uint32_t(val * DitherData::BrightnessBucketCount), 0, DitherData::BrightnessBucketCount - 1);
data.BrightnessBuckets[bucket] += 1; data.BrightnessBuckets[bucket] += 1;

View File

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

View File

@@ -40,6 +40,13 @@ namespace Game
char Name[MaxSocketNameLength]{}; 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 struct Model
{ {
static constexpr uint16_t MaxSocketCount = 16; static constexpr uint16_t MaxSocketCount = 16;
@@ -49,6 +56,12 @@ namespace Game
Gen::ModelHandle Handle; Gen::ModelHandle Handle;
uint16_t SocketCount = 0; uint16_t SocketCount = 0;
ModelSocket Sockets[MaxSocketCount]; 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 struct Material

View File

@@ -32,7 +32,7 @@ vec3 desaturate(vec3 color)
float dither(float brightness, vec2 inputUv) float dither(float brightness, vec2 inputUv)
{ {
float globalScale = 8; float globalScale = 6;
// constants // constants
float xRes = u_texInfo.z; float xRes = u_texInfo.z;
@@ -42,31 +42,30 @@ float dither(float brightness, vec2 inputUv)
float zRes = dotsTotal; float zRes = dotsTotal;
float invZRes = 1 / zRes; 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; float brightnessCurve = texture2D(s_rampSampler, rampLookupUv).r;
// Magic dot frequency calculation // Magic dot frequency calculation
float2 dx = ddx(inputUv); vec2 dx = dFdx(inputUv);
float2 dy = ddy(inputUv); vec2 dy = dFdy(inputUv);
float2x2 mat = float2x2(dx, dy); mat2 mat = mat2(dx, dy);
float4 vectorized = float4(dx, dy); vec4 vectorized = vec4(dx, dy);
float qq = dot(vectorized, vectorized); float qq = dot(vectorized, vectorized);
float rr = determinant(mat); float rr = determinant(mat);
float discriminantSqr = max(0.0, qq*qq - 4.0*rr*rr); float discriminantSqr = max(0.0, qq*qq - 4.0*rr*rr);
float discriminant = sqrt(discriminantSqr); 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 // Figuring out how many dots we want
float scaleExp = exp2(globalScale); float scaleExp = exp2(globalScale);
float spacing = freq.y * scaleExp; 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 = pow(brightnessCurve * 2 + 0.001, -(1 - 0.5));
// float brightnessSpacingMultiplier = 1;
spacing *= brightnessSpacingMultiplier; spacing *= brightnessSpacingMultiplier;
float spacingLog = log2(spacing); float spacingLog = log2(spacing);
int patternScaleLevel = floor(spacingLog); int patternScaleLevel = int(floor(spacingLog));
float patternFractional = spacingLog - patternScaleLevel; float patternFractional = spacingLog - patternScaleLevel;
vec2 uv = inputUv / exp2(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 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); contrast *= pow(freq.y / freq.x, 1.0);
float baseVal = lerp(0.5, brightness, saturate(1.05 / (1 + contrast))); 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); 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() void main()
{ {
// setup // setup
bool isTextured = u_dotColor.x < 0.02;
float testRadius = 30.0; float testRadius = 30.0;
float testSpeed = 1.0; float testSpeed = 1.0;
vec3 testOffset = vec3(0.0, 0.0, 50.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 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 baseColor = u_baseColor.xyz;
vec3 texColor = isTextured ? texture2D(s_texColor, v_uv0).xyz : u_dotColor.xyz;
// lighting // lighting
// float brightness = calcBrightness(lightPos, v_wpos, v_normal); float brightness = lerp(0.2, 0.8, calcBrightnessDirectional(vec3(0.5, 0.3, 1.0), 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 r = dither(brightness * texColor.r, v_uv0); // dither
float g = dither(brightness * texColor.g, v_uv0); float r = dither(texColor.r * brightness, v_uv0);
float b = dither(brightness * texColor.b, v_uv0); float g = dither(texColor.g * brightness, v_uv0);
// float3 finalColor = vec3(r, g, b); float b = dither(texColor.b * brightness, v_uv0);
float3 ditheredColor = dither(brightness, v_uv0); // vec3 ditheredColor = vec3(r,g,b);
float3 finalColor = mix(u_baseColor, texColor, ditheredColor);
gl_FragColor = vec4(finalColor, 1.0);
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_color0 = a_color0;
v_uv0 = a_texcoord0; v_uv0 = a_texcoord0;
v_wpos = mul(u_model[0], vec4(a_position, 1.0)).xyz; v_wpos = mul(u_model[0], vec4(a_position, 1.0)).xyz;
v_normal = normalize(mul(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 zRes = dotsTotal;
float invZRes = 1 / zRes; 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; float brightnessCurve = texture2D(s_rampSampler, rampLookupUv).r;
// Magic dot frequency calculation // Magic dot frequency calculation
float2 dx = ddx(inputUv); vec2 dx = dFdx(inputUv);
float2 dy = ddy(inputUv); vec2 dy = dFdy(inputUv);
float2x2 mat = float2x2(dx, dy); mat2 mat = mat2(dx, dy);
float4 vectorized = float4(dx, dy); vec4 vectorized = vec4(dx, dy);
float qq = dot(vectorized, vectorized); float qq = dot(vectorized, vectorized);
float rr = determinant(mat); float rr = determinant(mat);
float discriminantSqr = max(0.0, qq*qq - 4.0*rr*rr); float discriminantSqr = max(0.0, qq*qq - 4.0*rr*rr);
float discriminant = sqrt(discriminantSqr); 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 // Figuring out how many dots we want
float scaleExp = exp2(globalScale); float scaleExp = exp2(globalScale);
@@ -66,7 +66,7 @@ float dither(float brightness, vec2 inputUv)
spacing *= brightnessSpacingMultiplier; spacing *= brightnessSpacingMultiplier;
float spacingLog = log2(spacing); float spacingLog = log2(spacing);
int patternScaleLevel = floor(spacingLog); int patternScaleLevel = int(floor(spacingLog));
float patternFractional = spacingLog - patternScaleLevel; float patternFractional = spacingLog - patternScaleLevel;
vec2 uv = inputUv / exp2(patternScaleLevel); vec2 uv = inputUv / exp2(patternScaleLevel);

View File

@@ -9,5 +9,5 @@ void main()
v_color0 = a_color0; v_color0 = a_color0;
v_uv0 = a_texcoord0; v_uv0 = a_texcoord0;
v_wpos = mul(u_model[0], vec4(a_position, 1.0)).xyz; v_wpos = mul(u_model[0], vec4(a_position, 1.0)).xyz;
v_normal = normalize(mul(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 uint16_t TypeIdx = 33;
static constexpr int32_t EntryCount = 2; 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 enum Enum : int32_t
{ {
Default, Default,
@@ -192,7 +223,7 @@ namespace Gen
StaticPuzzleCardHandle RefCard = {}; StaticPuzzleCardHandle RefCard = {};
PuzPos Position = {}; PuzPos Position = {};
uint8_t Rotation = {}; uint8_t Rotation = {};
bool IsLocked = {}; PlacedPuzzleCardFlags::Enum Flags = {};
}; };
struct PuzzleData struct PuzzleData
{ {
@@ -204,6 +235,7 @@ namespace Gen
uint32_t AvailableCardCount = {}; uint32_t AvailableCardCount = {};
PuzzleCardStack AvailableCards[16] = {}; PuzzleCardStack AvailableCards[16] = {};
PlacedPuzzleCard PlacedCards[256] = {}; PlacedPuzzleCard PlacedCards[256] = {};
PlacedPuzzleCard InitialPlacedCards[256] = {};
PuzzleElementType::Enum BackgroundTiles[1024] = {}; PuzzleElementType::Enum BackgroundTiles[1024] = {};
uint32_t GoalPositionCount = {}; uint32_t GoalPositionCount = {};
PuzPos GoalPositions[16] = {}; PuzPos GoalPositions[16] = {};
@@ -227,9 +259,12 @@ namespace Gen
TextureHandle TabletStatusNotSolvedTexture = {}; TextureHandle TabletStatusNotSolvedTexture = {};
TextureHandle TabletStatusSolvedTexture = {}; TextureHandle TabletStatusSolvedTexture = {};
SavedEntityRenderData TabletResetRenderData = {}; SavedEntityRenderData TabletResetRenderData = {};
SavedEntityRenderData BackgroundLevelRenderData[16] = {};
}; };
bool Save(const PuzzleElementType::Enum* obj, uint32_t count, Serializer& serializer); bool Save(const PuzzleElementType::Enum* obj, uint32_t count, Serializer& serializer);
bool Load(PuzzleElementType::Enum* obj, uint32_t count, Deserializer& 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 Save(const EMaterial::Enum* obj, uint32_t count, Serializer& serializer);
bool Load(EMaterial::Enum* obj, uint32_t count, Deserializer& serializer); bool Load(EMaterial::Enum* obj, uint32_t count, Deserializer& serializer);
bool Save(const int8_t* obj, uint32_t count, Serializer& serializer); bool Save(const int8_t* obj, uint32_t count, Serializer& serializer);
@@ -319,7 +354,7 @@ namespace Gen
struct MetadataTable struct MetadataTable
{ {
TypeDef TypeDefinitions[34] TypeDef TypeDefinitions[35]
{ {
TypeDef{sizeof(int8_t), 0, "i8", 0, {}, {}, {}}, TypeDef{sizeof(int8_t), 0, "i8", 0, {}, {}, {}},
TypeDef{sizeof(int16_t), 1, "i16", 0, {}, {}, {}}, TypeDef{sizeof(int16_t), 1, "i16", 0, {}, {}, {}},
@@ -349,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(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(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(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(PlacedPuzzleCard), 838818025, "PlacedPuzzleCard", 4, {24, 21, 4, 33}, {0, 0, 0, 0}, {{313, 7}, {320, 8}, {328, 8}, {336, 5}}},
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(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, 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(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), 3685229621, "SavedPlayerConfig", 5, {30, 30, 20, 20, 30}, {0, 0, 0, 0, 0}, {{517, 26}, {543, 22}, {565, 28}, {593, 25}, {618, 21}}}, TypeDef{sizeof(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(PuzzleElementType::Enum), 2983807453, "PuzzleElementType", 0, {}, {}, {}},
TypeDef{sizeof(PlacedPuzzleCardFlags::Enum), 2983807453, "PlacedPuzzleCardFlags", 0, {}, {}, {}},
TypeDef{sizeof(EMaterial::Enum), 2024002654, "EMaterial", 0, {}, {}, {}}, TypeDef{sizeof(EMaterial::Enum), 2024002654, "EMaterial", 0, {}, {}, {}},
}; };
char MemberNameBuffer[64*64*64]{"xyxyzxyzwMMMMIPositionRotationScaleIdxModelIdxAssetTextureIdxAssetXYModelConnectionDirectionElementsBaseModelHandleNorthCoverHandleEastCoverHandleSouthCoverHandleWestCoverHandleSocketsModelTextureHandleBoardTextureHandleIdxTileBaseColorTileDotColorTestDisabledCardTintCardsVisualsRefCardMaxAvailableCountUsedCountRefCardPositionRotationIsLockedIDPuzzleNameWidthTilesHeightTilesAvailableCardCountAvailableCardsPlacedCardsBackgroundTilesGoalPositionCountGoalPositionsBaseColorHighlightColorTFMaterialTextureModelVisibleTabletBackgroundRenderDataTabletStatusRenderDataTabletStatusNotSolvedTextureTabletStatusSolvedTextureTabletResetRenderData"}; char MemberNameBuffer[64*64*64]{"xyxyzxyzwMMMMIPositionRotationScaleIdxModelIdxAssetTextureIdxAssetXYModelConnectionDirectionElementsBaseModelHandleNorthCoverHandleEastCoverHandleSouthCoverHandleWestCoverHandleSocketsModelTextureHandleBoardTextureHandleIdxTileBaseColorTileDotColorTestDisabledCardTintCardsVisualsRefCardMaxAvailableCountUsedCountRefCardPositionRotationFlagsIDPuzzleNameWidthTilesHeightTilesAvailableCardCountAvailableCardsPlacedCardsInitialPlacedCardsBackgroundTilesGoalPositionCountGoalPositionsBaseColorHighlightColorTFMaterialTextureModelVisibleTabletBackgroundRenderDataTabletStatusRenderDataTabletStatusNotSolvedTextureTabletStatusSolvedTextureTabletResetRenderDataBackgroundLevelRenderData"};
}; };
constexpr MetadataTable Metadata; 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" $outputBaseDir = ".\game\compiled-shaders"
$includeDir = ".\dependency\bgfx.cmake\bgfx\src" $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 { function Process-Directory {
param ([string]$DirectoryFull, [string]$DirectoryName) param ([string]$DirectoryFull, [string]$DirectoryName)
Write-Host "Dir: $DirectoryName" Write-Host "Dir: $DirectoryName"
$outDir = "$outputBaseDir\dx11\$DirectoryName" CompileForAPI -API "dx11" -ShaderProfile "s_5_0"
New-Item -ItemType Directory -Path $outDir -Force -ErrorAction Stop | Out-Null CompileForAPI -API "glsl" -ShaderProfile "430"
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
} }
$subdirectories = Get-ChildItem -Path $shadersDir -Directory -Recurse -ErrorAction Stop $subdirectories = Get-ChildItem -Path $shadersDir -Directory -Recurse -ErrorAction Stop

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.