working puzzle editor?

This commit is contained in:
Asuro
2025-03-17 17:59:39 +01:00
parent 93bb1553be
commit ffd2e45d81
18 changed files with 203 additions and 47 deletions

View File

@@ -78,7 +78,15 @@ void Transform::UpdateMatrix()
bx::mtxScale(scale.M, Scale.x, Scale.y, Scale.z);
Mat4 temp;
bx::mtxMul(temp.M, scale.M, Rotation.M);
bx::mtxMul(M.M, pos.M, temp.M);
bx::mtxMul(M.M, temp.M, pos.M);
bx::mtxInverse(MI.M, M.M);
}
void Transform::UpdateMatrixForCam()
{
Mat4 pos;
bx::mtxTranslate(pos.M, Position.x, Position.y, Position.z);
bx::mtxMul(M.M, pos.M, Rotation.M);
bx::mtxInverse(MI.M, M.M);
}

View File

@@ -227,6 +227,7 @@ struct Transform
Vec3 GetPosition();
const float* GetPtr();
void UpdateMatrix();
void UpdateMatrixForCam();
};
struct SharedData;

View File

@@ -152,13 +152,16 @@ namespace Game
{
Tests.Get(Tests.New()).Setup();
}
UIQuads.Count = 0;
PuzzleTiles.Count = 0;
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
{
if (Puzzles[i].Data.ID != UINT16_MAX && !Puzzles[i].IsSetup)
if (Puzzles[i].Data.ID != UINT16_MAX)
{
Puzzles[i].Setup();
}
}
LOG("Tiles: %u", PuzzleTiles.Count);
UpdatePlayerInputMode();
}
@@ -170,9 +173,8 @@ namespace Game
// Input
float delta = GetInstance().Time.Delta;
delta = 1.0f / 144.0f;
constexpr float moveSpeed = 10.0f;
constexpr float rotSpeed = 0.6f;
constexpr float rotSpeed = 1.6f;
float forwardInput = (GetKey(ScanCode::W) ? 1.0f : 0.0f) + (GetKey(ScanCode::S) ? -1.0f : 0.0f);
float rightInput = (GetKey(ScanCode::D) ? 1.0f : 0.0f) + (GetKey(ScanCode::A) ? -1.0f : 0.0f);
@@ -256,12 +258,12 @@ namespace Game
auto& player = GetInstance().Player;
if (player.CameraM == CameraMode::Freefly)
{
player.FreeflyCamTransform.UpdateMatrix();
player.FreeflyCamTransform.UpdateMatrixForCam();
bgfx::setViewTransform(viewId, player.FreeflyCamTransform.M.M, proj);
}
else
{
player.PlayerCamTransform.UpdateMatrix();
player.PlayerCamTransform.UpdateMatrixForCam();
bgfx::setViewTransform(viewId, player.PlayerCamTransform.M.M, proj);
}
@@ -308,8 +310,12 @@ namespace Game
for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i)
{
TileHandles[i] = level.PuzzleTiles.New();
auto& tile = level.PuzzleTiles.Get(TileHandles[i]);
tile.EData.MaterialHandle = 0;
UIPlacedCards[i] = level.UIQuads.New();
}
IsSetup = true;
LOG("finished setup!");
}
void WorldPuzzle::Update()
@@ -317,21 +323,31 @@ namespace Game
Transform& camTransform = GetInstance().Player.PlayerCamTransform;
Vec3 cameraPos = camTransform.GetPosition() * -1;
Level& level = GetInstance().GameLevel;
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
for (int8_t y = 0; y < Data.WidthTiles / Puzzle::Config::CardSize; ++y)
{
for (int8_t x = 0; x < Data.WidthTiles / Puzzle::Config::CardSize; ++x)
{
Generated::PlacedPuzzleCard& card = Data.PlacedCards[y * Puzzle::Config::MaxPuzzleSizeCards + x];
if (!Puzzle::IsValid(card.RefCard))
const Generated::StaticPuzzleCard& cData = Puzzle::GetCard(card.RefCard);
auto& tile = level.PuzzleTiles.Get(TileHandles[y * Puzzle::Config::MaxPuzzleSizeCards + x]);
tile.EData.ModelHandle = Puzzle::GetStaticPuzzleData().Cards[card.RefCard.Idx].ModelHandle;
tile.EData.Transform.SetPosition({(float)card.Position.X, (float)card.Position.Y, 0.0f});
auto& quad = level.UIQuads.Get(UIPlacedCards[y * Puzzle::Config::MaxPuzzleSizeCards + x]);
bool IsValid = Puzzle::IsValid(card.RefCard);
tile.EData.Visible = true;
quad.EData.Visible = IsValid;
// const Generated::StaticPuzzleCard& cData = Puzzle::GetCard(card.RefCard);
tile.EData.ModelHandle =
IsValid ? staticCards[card.RefCard.Idx].ModelHandle : staticCards[0].ModelHandle;
tile.EData.Transform.SetPosition({
(float)card.Position.X * Puzzle::Config::CardScaleWorld,
-5.0f,
(float)card.Position.Y * Puzzle::Config::CardScaleWorld,
});
bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * 0.5f);
Vec3 fw = {0, -1, 0};
// quad.EData.Transform.SetPosition(cameraPos + Vec3{0, -2, 0});
quad.EData.Transform.SetPosition({});
quad.EData.Transform.Rotation = camTransform.Rotation;
}

