Compare commits

..

21 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
41 changed files with 621 additions and 166 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

@@ -20,6 +20,8 @@
namespace Game
{
int32_t GetNextRenderID();
struct EntityRenderData
{
Gen::Vec4 DotColor{1.0f, 1.0f, 1.0f, 1.0f};
@@ -29,7 +31,7 @@ namespace Game
Gen::TextureHandle TextureHandle;
Gen::ModelHandle ModelH;
bool Visible = true;
bool DebugBreakOnRender = false;
int32_t RenderID = 0;
void Render(const Model* models, const Material* materials, const Texture* textures);
void LoadFromSaved(const Gen::SavedEntityRenderData& saved);
@@ -124,6 +126,7 @@ namespace Game
return {};
}
Data[Count] = {};
Data[Count].EData.RenderID = GetNextRenderID();
HandleT H;
H.Idx = Count;
++Count;

View File

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

View File

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

View File

@@ -60,6 +60,8 @@ namespace Game
Gen::AssetHandle AssetHandles[MaxAssets]{0};
char AssetHandlePaths[MaxAssets][128];
bool ShowImguiDemo = false;
bool DebugBreakIDEnabled = false;
int DebugBreakID = -1;
uint8_t DebugCardRotation = 0;
bool ShortenLogFileNames = true;
bool ShowStats = true;

View File

@@ -29,10 +29,11 @@ namespace Game
{
void EntityRenderData::Render(const Model* models, const Material* materials, const Texture* textures)
{
if (DebugBreakOnRender)
auto& debug = GetInstance().DebugData;
if ((int32_t)debug.DebugBreakID == RenderID && debug.DebugBreakIDEnabled)
{
bx::debugBreak();
DebugBreakOnRender = false;
debug.DebugBreakIDEnabled = false;
}
if (models == nullptr || materials == nullptr || textures == nullptr) return;
@@ -108,7 +109,7 @@ namespace Game
{
auto& IO = ImGui::GetIO();
IO.ConfigFlags =
FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, IsGaming);
FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, captureMouse);
}
rendering.UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug;
}
@@ -210,6 +211,84 @@ namespace Game
ReloadLevelEntities();
UpdatePlayerInputMode();
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
{
Puzzles[i].WorldPosition = {0.0f, 0.0f, i * 50.0f};
}
}
bool IsInPuzzle(WorldPuzzle& puz, Vec3 worldPos)
{
Vec3 offsetToPuzzle = worldPos - puz.WorldPosition + (Vec3{0.5f, 0.0f, 0.5f} * Puzzle::Config::CardScaleWorld);
Vec3 scaledOffset = offsetToPuzzle / Puzzle::Config::CardScaleWorld;
int32_t offsetX = (int32_t)bx::floor(scaledOffset.x);
int32_t offsetY = (int32_t)bx::floor(scaledOffset.z);
return (offsetX >= 0 && offsetX < puz.Data.WidthTiles / 2 && offsetY >= -1 &&
offsetY < puz.Data.HeightTiles / 2);
}
bool IsOnGround(Level& level, Vec3 worldPos)
{
for (auto& puz : level.Puzzles)
{
Vec3 offsetToPuzzle =
worldPos - puz.WorldPosition + (Vec3{0.5f, 0.0f, 0.5f} * Puzzle::Config::CardScaleWorld);
Vec3 scaledOffset = offsetToPuzzle / Puzzle::Config::CardScaleWorld;
int32_t offsetX = (int32_t)bx::floor(scaledOffset.x);
int32_t offsetY = puz.Data.HeightTiles / 2 - (int32_t)bx::floor(scaledOffset.z) - 1;
float fracOffsetX = scaledOffset.x - offsetX;
float fracOffsetY = scaledOffset.z - bx::floor(scaledOffset.z);
if (offsetX >= 0 && offsetX < puz.Data.WidthTiles / 2 && offsetY >= 0 && offsetY < puz.Data.HeightTiles / 2)
{
auto& card = puz.Data.PlacedCards[offsetY * Puzzle::Config::MaxPuzzleSizeCards + offsetX];
if (card.RefCard.Idx == UINT16_MAX)
{
return true;
}
auto& refCard = Puzzle::GetStaticPuzzleData().Cards[card.RefCard.Idx];
if (!IsValid(refCard.BaseModelHandle))
{
LOG_WARN("missing base model! @ %i %i", offsetX, offsetY);
return true;
}
auto& heightmap = GameRendering::Get().Models[refCard.BaseModelHandle.ModelIdx].Height;
int32_t xPos = (int32_t)(fracOffsetX * heightmap.Width);
int32_t yPos = (int32_t)(fracOffsetY * heightmap.Height);
uint8_t height = 0;
switch (card.Rotation)
{
case 0:
height = heightmap.Values[yPos * heightmap.Width + xPos];
break;
case 1:
height = heightmap.Values[xPos * heightmap.Width + (heightmap.Height - yPos - 1)];
break;
case 2:
height =
heightmap
.Values[(heightmap.Height - yPos - 1) * heightmap.Width + (heightmap.Width - xPos - 1)];
break;
default:
height = heightmap.Values[(heightmap.Height - xPos - 1) * heightmap.Width + yPos];
break;
}
return height >= 110 && height <= 125;
}
if (offsetX == 1 && offsetY == puz.Data.HeightTiles / Puzzle::Config::CardSize)
{
if (puz.IsSolved)
{
return true;
}
return true; // TODO!
}
}
return false;
}
void Level::Update()
@@ -263,9 +342,38 @@ namespace Game
}
else if (player.CameraM == CameraMode::Walk)
{
TranslateLocal(player.PlayerCamTransform, {0.0f, 0.0f, inputVec.z});
TranslateLocal(player.PlayerCamTransform, {inputVec.x, 0.0f, 0.0f});
player.PlayerCamTransform.Position.y = 3.0f;
auto newTransform = player.PlayerCamTransform;
// Global and local are inverted because camera
Vec3 globalInput = GlobalToLocalDirection(newTransform, {inputVec.x, 0.0f, inputVec.z});
Translate(newTransform, globalInput);
newTransform.Position.y = 3.0f;
if (IsOnGround(*this, newTransform.Position))
{
player.PlayerCamTransform = newTransform;
}
else
{
auto newTransform = player.PlayerCamTransform;
Translate(newTransform, {globalInput.x, 0.0f, 0.0f});
newTransform.Position.y = 3.0f;
if (IsOnGround(*this, newTransform.Position))
{
player.PlayerCamTransform = newTransform;
}
else
{
auto newTransform = player.PlayerCamTransform;
Translate(newTransform, {0.0f, 0.0f, globalInput.z});
newTransform.Position.y = 3.0f;
if (IsOnGround(*this, newTransform.Position))
{
player.PlayerCamTransform = newTransform;
}
}
}
player.WalkXRot += rotInput.x;
player.WalkYRot += rotInput.y;
@@ -286,16 +394,20 @@ namespace Game
}
// Puzzle tiles
Puzzle::PuzzleSolver solver;
uint16_t activeIdx = GetInstance().DebugData.SelectedDebugLevel;
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].Update();
Puzzles[i].IsSolved = solver.IsPuzzleSolved(Puzzles[i].Data);
}
Puzzle::PuzzleSolver solver;
bool isPuzzleSolved = solver.IsPuzzleSolved(Puzzles[activeIdx].Data);
PuzzleUI.Update(Puzzles[activeIdx].Data, isPuzzleSolved);
PuzzleUI.Update(Puzzles[activeIdx].Data, Puzzles[activeIdx].IsSolved);
END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter);
}
@@ -361,26 +473,52 @@ namespace Game
void WorldPuzzle::Setup()
{
auto& level = GetInstance().GameLevel;
Level& level = GetInstance().GameLevel;
for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i)
{
TileHandles[i] = level.PuzzleTiles.New();
auto& tile = level.PuzzleTiles.Get(TileHandles[i]);
PuzzleTileEntity& tile = level.PuzzleTiles.Get(TileHandles[i]);
tile.EData.MaterialHandle = EMaterial::Default;
for (int32_t j = 0; j < Puzzle::Config::MaxCoversInTile; ++j)
{
int32_t idx = i * Puzzle::Config::MaxCoversInTile + j;
CoverHandles[idx] = level.PuzzleTileCovers.New();
auto& cover = level.PuzzleTileCovers.Get(CoverHandles[idx]);
PuzzleTileCover& cover = level.PuzzleTileCovers.Get(CoverHandles[idx]);
cover.EData.Visible = false;
}
}
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;
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()
{
Level& level = GetInstance().GameLevel;
@@ -400,23 +538,20 @@ namespace Game
auto& staticCard = isValid ? staticCards[card.RefCard.Idx] : staticCards[0];
// World Tile
tile.EData.Visible = IsActive;
tile.EData.Visible = true;
tile.EData.ModelH = staticCard.BaseModelHandle;
tile.EData.TextureHandle = staticCard.ModelTextureHandle;
tile.EData.DotColor = visuals.TileDotColor;
tile.EData.BaseColor = visuals.TileBaseColor;
Vec3 cardPos = {
(float)card.Position.X * Puzzle::Config::CardScaleWorld,
-5.0f,
(float)card.Position.Y * Puzzle::Config::CardScaleWorld,
};
Vec3 cardPos = PuzPosToWorldPos(Data, card.Position.X, card.Position.Y);
if (!isValid)
{
cardPos = {x * Puzzle::Config::CardScaleWorld, -5.0f, y * Puzzle::Config::CardScaleWorld};
cardPos = PuzPosToWorldPos(Data, x, y);
}
tile.EData.Transform.Position = cardPos;
bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * 0.5f);
tile.EData.Transform.Position = cardPos + WorldPosition;
bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * -0.5f);
// Covers
if (IsValid(staticCard.BaseModelHandle))
@@ -429,12 +564,48 @@ namespace Game
cover.EData.Visible = IsActive;
cover.EData.ModelH = staticCard.Sockets[i].Model;
cover.EData.Transform = tile.EData.Transform;
cover.EData.MaterialHandle = EMaterial::Default;
cover.EData.BaseColor = {0.2f, 0.1f, 0.7f, 1.0f};
cover.EData.DotColor = {0.2f, 0.2f, 0.8f, 1.0f};
Gen::TranslateLocal(cover.EData.Transform, model.Sockets[i].Pos);
Gen::RotateLocal(cover.EData.Transform, Gen::EulerFromRotation(model.Sockets[i].Rot));
}
}
}
}
// 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()
@@ -448,4 +619,10 @@ namespace Game
}
}
int32_t GetNextRenderID()
{
static int32_t RenderIDCounter = 0;
RenderIDCounter++;
return RenderIDCounter;
}
} // namespace Game