View File

@@ -19,6 +19,7 @@ namespace
};
Generated::StaticPuzzleData StaticData;
Generated::StaticPuzzleCard InvalidCard;
} // namespace
namespace Puzzle
@@ -61,7 +62,11 @@ namespace Puzzle
}
const StaticPuzzleCard& GetCard(StaticPuzzleCardHandle H)
{
assert(IsValid(H));
if (H.Idx == UINT16_MAX)
{
LOG_ERROR("Invalid static card handle!");
return InvalidCard;
}
return GetStaticPuzzleData().Cards[H.Idx];
}
@@ -83,22 +88,20 @@ namespace Puzzle
PuzzleElementType::Enum GetNodeAt(const PuzzleData& puz, PuzPos pos)
{
assert(pos.X < Puzzle::Config::MaxPuzzleSizeCards && pos.Y < Puzzle::Config::MaxPuzzleSizeCards && pos.X >= 0 &&
assert(pos.X < Puzzle::Config::MaxPuzzleSizeTiles && pos.Y < Puzzle::Config::MaxPuzzleSizeTiles && pos.X >= 0 &&
pos.Y >= 0);
// TODO: this is horrible
for (int32_t i = 0; i < puz.PlacedCardCount; ++i)
int32_t cardIdxX = pos.X / Puzzle::Config::CardSize;
int32_t cardIdxY = pos.Y / Puzzle::Config::CardSize;
auto& card = puz.PlacedCards[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))
{
auto& card = puz.PlacedCards[i];
int8_t offsetX = pos.X - card.Position.X;
int8_t offsetY = pos.Y - card.Position.Y;
if (offsetX >= 0 && offsetX < Puzzle::Config::CardSize && offsetY >= 0 &&
offsetY < Puzzle::Config::CardSize)
{
PuzzleElementType::Enum cardVal = GetCardNodeAt(GetCard(card.RefCard), card.Rotation, offsetX, offsetY);
if (cardVal != PuzzleElementType::None) return cardVal;
}
PuzzleElementType::Enum cardVal = GetCardNodeAt(GetCard(card.RefCard), card.Rotation, offsetX, offsetY);
if (cardVal != PuzzleElementType::None) return cardVal;
}
return puz.BackgroundTiles[pos.Y * Puzzle::Config::MaxPuzzleSizeCards + pos.X];
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)
@@ -260,9 +263,58 @@ namespace Puzzle
bx::snprintf(buf, bufSize, "%s/%u.pzl", Puzzle::PuzzleFileDir, puzID);
}
// TODO: targetPos is of type CardPos
bool ReturnPlacedCard(PuzzleData& obj, PuzPos targetPos)
{
auto& placedCard = obj.PlacedCards[targetPos.Y * Config::MaxPuzzleSizeCards + targetPos.X];
if (IsValid(placedCard.RefCard))
{
if (placedCard.IsLocked) return false;
bool found = false;
for (int32_t i = 0; i < obj.AvailableCardCount; ++i)
{
if (obj.AvailableCards[i].RefCard.Idx == placedCard.RefCard.Idx && obj.AvailableCards[i].UsedCount > 0)
{
obj.AvailableCards[i].UsedCount--;
found = true;
break;
}
}
if (!found)
{
LOG_ERROR("Failed to find available card to return placed card of type %u to!", placedCard.RefCard.Idx);
return false;
}
placedCard.RefCard = {};
}
return true;
}
// TODO: targetPos is of type CardPos
bool DragAvailableCardTo(PuzzleData& obj, PuzPos targetPos, int32_t availIdx, uint8_t rotation)
{
if (availIdx >= obj.AvailableCardCount)
{
LOG_ERROR("Invalid drag with avail idx %i!", availIdx);
return false;
}
if (!ReturnPlacedCard(obj, targetPos)) return false;
auto& draggedCard = obj.AvailableCards[availIdx];
draggedCard.UsedCount++;
auto& placedCard = obj.PlacedCards[targetPos.Y * Config::MaxPuzzleSizeCards + targetPos.X];
placedCard.RefCard = draggedCard.RefCard;
placedCard.IsLocked = false;
placedCard.Position = targetPos;
placedCard.Rotation = rotation;
return true;
}
bool RenderDebugUI(PuzzleData& obj)
{
bool dataChanged = false;
uint8_t debugRot = Game::GetInstance().DebugData.DebugCardRotation;
bool isVisible = true;
if (ImGui::Begin("Puzzle", &isVisible))
@@ -327,14 +379,61 @@ namespace Puzzle
ImGui::SetCursorScreenPos(pos);
if (x % Puzzle::Config::CardSize == 0 && y % Puzzle::Config::CardSize == 0)
{
int32_t cardX = x / Config::CardSize;
int32_t cardY = y / Config::CardSize;
PuzPos cardPos = {int8_t(cardX), int8_t(cardY)};
auto& placedCard = obj.PlacedCards[cardY * Config::MaxPuzzleSizeCards + cardX];
ImGui::InvisibleButton("bn", {UIPuzBoxSize * 2, UIPuzBoxSize * 2});
if (ImGui::IsItemClicked(ImGuiMouseButton_Right))
{
placedCard.Rotation += 1;
if (placedCard.Rotation >= 4) placedCard.Rotation = 0;
dataChanged = true;
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Middle) && IsValid(placedCard.RefCard))
{
if (placedCard.IsLocked)
{
placedCard.IsLocked = false;
placedCard.RefCard = {};
dataChanged = true;
}
else
{
if (!ReturnPlacedCard(obj, cardPos))
{
placedCard.IsLocked = false;
placedCard.RefCard = {};
dataChanged = true;
}
}
}
if (!placedCard.IsLocked && IsValid(placedCard.RefCard))
{
ImVec2 s = {puzCursorStart.x + x * UIPuzBoxSize, puzCursorStart.y + y * UIPuzBoxSize};
drawList.AddRectFilled(s,
{s.x + UIPuzBoxSize * Puzzle::Config::CardSize,
s.y + UIPuzBoxSize * Puzzle::Config::CardSize},
0x33FFFFFF);
}
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("cardtype", 0))
{
uint32_t CardIdx = *reinterpret_cast<uint32_t*>(payload->Data);
obj.PlacedCards[obj.PlacedCardCount].RefCard = {(uint16_t)CardIdx};
obj.PlacedCardCount++;
placedCard = {};
placedCard.RefCard = {(uint16_t)CardIdx};
placedCard.Rotation = debugRot;
placedCard.Position = cardPos;
placedCard.IsLocked = true;
dataChanged = true;
}
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("availcard", 0))
{
DragAvailableCardTo(obj,
cardPos,
*(int32_t*)payload->Data,
Game::GetInstance().DebugData.DebugCardRotation);
}
ImGui::EndDragDropTarget();
}
@@ -401,17 +500,42 @@ namespace Puzzle
}
if (bAvailOpen)
{
uint8_t debugRot = Game::GetInstance().DebugData.DebugCardRotation;
ImVec2 startPos = ImGui::GetCursorScreenPos();
for (uint32_t i = 0; i < obj.AvailableCardCount; ++i)
{
ImVec2 localPos = {startPos.x + i * 60.0f, startPos.y};
ImGui::SetCursorScreenPos(localPos);
ImGui::PushID(i);
auto& card = obj.AvailableCards[i];
DrawCard(GetCard(card.RefCard), debugRot, ImGui::GetCursorScreenPos());
if (ImGui::BeginDragDropSource())
int displayCount = card.MaxAvailableCount - card.UsedCount;
if (displayCount > 0 && ImGui::BeginDragDropSource())
{
ImGui::SetDragDropPayload("availcard", &i, sizeof(i));
DrawCard(GetCard(card.RefCard), debugRot, ImGui::GetCursorScreenPos());
ImGui::EndDragDropSource();
}
ImGui::SetCursorScreenPos({localPos.x, localPos.y + 55.0f});
ImGui::SetNextItemWidth(35);
ImGui::PushID("carc");
if (ImGui::DragInt("", &displayCount, 0.25f))
{
int diff = displayCount - (card.MaxAvailableCount - card.UsedCount);
card.MaxAvailableCount = bx::max(0, card.MaxAvailableCount + diff);
dataChanged = true;
}
ImGui::PopID();
ImGui::SameLine(0, 3);
if (ImGui::Button("x"))
{
if (i < obj.AvailableCardCount - 1)
{
obj.AvailableCards[i] = obj.AvailableCards[obj.AvailableCardCount - 1];
}
obj.AvailableCardCount--;
}
ImGui::PopID();
}
ImGui::TreePop();
}