View File

@@ -18,12 +18,15 @@ namespace Game
Gen::Vec3 WorldPosition;
PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle];
PuzzleTileCoverHandle CoverHandles[Puzzle::Config::MaxCardsInPuzzle * Puzzle::Config::MaxCoversInTile];
PuzzleTileEntityHandle EndHandles[Puzzle::Config::MaxPuzzleSizeCards];
PuzzleTileEntityHandle WallHandle;
PuzzleTileEntityHandle DoorHandle;
bool IsSetup = false;
bool IsActive = false;
bool IsSolved = false;
void Setup();
void Update();
void Reset(); // TODO!
};
class Level

View File

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

View File

@@ -1,7 +1,6 @@
#include "../gen/Def.h"
#include "Gen.h"
#include "Global.h"
#include "Instance.h"
#include "Log.h"
#include "Puzzle.h"

View File

@@ -19,7 +19,8 @@ namespace Puzzle
static constexpr uint32_t MaxCardsInPuzzle = MaxPuzzleSizeCards * MaxPuzzleSizeCards;
static constexpr uint32_t MaxPuzzleSizeTiles = 16 * CardSize;
static constexpr uint32_t MaxTilesInPuzzle = MaxPuzzleSizeTiles * MaxPuzzleSizeTiles;
static constexpr uint32_t MaxTilesTotal = MaxTilesInPuzzle * MaxVisiblePuzzles;
static constexpr uint32_t MaxTilesTotal =
MaxTilesInPuzzle * MaxVisiblePuzzles + MaxPuzzleSizeCards * MaxVisiblePuzzles + 64;
static constexpr uint32_t MaxAvailableStacks = 16;
static constexpr uint32_t MaxGoalPositions = 16;
static constexpr float CardScaleWorld = 10.0f;