View File

@@ -22,6 +22,7 @@ namespace Puzzle
static constexpr uint32_t MaxTilesInPuzzle = MaxPuzzleSizeTiles * MaxPuzzleSizeTiles;
static constexpr uint32_t MaxAvailableStacks = 16;
static constexpr uint32_t MaxGoalPositions = 16;
static constexpr float CardScaleWorld = 10.0f;
};
void Setup();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -48,10 +48,10 @@ enum PuzzleElementType(u8)
{
None GameName("Empty") ShortName(" ")
WaterIn GameName("Water Source") ShortName("~+")
WaterGoal GameName("Water Goal") ShortName("~-")
WaterGoal GameName("Water Goal") ShortName("~!")
WaterChannel GameName("Water Channel") ShortName("~")
ElectricIn GameName("Electricity Source") ShortName("e+")
ElectricGoal GameName("Electricity Goal") ShortName("e-")
ElectricGoal GameName("Electricity Goal") ShortName("e!")
Blocked GameName("Blocked") ShortName("B")
Bridge GameName("Bridge") ShortName("#")
}

View File

@@ -32,7 +32,7 @@ vec3 desaturate(vec3 color)
float dither(float brightness, vec2 inputUv)
{
float globalScale = 8.0;
float globalScale = 8;
// constants
float xRes = u_texInfo.z;
@@ -77,7 +77,7 @@ float dither(float brightness, vec2 inputUv)
float pattern = texture3D(s_ditherSampler, vec3(uv, subLayer)).r;
float contrast = 8 * scaleExp * brightnessSpacingMultiplier * 0.1;
float contrast = 2 * 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;

View File

@@ -44,10 +44,10 @@ namespace Generated
{
" ",
"~+",
"~-",
"~!",
"~",
"e+",
"e-",
"e!",
"B",
"#",
};

Binary file not shown.

BIN
src/models/w corner bridge.glb LFS Normal file

Binary file not shown.

Binary file not shown.

BIN
src/models/w+ corner short.glb LFS Normal file

Binary file not shown.