View File

@@ -7,9 +7,11 @@
#include "Puzzle.h"
#include "Tools.h"
#include "bgfx/bgfx.h"
#include "bx/filepath.h"
#include "bx/string.h"
#include "bx/timer.h"
#include "rendering/Rendering.h"
#include <imgui.h>
#include <tracy/Tracy.hpp>
@@ -269,10 +271,6 @@ namespace Tools
{
ImGui::TextColored({0.9f, 0.2f, 0.2f, 1.0f}, "Shader load Failiure!");
}
if (ImGui::Button("Reload Meshes"))
{
LoadModels(rendering.Models, rendering.ModelCount);
}
ImGui::SameLine();
if (ImGui::Button("Reload Level"))
{
@@ -280,6 +278,8 @@ namespace Tools
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("Player Speed", &player.MovementSpeed, 1.0f, 30.0f);
@@ -289,14 +289,15 @@ namespace Tools
ImGui::Separator();
ImGui::Text("Entity Groups");
if (ImGui::TreeNodeEx("Entity Groups"))
{
ImGui::Checkbox("Cubes", &level.Cubes.IsEnabled);
ImGui::Checkbox("Tests", &level.Tests.IsEnabled);
ImGui::Checkbox("PuzzleTiles", &level.PuzzleTiles.IsEnabled);
ImGui::Checkbox("UIQuads", &level.UIQuads.IsEnabled);
ImGui::Checkbox("Level", &level.LevelEntities.IsEnabled);
ImGui::Separator();
ImGui::TreePop();
}
bool uiconfigChanged = false;
if (ImGui::TreeNodeEx("Game Tablet"))
@@ -334,8 +335,8 @@ namespace Tools
level.ReloadLevelEntities();
}
ImGui::Separator();
if (ImGui::TreeNodeEx("Dithering"))
{
if (ImGui::Button("Dithergen"))
{
DitherGen(rendering.DitherTextures, rendering.DitherRecursion);
@@ -352,7 +353,8 @@ namespace Tools
}
else
{
ImGui::Image(rendering.DitherTextures.PreviewTex.idx,
ImGui::Image(
rendering.DitherTextures.PreviewTex.idx,
{(float)rendering.DitherTextures.DitherTexWH,
(float)rendering.DitherTextures.DitherTexWH * rendering.DitherTextures.DitherTexDepth});
}
@@ -361,11 +363,14 @@ namespace Tools
ImGui::Image(rendering.DitherTextures.RampTex.idx,
{BX_COUNTOF(rendering.DitherTextures.BrightnessRamp), 8});
}
Vec3 quadPos = level.UIQuads.Get({0}).EData.Transform.Position;
ImGui::Text("%f %f %f", quadPos.x, quadPos.y, quadPos.z);
ImGui::TreePop();
}
ImGui::Text("Shader log:");
if (ImGui::TreeNodeEx("Shader log"))
{
ImGui::TextWrapped("%s", Game::GetShared().Dev.ShaderLog);
ImGui::TreePop();
}
}
ImGui::End();
}
@@ -390,6 +395,33 @@ namespace Tools
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;
@@ -400,6 +432,7 @@ namespace Tools
char nameBuf[64]{0};
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
{
ImGui::PushID(i);
auto& puzzleData = level.Puzzles[i].Data;
bool isSelected = debug.SelectedDebugLevel == i;
@@ -409,6 +442,9 @@ namespace Tools
{
debug.SelectedDebugLevel = isSelected ? UINT16_MAX : i;
}
ImGui::DragFloat3("Pos", &level.Puzzles[i].WorldPosition.x);
ImGui::PopID();
ImGui::PopID();
}
}
@@ -464,7 +500,8 @@ namespace Tools
}
Tools::ModelDropdown(card.BaseModelHandle);
Tools::TextureDropdown(card.BoardTextureHandle);
Tools::TextureDropdown(card.ModelTextureHandle, "World Texture");
Tools::TextureDropdown(card.BoardTextureHandle, "UI Texture");
if (IsValid(card.BaseModelHandle))
{
auto& mdl = rendering.Models[card.BaseModelHandle.ModelIdx];
@@ -529,13 +566,12 @@ namespace Tools
ImGui::Text("%u", i);
ImGui::SameLine();
auto& quad = level.UIQuads.Get({i});
ImGui::Checkbox("Debug Break on Render", &quad.EData.DebugBreakOnRender);
ImGui::SameLine();
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();
@@ -550,12 +586,11 @@ namespace Tools
ImGui::Text("%u", i);
ImGui::SameLine();
auto& levelEnt = level.LevelEntities.Get({i});
ImGui::Checkbox("Debug Break on Render", &levelEnt.EData.DebugBreakOnRender);
ImGui::SameLine();
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();
@@ -587,7 +622,7 @@ namespace Tools
ImGui::Text("FPS: %.0f", 1.0 / time.Delta);
constexpr ImVec2 FpsPlotSize{200, 60};
if (ImGui::BeginChild("FpsPlot", FpsPlotSize))
if (ImGui::BeginChild("FpsPlot", FpsPlotSize, 0, ImGuiWindowFlags_NoInputs))
{
auto& drawList = *ImGui::GetWindowDrawList();
ImVec2 pos = ImGui::GetWindowPos();
@@ -629,6 +664,57 @@ namespace Tools
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))
@@ -641,6 +727,11 @@ namespace Tools
{
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");
@@ -653,6 +744,7 @@ namespace Tools
RenderLogUI();
RenderRenderSettingsUI(rendering);
RenderTexturesUI(rendering);
RenderModelsUI(rendering);
RenderPuzzlesUI();
RenderCardsUI(rendering);
RenderEntitiesUI();

View File

@@ -114,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)
{
auto& level = GetInstance().GameLevel;
@@ -134,7 +160,7 @@ namespace Game
{
quad.UIPos = Vec3{cardIdx * 0.05f + stackIdx * 1.2f,
4.2f + (cardIdx % 2 == 0 ? 0.02f : 0.0f),
cardIdx * 0.001f} *
cardIdx * 0.001f - 0.3f} *
UICardOffset * UICardScale;
UpdateQuad(level.UIQuads, h);
quad.EData.Visible = true;
@@ -159,10 +185,9 @@ namespace Game
dragPos += StaticData.ZAxis * -0.01f;
quad.EData.Transform.Position = dragPos;
Vec3 boardPos = GlobalToLocalPoint(StaticData.UITransform, quadPlaneIntersectPos);
Vec3 boardTilePos = boardPos / UICardOffset;
int32_t xPos = (int32_t)bx::round(boardTilePos.x);
int32_t yPos = (int32_t)bx::round(boardTilePos.y);
int32_t xPos;
int32_t yPos;
UIPosToCardPos(Data, quadPlaneIntersectPos, xPos, yPos);
if (!GetMouseButton(MouseButton::Left))
{
@@ -190,17 +215,6 @@ namespace Game
}
}
Vec3 CalcBoardOffset(const Gen::PuzzleData& puzData)
{
return {};
return Vec3{
(float)(puzData.WidthTiles) / (2.0f * Puzzle::Config::CardSize),
(float)(puzData.HeightTiles) / (2.0f * Puzzle::Config::CardSize),
0.0f,
} *
2.0f * WorldPuzzleUI::UICardScale * WorldPuzzleUI::UICardScale;
}
void WorldPuzzleUI::UpdateBoardCards(Gen::PuzzleData& Data)
{
auto& level = GetInstance().GameLevel;
@@ -219,9 +233,8 @@ namespace Game
bool isLocked = GetFlag(card.Flags, PlacedPuzzleCardFlags::Locked);
auto& quad = level.UIQuads.Get(UIPlacedCards[cardIdx]);
quad.UIPos = Vec3{(float)card.Position.X, (float)card.Position.Y, 0.0f} * UICardOffset * UICardScale;
quad.UIPos -= boardOffset;
quad.UIRot = card.Rotation * bx::kPi * 0.5f;
quad.UIPos = CardPosToUIPos(Data, card.Position.X, card.Position.Y);
quad.UIRot = card.Rotation * bx::kPi * -0.5f;
UpdateQuad(level.UIQuads, UIPlacedCards[cardIdx]);
quad.EData.Visible = isValid;
@@ -253,10 +266,9 @@ namespace Game
dragPos += StaticData.ZAxis * -0.01f;
quad.EData.Transform.Position = dragPos;
Vec3 boardPos = GlobalToLocalPoint(StaticData.UITransform, quadPlaneIntersectPos);
Vec3 boardTilePos = boardPos / UICardOffset;
int32_t xPos = (int32_t)bx::round(boardTilePos.x);
int32_t yPos = (int32_t)bx::round(boardTilePos.y);
int32_t xPos;
int32_t yPos;
UIPosToCardPos(Data, quadPlaneIntersectPos, xPos, yPos);
Gen::PuzPos srcCardPos = {(int8_t)DraggedCard.X, (int8_t)DraggedCard.Y};
Gen::PlacedPuzzleCard& srcCard =
Data.PlacedCards[srcCardPos.Y * Puzzle::Config::MaxPuzzleSizeCards + srcCardPos.X];
@@ -339,11 +351,6 @@ namespace Game
// NOLINTEND
uiOffset *= -UICardOffset * 0.5f;
Transform tileOriginTransform = StaticData.UITransform;
tileOriginTransform.Position += AxisForward(StaticData.UITransform.M) * -1.0f;
TranslateLocal(tileOriginTransform, Vec3{uiOffset.x, 0.0f, uiOffset.y} * 1.0f);
UpdateMatrix(tileOriginTransform);
auto& solvedQuad = level.UIQuads.Get(SolvedQuad);
solvedQuad.EData.Visible = true;
solvedQuad.EData.TextureHandle = IsPuzzleSolved ? GetInstance().Player.Config.TabletStatusSolvedTexture

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -40,6 +40,13 @@ namespace Game
char Name[MaxSocketNameLength]{};
};
struct HeightMap
{
static constexpr uint32_t Width = 64;
static constexpr uint32_t Height = 64;
uint8_t Values[Width * Height]{0};
};
struct Model
{
static constexpr uint16_t MaxSocketCount = 16;
@@ -49,6 +56,12 @@ namespace Game
Gen::ModelHandle Handle;
uint16_t SocketCount = 0;
ModelSocket Sockets[MaxSocketCount];
HeightMap Height;
bgfx::TextureHandle HeightMapTexture = {bgfx::kInvalidHandle};
Gen::Vec3 MinPos;
Gen::Vec3 MaxPos;
Gen::Vec3 Size;
char Name[128]{0};
};
struct Material
@@ -103,7 +116,7 @@ namespace Game
uint32_t ResetFlags = BGFX_RESET_VSYNC;
uint16_t MainViewID = 10;
float LastShaderLoadTime = 0.0f;
int32_t DitherRecursion = 3;
int32_t DitherRecursion = 1;
public:
void Setup(const RenderingSetup& setup);

View File

@@ -32,7 +32,7 @@ vec3 desaturate(vec3 color)
float dither(float brightness, vec2 inputUv)
{
float globalScale = 8;
float globalScale = 6;
// constants
float xRes = u_texInfo.z;
@@ -59,10 +59,9 @@ float dither(float brightness, vec2 inputUv)
// Figuring out how many dots we want
float scaleExp = exp2(globalScale);
float spacing = freq.y * scaleExp;
spacing *= dotsPerSide * 0.125;
spacing *= dotsPerSide * (1 / globalScale); // todo: just guessed that globalScale is the right variable here
float brightnessSpacingMultiplier = pow(brightnessCurve * 2 + 0.001, -(1 - 0.5));
// float brightnessSpacingMultiplier = 1;
spacing *= brightnessSpacingMultiplier;
float spacingLog = log2(spacing);
@@ -77,35 +76,72 @@ float dither(float brightness, vec2 inputUv)
float pattern = texture3D(s_ditherSampler, vec3(uv, subLayer)).r;
float contrast = 2 * scaleExp * brightnessSpacingMultiplier * 0.1;
float contrast = 0.5 * scaleExp * brightnessSpacingMultiplier * 0.1;
contrast *= pow(freq.y / freq.x, 1.0);
float baseVal = lerp(0.5, brightness, saturate(1.05 / (1 + contrast)));
float threshold = 1 - brightnessCurve + 0.6;
float threshold = 1 - brightnessCurve;
return saturate((pattern - threshold) * contrast + baseVal);
}
vec4 rgbToCmyk(vec3 rgb)
{
float k = min(1.0 - rgb.r, min(1.0 - rgb.g, 1.0 - rgb.b));
vec3 cmy = vec3(0.0, 0.0, 0.0);
float invK = 1.0 - k;
if (invK != 0.0)
{
cmy.x = 1.0 - rgb.r - k;
cmy.y = 1.0 - rgb.g - k;
cmy.z = 1.0 - rgb.b - k;
cmy /= invK;
}
return saturate(vec4(cmy, k));
}
vec3 cmykToRgb(vec4 cmyk)
{
float invK = 1.0 - cmyk.w;
float r = 1.0 - min(1.0, cmyk.x * invK + cmyk.w);
float g = 1.0 - min(1.0, cmyk.y * invK + cmyk.w);
float b = 1.0 - min(1.0, cmyk.z * invK + cmyk.w);
return saturate(vec3(r,g,b));
}
vec2 rotateUV(vec2 uv, vec2 angle)
{
return uv;
}
void main()
{
// setup
bool isTextured = u_dotColor.x < 0.02;
float testRadius = 30.0;
float testSpeed = 1.0;
vec3 testOffset = vec3(0.0, 0.0, 50.0);
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
// float brightness = calcBrightness(lightPos, v_wpos, v_normal);
float brightness = lerp(0.5, 0.9, calcBrightnessDirectional(vec3(0.5, 0.3, 1.0), v_normal));
// float brightness = 0.5;
// brightness = lerp(0.2, 1.0, sin(u_time.x) * 0.5 + 0.5);
float brightness = lerp(0.2, 0.8, calcBrightnessDirectional(vec3(0.5, 0.3, 1.0), v_normal));
float r = dither(brightness * texColor.r, v_uv0);
float g = dither(brightness * texColor.g, v_uv0);
float b = dither(brightness * texColor.b, v_uv0);
// vec3 finalColor = vec3(r, g, b);
vec3 ditheredColor = dither(brightness, v_uv0);
vec3 finalColor = mix(u_baseColor, texColor, ditheredColor);
gl_FragColor = vec4(finalColor, 1.0);
// dither
float r = dither(texColor.r * brightness, v_uv0);
float g = dither(texColor.g * brightness, v_uv0);
float b = dither(texColor.b * brightness, v_uv0);
// vec3 ditheredColor = vec3(r,g,b);
vec4 cmyk = rgbToCmyk(texColor * brightness);
cmyk.x = dither(cmyk.x, rotateUV(v_uv0, float2(0.966, 0.259)));
cmyk.y = dither(cmyk.y, rotateUV(v_uv0, float2(0.259, 0.966)));
cmyk.z = dither(cmyk.z, rotateUV(v_uv0, float2(1.000, 0.000)));
cmyk.w = dither(cmyk.w, rotateUV(v_uv0, float2(0.707, 0.707)));
vec3 ditheredColor = cmykToRgb(cmyk);
// finalize
vec3 finalColor = mix(baseColor, ditheredColor, ditheredColor);
gl_FragColor = vec4(finalColor.rg, finalColor.b * 0.99, 1.0);
// gl_FragColor = vec4(ditheredColor, 1.0);
}

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.

Binary file not shown.

Binary file not shown.

BIN
src/models/z_water_cover.glb LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,18 +1,20 @@
// raddbg 0.9.19 project file
recent_file: path: "../src/game/entity.h"
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/game/rendering/rendering.cpp"
recent_file: path: "../src/dependency/imgui/imgui_widgets.cpp"
recent_file: path: "../src/game/tools.cpp"
recent_file: path: "../src/dependency/bgfx.cmake/bx/src/debug.cpp"
recent_file: path: "../src/gen/def.h"
recent_file: path: "../src/game/global.cpp"
recent_file: path: "../src/game/Log.cpp"
target:
{
executable: "../src/cmake-build/PuzGameEngine.exe"