Compare commits

...

59 Commits

Author SHA1 Message Date
Till Wübbers
d6e0cbf41c more tutorial text 2025-06-26 11:12:10 +02:00
Asuro
f95d9dee91 final build ig 2025-06-21 12:31:46 +02:00
Asuro
3c0af71470 puzzle 2025-06-21 12:21:14 +02:00
Asuro
7e89d93a7d bridge 2025-06-21 12:10:53 +02:00
Asuro
05cf88d986 fixes 2025-06-21 11:06:05 +02:00
Asuro
d6bec9e870 rotation fix 2025-06-21 10:57:36 +02:00
Asuro
3ccbbf493f walls 2025-06-21 03:27:25 +02:00
Asuro
b47a0cf841 test puzzles 2025-06-21 00:26:44 +02:00
Asuro
db47297ea4 less sticky movement 2025-06-21 00:26:37 +02:00
Asuro
6461b442de (kinda) fix ui offset 2025-06-21 00:13:51 +02:00
Asuro
146bf4aa22 color changes 2025-06-21 00:04:33 +02:00
Asuro
42c5b55f95 fix texture rotation, add tutorial popup 2025-06-20 23:34:32 +02:00
Asuro
d7fc6b781e ui hack 2025-06-20 15:42:05 +02:00
Asuro
e15cd79e04 fix collision 2025-06-20 15:41:52 +02:00
Asuro
4e00355dbe working collision! 2025-06-20 05:15:35 +02:00
Asuro
ffcc5bd134 fix heightmaps 2025-06-20 03:00:42 +02:00
Till Wübbers
67c1489da0 heightmap wip 2025-06-18 00:28:40 +02:00
Till Wübbers
59b8eea3a7 heightmap previews 2025-06-13 13:10:31 +02:00
Till Wübbers
a936222711 new debug message 2025-06-01 14:26:13 +02:00
Asuro
3af10d120b landscape 2025-06-01 03:17:29 +02:00
Asuro
6c8bead6ab new dithering 2025-06-01 03:17:21 +02:00
Asuro
faa36dd679 fix dithergen 2025-06-01 02:06:32 +02:00
Asuro
196d119338 slight entity rework (todo: memory corruption >.<) 2025-05-31 01:39:34 +02:00
Asuro
383c6f975b fix asset upgrade for arrays 2025-05-31 00:20:23 +02:00
Till Wübbers
4b230be2a8 half assed bugfixing 2025-05-29 17:33:14 +02:00
Till W
87ce032833 wip 2025-05-26 18:04:51 +02:00
Till W
cac2ef3330 new puzzle tool 2025-05-25 13:19:50 +02:00
Till W
410f401aef flags enum stuff 2025-05-25 13:07:11 +02:00
Till W
0c2d10d631 fix upgrading native type changes 2025-05-25 10:34:28 +02:00
Till W
18e7085aeb build notes 2025-05-23 01:57:32 +02:00
Asuro
bd2962fc38 refactor 2025-05-21 02:48:36 +02:00
Asuro
15dc65530d reset 2025-05-19 18:41:10 +02:00
Asuro
70db6ca2aa solved status ui 2025-05-19 18:20:05 +02:00
Asuro
1a8be39c19 border shader 2025-05-19 18:19:43 +02:00
Asuro
ec7a709570 solved not solved textures 2025-05-19 18:19:21 +02:00
Asuro
5cdc7d720e socket connection direction wip 2025-05-16 01:50:19 +02:00
Asuro
79fe91981b small fixes 2025-05-16 00:26:19 +02:00
Asuro
0d91ec1ebb working sockets 2025-05-11 22:32:50 +02:00
Asuro
1616704c50 fix upgrades one more time 2025-05-10 19:09:59 +02:00
Asuro
5d1db591b7 fix log highlighting 2025-05-10 14:44:25 +02:00
Till Wübbers
234a9b1732 correctly destroy stuff 2025-04-29 09:52:19 +02:00
Till Wübbers
91e9566747 make imgui optional-ish 2025-04-29 08:46:05 +02:00
Till Wübbers
02c40aeea6 more fixes 2025-04-29 08:01:26 +02:00
Till Wübbers
171e25ac76 fix memory arena alloc 2025-04-28 10:03:09 +02:00
Till Wübbers
32d89d8f77 logging improvements 2025-04-28 08:23:16 +02:00
Till Wübbers
4cdd80977c wip 2025-04-27 12:00:22 +02:00
Asuro
d75e5627f9 stuff 2025-04-13 01:46:36 +02:00
Asuro
adbe518c6e fix enum upgrades 2025-04-13 00:24:03 +02:00
Till Wübbers
c9db7e7e8f smol fix 2025-04-07 19:26:35 +02:00
Asuro
d252da6359 puzzles idk 2025-04-07 18:04:59 +02:00
Asuro
3fd8937b25 drag available cards 2025-04-07 17:58:48 +02:00
Asuro
fd2654c944 multiple puzzles 2025-04-07 16:57:41 +02:00
Asuro
d0f9051af7 puzzle data 2025-04-07 16:57:28 +02:00
Asuro
e0016817dd card assets 2025-04-07 01:32:07 +02:00
Asuro
c7edebaeb8 upgradeable types! 2025-04-06 22:27:01 +02:00
Asuro
158d59e09e new save format 2025-04-05 18:10:43 +02:00
Asuro
ab5c8a489f generate metadata in code 2025-04-04 20:39:31 +02:00
Asuro
12c546b6dc save ui settings & toggle ui 2025-03-31 18:12:23 +02:00
Asuro
ae069c4949 puzzle ui positioning 2025-03-31 17:51:57 +02:00
102 changed files with 5912 additions and 1214 deletions

Binary file not shown.

BIN
assets/blender/cards.blend LFS Normal file

Binary file not shown.

Binary file not shown.

BIN
assets/textures/bridge.png LFS Normal file

Binary file not shown.

BIN
assets/textures/concrete_tile.png LFS Normal file

Binary file not shown.

BIN
assets/textures/notsolved.png LFS Normal file

Binary file not shown.

BIN
assets/textures/reset.png LFS Normal file

Binary file not shown.

BIN
assets/textures/solved.png LFS Normal file

Binary file not shown.

BIN
assets/textures/w corner long.png LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,5 @@
$texturecPath = ".\cmake-build\texturec.exe" $texturecPath = "..\tools\texturec.exe"
$textureAssetDir = "..\assets\textures" $textureAssetDir = "..\assets\textures"
$outputBaseDir = ".\textures" $outputBaseDir = ".\textures"

1
src/buildnotes.txt Normal file
View File

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

2
src/debug.ps1 Normal file
View File

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

View File

@@ -1,18 +0,0 @@
#pragma once
#include <cstdint>
#define LOG(line, fmt, ...) Logging::Log(Logging::ELogType::Log, line, fmt, ##__VA_ARGS__)
#define LOG_WARN(line, fmt, ...) Logging::Log(Logging::ELogType::Warn, line, fmt, ##__VA_ARGS__)
#define LOG_ERROR(line, fmt, ...) Logging::Log(Logging::ELogType::Error, line, fmt, ##__VA_ARGS__)
struct Logging
{
enum class ELogType
{
Log,
Warn,
Error,
};
static void Log(ELogType logType, uint32_t line, const char* format, ...);
};

View File

@@ -32,7 +32,7 @@ namespace Gen
constexpr char StructHeader2[] = constexpr char StructHeader2[] =
R"END( struct %s R"END( struct %s
{ {
static constexpr uint32_t Hash = %u; static constexpr uint16_t TypeIdx = %u;
)END"; )END";
constexpr char StructField4[] = constexpr char StructField4[] =
@@ -46,8 +46,8 @@ namespace Gen
constexpr char EnumHeader4[] = constexpr char EnumHeader4[] =
R"END( struct %s R"END( struct %s
{ {
static constexpr uint16_t TypeIdx = %u;
static constexpr int32_t EntryCount = %u; static constexpr int32_t EntryCount = %u;
static constexpr uint32_t Hash = %u;
enum Enum : %s enum Enum : %s
{ {
)END"; )END";
@@ -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";
@@ -85,6 +107,8 @@ namespace Gen
{ {
)END"; )END";
constexpr char SaveFuncBodyType3[] = R"END( isOk = Save(%sobj[i].%s, %u, serializer) && isOk; constexpr char SaveFuncBodyType3[] = R"END( isOk = Save(%sobj[i].%s, %u, serializer) && isOk;
)END";
constexpr char SaveFuncBodyNative[] = R"END( isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
)END"; )END";
constexpr char SaveFuncBodyEnum1[] = R"END( auto val = (%s)obj[i]; constexpr char SaveFuncBodyEnum1[] = R"END( auto val = (%s)obj[i];
isOk = Save(&val, 1, serializer) && isOk; isOk = Save(&val, 1, serializer) && isOk;
@@ -99,18 +123,148 @@ namespace Gen
)END"; )END";
constexpr char LoadFuncBodyStart1[] = R"END( bool Load(%s* obj, uint32_t count, Deserializer& serializer) constexpr char LoadFuncBodyStart1[] = R"END( bool Load(%s* obj, uint32_t count, Deserializer& serializer)
{ {
)END";
constexpr char LoadFuncBodySetupStart2[] =
R"END( const char* typeName = Meta::Metadata.TypeDefinitions[%s::TypeIdx].Name;
// Quick match
int32_t matchedHashIdx =
serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[%s::TypeIdx].Hash);
if (matchedHashIdx >= 0)
{
assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0);
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
)END";
constexpr char LoadFuncBodyQuickLoad2[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk;
)END";
constexpr char LoadFuncBodySetupEnd[] = R"END( }
// if we're not ok here, something went really wrong
assert(isOk);
return isOk;
}
// Failed to resolve hash, the type definition chaned since the file was saved! try to match by name.
*obj = {};
int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName);
if (nameMatchIdx < 0)
{
// Name match failed, caller has to handle this and potentially skip some bytes
return false;
}
// Successfully matched name, but we need to follow the definition of the file now!
const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx];
// Figure out new member mapping
uint64_t WriteDestinations[64];
for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i)
{
WriteDestinations[i] = UINT64_MAX;
}
for (uint32_t i = 0; i < matchedDef.ChildCount; ++i)
{
const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size};
const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name;
)END";
constexpr char LoadFuncBodyMemberCheck4[] =
R"END( if (bx::strCmp(memberName, "%s") == 0 && bx::strCmp(memberTypeName, "%s") == 0)
{
WriteDestinations[i] = offsetof(%s, %s);
}
)END";
constexpr char LoadFuncBodyTypeUpgradeStart[] = R"END( }
// Start reading in file order, skipping things that we don't know by name and type
bool isOk = true; bool isOk = true;
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i)
{ {
uint8_t* objBasePtr = reinterpret_cast<uint8_t*>(&obj[i]);
for (uint32_t j = 0; j < matchedDef.ChildCount; ++j)
{
const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]];
const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size};
if (WriteDestinations[j] == UINT64_MAX)
{
// Unknown member name or type changed
uint16_t count = bx::max(1, matchedDef.ChildArraySizes[matchedDef.ChildIndices[j]]);
serializer.Skip(childDef.Size * count);
continue;
}
)END"; )END";
constexpr char LoadFuncBodyType3[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk; constexpr char LoadFuncBodyTypeUpgradeMember3[] = R"END( if (bx::strCmp(memberName, "%s") == 0)
{
auto* fieldPtr = reinterpret_cast<%s*>(objBasePtr + WriteDestinations[j]);
uint16_t wantedCount = %u;
uint16_t existingCount = matchedDef.ChildArraySizes[j];
isOk = Load(fieldPtr, bx::min(wantedCount, existingCount), serializer) && isOk;
if (existingCount > wantedCount) serializer.Skip((existingCount - wantedCount) * childDef.Size);
continue;
}
)END"; )END";
constexpr char LoadFuncBodyEnum2[] = R"END( %s& val = (%s&)obj[i]; constexpr char LoadFuncBodyTypeUpgradeEnd[] = R"END( assert(false);
isOk = Load(&val, 1, serializer) && isOk; }
)END"; }
constexpr char LoadFuncBodyEnd[] = R"END( } assert(isOk);
return isOk; return isOk;
} }
)END";
constexpr char LoadFuncBodyNative[] = R"END( bool isOk = true;
for (int32_t i = 0; i < count; ++i)
{
isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
}
return isOk;
}
)END";
constexpr char LoadFuncBodyEnum2[] = R"END( bool isOk = true;
for (int32_t i = 0; i < count; ++i)
{
%s& val = (%s&)obj[i];
isOk = Load(&val, 1, serializer) && isOk;
}
return isOk;
}
)END";
constexpr char MetadataStart1[] = R"END(
namespace Meta {
constexpr uint16_t CurrentMetaVersion = 1;
struct StrRef
{
uint16_t Offset;
uint16_t Size;
};
struct TypeDef
{
uint32_t Size = 0;
uint32_t Hash = 0;
char Name[64]{"Dummy"};
uint16_t ChildCount = 0;
uint16_t ChildIndices[64]{0};
uint16_t ChildArraySizes[64]{0};
StrRef MemberNameIndices[64]{0};
};
struct MetadataTable
{
TypeDef TypeDefinitions[%u]
{
)END";
// TODO: Sizeof is wrong!! we don't use padding!!
constexpr char MetadataTypeEntry7[] = R"END( TypeDef{sizeof(%s), %u, "%s", %u, {%s}, {%s}, {%s}},
)END";
constexpr char MetadataEnd1[] = R"END( };
char MemberNameBuffer[64*64*64]{"%s"};
};
constexpr MetadataTable Metadata;
}
)END"; )END";
} // namespace WriteTemplates } // namespace WriteTemplates
@@ -164,30 +318,34 @@ void CppFileWriter::WriteInternal(WriteBuffer& buf, const char* templateStr, va_
buf.WrittenBytes += bx::vsnprintf(&buf.Data[buf.WrittenBytes], BufferRequestSize, templateStr, args); buf.WrittenBytes += bx::vsnprintf(&buf.Data[buf.WrittenBytes], BufferRequestSize, templateStr, args);
} }
void CppFileWriter::PrintTypeName(char* buf, void CppFileWriter::PrintTypeName(
int32_t bufSize, char* buf, int32_t bufSize, Def::TypeRef type, const Def::DefinitionFile& definitions, PrintFlags flags)
const Def::FieldType& type,
const Def::DefinitionFile& definitions)
{ {
if (type.FieldKind == Def::EFieldType::Native) if (buf == nullptr || bufSize == 0 || !IsValid(type))
{ {
if (int32_t(type.Native) < Gen::KnownType::EntryCount) LOG_ERROR(0, "Invalid PrintTypeName call!");
return;
}
if (type.FieldKind == Def::EFieldType::DefinedClass)
{
auto& t = definitions.Types[type.TypeIdx];
if (((uint32_t)t.TypeFlags & (uint32_t)Def::ETypeFlags::IsNative) &&
((uint32_t)flags & (uint32_t)PrintFlags::PrintNativeTypeName))
{ {
bx::strCopy(buf, bufSize, Gen::KnownType::CName[size_t(type.Native)]); bx::strCopy(buf, bufSize, t.NativeCName);
} }
else else
{ {
LOG_ERROR(0, "Unknown native type index: %u", type.Native); bx::strCopy(buf, bufSize, t.Name);
} }
} }
else if (type.FieldKind == Def::EFieldType::DefinedClass)
{
bx::strCopy(buf, bufSize, definitions.Types[type.TypeIdx].Name);
}
else if (type.FieldKind == Def::EFieldType::DefinedEnum) else if (type.FieldKind == Def::EFieldType::DefinedEnum)
{ {
bx::strCopy(buf, bufSize, definitions.Enums[type.TypeIdx].Name); bx::strCopy(buf, bufSize, definitions.Enums[type.TypeIdx].Name);
bx::strCat(buf, bufSize, "::Enum"); if ((int32_t)flags & (int32_t)PrintFlags::PrintFullEnumName)
{
bx::strCat(buf, bufSize, "::Enum");
}
} }
} }
@@ -196,15 +354,32 @@ 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;
Write(WriteTemplates::EnumHeader4, if (!IsValid(e.EnumType))
e.Name, {
e.EntryCount, LOG_ERROR(0, "Invalid enum type (enum %i)", enumIdx);
e.Hash, continue;
Gen::KnownType::CName[(int32_t)e.EnumType.Native]); }
char enumTypeNameBuf[Def::MaxNameLength]{0};
PrintTypeName(enumTypeNameBuf, sizeof(enumTypeNameBuf), e.EnumType, definitions);
Write(WriteTemplates::EnumHeader4, e.Name, definitions.TypeCount + enumIdx, e.EntryCount, enumTypeNameBuf);
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx) for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx)
{ {
Write(WriteTemplates::EnumField1, e.EntryNames[entryIdx]); if (isFlagsEnum)
{
char numBuf[64] = "0";
if (entryIdx > 0)
{
bx::snprintf(numBuf, sizeof(numBuf), "1 << %u", entryIdx - 1);
}
Write(WriteTemplates::EnumFieldNumbered2, e.EntryNames[entryIdx], numBuf);
}
else
{
Write(WriteTemplates::EnumField1, e.EntryNames[entryIdx]);
}
} }
Write(WriteTemplates::EnumNamesStart2, "EntryNames", Def::MaxNameLength); Write(WriteTemplates::EnumNamesStart2, "EntryNames", Def::MaxNameLength);
@@ -223,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)
@@ -230,15 +422,16 @@ void CppFileWriter::WriteTypes(const Def::DefinitionFile& definitions)
for (int32_t typeIdx = 0; typeIdx < definitions.TypeCount; ++typeIdx) for (int32_t typeIdx = 0; typeIdx < definitions.TypeCount; ++typeIdx)
{ {
const Def::Type& t = definitions.Types[typeIdx]; const Def::Type& t = definitions.Types[typeIdx];
if ((uint32_t)t.TypeFlags & (uint32_t)Def::ETypeFlags::IsNative) continue;
Write(WriteTemplates::StructHeader2, t.Name, t.Hash); Write(WriteTemplates::StructHeader2, t.Name, typeIdx);
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx) for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
{ {
char Type[64]{0}; char Type[64]{0};
PrintTypeName(Type, sizeof(Type), t.FieldTypes[fieldIdx], definitions); PrintTypeName(Type, sizeof(Type), t.FieldTypes[fieldIdx], definitions);
char Array[32]{0}; char Array[32]{0};
uint32_t ArraySize = t.FieldArraySizes[fieldIdx]; uint32_t ArraySize = t.FieldArraySizes[fieldIdx];
if (ArraySize > 0) if (ArraySize > 0 && ArraySize != UINT32_MAX)
{ {
bx::snprintf(Array, sizeof(Array), "[%u]", ArraySize); bx::snprintf(Array, sizeof(Array), "[%u]", ArraySize);
} }
@@ -254,6 +447,11 @@ void CppFileWriter::WriteSaveLoadMethods(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];
if (!IsValid(e.EnumType))
{
LOG_ERROR(0, "Invalid enum!");
continue;
}
bx::snprintf(nameBuf, sizeof(nameBuf), "%s::Enum", e.Name); bx::snprintf(nameBuf, sizeof(nameBuf), "%s::Enum", e.Name);
PrintTypeName(fieldBuf, sizeof(fieldBuf), e.EnumType, definitions); PrintTypeName(fieldBuf, sizeof(fieldBuf), e.EnumType, definitions);
@@ -266,35 +464,143 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions)
WriteCpp(WriteTemplates::LoadFuncBodyStart1, nameBuf); WriteCpp(WriteTemplates::LoadFuncBodyStart1, nameBuf);
WriteCpp(WriteTemplates::LoadFuncBodyEnum2, fieldBuf, fieldBuf); WriteCpp(WriteTemplates::LoadFuncBodyEnum2, fieldBuf, fieldBuf);
WriteCpp(WriteTemplates::LoadFuncBodyEnd);
} }
for (int32_t typeIdx = 0; typeIdx < definitions.TypeCount; ++typeIdx) for (uint16_t typeIdx = 0; typeIdx < definitions.TypeCount; ++typeIdx)
{ {
const Def::Type& t = definitions.Types[typeIdx]; const Def::Type& t = definitions.Types[typeIdx];
Write(WriteTemplates::SaveFuncHeader1, t.Name); char typeName[Def::MaxNameLength]{0};
Write(WriteTemplates::LoadFuncHeader1, t.Name); PrintTypeName(typeName, sizeof(typeName), {typeIdx, Def::EFieldType::DefinedClass}, definitions);
WriteCpp(WriteTemplates::SaveFuncBodyStart1, t.Name); Write(WriteTemplates::SaveFuncHeader1, typeName);
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx) Write(WriteTemplates::LoadFuncHeader1, typeName);
WriteCpp(WriteTemplates::SaveFuncBodyStart1, typeName);
if ((int32_t)t.TypeFlags & (int32_t)Def::ETypeFlags::IsNative)
{ {
WriteCpp(WriteTemplates::SaveFuncBodyType3, WriteCpp(WriteTemplates::SaveFuncBodyNative);
t.FieldArraySizes[fieldIdx] > 0 ? "" : "&", }
t.FieldNames[fieldIdx], else
bx::max(1, t.FieldArraySizes[fieldIdx])); {
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
{
WriteCpp(WriteTemplates::SaveFuncBodyType3,
t.FieldArraySizes[fieldIdx] > 0 ? "" : "&",
t.FieldNames[fieldIdx],
bx::max(1, t.FieldArraySizes[fieldIdx]));
}
} }
WriteCpp(WriteTemplates::SaveFuncBodyEnd); WriteCpp(WriteTemplates::SaveFuncBodyEnd);
WriteCpp(WriteTemplates::LoadFuncBodyStart1, t.Name); WriteCpp(WriteTemplates::LoadFuncBodyStart1, typeName);
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx) if ((int32_t)t.TypeFlags & (int32_t)Def::ETypeFlags::IsNative)
{ {
WriteCpp(WriteTemplates::LoadFuncBodyType3, WriteCpp(WriteTemplates::LoadFuncBodyNative);
t.FieldArraySizes[fieldIdx] > 0 ? "" : "&", }
t.FieldNames[fieldIdx], else
bx::max(1, t.FieldArraySizes[fieldIdx])); {
WriteCpp(WriteTemplates::LoadFuncBodySetupStart2, typeName, typeName);
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
{
WriteCpp(WriteTemplates::LoadFuncBodyQuickLoad2,
t.FieldArraySizes[fieldIdx] > 0 ? "" : "&",
t.FieldNames[fieldIdx],
bx::max(1, t.FieldArraySizes[fieldIdx]));
}
WriteCpp(WriteTemplates::LoadFuncBodySetupEnd);
char fieldTypeName[Def::MaxNameLength]{0};
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
{
const char* fieldName = t.FieldNames[fieldIdx];
// This prints native type name, seems wrong??
// Havent i already fixed this???
PrintTypeName(
fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions, PrintFlags::None);
WriteCpp(WriteTemplates::LoadFuncBodyMemberCheck4, fieldName, fieldTypeName, typeName, fieldName);
}
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeStart);
for (uint32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
{
const char* fieldName = t.FieldNames[fieldIdx];
PrintTypeName(fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions);
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeMember3,
fieldName,
fieldTypeName,
bx::max(1, t.FieldArraySizes[fieldIdx]));
}
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeEnd);
} }
WriteCpp(WriteTemplates::LoadFuncBodyEnd);
} }
} }
namespace
{
char MemberNameBuffer[64 * 64 * 64]{0};
}
void CppFileWriter::WriteMetadata(const Def::DefinitionFile& definitions)
{
uint32_t memberNameBufferIdx = 0;
Write(WriteTemplates::MetadataStart1, definitions.TypeCount + definitions.EnumCount);
for (uint16_t i = 0; i < definitions.TypeCount; ++i)
{
auto& type = definitions.Types[i];
char fieldStr[256]{0};
for (int32_t j = 0; j < type.FieldCount; ++j)
{
if (j != 0) bx::strCat(fieldStr, sizeof(fieldStr), ", ");
char numBuf[8]{0};
int32_t idx = type.FieldTypes[j].TypeIdx;
if (type.FieldTypes[j].FieldKind == Def::EFieldType::DefinedEnum) idx += definitions.TypeCount;
bx::snprintf(numBuf, sizeof(numBuf), "%u", idx);
bx::strCat(fieldStr, sizeof(fieldStr), numBuf);
}
char typeStr[Def::MaxNameLength]{0};
PrintTypeName(typeStr, sizeof(typeStr), {i, Def::EFieldType::DefinedClass}, definitions);
char memberIdxStr[256]{0};
for (int32_t j = 0; j < type.FieldCount; ++j)
{
if (j != 0) bx::strCat(memberIdxStr, sizeof(memberIdxStr), ", ");
char numBuf[16]{0};
bx::snprintf(numBuf, sizeof(numBuf), "{%u, %u}", memberNameBufferIdx, bx::strLen(type.FieldNames[j]));
bx::strCat(memberIdxStr, sizeof(memberIdxStr), numBuf);
memberNameBufferIdx += bx::strCopy(&MemberNameBuffer[memberNameBufferIdx],
sizeof(MemberNameBuffer) - memberNameBufferIdx,
type.FieldNames[j]);
}
char arrStr[256]{0};
for (int32_t j = 0; j < type.FieldCount; ++j)
{
if (j != 0) bx::strCat(arrStr, sizeof(arrStr), ", ");
char numBuf[16]{0};
bx::snprintf(numBuf, sizeof(numBuf), "%u", type.FieldArraySizes[j]);
bx::strCat(arrStr, sizeof(arrStr), numBuf);
}
Write(WriteTemplates::MetadataTypeEntry7,
typeStr,
type.Hash,
type.Name,
type.FieldCount,
fieldStr,
arrStr,
memberIdxStr);
}
for (uint16_t i = 0; i < definitions.EnumCount; ++i)
{
auto& enumType = definitions.Enums[i];
char typeStr[Def::MaxNameLength]{0};
PrintTypeName(typeStr, sizeof(typeStr), {i, Def::EFieldType::DefinedEnum}, definitions);
Write(WriteTemplates::MetadataTypeEntry7, typeStr, enumType.Hash, enumType.Name, 0, "", "", "");
}
Write(WriteTemplates::MetadataEnd1, MemberNameBuffer);
}
void CppFileWriter::GenerateCpp(const bx::FilePath& outDir, const Def::DefinitionFile& definitions) void CppFileWriter::GenerateCpp(const bx::FilePath& outDir, const Def::DefinitionFile& definitions)
{ {
LOG(0, "Generating output files..."); LOG(0, "Generating output files...");
@@ -307,6 +613,7 @@ void CppFileWriter::GenerateCpp(const bx::FilePath& outDir, const Def::Definitio
WriteEnums(definitions); WriteEnums(definitions);
WriteTypes(definitions); WriteTypes(definitions);
WriteSaveLoadMethods(definitions); WriteSaveLoadMethods(definitions);
WriteMetadata(definitions);
Write(WriteTemplates::FileEnd); Write(WriteTemplates::FileEnd);
WriteCpp(WriteTemplates::FileEnd); WriteCpp(WriteTemplates::FileEnd);
@@ -334,36 +641,3 @@ void CppFileWriter::WriteCpp(const char* templateStr, ...)
WriteInternal(CppWrite, templateStr, args); WriteInternal(CppWrite, templateStr, args);
va_end(args); va_end(args);
} }
void CppFileWriter::WriteTypeDataFile(const bx::FilePath& outDir, const Def::DefinitionFile& definitions)
{
constexpr const char _4cc[] = "TDAT";
constexpr uint32_t version = 1;
bx::FilePath typeDataFilePath = outDir;
typeDataFilePath.join("TypeData.bin");
bx::Error err;
bx::FileWriter writer;
if (!writer.open(typeDataFilePath, false, &err))
{
LOG_ERROR(0, "Failed to open type data file to write: %s", err.getMessage().getCPtr());
return;
}
uint32_t size = sizeof(definitions);
writer.write(_4cc, 4, &err);
if (!err.isOk())
{
LOG_ERROR(0, "Failed to write type data: %s", err.getMessage().getCPtr());
writer.close();
return;
}
writer.write(&version, sizeof(version), &err);
writer.write(&size, sizeof(size), &err);
writer.write(&definitions, sizeof(definitions), &err);
if (!err.isOk())
{
LOG_ERROR(0, "Failed to write type data: %s", err.getMessage().getCPtr());
}
writer.close();
return;
}

View File

@@ -10,6 +10,13 @@ struct WriteBuffer
uint64_t WrittenBytes = 0; uint64_t WrittenBytes = 0;
}; };
enum class PrintFlags : uint32_t
{
None = 0,
PrintFullEnumName = 1 << 0,
PrintNativeTypeName = 1 << 1,
};
struct CppFileWriter struct CppFileWriter
{ {
private: private:
@@ -21,13 +28,18 @@ struct CppFileWriter
void WriteInternal(WriteBuffer& buf, const char* templateStr, va_list args); void WriteInternal(WriteBuffer& buf, const char* templateStr, va_list args);
public: public:
void PrintTypeName(char* buf, int32_t bufSize, const Def::FieldType& type, const Def::DefinitionFile& definitions); void PrintTypeName(char* buf,
int32_t bufSize,
Def::TypeRef type,
const Def::DefinitionFile& definitions,
PrintFlags flags = (PrintFlags)((uint32_t)PrintFlags::PrintFullEnumName |
(uint32_t)PrintFlags::PrintNativeTypeName));
void WriteEnums(const Def::DefinitionFile& definitions); void WriteEnums(const Def::DefinitionFile& definitions);
void WriteTypes(const Def::DefinitionFile& definitions); void WriteTypes(const Def::DefinitionFile& definitions);
void WriteSaveLoadMethods(const Def::DefinitionFile& definitions); void WriteSaveLoadMethods(const Def::DefinitionFile& definitions);
void WriteMetadata(const Def::DefinitionFile& definitions);
void GenerateCpp(const bx::FilePath& outDir, const Def::DefinitionFile& definitions); void GenerateCpp(const bx::FilePath& outDir, const Def::DefinitionFile& definitions);
void Write(const char* templateStr, ...); void Write(const char* templateStr, ...);
void WriteCpp(const char* templateStr, ...); void WriteCpp(const char* templateStr, ...);
void WriteTypeDataFile(const bx::FilePath& outDir, const Def::DefinitionFile& definitions);
}; };

View File

@@ -1,41 +0,0 @@
#include "Def.h"
#define INST(T) \
template bool Save<T>(const T* obj, uint32_t count, Serializer& serializer); \
template bool Load<T>(T * obj, uint32_t count, Deserializer & serializer);
namespace Gen
{
template <typename T> bool Save(const T* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
}
return isOk;
}
template <typename T> bool Load(T* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
}
return isOk;
}
INST(uint8_t)
INST(uint16_t)
INST(uint32_t)
INST(uint64_t)
INST(int8_t)
INST(int16_t)
INST(int32_t)
INST(int64_t)
INST(float)
INST(double)
INST(bool)
INST(char)
} // namespace Gen

View File

@@ -1,125 +0,0 @@
#pragma once
#include "../TypeDef.h"
// #include "../game/Log.h"
#include "bx/string.h"
#include <bx/file.h>
#include <cstdint>
#ifndef LOG_ERROR
#define LOG_ERROR(...)
#endif
namespace Gen
{
struct EmbeddedTypeDef
{
uint32_t Size = sizeof(Def::DefinitionFile);
Def::DefinitionFile Data;
};
struct Serializer
{
bx::Error Err;
bx::FilePath Path;
bx::FileWriter Writer;
bool Init(const bx::FilePath& path)
{
Path = path;
Writer.open(path, false, &Err);
return Err.isOk();
}
template <typename T> bool WriteT(const char* _4cc, const T& data)
{
if (!Write(_4cc, 4)) return false;
uint32_t hash = data.Hash;
if (!Write(&hash, sizeof(hash))) return false;
uint32_t size = sizeof(T);
if (!Write(&size, sizeof(size))) return false;
return Save(&data, 1, *this);
}
bool Write(const void* data, uint32_t size)
{
Writer.write(data, size, &Err);
if (!Err.isOk()) LOG_ERROR("Write error: %s", Err.getMessage().getCPtr());
return Err.isOk();
}
void Finish()
{
Writer.close();
}
};
struct Deserializer
{
bx::Error Err;
bx::FilePath Path;
bx::FileReader Reader;
bool Init(const bx::FilePath& path)
{
Path = path;
Reader.open(path, &Err);
return Err.isOk();
}
bool Read(void* data, uint32_t size)
{
Reader.read(data, size, &Err);
if (!Err.isOk()) LOG_ERROR("Read error: %s", Err.getMessage().getCPtr());
return Err.isOk();
}
template <typename T> bool ReadT(const char* _4cc, T& data)
{
char magic[5]{0};
if (!Read(magic, 4)) return false;
bx::StringView given{_4cc, 4};
bx::StringView loaded{magic, 4};
if (bx::strCmp(given, loaded) != 0)
{
LOG_ERROR("Magic mismatch! %s != %s", _4cc, magic);
return false;
}
uint32_t hash = 0;
if (!Read(&hash, sizeof(hash))) return false;
if (data.Hash != hash)
{
LOG_ERROR("Hash mismatch! %u != %u", data.Hash, hash);
return false;
}
uint32_t size = 0;
if (!Read(&size, sizeof(size))) return false;
if (sizeof(T) != size)
{
LOG_ERROR("Size mismatch! %u != %u", sizeof(T), size);
return false;
}
if (!Load(&data, 1, *this))
{
LOG_ERROR("Failed to load: %s", Err.getMessage().getCPtr());
return false;
}
return true;
}
void Finish()
{
Reader.close();
}
};
template <typename T> bool Save(const T* obj, uint32_t count, Serializer& serializer);
template <typename T> bool Load(T* obj, uint32_t count, Deserializer& serializer);
} // namespace Gen

View File

@@ -8,7 +8,7 @@ namespace Gen
bool isOk = true; bool isOk = true;
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i)
{ {
auto val = (int32_t)obj[i]; auto val = (uint8_t)obj[i];
isOk = Save(&val, 1, serializer) && isOk; isOk = Save(&val, 1, serializer) && isOk;
} }
return isOk; return isOk;
@@ -18,17 +18,209 @@ namespace Gen
bool isOk = true; bool isOk = true;
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i)
{ {
int32_t& val = (int32_t&)obj[i]; uint8_t& val = (uint8_t&)obj[i];
isOk = Load(&val, 1, serializer) && isOk; isOk = Load(&val, 1, serializer) && isOk;
} }
return isOk; return isOk;
} }
bool Save(const int8_t* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(int8_t* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const int16_t* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(int16_t* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const int32_t* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(int32_t* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const int64_t* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(int64_t* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const uint8_t* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(uint8_t* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const uint16_t* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(uint16_t* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const uint32_t* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(uint32_t* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const uint64_t* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(uint64_t* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const bool* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(bool* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const float* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(float* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const double* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(double* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const char* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Load(char* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
}
return isOk;
}
bool Save(const Test* obj, uint32_t count, Serializer& serializer) bool Save(const Test* obj, uint32_t count, Serializer& serializer)
{ {
bool isOk = true; bool isOk = true;
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i)
{ {
isOk = Save(&obj[i].Number, 1, serializer) && isOk; isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
} }
return isOk; return isOk;
} }
@@ -37,7 +229,7 @@ namespace Gen
bool isOk = true; bool isOk = true;
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i)
{ {
isOk = Load(&obj[i].Number, 1, serializer) && isOk; isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
} }
return isOk; return isOk;
} }
@@ -46,9 +238,9 @@ namespace Gen
bool isOk = true; bool isOk = true;
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i)
{ {
isOk = Save(&obj[i].Width, 1, serializer) && isOk; isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
isOk = Save(&obj[i].Height, 1, serializer) && isOk; isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
isOk = Save(obj[i].StrTest, 3, serializer) && isOk; isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
isOk = Save(&obj[i].T, 1, serializer) && isOk; isOk = Save(&obj[i].T, 1, serializer) && isOk;
} }
return isOk; return isOk;
@@ -58,9 +250,9 @@ namespace Gen
bool isOk = true; bool isOk = true;
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i)
{ {
isOk = Load(&obj[i].Width, 1, serializer) && isOk; isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
isOk = Load(&obj[i].Height, 1, serializer) && isOk; isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
isOk = Load(obj[i].StrTest, 3, serializer) && isOk; isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
isOk = Load(&obj[i].T, 1, serializer) && isOk; isOk = Load(&obj[i].T, 1, serializer) && isOk;
} }
return isOk; return isOk;

View File

@@ -7,9 +7,9 @@ namespace Gen
struct Deserializer; struct Deserializer;
struct KnownType struct KnownType
{ {
static constexpr uint16_t EnumIdx = 0;
static constexpr int32_t EntryCount = 12; static constexpr int32_t EntryCount = 12;
static constexpr uint32_t Hash = 2024002654; enum Enum : uint8_t
enum Enum : int32_t
{ {
i8, i8,
i16, i16,
@@ -57,12 +57,12 @@ namespace Gen
}; };
struct Test struct Test
{ {
static constexpr uint32_t Hash = 273256278; static constexpr uint16_t TypeIdx = 12;
uint32_t Number = {}; uint32_t Number = {};
}; };
struct Texture struct Texture
{ {
static constexpr uint32_t Hash = 992460010; static constexpr uint16_t TypeIdx = 13;
uint32_t Width = {}; uint32_t Width = {};
uint32_t Height = {}; uint32_t Height = {};
char StrTest[3] = {}; char StrTest[3] = {};
@@ -70,8 +70,76 @@ namespace Gen
}; };
bool Save(const KnownType::Enum* obj, uint32_t count, Serializer& serializer); bool Save(const KnownType::Enum* obj, uint32_t count, Serializer& serializer);
bool Load(KnownType::Enum* obj, uint32_t count, Deserializer& serializer); bool Load(KnownType::Enum* obj, uint32_t count, Deserializer& serializer);
bool Save(const int8_t* obj, uint32_t count, Serializer& serializer);
bool Load(int8_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const int16_t* obj, uint32_t count, Serializer& serializer);
bool Load(int16_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const int32_t* obj, uint32_t count, Serializer& serializer);
bool Load(int32_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const int64_t* obj, uint32_t count, Serializer& serializer);
bool Load(int64_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const uint8_t* obj, uint32_t count, Serializer& serializer);
bool Load(uint8_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const uint16_t* obj, uint32_t count, Serializer& serializer);
bool Load(uint16_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const uint32_t* obj, uint32_t count, Serializer& serializer);
bool Load(uint32_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const uint64_t* obj, uint32_t count, Serializer& serializer);
bool Load(uint64_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const bool* obj, uint32_t count, Serializer& serializer);
bool Load(bool* obj, uint32_t count, Deserializer& serializer);
bool Save(const float* obj, uint32_t count, Serializer& serializer);
bool Load(float* obj, uint32_t count, Deserializer& serializer);
bool Save(const double* obj, uint32_t count, Serializer& serializer);
bool Load(double* obj, uint32_t count, Deserializer& serializer);
bool Save(const char* obj, uint32_t count, Serializer& serializer);
bool Load(char* obj, uint32_t count, Deserializer& serializer);
bool Save(const Test* obj, uint32_t count, Serializer& serializer); bool Save(const Test* obj, uint32_t count, Serializer& serializer);
bool Load(Test* obj, uint32_t count, Deserializer& serializer); bool Load(Test* obj, uint32_t count, Deserializer& serializer);
bool Save(const Texture* obj, uint32_t count, Serializer& serializer); bool Save(const Texture* obj, uint32_t count, Serializer& serializer);
bool Load(Texture* obj, uint32_t count, Deserializer& serializer); bool Load(Texture* obj, uint32_t count, Deserializer& serializer);
namespace Meta {
struct TypeDef
{
uint32_t Size = 0;
uint32_t Hash = 0;
char Name[64]{"Dummy"};
uint16_t ChildCount = 0;
uint16_t ChildIndices[64]{0};
};
struct EnumDef
{
uint32_t Size = 0;
uint32_t Hash = 0;
};
struct MetadataTable
{
TypeDef TypeDefinitions[14]
{
TypeDef{sizeof(int8_t), 0, "i8", 0, {}},
TypeDef{sizeof(int16_t), 1, "i16", 0, {}},
TypeDef{sizeof(int32_t), 2, "i32", 0, {}},
TypeDef{sizeof(int64_t), 3, "i64", 0, {}},
TypeDef{sizeof(uint8_t), 4, "u8", 0, {}},
TypeDef{sizeof(uint16_t), 5, "u16", 0, {}},
TypeDef{sizeof(uint32_t), 6, "u32", 0, {}},
TypeDef{sizeof(uint64_t), 7, "u64", 0, {}},
TypeDef{sizeof(bool), 8, "b", 0, {}},
TypeDef{sizeof(float), 9, "f32", 0, {}},
TypeDef{sizeof(double), 10, "f64", 0, {}},
TypeDef{sizeof(char), 11, "str", 0, {}},
TypeDef{sizeof(Test), 273256278, "Test", 1, {6}},
TypeDef{sizeof(Texture), 992460010, "Texture", 4, {6, 6, 11, 12}},
};
EnumDef EnumDefinitions[1]
{
EnumDef{sizeof(KnownType::Enum), 2983807453},
};
};
constexpr MetadataTable Metadata;
}
} }

View File

@@ -2,8 +2,8 @@
#include "Gen/Generated.h" #include "Gen/Generated.h"
#include "Logging.h" #include "Logging.h"
#include "MiniDef.h" #include "MiniDef.h"
#include "TypeDef.h" #include "TypeDef.h"
#include "bx/hash.h" #include "bx/hash.h"
#include "bx/string.h" #include "bx/string.h"
#include <bx/filepath.h> #include <bx/filepath.h>
@@ -114,6 +114,8 @@ Parser::Result Parser::Parse()
{ {
ReadPtr = &Buffer[0]; ReadPtr = &Buffer[0];
Parser::Result Res = Parser::OK; Parser::Result Res = Parser::OK;
CHECK(LoadNativeTypes());
while (Res == Parser::OK) while (Res == Parser::OK)
{ {
Res = SkipWhitespace(); Res = SkipWhitespace();
@@ -136,6 +138,7 @@ Parser::Result Parser::Parse()
Parser::Result Parser::HandleFileStart() Parser::Result Parser::HandleFileStart()
{ {
Result Res = OK; Result Res = OK;
if (CmpAdvance("type", Res, true) && Res == OK) if (CmpAdvance("type", Res, true) && Res == OK)
{ {
return HandleType(); return HandleType();
@@ -152,6 +155,20 @@ Parser::Result Parser::HandleFileStart()
return Error; return Error;
} }
Parser::Result Parser::LoadNativeTypes()
{
for (int32_t i = 0; i < Gen::KnownType::EntryCount; ++i)
{
auto& t = Definitions.Types[i];
t.Hash = i; // TODO!
bx::strCopy(t.Name, sizeof(t.Name), Gen::KnownType::EntryNames[i]);
bx::strCopy(t.NativeCName, sizeof(t.NativeCName), Gen::KnownType::CName[i]);
t.TypeFlags = Def::ETypeFlags::IsNative;
++Definitions.TypeCount;
}
return OK;
}
Parser::Result Parser::HandleType() Parser::Result Parser::HandleType()
{ {
Result Res = OK; Result Res = OK;
@@ -200,6 +217,13 @@ Parser::Result Parser::HandleType()
CHECK(ReadUint(t.FieldArraySizes[t.FieldCount])); CHECK(ReadUint(t.FieldArraySizes[t.FieldCount]));
CHECK(ExpectChar(")")); CHECK(ExpectChar(")"));
} }
else if (CmpAdvance("ArrDynamic", Res, true) && Res == Result::OK)
{
CHECK(ExpectChar("("));
CHECK(ReadUint(t.FieldArraySizes[t.FieldCount]));
t.FieldFlags[t.FieldCount] = Def::ETypeFieldFlags::DynamicArray;
CHECK(ExpectChar(")"));
}
else if (CmpAdvance("Default", Res, true) && Res == OK) else if (CmpAdvance("Default", Res, true) && Res == OK)
{ {
CHECK(ExpectChar("(")); CHECK(ExpectChar("("));
@@ -249,12 +273,21 @@ Parser::Result Parser::HandleEnum()
if (CmpAdvance("(", Res) && Res == OK) if (CmpAdvance("(", Res) && Res == OK)
{ {
CHECK(SkipWhitespace()); CHECK(SkipWhitespace());
Def::FieldType field; CHECK(ReadDefinedFieldType(e.EnumType));
CHECK(ReadNativeFieldType(field));
CHECK(SkipWhitespace()); CHECK(SkipWhitespace());
CHECK(ExpectChar(")")); CHECK(ExpectChar(")"));
CHECK(SkipWhitespace()); CHECK(SkipWhitespace());
} }
else
{
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());
@@ -338,29 +371,13 @@ Parser::Result Parser::ReadTypeToken()
{ {
Result Res = OK; Result Res = OK;
Def::Type& t = Definitions.Types[Definitions.TypeCount]; Def::Type& t = Definitions.Types[Definitions.TypeCount];
if (ReadNativeFieldType(t.FieldTypes[t.FieldCount]) == OK) return OK;
if (ReadDefinedFieldType(t.FieldTypes[t.FieldCount]) == OK) return OK; if (ReadDefinedFieldType(t.FieldTypes[t.FieldCount]) == OK) return OK;
LOG_ERROR(Line, "Unknown type token!"); LOG_ERROR(Line, "Unknown type token!");
ErrorLine(); ErrorLine();
return Error; return Error;
} }
Parser::Result Parser::ReadNativeFieldType(Def::FieldType& FieldT) Parser::Result Parser::ReadDefinedFieldType(Def::TypeRef& FieldT)
{
Result Res = OK;
for (int32_t i = 0; i < Gen::KnownType::EntryCount; ++i)
{
if (CmpAdvance(Gen::KnownType::EntryNames[i], Res, true) && Res == OK)
{
FieldT.FieldKind = Def::EFieldType::Native;
FieldT.Native = Gen::KnownType::Enum(i);
return OK;
}
}
return Error;
}
Parser::Result Parser::ReadDefinedFieldType(Def::FieldType& FieldT)
{ {
Result Res = OK; Result Res = OK;
for (uint16_t i = 0; i < Definitions.TypeCount; ++i) for (uint16_t i = 0; i < Definitions.TypeCount; ++i)
@@ -437,11 +454,7 @@ uint32_t Parser::CalculateTypeHash(const Def::Type& t)
hash.add(t.FieldArraySizes[i]); hash.add(t.FieldArraySizes[i]);
Def::EFieldType fieldType = t.FieldTypes[i].FieldKind; Def::EFieldType fieldType = t.FieldTypes[i].FieldKind;
if (fieldType == Def::EFieldType::Native) if (fieldType == Def::EFieldType::DefinedClass)
{
hash.add(t.FieldTypes[i].Native);
}
else if (fieldType == Def::EFieldType::DefinedClass)
{ {
Def::Type& dependType = Definitions.Types[t.FieldTypes[i].TypeIdx]; Def::Type& dependType = Definitions.Types[t.FieldTypes[i].TypeIdx];
if (dependType.Hash == 0) if (dependType.Hash == 0)
@@ -456,7 +469,7 @@ uint32_t Parser::CalculateTypeHash(const Def::Type& t)
} }
else else
{ {
LOG_ERROR(0, "TODO!"); LOG_ERROR(Line, "TODO!");
} }
} }
return hash.end(); return hash.end();
@@ -466,9 +479,14 @@ void Parser::CalculateHashes()
for (int32_t i = 0; i < Definitions.EnumCount; ++i) for (int32_t i = 0; i < Definitions.EnumCount; ++i)
{ {
Def::Enum& e = Definitions.Enums[i]; Def::Enum& e = Definitions.Enums[i];
if (!IsValid(e.EnumType))
{
LOG_ERROR(0, "Invalid enum type at idx %i", i);
continue;
}
bx::HashMurmur2A hash; bx::HashMurmur2A hash;
hash.begin(); hash.begin();
hash.add(e.EnumType.Native); hash.add(Definitions.Types[e.EnumType.TypeIdx].Hash); // TODO: add enum entries?
e.Hash = hash.end(); e.Hash = hash.end();
} }
for (int32_t i = 0; i < Definitions.TypeCount; ++i) for (int32_t i = 0; i < Definitions.TypeCount; ++i)
@@ -519,9 +537,5 @@ int main(int argc, const char** argv)
FileParser.CalculateHashes(); FileParser.CalculateHashes();
Writer.GenerateCpp(outPath, FileParser.Definitions); Writer.GenerateCpp(outPath, FileParser.Definitions);
LOG(0, "Writing type data file");
Writer.WriteTypeDataFile(outPath, FileParser.Definitions);
LOG(0, "Finished writing type data file!");
return 0; return 0;
} }

View File

@@ -86,12 +86,12 @@ class Parser
Result ExpectChar(bx::StringView expect); Result ExpectChar(bx::StringView expect);
Result Advance(int32_t Amount); Result Advance(int32_t Amount);
Result HandleFileStart(); Result HandleFileStart();
Result LoadNativeTypes();
Result HandleType(); Result HandleType();
Result HandleEnum(); Result HandleEnum();
Result ReadName(char* Target); Result ReadName(char* Target);
Result ReadUint(uint32_t& Out); Result ReadUint(uint32_t& Out);
Result ReadNativeFieldType(Def::FieldType& FieldT); Result ReadDefinedFieldType(Def::TypeRef& FieldT);
Result ReadDefinedFieldType(Def::FieldType& FieldT);
Result ReadTypeToken(); Result ReadTypeToken();
Result ReadOptionalEnumValues(Def::Enum& Enum, int32_t EntryIdx); Result ReadOptionalEnumValues(Def::Enum& Enum, int32_t EntryIdx);

View File

@@ -1,5 +1,4 @@
#pragma once #pragma once
#include "Gen/Generated.h"
#include <cstdint> #include <cstdint>
namespace Def namespace Def
@@ -7,39 +6,65 @@ namespace Def
constexpr int32_t MaxNameLength = 64; constexpr int32_t MaxNameLength = 64;
constexpr int32_t MaxFields = 64; constexpr int32_t MaxFields = 64;
constexpr int32_t MaxExtraEnumFields = 2; constexpr int32_t MaxExtraEnumFields = 2;
enum class EFieldType
enum class EFieldType : uint8_t
{ {
Native,
DefinedClass, DefinedClass,
DefinedEnum DefinedEnum
}; };
struct FieldType
enum class ETypeFlags : uint32_t
{ {
EFieldType FieldKind = EFieldType::Native; None = 0,
Gen::KnownType::Enum Native = Gen::KnownType::Enum::i32; IsNative = 1 << 0,
uint16_t TypeIdx = UINT16_MAX;
}; };
enum class ETypeFieldFlags : uint32_t
{
None = 0,
DynamicArray = 1 << 0,
};
enum class EEnumFlags : uint32_t
{
None = 0,
FlagsEnum = 1,
};
struct TypeRef
{
uint16_t TypeIdx = UINT16_MAX;
EFieldType FieldKind = EFieldType::DefinedClass;
};
inline bool IsValid(TypeRef ref)
{
return ref.TypeIdx != UINT16_MAX;
}
struct Type struct Type
{ {
int32_t FieldCount = 0; int32_t FieldCount = 0;
FieldType FieldTypes[MaxFields]; TypeRef FieldTypes[MaxFields];
char FieldNames[MaxFields][MaxNameLength]; char FieldNames[MaxFields][MaxNameLength];
uint32_t FieldArraySizes[MaxFields]{0}; uint32_t FieldArraySizes[MaxFields]{0};
char FieldValues[MaxFields][128]{0}; char FieldValues[MaxFields][128]{0};
ETypeFlags TypeFlags = ETypeFlags::None;
ETypeFieldFlags FieldFlags[MaxFields]{ETypeFieldFlags::None};
char Name[MaxNameLength]{0}; char Name[MaxNameLength]{0};
char NativeCName[MaxNameLength]{0};
uint32_t Hash = 0; uint32_t Hash = 0;
}; };
struct Enum struct Enum
{ {
FieldType EnumType; TypeRef EnumType;
int32_t EntryCount = 0; int32_t EntryCount = 0;
char EntryNames[MaxFields][MaxNameLength]; char EntryNames[MaxFields][MaxNameLength];
int32_t ExtraStringFieldCount = 0; int32_t ExtraStringFieldCount = 0;
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

@@ -96,16 +96,19 @@ struct SharedDevData
char ShaderLog[2048]{0}; char ShaderLog[2048]{0};
}; };
struct MemoryArena
{
uint8_t* Base = nullptr;
uint64_t Used = 0;
uint64_t MaxSize = 0;
uint64_t LastAllocSize = 0;
};
struct GameData struct GameData
{ {
void* PermanentStorage = nullptr; MemoryArena PermanentArena;
uint64_t PermanentStorageSize = 0; MemoryArena EntityArena;
MemoryArena TransientArena;
void* EntityStorage = nullptr;
uint64_t EntityStorageSize = 0;
void* TransientStorage = nullptr;
uint64_t TransientStorageSize = 0;
}; };
struct SharedData struct SharedData

View File

@@ -23,6 +23,10 @@ constexpr const char* DLLPath = "libPuzGame.dll";
constexpr const wchar_t* DLLWatch = L"libPuzGame2.dll"; constexpr const wchar_t* DLLWatch = L"libPuzGame2.dll";
#endif #endif
constexpr uint64_t KB = 1024LLU;
constexpr uint64_t MB = 1024LLU * 1024LLU;
constexpr uint64_t GB = 1024LLU * 1024LLU * 1024LLU;
namespace namespace
{ {
bx::AllocatorI* defaultAllocator = new bx::DefaultAllocator{}; bx::AllocatorI* defaultAllocator = new bx::DefaultAllocator{};
@@ -260,6 +264,15 @@ bool ReloadDLL()
return true; return true;
} }
void InitMemoryArena(MemoryArena& arena, uint64_t size)
{
arena.MaxSize = size;
arena.Base = reinterpret_cast<uint8_t*>(
VirtualAllocEx(GetCurrentProcess(), NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
arena.Used = 0;
arena.LastAllocSize = 0;
}
int main() int main()
{ {
char PathBuf[512]{0}; char PathBuf[512]{0};
@@ -301,15 +314,9 @@ int main()
HANDLE compiledShaderThread = HANDLE compiledShaderThread =
CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.CompiledShaderWatcher, 0, &fileWatcherThreadId); CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.CompiledShaderWatcher, 0, &fileWatcherThreadId);
Shared.Game.PermanentStorageSize = 1024 * 1024; InitMemoryArena(Shared.Game.PermanentArena, MB);
Shared.Game.PermanentStorage = VirtualAllocEx( InitMemoryArena(Shared.Game.EntityArena, MB);
GetCurrentProcess(), NULL, Shared.Game.PermanentStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); InitMemoryArena(Shared.Game.TransientArena, 2 * GB);
Shared.Game.EntityStorageSize = 1024 * 1024;
Shared.Game.EntityStorage = VirtualAllocEx(
GetCurrentProcess(), NULL, Shared.Game.EntityStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Shared.Game.TransientStorageSize = 1024 * 1024 * 1024;
Shared.Game.TransientStorage = VirtualAllocEx(
GetCurrentProcess(), NULL, Shared.Game.TransientStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
StartupFunc(Shared); StartupFunc(Shared);
bool isRunning = true; bool isRunning = true;

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

@@ -0,0 +1,158 @@
#pragma once
#include "../gen/Generated.h"
#include "Log.h"
#include "Puzzle.h" // TODO: remove
#include "bgfx/bgfx.h"
#include "rendering/Rendering.h"
#include <cstdint>
#include <typeinfo>
#define ENTITY_HANDLE(X) \
struct X \
{ \
uint16_t Idx = UINT16_MAX; \
}; \
inline bool IsValid(X h) \
{ \
return h.Idx != UINT16_MAX; \
}
namespace Game
{
int32_t GetNextRenderID();
struct EntityRenderData
{
Gen::Vec4 DotColor{1.0f, 1.0f, 1.0f, 1.0f};
Gen::Vec4 BaseColor{0.0f, 0.0f, 0.0f, 1.0f};
Gen::Transform Transform;
Gen::EMaterial::Enum MaterialHandle = Gen::EMaterial::UI;
Gen::TextureHandle TextureHandle;
Gen::ModelHandle ModelH;
bool Visible = true;
int32_t RenderID = 0;
void Render(const Model* models, const Material* materials, const Texture* textures);
void LoadFromSaved(const Gen::SavedEntityRenderData& saved);
};
ENTITY_HANDLE(CubeHandle);
struct Cube
{
int32_t TestX = -1;
int32_t TestY = -1;
EntityRenderData EData;
void Setup();
void Update();
};
ENTITY_HANDLE(TestEntityHandle);
struct TestEntity
{
EntityRenderData EData;
void Setup();
};
ENTITY_HANDLE(PuzzleTileEntityHandle);
struct PuzzleTileEntity
{
EntityRenderData EData;
};
ENTITY_HANDLE(PuzzleTileCoverHandle);
struct PuzzleTileCover
{
EntityRenderData EData;
};
ENTITY_HANDLE(UIQuadEntityHandle);
struct UIQuadEntity
{
EntityRenderData EData;
Gen::Vec3 UIPos;
float UIRot = 0.0f;
};
ENTITY_HANDLE(LevelEntityHandle);
struct LevelEntity
{
EntityRenderData EData;
};
class IEntityManager
{
public:
virtual bool Setup(uint8_t*& ptr, bool forceReset) = 0;
};
template <typename T, typename HandleT, uint32_t C> class EntityManager : public IEntityManager
{
public:
uint16_t Count = 0;
T* Data = nullptr;
uint32_t EntitySize = 0;
T InvalidObject{};
bool IsEnabled = true;
public:
// Returns true if size changed
bool Setup(uint8_t*& ptr, bool forceReset)
{
bool changed = false;
if (EntitySize != sizeof(T) || forceReset)
{
Count = 0;
changed = true;
}
EntitySize = sizeof(T);
Data = reinterpret_cast<T*>(ptr);
ptr += C * EntitySize;
return changed;
}
HandleT New()
{
if (Data == nullptr)
{
ERROR_ONCE("Accessed EntityManager before setup!");
return {};
}
if (Count >= C)
{
ERROR_ONCE("Too many entities!");
return {};
}
Data[Count] = {};
Data[Count].EData.RenderID = GetNextRenderID();
HandleT H;
H.Idx = Count;
++Count;
return H;
}
T& Get(HandleT handle)
{
if (handle.Idx >= Count)
{
ERROR_ONCE("OOB Access!");
return InvalidObject;
}
return Data[handle.Idx];
}
void Render(const Model* models, const Material* materials, const Texture* textures)
{
if (!IsEnabled) return;
bgfx::setMarker(typeid(T).name());
for (uint16_t i = 0; i < Count; ++i)
{
Get({i}).EData.Render(models, materials, textures);
}
}
};
typedef EntityManager<UIQuadEntity, UIQuadEntityHandle, Puzzle::Config::MaxTilesInPuzzle * 2> UIQuadEntityManager;
} // namespace Game

View File

@@ -320,6 +320,14 @@ namespace Gen
return mat; return mat;
} }
Mat4 RotationFromQuaternion(const Vec4& quaternion)
{
Mat4 mat;
bx::Quaternion quat{quaternion.x, quaternion.y, quaternion.z, quaternion.w};
bx::mtxFromQuaternion(mat.M, quat);
return mat;
}
float Magnitude(const Vec4& vec) float Magnitude(const Vec4& vec)
{ {
return bx::sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z + vec.w * vec.w); return bx::sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z + vec.w * vec.w);
@@ -385,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

@@ -75,11 +75,13 @@ namespace Gen
Vec3 EulerFromRotation(const Mat4& rotation); Vec3 EulerFromRotation(const Mat4& rotation);
Mat4 RotationFromEuler(const Vec3& euler); Mat4 RotationFromEuler(const Vec3& euler);
Mat4 RotationFromQuaternion(const Vec4& quaternion);
float DotProduct(Vec3 a, Vec3 b); float DotProduct(Vec3 a, Vec3 b);
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

@@ -37,16 +37,36 @@ namespace Game
GameInst = &instance; GameInst = &instance;
} }
void* AllocateScratch(size_t byteCount, size_t align) uint8_t* AllocateScratch(uint64_t byteCount, uint32_t align)
{ {
size_t offset = GetInstance().UsedScratchAmount; assert(align <= 64); // The alignment of the arena limits the alignment that can be specified here!
uint8_t* base = static_cast<uint8_t*>(GetShared().Game.TransientStorage); auto& arena = GetShared().Game.TransientArena;
uint8_t* current = base + offset; uint64_t offsetAligned = ((arena.Used + align - 1) / align) * align;
size_t offsetAligned = ((offset + align - 1) / align) * align; uint8_t* ptrAligned = arena.Base + offsetAligned;
uint8_t* ptrAligned = base + offsetAligned; uint64_t newOffset = offsetAligned + byteCount;
size_t newOffset = offsetAligned + byteCount; if (newOffset > arena.MaxSize) return nullptr;
if (newOffset > GetShared().Game.TransientStorageSize) return nullptr; arena.Used = newOffset;
GetInstance().UsedScratchAmount = newOffset; arena.LastAllocSize = byteCount;
return reinterpret_cast<void*>(ptrAligned); return ptrAligned;
}
bool ResizeLastScratchAlloc(uint64_t newByteCount)
{
auto& arena = GetShared().Game.TransientArena;
if (newByteCount > arena.LastAllocSize)
{
LOG_ERROR("Can't resize to more than previous size!");
return false;
}
arena.Used -= arena.LastAllocSize;
arena.Used += newByteCount;
return true;
}
void ResetScratch()
{
auto& arena = GetShared().Game.TransientArena;
arena.Used = 0;
arena.LastAllocSize = 0;
} }
} // namespace Game } // namespace Game

View File

@@ -33,5 +33,7 @@ namespace Game
void SetShared(SharedData& instance); void SetShared(SharedData& instance);
GameInstance& GetInstance(); GameInstance& GetInstance();
void SetInstance(GameInstance& instance); void SetInstance(GameInstance& instance);
void* AllocateScratch(size_t byteCount, size_t align = 16); uint8_t* AllocateScratch(uint64_t byteCount, uint32_t align = 16);
bool ResizeLastScratchAlloc(uint64_t newByteCount);
void ResetScratch();
} // namespace Game } // namespace Game

View File

@@ -2,6 +2,7 @@
#include "Global.h" #include "Global.h"
#include "Input.h" #include "Input.h"
#include "imgui.h" #include "imgui.h"
#include "imgui_internal.h"
namespace Game namespace Game
{ {
@@ -9,12 +10,14 @@ namespace Game
bool IsKeyboardAllowed() bool IsKeyboardAllowed()
{ {
if (GImGui == nullptr) return true;
auto& IO = ImGui::GetIO(); auto& IO = ImGui::GetIO();
return !IO.WantCaptureKeyboard || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoKeyboard); return !IO.WantCaptureKeyboard || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
} }
bool IsMouseAllowed() bool IsMouseAllowed()
{ {
if (GImGui == nullptr) return true;
auto& IO = ImGui::GetIO(); auto& IO = ImGui::GetIO();
return !IO.WantCaptureMouse || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoMouse); return !IO.WantCaptureMouse || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoMouse);
} }
@@ -60,6 +63,8 @@ namespace Game
} }
Vec2 GetMousePos() Vec2 GetMousePos()
{ {
// TODO: fix this!!
if (GImGui == nullptr) return {};
ImVec2 pos = ImGui::GetMousePos(); ImVec2 pos = ImGui::GetMousePos();
return {pos.x, pos.y}; return {pos.x, pos.y};
} }

View File

@@ -17,6 +17,12 @@ namespace Game
Game, Game,
}; };
enum class InteractionMode
{
Walk,
ReadTablet,
};
struct Time struct Time
{ {
double Now = 0.0; double Now = 0.0;
@@ -26,12 +32,6 @@ namespace Game
int64_t StartTime = 0; int64_t StartTime = 0;
}; };
// TODO: move to generated data and save
struct SavedPlayerConfig
{
Gen::SavedEntityRenderData TabletRenderData;
};
struct PlayerData struct PlayerData
{ {
Gen::Transform PlayerCamTransform; Gen::Transform PlayerCamTransform;
@@ -42,23 +42,26 @@ namespace Game
float FreeflyYRot = 0.0f; float FreeflyYRot = 0.0f;
float WalkXRot = 0.0f; float WalkXRot = 0.0f;
float WalkYRot = 0.0f; float WalkYRot = 0.0f;
CameraMode CameraM = CameraMode::Freefly; CameraMode CameraM = CameraMode::Walk;
InputMode InputM = InputMode::Game; InputMode InputM = InputMode::Game;
InteractionMode InteractionM = InteractionMode::Walk;
float MouseSensitivity = 1.0f; float MouseSensitivity = 1.0f;
float MovementSpeed = 10.0f; float MovementSpeed = 10.0f;
SavedPlayerConfig Config; Gen::SavedPlayerConfig Config;
}; };
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;
@@ -68,7 +71,6 @@ namespace Game
{ {
bool IsInitialized = false; bool IsInitialized = false;
uint64_t Size = sizeof(GameInstance); uint64_t Size = sizeof(GameInstance);
uint64_t UsedScratchAmount = 0;
Time Time; Time Time;
PlayerData Player; PlayerData Player;
Level GameLevel; Level GameLevel;

View File

@@ -6,6 +6,9 @@
#include "Level.h" #include "Level.h"
#include "Log.h" #include "Log.h"
#include "Puzzle.h" #include "Puzzle.h"
#include "UI.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"
@@ -26,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;
@@ -91,25 +101,35 @@ namespace Game
void UpdatePlayerInputMode() void UpdatePlayerInputMode()
{ {
bool IsGaming = GetInstance().Player.InputM == InputMode::Game; bool IsGaming = GetInstance().Player.InputM == InputMode::Game;
SDL_SetWindowRelativeMouseMode(GetShared().Window.SDLWindow, IsGaming); bool captureMouse = IsGaming && GetInstance().Player.InteractionM == InteractionMode::Walk;
auto& IO = ImGui::GetIO(); SDL_SetWindowRelativeMouseMode(GetShared().Window.SDLWindow, captureMouse);
IO.ConfigFlags = FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, IsGaming);
GameRendering::Get().UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug; auto& rendering = GameRendering::Get();
if (rendering.SetupData.UseImgui)
{
auto& IO = ImGui::GetIO();
IO.ConfigFlags =
FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, captureMouse);
}
rendering.UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug;
} }
} // namespace } // namespace
void Level::Setup(GameData& data) void Level::Setup(GameData& data)
{ {
LOG("Level setup"); LOG("Level setup");
void* storagePtr = data.EntityStorage; uint8_t* storagePtr = data.EntityArena.Base;
bool needReset = false; bool needReset = false;
needReset |= Cubes.Setup(storagePtr, needReset); needReset |= Cubes.Setup(storagePtr, needReset);
needReset |= Tests.Setup(storagePtr, needReset); needReset |= Tests.Setup(storagePtr, needReset);
needReset |= PuzzleTiles.Setup(storagePtr, needReset); needReset |= PuzzleTiles.Setup(storagePtr, needReset);
needReset |= PuzzleTileCovers.Setup(storagePtr, needReset);
needReset |= UIQuads.Setup(storagePtr, needReset); needReset |= UIQuads.Setup(storagePtr, needReset);
needReset |= LevelEntities.Setup(storagePtr, needReset); needReset |= LevelEntities.Setup(storagePtr, needReset);
Puzzle::Setup(); Puzzle::Setup();
UIQuads.Count = 0;
PuzzleTiles.Count = 0;
bx::Error err; bx::Error err;
bx::DirectoryReader dirIter; bx::DirectoryReader dirIter;
@@ -168,8 +188,16 @@ 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;
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i) for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
{ {
if (Puzzles[i].Data.ID != UINT16_MAX) if (Puzzles[i].Data.ID != UINT16_MAX)
@@ -177,8 +205,90 @@ namespace Game
Puzzles[i].Setup(); Puzzles[i].Setup();
} }
} }
TabletHandle = UIQuads.New();
PuzzleUI.Setup();
ReloadLevelEntities();
UpdatePlayerInputMode(); 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() void Level::Update()
@@ -232,25 +342,49 @@ 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;
bx::mtxRotateXYZ(player.PlayerCamTransform.Rotation.M, player.WalkXRot, player.WalkYRot, 0.0f); bx::mtxRotateXYZ(player.PlayerCamTransform.Rotation.M, player.WalkXRot, player.WalkYRot, 0.0f);
} }
// UI Tablet if (GetKeyPressedNow(ScanCode::SPACE))
if (IsValid(TabletHandle))
{ {
auto& tablet = UIQuads.Get(TabletHandle); player.InteractionM = player.InteractionM == InteractionMode::ReadTablet ? InteractionMode::Walk
tablet.EData.LoadFromSaved(player.Config.TabletRenderData); : InteractionMode::ReadTablet;
UpdateMatrix(player.PlayerCamTransform); UpdatePlayerInputMode();
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
@@ -260,11 +394,21 @@ namespace Game
} }
// Puzzle tiles // Puzzle tiles
Puzzle::PuzzleSolver solver;
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].Update(); Puzzles[i].Update();
Puzzles[i].IsSolved = solver.IsPuzzleSolved(Puzzles[i].Data);
} }
PuzzleUI.Update(Puzzles[activeIdx].Data, Puzzles[activeIdx].IsSolved);
END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter); END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter);
} }
@@ -300,7 +444,12 @@ namespace Game
Cubes.Render(models, materials, textures); Cubes.Render(models, materials, textures);
Tests.Render(models, materials, textures); Tests.Render(models, materials, textures);
PuzzleTiles.Render(models, materials, textures); PuzzleTiles.Render(models, materials, textures);
UIQuads.Render(models, materials, textures); PuzzleTileCovers.Render(models, materials, textures);
if (player.InteractionM == InteractionMode::ReadTablet)
{
UIQuads.Render(models, materials, textures);
}
LevelEntities.Render(models, materials, textures);
} }
void Cube::Setup() void Cube::Setup()
@@ -324,55 +473,59 @@ 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;
tile.EData.Visible = false;
UIPlacedCards[i] = level.UIQuads.New(); for (int32_t j = 0; j < Puzzle::Config::MaxCoversInTile; ++j)
auto& quad = level.UIQuads.Get(UIPlacedCards[i]); {
quad.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/plane.glb"); int32_t idx = i * Puzzle::Config::MaxCoversInTile + j;
quad.EData.MaterialHandle = EMaterial::UI; CoverHandles[idx] = level.PuzzleTileCovers.New();
quad.EData.Visible = false; 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; 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;
auto& window = GetShared().Window;
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards; auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
auto& visuals = Puzzle::GetStaticPuzzleData().Visuals; auto& visuals = Puzzle::GetStaticPuzzleData().Visuals;
Transform& camTransform = GetInstance().Player.PlayerCamTransform; // Board
UpdateMatrix(camTransform);
Vec3 cameraPos = camTransform.Position;
Transform& boardTransform = level.UIQuads.Get(level.TabletHandle).EData.Transform;
Transform tileOriginTransform = boardTransform;
tileOriginTransform.Position += AxisForward(camTransform.M) * -0.01f;
UpdateMatrix(tileOriginTransform);
Vec2 mousePos = GetMousePos();
mousePos.x = mousePos.x / window.WindowWidth;
mousePos.y = mousePos.y / window.WindowHeight;
mousePos *= 2.0f;
mousePos -= 1.0f;
Vec4 mousePosView = {mousePos.x, -mousePos.y, 0.0f, 1.0f};
Vec4 mousePosCam4 = Mul(GetInstance().Player.ProjectionInverse, mousePosView);
Vec3 mousePosCam = Vec3{
mousePosCam4.x /= mousePosCam4.w,
mousePosCam4.y /= mousePosCam4.w,
mousePosCam4.z /= mousePosCam4.w,
};
Vec3 mousePosWorld = LocalToGlobalPoint(camTransform, mousePosCam);
for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y) for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y)
{ {
for (int8_t x = 0; x < Data.WidthTiles / Puzzle::Config::CardSize; ++x) for (int8_t x = 0; x < Data.WidthTiles / Puzzle::Config::CardSize; ++x)
@@ -380,106 +533,96 @@ namespace Game
int32_t cardIdx = y * Puzzle::Config::MaxPuzzleSizeCards + x; int32_t cardIdx = y * Puzzle::Config::MaxPuzzleSizeCards + x;
Gen::PlacedPuzzleCard& card = Data.PlacedCards[cardIdx]; Gen::PlacedPuzzleCard& card = Data.PlacedCards[cardIdx];
auto& tile = level.PuzzleTiles.Get(TileHandles[cardIdx]); auto& tile = level.PuzzleTiles.Get(TileHandles[cardIdx]);
auto& quad = level.UIQuads.Get(UIPlacedCards[cardIdx]);
bool isValid = Puzzle::IsValid(card.RefCard); bool isValid = Puzzle::IsValid(card.RefCard);
auto& staticCard = isValid ? staticCards[card.RefCard.Idx] : staticCards[0];
// Tile // World Tile
tile.EData.Visible = true; tile.EData.Visible = true;
tile.EData.ModelH = isValid ? staticCards[card.RefCard.Idx].ModelHandle : staticCards[0].ModelHandle; 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);
// Quad // Covers
quad.EData.Visible = isValid; if (IsValid(staticCard.BaseModelHandle))
quad.EData.TextureHandle =
isValid ? staticCards[card.RefCard.Idx].BoardTextureHandle : Gen::TextureHandle{};
quad.EData.DotColor = card.IsLocked ? Puzzle::GetStaticPuzzleData().Visuals.DisabledCardTint
: Vec4{1.0f, 1.0f, 1.0f, 1.0f};
quad.EData.Transform.Position = tileOriginTransform.Position;
quad.EData.Transform.Rotation = camTransform.Rotation;
TranslateLocal(quad.EData.Transform,
Vec3{(float)card.Position.X, (float)card.Position.Y, 0.0f} * UICardOffset *
0.1f); // no clue where the 0.1 comes from
Rotate(quad.EData.Transform, Vec3{bx::kPi * 0.5f, 0.0f, (1.0f - card.Rotation * 0.5f) * bx::kPi});
quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale};
Vec3 quadPosWorld = quad.EData.Transform.Position;
Vec3 quadXWorld = LocalToGlobalPoint(quad.EData.Transform, {1, 0, 0});
Vec3 quadZWorld = LocalToGlobalPoint(quad.EData.Transform, {0, 0, 1});
Vec3 intersectPos;
if (RayPlaneIntersect(
camTransform.Position, mousePosWorld, quadPosWorld, quadXWorld, quadZWorld, intersectPos))
{ {
Vec3 quadSpaceIntersect = GlobalToLocalPoint(quad.EData.Transform, intersectPos); auto& model = GameRendering::Get().Models[staticCard.BaseModelHandle.ModelIdx];
if (isValid && quadSpaceIntersect.x >= -1.0f && quadSpaceIntersect.x <= 1.0f && for (int32_t i = 0; i < model.SocketCount; ++i)
quadSpaceIntersect.z >= -1.0f && quadSpaceIntersect.z <= 1.0f)
{ {
if (!card.IsLocked && DraggedCard.X == -1) auto& cover =
{ level.PuzzleTileCovers.Get(CoverHandles[cardIdx * Puzzle::Config::MaxCoversInTile + i]);
if (GetMouseButtonPressedNow(MouseButton::Left)) cover.EData.Visible = IsActive;
{ cover.EData.ModelH = staticCard.Sockets[i].Model;
DraggedCard.X = x; cover.EData.Transform = tile.EData.Transform;
DraggedCard.Y = y; cover.EData.MaterialHandle = EMaterial::Default;
} cover.EData.BaseColor = {0.2f, 0.1f, 0.7f, 1.0f};
if (GetMouseButtonPressedNow(MouseButton::Right)) cover.EData.DotColor = {0.2f, 0.2f, 0.8f, 1.0f};
{ Gen::TranslateLocal(cover.EData.Transform, model.Sockets[i].Pos);
Puzzle::RotateCard(card); Gen::RotateLocal(cover.EData.Transform, Gen::EulerFromRotation(model.Sockets[i].Rot));
}
}
}
}
if (DraggedCard.X == x && DraggedCard.Y == y)
{
Vec3 dragPos = intersectPos;
dragPos -= AxisForward(camTransform.M) * 0.01f;
quad.EData.Transform.Position = dragPos;
Vec3 boardPos = GlobalToLocalPoint(tileOriginTransform, intersectPos);
Vec3 boardTilePos = boardPos / UICardOffset;
int32_t xPos = (int32_t)bx::round(boardTilePos.x);
int32_t yPos = (int32_t)bx::round(boardTilePos.z);
Gen::PuzPos srcCardPos = {(int8_t)DraggedCard.X, (int8_t)DraggedCard.Y};
Gen::PlacedPuzzleCard& srcCard =
Data.PlacedCards[srcCardPos.Y * Puzzle::Config::MaxPuzzleSizeCards + srcCardPos.X];
if (GetMouseButtonPressedNow(MouseButton::Right))
{
Puzzle::RotateCard(srcCard);
}
if (!GetMouseButton(MouseButton::Left))
{
Gen::PuzPos targetCardPos = {(int8_t)xPos, (int8_t)yPos};
if (xPos >= 0 && xPos < Data.WidthTiles / Puzzle::Config::CardSize && yPos >= 0 &&
yPos < Data.HeightTiles / Puzzle::Config::CardSize)
{
Gen::PlacedPuzzleCard& targetCard =
Data.PlacedCards[yPos * Puzzle::Config::MaxPuzzleSizeCards + xPos];
bool canBeReplaced = !Puzzle::IsValid(targetCard.RefCard) || targetCard.RefCard.Idx == 0;
if (canBeReplaced && Puzzle::ReturnPlacedCard(Data, srcCardPos))
{
Puzzle::DragAvailableCardTo(Data, targetCardPos, 0, srcCard.Rotation);
}
}
DraggedCard.X = -1;
DraggedCard.Y = -1;
} }
} }
} }
} }
// End
for (int32_t i = 0; i < BX_COUNTOF(EndHandles); ++i)
{
auto& tile = level.PuzzleTiles.Get(EndHandles[i]);
if (i < Data.WidthTiles / 2)
{
tile.EData.Visible = true;
tile.EData.ModelH = staticCards[0].BaseModelHandle;
tile.EData.TextureHandle = staticCards[0].ModelTextureHandle;
tile.EData.DotColor = visuals.TileDotColor;
tile.EData.BaseColor = visuals.TileBaseColor + Vec4{0.1f, 0.1f, 0.1f, 0.0f};
tile.EData.Transform.Position = WorldPosition + Vec3{
i * Puzzle::Config::CardScaleWorld,
-5.0f,
(float)Data.HeightTiles / Puzzle::Config::CardSize *
Puzzle::Config::CardScaleWorld,
};
}
else
{
tile.EData.Visible = false;
}
}
auto& wall = level.PuzzleTiles.Get(WallHandle);
wall.EData.Visible = true;
wall.EData.Transform.Position =
WorldPosition + Vec3{0.0f, 0.0f, Data.HeightTiles * 5.0f} + Vec3{30.0f, -5.0f, 0.2f};
auto& door = level.PuzzleTiles.Get(DoorHandle);
door.EData.Visible = !IsSolved;
door.EData.Transform.Position =
WorldPosition + Vec3{0.0f, 0.0f, Data.HeightTiles * 5.0f} + Vec3{30.0f, -5.0f, 0.2f};
}
void Level::ReloadLevelEntities()
{
LevelEntities.Count = 0;
for (int32_t i = 0; i < BX_COUNTOF(BackgroundEntityHandles); ++i)
{
BackgroundEntityHandles[i] = LevelEntities.New();
auto& levelBgEntity = LevelEntities.Get(BackgroundEntityHandles[i]);
levelBgEntity.EData.LoadFromSaved(GetInstance().Player.Config.BackgroundLevelRenderData[i]);
}
}
int32_t GetNextRenderID()
{
static int32_t RenderIDCounter = 0;
RenderIDCounter++;
return RenderIDCounter;
} }
} // namespace Game } // namespace Game

View File

@@ -1,155 +1,29 @@
#pragma once #pragma once
#include "../engine/Shared.h" #include "../engine/Shared.h"
#include "Log.h" #include "Entity.h"
#include "Puzzle.h" #include "Puzzle.h"
#include "UI.h"
#include "rendering/Rendering.h" #include "rendering/Rendering.h"
#include <bgfx/bgfx.h> #include <bgfx/bgfx.h>
#include <cstdint> #include <cstdint>
#define ENTITY_HANDLE(X) \
struct X \
{ \
uint16_t Idx = UINT16_MAX; \
}; \
inline bool IsValid(X h) \
{ \
return h.Idx != UINT16_MAX; \
}
namespace Game namespace Game
{ {
struct EntityRenderData
{
Gen::Vec4 DotColor{1.0f, 1.0f, 1.0f, 1.0f};
Gen::Vec4 BaseColor{0.0f, 0.0f, 0.0f, 1.0f};
Gen::Transform Transform;
Gen::EMaterial::Enum MaterialHandle = Gen::EMaterial::UI;
Gen::TextureHandle TextureHandle;
Gen::ModelHandle ModelH;
bool Visible = true;
void Render(const Model* models, const Material* materials, const Texture* textures);
void LoadFromSaved(const Gen::SavedEntityRenderData& saved);
};
ENTITY_HANDLE(CubeHandle);
struct Cube
{
int32_t TestX = -1;
int32_t TestY = -1;
EntityRenderData EData;
void Setup();
void Update();
};
ENTITY_HANDLE(TestEntityHandle);
struct TestEntity
{
EntityRenderData EData;
void Setup();
};
ENTITY_HANDLE(PuzzleTileEntityHandle);
struct PuzzleTileEntity
{
EntityRenderData EData;
};
ENTITY_HANDLE(UIQuadEntityHandle);
struct UIQuadEntity
{
EntityRenderData EData;
};
ENTITY_HANDLE(LevelEntityHandle);
struct LevelEntity
{
EntityRenderData EData;
};
class IEntityManager
{
public:
virtual bool Setup(void*& ptr, bool forceReset) = 0;
};
template <typename T, typename HandleT, uint32_t C> class EntityManager : public IEntityManager
{
public:
uint16_t Count = 0;
T* Data = nullptr;
uint32_t EntitySize = 0;
T InvalidObject{};
bool IsEnabled = true;
public:
// Returns true if size changed
bool Setup(void*& ptr, bool forceReset)
{
bool changed = false;
if (EntitySize != sizeof(T) || forceReset)
{
Count = 0;
changed = true;
}
EntitySize = sizeof(T);
Data = reinterpret_cast<T*>(ptr);
ptr = (uint8_t*)ptr + (C * EntitySize);
return changed;
}
HandleT New()
{
if (Data == nullptr)
{
ERROR_ONCE("Accessed EntityManager before setup!");
return {};
}
if (Count >= C)
{
ERROR_ONCE("Too many entities!");
return {};
}
Data[Count] = {};
HandleT H;
H.Idx = Count;
++Count;
return H;
}
T& Get(HandleT handle)
{
if (handle.Idx >= Count)
{
ERROR_ONCE("OOB Access!");
return InvalidObject;
}
return Data[handle.Idx];
}
void Render(const Model* models, const Material* materials, const Texture* textures)
{
if (!IsEnabled) return;
for (uint16_t i = 0; i < Count; ++i)
{
Get({i}).EData.Render(models, materials, textures);
}
}
};
struct WorldPuzzle struct WorldPuzzle
{ {
static constexpr Gen::Vec2 WorldCardSize{10.0f, 10.0f}; static constexpr Gen::Vec2 WorldCardSize{10.0f, 10.0f};
static constexpr float UICardOffset = 0.21f;
static constexpr float UICardScale = 0.1f;
Gen::PuzzleData Data; Gen::PuzzleData Data;
Gen::Vec3 WorldPosition; Gen::Vec3 WorldPosition;
PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle]; PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle];
UIQuadEntityHandle UIPlacedCards[Puzzle::Config::MaxCardsInPuzzle]; PuzzleTileCoverHandle CoverHandles[Puzzle::Config::MaxCardsInPuzzle * Puzzle::Config::MaxCoversInTile];
Gen::PuzPos DraggedCard{-1, -1}; PuzzleTileEntityHandle EndHandles[Puzzle::Config::MaxPuzzleSizeCards];
PuzzleTileEntityHandle WallHandle;
PuzzleTileEntityHandle DoorHandle;
bool IsSetup = false; bool IsSetup = false;
bool IsActive = false;
bool IsSolved = false;
void Setup(); void Setup();
void Update(); void Update();
@@ -160,20 +34,23 @@ namespace Game
public: public:
EntityManager<Cube, CubeHandle, 1024> Cubes; EntityManager<Cube, CubeHandle, 1024> Cubes;
EntityManager<TestEntity, TestEntityHandle, 32> Tests; EntityManager<TestEntity, TestEntityHandle, 32> Tests;
EntityManager<PuzzleTileEntity, PuzzleTileEntityHandle, 1024> PuzzleTiles; EntityManager<PuzzleTileEntity, PuzzleTileEntityHandle, Puzzle::Config::MaxTilesTotal> PuzzleTiles;
EntityManager<UIQuadEntity, UIQuadEntityHandle, 1024> UIQuads; EntityManager<PuzzleTileCover, PuzzleTileCoverHandle, Puzzle::Config::MaxCoversTotal> PuzzleTileCovers;
UIQuadEntityManager UIQuads;
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;
WorldPuzzle Puzzles[1]; WorldPuzzle Puzzles[Puzzle::Config::MaxVisiblePuzzles];
WorldPuzzleUI PuzzleUI;
public: public:
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

@@ -17,6 +17,7 @@ namespace
{ {
char LineBuffer[LogInternal::MaxLineSize]{0}; char LineBuffer[LogInternal::MaxLineSize]{0};
char OutBuffer[LogInternal::MaxLineSize]{0}; char OutBuffer[LogInternal::MaxLineSize]{0};
char OutBufferUI[LogInternal::MaxLineSize]{0};
bx::HandleHashMapT<1024> OnceMap; bx::HandleHashMapT<1024> OnceMap;
LogHistory History; LogHistory History;
@@ -36,11 +37,13 @@ void Log(ELogType logType, const char* file, uint32_t line, const char* format,
bx::snprintf(LineBuffer, sizeof(LineBuffer), LineFormat, format); bx::snprintf(LineBuffer, sizeof(LineBuffer), LineFormat, format);
bx::vprintf(LineBuffer, args); bx::vprintf(LineBuffer, args);
bx::vsnprintf(OutBuffer, sizeof(OutBuffer), LineBuffer, args); bx::vsnprintf(OutBuffer, sizeof(OutBuffer), LineBuffer, args);
bx::vsnprintf(OutBufferUI, sizeof(OutBufferUI), format, args);
va_end(args); va_end(args);
OutputDebugStringA(OutBuffer); OutputDebugStringA(OutBuffer);
bx::strCopy(&History.LogBuffer[History.WriteIdx * LogInternal::MaxLineSize], LogInternal::MaxLineSize, OutBuffer); bx::strCopy(&History.LogBuffer[History.WriteIdx * LogInternal::MaxLineSize], LogInternal::MaxLineSize, OutBufferUI);
History.WriteTime[History.WriteIdx] = bx::getHPCounter(); History.WriteTime[History.WriteIdx] = bx::getHPCounter();
History.WriteType[History.WriteIdx] = logType;
bx::strCopy(&History.FileBuffer[History.WriteIdx * LogInternal::MaxLineSize], LogInternal::MaxLineSize, file); bx::strCopy(&History.FileBuffer[History.WriteIdx * LogInternal::MaxLineSize], LogInternal::MaxLineSize, file);
History.LineBuffer[History.WriteIdx] = line; History.LineBuffer[History.WriteIdx] = line;

View File

@@ -40,6 +40,7 @@ struct LogHistory
uint32_t LineBuffer[LogInternal::LogHistorySize]{0}; uint32_t LineBuffer[LogInternal::LogHistorySize]{0};
int32_t WriteIdx = 0; int32_t WriteIdx = 0;
int64_t WriteTime[LogInternal::LogHistorySize]{0}; int64_t WriteTime[LogInternal::LogHistorySize]{0};
ELogType WriteType[LogInternal::LogHistorySize]{ELogType::Log};
}; };
void Log(ELogType logType, const char* file, uint32_t line, const char* format, ...); void Log(ELogType logType, const char* file, uint32_t line, const char* format, ...);

View File

@@ -1,15 +1,19 @@
#include "Gen.h"
#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
@@ -20,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)
@@ -57,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];
@@ -91,7 +96,113 @@ 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)
{
if (bx::strFindI(node.name.c_str(), "_slot_").getLength() > 0)
{
if (mesh.SocketCount >= mesh.MaxSocketCount)
{
LOG_WARN("Too many sockets on mesh!");
break;
}
auto& socket = mesh.Sockets[mesh.SocketCount];
if (node.translation.size() >= 3)
{
socket.Pos.x = node.translation[0];
socket.Pos.y = node.translation[1];
socket.Pos.z = node.translation[2];
}
if (node.rotation.size() >= 4)
{
socket.Rot = Gen::RotationFromQuaternion({static_cast<float>(node.rotation[0]),
static_cast<float>(node.rotation[1]),
static_cast<float>(node.rotation[2]),
static_cast<float>(node.rotation[3])});
}
if (node.matrix.size() >= 0)
{
LOG_WARN("TODO: support matrix!");
}
bx::strCopy(&socket.Name[0], socket.MaxSocketNameLength, node.name.c_str());
++mesh.SocketCount;
}
}
return true; return true;
} }

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);
@@ -173,6 +191,11 @@ namespace Puzzle
bool PuzzleSolver::IsExitSatisfied(const PuzzleData& puzzle, PuzPos pos) bool PuzzleSolver::IsExitSatisfied(const PuzzleData& puzzle, PuzPos pos)
{ {
PuzzleElementType::Enum goalType = GetNodeAt(puzzle, pos); PuzzleElementType::Enum goalType = GetNodeAt(puzzle, pos);
if (goalType == PuzzleElementType::None)
{
WARN_ONCE("TODO!");
return false;
}
uint32_t currentPositionQueueIdx = 0; uint32_t currentPositionQueueIdx = 0;
uint32_t positionQueueCount = 0; uint32_t positionQueueCount = 0;
@@ -235,7 +258,7 @@ namespace Puzzle
return from == PuzzleElementType::ElectricIn || from == PuzzleElementType::ElectricGoal || return from == PuzzleElementType::ElectricIn || from == PuzzleElementType::ElectricGoal ||
from == PuzzleElementType::None; from == PuzzleElementType::None;
} }
assert(false); // assert(false);
return false; return false;
} }
bool PuzzleSolver::IsValidSource(PuzzleElementType::Enum sourceType, PuzzleElementType::Enum goalType) bool PuzzleSolver::IsValidSource(PuzzleElementType::Enum sourceType, PuzzleElementType::Enum goalType)
@@ -283,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;
@@ -325,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))
{ {
@@ -351,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;
@@ -370,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();
@@ -381,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();
@@ -396,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;
@@ -409,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 (!placedCard.IsLocked && IsValid(placedCard.RefCard)) if (!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,
@@ -453,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();
} }
@@ -529,7 +611,6 @@ namespace Puzzle
obj.AvailableCardCount++; obj.AvailableCardCount++;
} }
} }
dataChanged = true;
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
@@ -542,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);
@@ -558,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);
@@ -577,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

@@ -12,16 +12,20 @@ namespace Puzzle
struct Config struct Config
{ {
static constexpr uint32_t MaxVisiblePuzzles = 3;
static constexpr uint32_t CardSize = 2; static constexpr uint32_t CardSize = 2;
static constexpr uint32_t NodesPerCard = CardSize * CardSize; static constexpr uint32_t NodesPerCard = CardSize * CardSize;
static constexpr uint32_t MaxElementsPerTile = 4;
static constexpr uint32_t MaxPuzzleSizeCards = 16; static constexpr uint32_t MaxPuzzleSizeCards = 16;
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 + 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;
static constexpr uint32_t MaxCoversInTile = 8;
static constexpr uint32_t MaxCoversTotal = MaxCoversInTile * MaxTilesTotal;
}; };
void Setup(); void Setup();
@@ -32,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

@@ -33,32 +33,32 @@ namespace Game
tracy::StartupProfiler(); tracy::StartupProfiler();
#endif #endif
if (shared.Game.PermanentStorage == nullptr) if (shared.Game.PermanentArena.Base == nullptr)
{ {
LOG_ERROR("Game memory not initialized!!"); LOG_ERROR("Game memory not initialized!!");
return; return;
} }
if (shared.Game.EntityStorage == nullptr) if (shared.Game.EntityArena.Base == nullptr)
{ {
LOG_ERROR("Entity memory not initialized!"); LOG_ERROR("Entity memory not initialized!");
return; return;
} }
if (shared.Game.PermanentStorageSize < sizeof(GameInstance)) if (shared.Game.PermanentArena.MaxSize < sizeof(GameInstance))
{ {
LOG_ERROR("Game memory too small! %u < %u", shared.Game.PermanentStorageSize, sizeof(GameInstance)); LOG_ERROR("Game memory too small! %u < %u", shared.Game.PermanentArena.MaxSize, sizeof(GameInstance));
return; return;
} }
GameInstance& instance = *reinterpret_cast<GameInstance*>(shared.Game.PermanentStorage); GameInstance& instance = *reinterpret_cast<GameInstance*>(shared.Game.PermanentArena.Base);
if (sizeof(GameInstance) != instance.Size) if (sizeof(GameInstance) != instance.Size)
{ {
LOG_WARN("Game instance size changed, resetting!"); LOG_WARN("Game instance size changed, resetting!");
instance = {}; instance = {};
} }
instance.UsedScratchAmount = 0;
SetShared(shared); SetShared(shared);
SetInstance(instance); SetInstance(instance);
ResetScratch();
Puzzle::LoadStaticPuzzleData(); Puzzle::LoadStaticPuzzleData();
SetupInstance.Rendering.Setup(); SetupInstance.Rendering.Setup({});
instance.GameLevel.Setup(shared.Game); instance.GameLevel.Setup(shared.Game);
instance.IsInitialized = true; instance.IsInitialized = true;
} }

View File

@@ -1,13 +1,17 @@
#include "../gen/Def.h"
#include "Gen.h" #include "Gen.h"
#include "Global.h" #include "Global.h"
#include "Instance.h" #include "Instance.h"
#include "Log.h"
#include "Mesh.h" #include "Mesh.h"
#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/math.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>
@@ -37,6 +41,7 @@ namespace Tools
bool EntityDataSettings(Gen::SavedEntityRenderData& data) bool EntityDataSettings(Gen::SavedEntityRenderData& data)
{ {
ImGui::PushID(&data);
bool changed = false; bool changed = false;
changed |= ModelDropdown(data.Model); changed |= ModelDropdown(data.Model);
changed |= MaterialDropdown(data.Material); changed |= MaterialDropdown(data.Material);
@@ -45,15 +50,16 @@ namespace Tools
changed |= ImGui::Checkbox("Visible", &data.Visible); changed |= ImGui::Checkbox("Visible", &data.Visible);
changed |= ImGui::ColorEdit4("Color 1", &data.BaseColor.x); changed |= ImGui::ColorEdit4("Color 1", &data.BaseColor.x);
changed |= ImGui::ColorEdit4("Color 2", &data.HighlightColor.x); changed |= ImGui::ColorEdit4("Color 2", &data.HighlightColor.x);
ImGui::PopID();
return changed; return changed;
} }
bool ModelDropdown(Gen::ModelHandle& modelHandle) bool ModelDropdown(Gen::ModelHandle& modelHandle, const char* title)
{ {
bool changed = false; bool changed = false;
auto& R = Game::GameRendering::Get(); auto& R = Game::GameRendering::Get();
const char* name = GetAssetPath(modelHandle.Asset); const char* assetName = GetAssetPath(modelHandle.Asset);
if (ImGui::BeginCombo("Model", name)) if (ImGui::BeginCombo(title, assetName))
{ {
for (int32_t i = 0; i < R.ModelCount; ++i) for (int32_t i = 0; i < R.ModelCount; ++i)
{ {
@@ -68,12 +74,12 @@ namespace Tools
return changed; return changed;
} }
bool TextureDropdown(Gen::TextureHandle& texHandle) bool TextureDropdown(Gen::TextureHandle& texHandle, const char* title)
{ {
bool changed = false; bool changed = false;
auto& R = Game::GameRendering::Get(); auto& R = Game::GameRendering::Get();
const char* name = GetAssetPath(texHandle.Asset); const char* name = GetAssetPath(texHandle.Asset);
if (ImGui::BeginCombo("Texture", name)) if (ImGui::BeginCombo(title, name))
{ {
for (int32_t i = 0; i < R.MaxTextures; ++i) for (int32_t i = 0; i < R.MaxTextures; ++i)
{ {
@@ -120,6 +126,50 @@ namespace Tools
return changed; return changed;
} }
constexpr const char* UnitStrings[]{
"b",
"kb",
"mb",
"gb",
};
const char* GetUnitString(uint64_t byteCount, uint64_t& outCount)
{
outCount = byteCount;
int32_t strIdx = 0;
for (int32_t i = 0; i < BX_COUNTOF(UnitStrings); ++i)
{
if (outCount < 1024) break;
++strIdx;
outCount /= 1024;
}
return UnitStrings[strIdx];
}
void ProgressBar(const char* title, uint64_t current, uint64_t max)
{
ImGui::PushID(title);
float percent = static_cast<double>(current) / static_cast<double>(max);
ImVec2 startPos = ImGui::GetCursorScreenPos();
char content[128]{0};
uint64_t currentUnit = 0;
const char* currentUnitStr = GetUnitString(current, currentUnit);
uint64_t maxUnit = 0;
const char* maxUnitStr = GetUnitString(max, maxUnit);
bx::snprintf(content,
sizeof(content),
"%s: %u %s/%u %s (%.2f%%)",
title,
currentUnit,
currentUnitStr,
maxUnit,
maxUnitStr,
percent);
ImGui::Text("%s", content);
ImGui::PopID();
}
bool TransformUI(Gen::Transform& transform) bool TransformUI(Gen::Transform& transform)
{ {
bool changed = false; bool changed = false;
@@ -134,7 +184,74 @@ namespace Tools
return changed; return changed;
} }
void RenderDebugUI(Game::GameRendering& rendering) void RenderLogUI()
{
auto& time = Game::GetInstance().Time;
auto& debug = Game::GetInstance().DebugData;
if (ImGui::Begin("Log"))
{
ImGui::Checkbox("Shorten File Names", &debug.ShortenLogFileNames);
ImGui::BeginTable("tbl",
4,
ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_SizingFixedFit |
ImGuiTableFlags_RowBg);
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_NoResize);
ImGui::TableSetupColumn("Log");
ImGui::TableSetupColumn("Line", ImGuiTableColumnFlags_NoResize);
ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_NoResize);
ImGui::TableHeadersRow();
auto& logs = GetLogHistory();
int32_t lineCount = bx::min(100, LogInternal::LogHistorySize);
for (int32_t i = 0; i < lineCount; ++i)
{
int32_t idx = logs.WriteIdx - i - 1;
if (idx < 0) idx += LogInternal::LogHistorySize;
const char* line = &logs.LogBuffer[idx * LogInternal::MaxLineSize];
if (line[0] != 0)
{
int64_t timeOffset = logs.WriteTime[idx] - time.StartTime;
double writeTime = (double)timeOffset / bx::getHPFrequency();
uint32_t fileLine = logs.LineBuffer[idx];
const char* filePath = &logs.FileBuffer[idx * LogInternal::MaxLineSize];
const char* filePathRes =
debug.ShortenLogFileNames ? bx::FilePath{filePath}.getFileName().getPtr() : filePath;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%.01f", writeTime);
ImGui::TableNextColumn();
ImGui::Text("%s", line);
ImGui::SetItemTooltip("%f\n%s%s:%u", writeTime, line, filePath, fileLine);
ImGui::TableNextColumn();
ImGui::Text("%u", fileLine);
ImGui::TableNextColumn();
ImGui::Text("%s", filePathRes);
if (i > 0) ImGui::PopStyleColor(2);
ImVec4 bgCol = {0.0f, 0.0f, 0.0f, 1.0f};
if (logs.WriteType[idx] == ELogType::Warn)
bgCol = {0.2f, 0.2f, 0.0f, 1.0f};
else if (logs.WriteType[idx] == ELogType::Error)
bgCol = {0.2f, 0.0f, 0.0f, 1.0f};
ImGui::PushStyleColor(ImGuiCol_TableRowBg, bgCol);
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, bgCol);
}
}
ImGui::EndTable();
if (lineCount > 0) ImGui::PopStyleColor(2);
}
ImGui::End();
}
void RenderRenderSettingsUI(Game::GameRendering& rendering)
{ {
auto& time = Game::GetInstance().Time; auto& time = Game::GetInstance().Time;
auto& shared = Game::GetShared(); auto& shared = Game::GetShared();
@@ -142,101 +259,84 @@ namespace Tools
auto& level = Game::GetInstance().GameLevel; auto& level = Game::GetInstance().GameLevel;
auto& player = Game::GetInstance().Player; auto& player = Game::GetInstance().Player;
if (rendering.UIVisible == Game::UIVisibilityState::Debug) if (ImGui::Begin("Rendering"))
{ {
ZoneScopedN("DebugUI"); if (rendering.LastShaderLoadTime >= 0.0f)
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right))
{ {
debug.DebugCardRotation++; ImGui::TextColored({0.2f, 0.9f, 0.2f, 1.0f},
if (debug.DebugCardRotation >= 4) debug.DebugCardRotation = 0; "Shader loaded %.0f seconds ago",
time.Now - rendering.LastShaderLoadTime);
} }
if (ImGui::Begin("Log")) else
{ {
ImGui::Checkbox("Shorten File Names", &debug.ShortenLogFileNames); ImGui::TextColored({0.9f, 0.2f, 0.2f, 1.0f}, "Shader load Failiure!");
ImGui::BeginTable(
"tbl", 4, ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_SizingFixedFit);
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_NoResize);
ImGui::TableSetupColumn("Log");
ImGui::TableSetupColumn("Line", ImGuiTableColumnFlags_NoResize);
ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_NoResize);
ImGui::TableHeadersRow();
for (int32_t i = 0; i < bx::min(100, LogInternal::LogHistorySize); ++i)
{
int32_t idx = GetLogHistory().WriteIdx - i - 1;
if (idx < 0) idx += LogInternal::LogHistorySize;
const char* line = &GetLogHistory().LogBuffer[idx * LogInternal::MaxLineSize];
if (line[0] != 0)
{
int64_t timeOffset = GetLogHistory().WriteTime[idx] - time.StartTime;
double writeTime = (double)timeOffset / bx::getHPFrequency();
uint32_t fileLine = GetLogHistory().LineBuffer[idx];
const char* filePath = &GetLogHistory().FileBuffer[idx * LogInternal::MaxLineSize];
const char* filePathRes =
debug.ShortenLogFileNames ? bx::FilePath{filePath}.getFileName().getPtr() : filePath;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%.01f", writeTime);
ImGui::TableNextColumn();
ImGui::Text("%s", line);
ImGui::SetItemTooltip("%f\n%s%s:%u", writeTime, line, filePath, fileLine);
ImGui::TableNextColumn();
ImGui::Text("%u", fileLine);
ImGui::TableNextColumn();
ImGui::Text("%s", filePathRes);
}
}
ImGui::EndTable();
} }
ImGui::End(); ImGui::SameLine();
if (ImGui::Begin("Rendering")) if (ImGui::Button("Reload Level"))
{ {
if (rendering.LastShaderLoadTime >= 0.0f) level = {};
{ level.Setup(shared.Game);
ImGui::TextColored({0.2f, 0.9f, 0.2f, 1.0f}, }
"Shader loaded %.0f seconds ago",
time.Now - rendering.LastShaderLoadTime);
}
else
{
ImGui::TextColored({0.9f, 0.2f, 0.2f, 1.0f}, "Shader load Failiure!");
}
if (ImGui::Button("Reload Meshes"))
{
LoadModels(rendering.Models, rendering.ModelCount);
}
ImGui::SameLine();
if (ImGui::Button("Reload Level"))
{
level = {};
level.Setup(shared.Game);
}
ImGui::SliderFloat("Mouse Sensitivity", &player.MouseSensitivity, 0.1f, 5.0f); ImGui::DragFloat3("Player Pos", &player.PlayerCamTransform.Position.x);
ImGui::SliderFloat("Player Speed", &player.MovementSpeed, 1.0f, 30.0f); ImGui::DragFloat3("Puz0 Pos", &level.Puzzles[0].WorldPosition.x);
ImGui::SliderFloat("Mouse Sensitivity", &player.MouseSensitivity, 0.1f, 5.0f);
ImGui::SliderFloat("Player Speed", &player.MovementSpeed, 1.0f, 30.0f);
ImGui::Checkbox("Show ImGui Demo", &debug.ShowImguiDemo); ImGui::Checkbox("Show ImGui Demo", &debug.ShowImguiDemo);
ImGui::Checkbox("Show Stats", &debug.ShowStats); ImGui::Checkbox("Show Stats", &debug.ShowStats);
if (debug.ShowImguiDemo) ImGui::ShowDemoWindow(&debug.ShowImguiDemo); if (debug.ShowImguiDemo) ImGui::ShowDemoWindow(&debug.ShowImguiDemo);
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Entity Groups"); if (ImGui::TreeNodeEx("Entity Groups"))
{
ImGui::Checkbox("Cubes", &level.Cubes.IsEnabled); ImGui::Checkbox("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("Status");
ImGui::Text("Game Tablet"); uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletStatusRenderData);
Tools::EntityDataSettings(player.Config.TabletRenderData); uiconfigChanged |= Tools::TextureDropdown(player.Config.TabletStatusSolvedTexture, "Solved Texture");
uiconfigChanged |=
Tools::TextureDropdown(player.Config.TabletStatusNotSolvedTexture, "Not Solved Texture");
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Reset");
uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletResetRenderData);
ImGui::TreePop();
}
if (ImGui::TreeNodeEx("Background Level"))
{
for (int32_t i = 0; i < BX_COUNTOF(player.Config.BackgroundLevelRenderData); ++i)
{
if (i > 0) ImGui::Separator();
uiconfigChanged |= Tools::EntityDataSettings(player.Config.BackgroundLevelRenderData[i]);
}
ImGui::TreePop();
}
if (uiconfigChanged)
{
Serializer s;
s.Init("game/data/static/uiconfig.dat", "UICO");
s.WriteT(player.Config);
s.Finish();
level.PuzzleUI.Reset();
level.ReloadLevelEntities();
}
if (ImGui::TreeNodeEx("Dithering"))
{
if (ImGui::Button("Dithergen")) if (ImGui::Button("Dithergen"))
{ {
DitherGen(rendering.DitherTextures, rendering.DitherRecursion); DitherGen(rendering.DitherTextures, rendering.DitherRecursion);
@@ -263,137 +363,247 @@ 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(); }
if (ImGui::Begin("Textures")) ImGui::End();
{ }
if (ImGui::Button("Reload"))
{
rendering.LoadTextures();
}
for (int32_t i = 0; i < rendering.MaxTextures; ++i)
{
if (!isValid(rendering.Textures[i].RenderHandle)) continue;
ImGui::Text("%i", i);
float width = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.width);
float height = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.height);
ImGui::Image(rendering.Textures[i].RenderHandle.idx, {width, height});
}
}
ImGui::End();
if (ImGui::Begin("Puzzles"))
{
if (ImGui::Button("Add"))
{
bool found = false;
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
{
auto& puz = level.Puzzles[i].Data;
if (puz.ID == UINT16_MAX)
{
bx::strCopy(puz.PuzzleName, sizeof(puz.PuzzleName), "Unnamed Puzzle");
puz.ID = i;
found = true;
break;
}
}
if (!found)
{
LOG_ERROR("Too many puzzles!");
}
}
ImGui::Separator();
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
{
auto& puzzleData = level.Puzzles[i].Data;
if (puzzleData.ID == UINT16_MAX) continue;
bool isSelected = debug.SelectedDebugLevel == i; void RenderTexturesUI(Game::GameRendering& rendering)
ImGui::PushID("selectable"); {
if (ImGui::Selectable(puzzleData.PuzzleName, isSelected)) if (ImGui::Begin("Textures"))
{ {
debug.SelectedDebugLevel = isSelected ? UINT16_MAX : i; if (ImGui::Button("Reload"))
}
ImGui::PopID();
}
}
ImGui::End();
if (debug.SelectedDebugLevel < BX_COUNTOF(level.Puzzles))
{ {
if (!Puzzle::RenderDebugUI(level.Puzzles[debug.SelectedDebugLevel].Data)) rendering.LoadTextures();
{
debug.SelectedDebugLevel = UINT16_MAX;
}
} }
if (ImGui::Begin("Cards")) for (int32_t i = 0; i < rendering.MaxTextures; ++i)
{ {
Gen::StaticPuzzleData& staticData = Puzzle::GetStaticPuzzleData(); if (!isValid(rendering.Textures[i].RenderHandle)) continue;
ImGui::Text("%i", i);
float width = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.width);
float height = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.height);
ImGui::Image(rendering.Textures[i].RenderHandle.idx, {width, height});
}
}
ImGui::End();
}
if (ImGui::Button("Save")) void RenderModelsUI(Game::GameRendering& rendering)
{
if (ImGui::Begin("Models"))
{
if (ImGui::Button("Reload"))
{
LoadModels(rendering.Models, rendering.ModelCount);
}
for (int32_t i = 0; i < rendering.ModelCount; ++i)
{
auto& mdl = rendering.Models[i];
if (bgfx::isValid(mdl.HeightMapTexture))
{ {
Puzzle::SaveStaticPuzzleData(); ImGui::Text("%s", mdl.Name);
ImGui::Image(mdl.HeightMapTexture.idx,
ImVec2{(float)Game::HeightMap::Height, (float)Game::HeightMap::Width});
} }
ImGui::SameLine(); else
if (ImGui::Button("Reload"))
{ {
Puzzle::LoadStaticPuzzleData(); ImGui::Text("Invalid Handle!");
} }
ImGui::Spacing();
}
}
ImGui::End();
}
void RenderPuzzlesUI()
{
auto& debug = Game::GetInstance().DebugData;
auto& level = Game::GetInstance().GameLevel;
if (ImGui::Begin("Puzzles"))
{
char nameBuf[64]{0};
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
{
ImGui::PushID(i);
auto& puzzleData = level.Puzzles[i].Data;
bool isSelected = debug.SelectedDebugLevel == i;
ImGui::PushID("selectable");
bx::snprintf(nameBuf, sizeof(nameBuf), "%u: %s", i, puzzleData.PuzzleName);
if (ImGui::Selectable(nameBuf, isSelected))
{
debug.SelectedDebugLevel = isSelected ? UINT16_MAX : i;
}
ImGui::DragFloat3("Pos", &level.Puzzles[i].WorldPosition.x);
ImGui::PopID();
ImGui::PopID();
}
}
ImGui::End();
if (debug.SelectedDebugLevel < BX_COUNTOF(level.Puzzles))
{
if (!Puzzle::RenderDebugUI(level.Puzzles[debug.SelectedDebugLevel].Data))
{
debug.SelectedDebugLevel = UINT16_MAX;
}
}
}
void RenderCardsUI(Game::GameRendering& rendering)
{
auto& debug = Game::GetInstance().DebugData;
if (ImGui::Begin("Cards"))
{
Gen::StaticPuzzleData& staticData = Puzzle::GetStaticPuzzleData();
if (ImGui::Button("Save"))
{
Puzzle::SaveStaticPuzzleData();
}
ImGui::SameLine();
if (ImGui::Button("Reload"))
{
Puzzle::LoadStaticPuzzleData();
}
ImGui::Separator();
ImGui::ColorEdit3("Disabled Tint", &staticData.Visuals.DisabledCardTint.x);
ImGui::ColorEdit3("Tile Base Color", &staticData.Visuals.TileBaseColor.x);
ImGui::ColorEdit3("Tile Dot Color", &staticData.Visuals.TileDotColor.x);
for (int32_t i = 0; i < BX_COUNTOF(staticData.Cards); ++i)
{
ImGui::Separator(); ImGui::Separator();
ImGui::ColorEdit3("Disabled Tint", &staticData.Visuals.DisabledCardTint.x); Gen::StaticPuzzleCard& card = staticData.Cards[i];
ImGui::ColorEdit3("Tile Base Color", &staticData.Visuals.TileBaseColor.x); ImGui::PushID(i);
ImGui::ColorEdit3("Tile Dot Color", &staticData.Visuals.TileDotColor.x); char cardName[64]{0};
bx::snprintf(cardName, sizeof(cardName), "%i", i);
for (int32_t i = 0; i < BX_COUNTOF(staticData.Cards); ++i) ImGui::Selectable(cardName);
if (ImGui::BeginDragDropSource())
{ {
ImGui::Separator(); Puzzle::DrawCard(card, debug.DebugCardRotation, ImGui::GetCursorScreenPos());
ImGui::SetDragDropPayload("cardtype", &i, sizeof(i));
ImGui::EndDragDropSource();
}
Gen::StaticPuzzleCard& card = staticData.Cards[i]; Tools::ModelDropdown(card.BaseModelHandle);
ImGui::PushID(i); Tools::TextureDropdown(card.ModelTextureHandle, "World Texture");
char cardName[64]{0}; Tools::TextureDropdown(card.BoardTextureHandle, "UI Texture");
bx::snprintf(cardName, sizeof(cardName), "%i", i); if (IsValid(card.BaseModelHandle))
ImGui::Selectable(cardName); {
if (ImGui::BeginDragDropSource()) auto& mdl = rendering.Models[card.BaseModelHandle.ModelIdx];
if (mdl.SocketCount > 0 && ImGui::TreeNodeEx("Slots"))
{ {
Puzzle::DrawCard(card, debug.DebugCardRotation, ImGui::GetCursorScreenPos()); for (int32_t sIdx = 0; sIdx < mdl.SocketCount; ++sIdx)
ImGui::SetDragDropPayload("cardtype", &i, sizeof(i));
ImGui::EndDragDropSource();
}
Tools::ModelDropdown(card.ModelHandle);
Tools::TextureDropdown(card.BoardTextureHandle);
for (int8_t y = 0; y < Puzzle::Config::CardSize; ++y)
{
ImGui::PushID(y);
for (int8_t x = 0; x < Puzzle::Config::CardSize; ++x)
{ {
if (x > 0) ImGui::SameLine(); Tools::ModelDropdown(card.Sockets[sIdx].Model, mdl.Sockets[sIdx].Name);
ImGui::PushID(x); int val = card.Sockets[sIdx].ConnectionDirection;
auto& node = Puzzle::EditCardNodeAt(card, 0, x, y); ImGui::PushID(sIdx);
if (ImGui::Button(Gen::PuzzleElementType::ShortName[node], {26, 24})) if (ImGui::Combo("Connection Direction", &val, "North\0East\0South\0West\0"))
{ {
int32_t newVal = int32_t(node) + 1; card.Sockets[sIdx].ConnectionDirection = val;
if (newVal >= Gen::PuzzleElementType::EntryCount)
{
newVal = 0;
}
node = Gen::PuzzleElementType::Enum(newVal);
} }
ImGui::PopID(); ImGui::PopID();
} }
ImGui::TreePop();
}
}
ImGui::Text("Card");
for (int8_t y = 0; y < Puzzle::Config::CardSize; ++y)
{
ImGui::PushID(y);
for (int8_t x = 0; x < Puzzle::Config::CardSize; ++x)
{
if (x > 0) ImGui::SameLine();
ImGui::PushID(x);
auto& node = Puzzle::EditCardNodeAt(card, 0, x, y);
if (ImGui::Button(Gen::PuzzleElementType::ShortName[node], {26, 24}))
{
int32_t newVal = int32_t(node) + 1;
if (newVal >= Gen::PuzzleElementType::EntryCount)
{
newVal = 0;
}
node = Gen::PuzzleElementType::Enum(newVal);
}
ImGui::PopID(); ImGui::PopID();
} }
ImGui::PopID(); ImGui::PopID();
} }
ImGui::PopID();
} }
ImGui::End();
} }
ImGui::End();
}
void RenderEntitiesUI()
{
auto& level = Game::GetInstance().GameLevel;
if (ImGui::Begin("Entities"))
{
if (ImGui::TreeNodeEx("UIQuads"))
{
ImGui::Text("Count: %u", level.UIQuads.Count);
for (uint16_t i = 0; i < level.UIQuads.Count; ++i)
{
ImGui::Separator();
ImGui::PushID(i);
ImGui::Text("%u", i);
ImGui::SameLine();
auto& quad = level.UIQuads.Get({i});
ImGui::Checkbox("Visible", &quad.EData.Visible);
TextureDropdown(quad.EData.TextureHandle);
MaterialDropdown(quad.EData.MaterialHandle);
ImGui::DragFloat3("Pos", &quad.EData.Transform.Position.x);
ImGui::DragFloat3("UI Pos", &quad.UIPos.x);
ImGui::Text("RenderID: %i", quad.EData.RenderID);
ImGui::PopID();
}
ImGui::TreePop();
}
if (ImGui::TreeNodeEx("Level"))
{
ImGui::Text("Count: %u", level.LevelEntities.Count);
for (uint16_t i = 0; i < level.LevelEntities.Count; ++i)
{
ImGui::Separator();
ImGui::PushID(i);
ImGui::Text("%u", i);
ImGui::SameLine();
auto& levelEnt = level.LevelEntities.Get({i});
ImGui::Checkbox("Visible", &levelEnt.EData.Visible);
TextureDropdown(levelEnt.EData.TextureHandle);
MaterialDropdown(levelEnt.EData.MaterialHandle);
ImGui::DragFloat3("Pos", &levelEnt.EData.Transform.Position.x);
ImGui::Text("RenderID: %i", levelEnt.EData.RenderID);
ImGui::PopID();
}
ImGui::TreePop();
}
}
ImGui::End();
}
void RenderStatsUI()
{
auto& time = Game::GetInstance().Time;
auto& debug = Game::GetInstance().DebugData;
if (debug.ShowStats) if (debug.ShowStats)
{ {
ImGui::SetNextWindowPos({0, 0}); ImGui::SetNextWindowPos({0, 0});
@@ -412,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();
@@ -442,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

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

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

@@ -0,0 +1,382 @@
#include "UI.h"
#include "Entity.h"
#include "Gen.h"
#include "Global.h"
#include "Input.h"
#include "Instance.h"
#include "Level.h"
#include "Puzzle.h"
#include "bx/math.h"
using namespace Gen;
namespace
{
Game::StaticUIData StaticData;
}
namespace Game
{
UIQuadEntityHandle NewQuad(UIQuadEntityManager& manager,
const Gen::SavedEntityRenderData& loadData,
UIQuadEntityHandle oldHandle)
{
UIQuadEntityHandle h = oldHandle;
if (!IsValid(h))
{
h = manager.New();
if (!IsValid(h)) return h;
}
UIQuadEntity& entity = manager.Get(h);
entity.EData.LoadFromSaved(loadData);
entity.UIPos = entity.EData.Transform.Position;
return h;
}
void UpdateQuad(UIQuadEntityManager& manager, UIQuadEntityHandle handle)
{
if (!IsValid(handle)) return;
UIQuadEntity& entity = manager.Get(handle);
entity.EData.Transform.Position = StaticData.UITransform.Position;
entity.EData.Transform.Rotation = StaticData.UITransform.Rotation;
TranslateLocal(entity.EData.Transform, entity.UIPos);
Rotate(entity.EData.Transform, Vec3{bx::kPi * 0.5f, 0.0f, (1.0f - 0 * 0.5f) * bx::kPi});
Rotate(entity.EData.Transform, {0.0f, entity.UIRot, 0.0f});
}
Vec3 GetMousePosWorld()
{
auto& window = GetShared().Window;
Vec2 mousePos = GetMousePos();
mousePos.x = mousePos.x / window.WindowWidth;
mousePos.y = mousePos.y / window.WindowHeight;
mousePos *= 2.0f;
mousePos -= 1.0f;
Vec4 mousePosView = {mousePos.x, -mousePos.y, 0.0f, 1.0f};
Vec4 mousePosCam4 = Mul(GetInstance().Player.ProjectionInverse, mousePosView);
Vec3 mousePosCam = Vec3{
mousePosCam4.x /= mousePosCam4.w,
mousePosCam4.y /= mousePosCam4.w,
mousePosCam4.z /= mousePosCam4.w,
};
return LocalToGlobalPoint(GetInstance().Player.PlayerCamTransform, mousePosCam);
}
bool IsQuadHovered(Transform& quadTransform, Vec3 mousePosWorld, Vec3& outQuadPlaneIntersectPos)
{
Vec3 quadPosWorld = quadTransform.Position;
Vec3 quadXWorld = LocalToGlobalPoint(quadTransform, {1, 0, 0});
Vec3 quadZWorld = LocalToGlobalPoint(quadTransform, {0, 0, 1});
if (RayPlaneIntersect(GetInstance().Player.PlayerCamTransform.Position,
mousePosWorld,
quadPosWorld,
quadXWorld,
quadZWorld,
outQuadPlaneIntersectPos))
{
Vec3 quadSpaceIntersect = GlobalToLocalPoint(quadTransform, outQuadPlaneIntersectPos);
if (quadSpaceIntersect.x >= -1.0f && quadSpaceIntersect.x <= 1.0f && quadSpaceIntersect.z >= -1.0f &&
quadSpaceIntersect.z <= 1.0f)
{
return true;
}
}
return false;
}
void WorldPuzzleUI::Setup()
{
auto& level = GetInstance().GameLevel;
auto& player = GetInstance().Player;
TabletHandle = NewQuad(level.UIQuads, player.Config.TabletBackgroundRenderData);
SolvedQuad = NewQuad(level.UIQuads, player.Config.TabletStatusRenderData);
ResetQuad = NewQuad(level.UIQuads, player.Config.TabletResetRenderData);
for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i)
{
UIPlacedCards[i] = level.UIQuads.New();
auto& quad = level.UIQuads.Get(UIPlacedCards[i]);
quad.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/plane.glb");
quad.EData.MaterialHandle = EMaterial::UI;
}
for (int32_t i = 0; i < Puzzle::Config::MaxAvailableStacks * UIAvailableCardMaxStackPreview; ++i)
{
UIAvailableCards[i] = level.UIQuads.New();
auto& quad = level.UIQuads.Get(UIAvailableCards[i]);
quad.EData.MaterialHandle = EMaterial::UI;
quad.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/plane.glb");
}
}
Vec3 CalcBoardOffset(const Gen::PuzzleData& puzData)
{
return Vec3{
(float)(puzData.WidthTiles) / 2.0f - 0.5f,
(float)(puzData.HeightTiles) / 2.0f - 0.5f,
0.0f,
} *
WorldPuzzleUI::UICardScale * WorldPuzzleUI::UICardScale;
}
Vec3 CardPosToUIPos(const Gen::PuzzleData& data, int32_t cardX, int32_t cardY)
{
return Vec3{(float)cardX, (float)(data.HeightTiles / 2 - cardY - 1), -0.3f} * WorldPuzzleUI::UICardOffset *
WorldPuzzleUI::UICardScale -
CalcBoardOffset(data);
}
void UIPosToCardPos(const Gen::PuzzleData& data, Vec3 uiPos, int32_t& cardXOut, int32_t& cardYOut)
{
Vec3 boardOffset = CalcBoardOffset(data) / WorldPuzzleUI::UICardScale;
Vec3 boardPos = GlobalToLocalPoint(StaticData.UITransform, uiPos);
Vec3 boardTilePos = (boardPos + boardOffset) / WorldPuzzleUI::UICardOffset;
cardXOut = (int32_t)bx::round(boardTilePos.x);
cardYOut = data.HeightTiles / 2 - (int32_t)bx::round(boardTilePos.y) - 1;
}
void WorldPuzzleUI::UpdateAvailableCards(Gen::PuzzleData& Data)
{
auto& level = GetInstance().GameLevel;
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
Vec3 quadPlaneIntersectPos;
Vec3 mousePosWorld = GetMousePosWorld();
for (int32_t stackIdx = 0; stackIdx < Puzzle::Config::MaxAvailableStacks; ++stackIdx)
{
auto& card = Data.AvailableCards[stackIdx];
for (int32_t cardIdx = 0; cardIdx < UIAvailableCardMaxStackPreview; cardIdx++)
{
auto h = UIAvailableCards[stackIdx * UIAvailableCardMaxStackPreview + cardIdx];
auto& quad = level.UIQuads.Get(h);
int32_t remaining = (int32_t)card.MaxAvailableCount - (int32_t)card.UsedCount;
if (stackIdx < Data.AvailableCardCount && cardIdx < remaining)
{
quad.UIPos = Vec3{cardIdx * 0.05f + stackIdx * 1.2f,
4.2f + (cardIdx % 2 == 0 ? 0.02f : 0.0f),
cardIdx * 0.001f - 0.3f} *
UICardOffset * UICardScale;
UpdateQuad(level.UIQuads, h);
quad.EData.Visible = true;
quad.EData.TextureHandle = Puzzle::IsValid(card.RefCard)
? staticCards[card.RefCard.Idx].BoardTextureHandle
: Gen::TextureHandle{0};
quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale};
quad.EData.DotColor = {1.0f, 1.0f, 1.0f, 1.0f};
quad.EData.BaseColor = {1.0f, 1.0f, 1.0f, 1.0f};
if (cardIdx == 0)
{
if (IsQuadHovered(quad.EData.Transform, mousePosWorld, quadPlaneIntersectPos) &&
DraggedAvailableCardIdx == UINT16_MAX && DraggedCard.X == -1 &&
GetMouseButtonPressedNow(MouseButton::Left))
{
DraggedAvailableCardIdx = stackIdx;
}
if (DraggedAvailableCardIdx == stackIdx)
{
Vec3 dragPos = quadPlaneIntersectPos;
dragPos += StaticData.ZAxis * -0.01f;
quad.EData.Transform.Position = dragPos;
int32_t xPos;
int32_t yPos;
UIPosToCardPos(Data, quadPlaneIntersectPos, xPos, yPos);
if (!GetMouseButton(MouseButton::Left))
{
if (xPos >= 0 && xPos < Data.WidthTiles / Puzzle::Config::CardSize && yPos >= 0 &&
yPos < Data.HeightTiles / Puzzle::Config::CardSize)
{
Gen::PuzPos targetCardPos = {(int8_t)xPos, (int8_t)yPos};
Gen::PlacedPuzzleCard& targetCard =
Data.PlacedCards[yPos * Puzzle::Config::MaxPuzzleSizeCards + xPos];
if (!Puzzle::IsValid(targetCard.RefCard) || targetCard.RefCard.Idx == 0)
{
Puzzle::DragAvailableCardTo(Data, targetCardPos, DraggedAvailableCardIdx, 0);
}
}
DraggedAvailableCardIdx = UINT16_MAX;
}
}
}
}
else
{
quad.EData.Visible = false;
}
}
}
}
void WorldPuzzleUI::UpdateBoardCards(Gen::PuzzleData& Data)
{
auto& level = GetInstance().GameLevel;
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
Vec3 quadPlaneIntersectPos;
Vec3 boardOffset = CalcBoardOffset(Data);
for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y)
{
for (int8_t x = 0; x < Data.WidthTiles / Puzzle::Config::CardSize; ++x)
{
// UI Quad
int32_t cardIdx = y * Puzzle::Config::MaxPuzzleSizeCards + x;
PlacedPuzzleCard& card = Data.PlacedCards[cardIdx];
bool isValid = Puzzle::IsValid(card.RefCard);
bool isLocked = GetFlag(card.Flags, PlacedPuzzleCardFlags::Locked);
auto& quad = level.UIQuads.Get(UIPlacedCards[cardIdx]);
quad.UIPos = CardPosToUIPos(Data, card.Position.X, card.Position.Y);
quad.UIRot = card.Rotation * bx::kPi * -0.5f;
UpdateQuad(level.UIQuads, UIPlacedCards[cardIdx]);
quad.EData.Visible = isValid;
quad.EData.TextureHandle =
isValid ? staticCards[card.RefCard.Idx].BoardTextureHandle : Gen::TextureHandle{};
quad.EData.DotColor =
isLocked ? Puzzle::GetStaticPuzzleData().Visuals.DisabledCardTint : Vec4{1.0f, 1.0f, 1.0f, 1.0f};
quad.EData.Transform.Scale = {UICardScale, UICardScale, UICardScale};
if (isValid && IsQuadHovered(quad.EData.Transform, StaticData.MousePosWorld, quadPlaneIntersectPos))
{
if (!isLocked && DraggedCard.X == -1 && DraggedAvailableCardIdx == UINT16_MAX)
{
if (GetMouseButtonPressedNow(MouseButton::Left))
{
DraggedCard.X = x;
DraggedCard.Y = y;
}
if (GetMouseButtonPressedNow(MouseButton::Right))
{
Puzzle::RotateCard(card);
}
}
}
if (DraggedCard.X == x && DraggedCard.Y == y)
{
Vec3 dragPos = quadPlaneIntersectPos;
dragPos += StaticData.ZAxis * -0.01f;
quad.EData.Transform.Position = dragPos;
int32_t xPos;
int32_t yPos;
UIPosToCardPos(Data, quadPlaneIntersectPos, xPos, yPos);
Gen::PuzPos srcCardPos = {(int8_t)DraggedCard.X, (int8_t)DraggedCard.Y};
Gen::PlacedPuzzleCard& srcCard =
Data.PlacedCards[srcCardPos.Y * Puzzle::Config::MaxPuzzleSizeCards + srcCardPos.X];
if (GetMouseButtonPressedNow(MouseButton::Right))
{
Puzzle::RotateCard(srcCard);
}
if (!GetMouseButton(MouseButton::Left))
{
Gen::PuzPos targetCardPos = {(int8_t)xPos, (int8_t)yPos};
if (xPos >= 0 && xPos < Data.WidthTiles / Puzzle::Config::CardSize && yPos >= 0 &&
yPos < Data.HeightTiles / Puzzle::Config::CardSize)
{
PlacedPuzzleCard srcCardCopy = srcCard;
Gen::PlacedPuzzleCard& targetCard =
Data.PlacedCards[yPos * Puzzle::Config::MaxPuzzleSizeCards + xPos];
bool canBeReplaced = !Puzzle::IsValid(targetCard.RefCard) || targetCard.RefCard.Idx == 0;
if (canBeReplaced && Puzzle::ReturnPlacedCard(Data, srcCardPos))
{
int32_t foundIdx = -1;
for (int32_t availCardIdx = 0; availCardIdx < Data.AvailableCardCount; ++availCardIdx)
{
if (Data.AvailableCards[availCardIdx].RefCard.Idx == srcCardCopy.RefCard.Idx)
{
foundIdx = availCardIdx;
break;
}
}
if (foundIdx >= 0)
{
Puzzle::DragAvailableCardTo(Data, targetCardPos, foundIdx, srcCard.Rotation);
}
else
{
LOG_ERROR("NOTFOUND: %u", srcCardCopy.RefCard.Idx);
}
}
}
else
{
Puzzle::ReturnPlacedCard(Data, srcCardPos);
}
DraggedCard.X = -1;
DraggedCard.Y = -1;
}
}
}
}
}
void WorldPuzzleUI::Update(Gen::PuzzleData& Data, bool IsPuzzleSolved)
{
auto& level = GetInstance().GameLevel;
auto& player = GetInstance().Player;
Transform& camTransform = player.PlayerCamTransform;
UpdateMatrix(camTransform);
// UI Tablet
if (IsValid(TabletHandle))
{
auto& tablet = level.UIQuads.Get(TabletHandle);
tablet.EData.Transform.Rotation = camTransform.Rotation;
Rotate(tablet.EData.Transform, {0.5f * bx::kPi, 0.0f, 0.0f});
tablet.EData.Transform.Position = camTransform.Position + AxisForward(camTransform.M) * 1.0f;
StaticData.UITransform = tablet.EData.Transform;
tablet.EData.Transform.Position += {0.0f, 0.0f, 0.01f};
}
StaticData.UITransform.Rotation = camTransform.Rotation;
StaticData.ZAxis = AxisForward(StaticData.UITransform.M);
StaticData.UITransform.Position += StaticData.ZAxis * -0.01f;
StaticData.MousePosWorld = GetMousePosWorld();
// NOLINTBEGIN
Vec2 uiOffset = Vec2{static_cast<float>(Data.WidthTiles / Puzzle::Config::CardSize - 1),
static_cast<float>(Data.HeightTiles / Puzzle::Config::CardSize - 1)};
// NOLINTEND
uiOffset *= -UICardOffset * 0.5f;
auto& solvedQuad = level.UIQuads.Get(SolvedQuad);
solvedQuad.EData.Visible = true;
solvedQuad.EData.TextureHandle = IsPuzzleSolved ? GetInstance().Player.Config.TabletStatusSolvedTexture
: GetInstance().Player.Config.TabletStatusNotSolvedTexture;
UpdateQuad(level.UIQuads, SolvedQuad);
auto& resetQuad = level.UIQuads.Get(ResetQuad);
resetQuad.EData.Visible = true;
UpdateQuad(level.UIQuads, ResetQuad);
Vec3 hoverPosWorld;
if (GetMouseButtonPressedNow(MouseButton::Left) &&
IsQuadHovered(resetQuad.EData.Transform, StaticData.MousePosWorld, hoverPosWorld))
{
Puzzle::ResetPuzzle(Data);
}
UpdateAvailableCards(Data);
UpdateBoardCards(Data);
}
void WorldPuzzleUI::Reset()
{
auto& level = GetInstance().GameLevel;
auto& config = GetInstance().Player.Config;
TabletHandle = NewQuad(level.UIQuads, config.TabletBackgroundRenderData, TabletHandle);
SolvedQuad = NewQuad(level.UIQuads, config.TabletStatusRenderData, SolvedQuad);
ResetQuad = NewQuad(level.UIQuads, config.TabletResetRenderData, ResetQuad);
}
} // namespace Game

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

@@ -0,0 +1,44 @@
#pragma once
#include "../gen/Generated.h"
#include "Entity.h"
#include "Puzzle.h"
namespace Game
{
struct StaticUIData
{
Gen::Transform UITransform;
Gen::Vec3 ZAxis;
Gen::Vec3 MousePosWorld;
};
struct WorldPuzzleUI
{
static constexpr float UICardScale = 0.05f;
static constexpr float UICardOffset = 2.1f * UICardScale;
static constexpr int32_t UIAvailableCardMaxStackPreview = 3;
UIQuadEntityHandle TabletHandle;
UIQuadEntityHandle SolvedQuad;
UIQuadEntityHandle ResetQuad;
UIQuadEntityHandle UIPlacedCards[Puzzle::Config::MaxCardsInPuzzle];
UIQuadEntityHandle UIAvailableCards[Puzzle::Config::MaxAvailableStacks * UIAvailableCardMaxStackPreview];
Gen::PuzPos DraggedCard{-1, -1};
uint16_t DraggedAvailableCardIdx = UINT16_MAX;
void Setup();
void UpdateAvailableCards(Gen::PuzzleData& Data);
void UpdateBoardCards(Gen::PuzzleData& Data);
void Update(Gen::PuzzleData& Data, bool IsPuzzleSolved);
void Reset();
};
UIQuadEntityHandle NewQuad(UIQuadEntityManager& manager,
const Gen::SavedEntityRenderData& loadData,
UIQuadEntityHandle oldHandle = {});
void UpdateQuad(UIQuadEntityManager& manager, UIQuadEntityHandle handle);
Gen::Vec3 GetMousePosWorld();
bool IsQuadHovered(Gen::Transform& quadTransform, Gen::Vec3 mousePosWorld, Gen::Vec3& outQuadPlaneIntersectPos);
} // namespace Game

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/game/data/puzzles/1.pzl LFS Normal file

Binary file not shown.

BIN
src/game/data/puzzles/2.pzl LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -82,10 +82,22 @@ enum PuzzleElementType(u8)
Bridge GameName("Bridge") ShortName("#") Bridge GameName("Bridge") ShortName("#")
} }
type CardSocket
{
ModelHandle Model
u8 ConnectionDirection
}
type StaticPuzzleCard type StaticPuzzleCard
{ {
PuzzleElementType Elements Arr(4) PuzzleElementType Elements Arr(4)
ModelHandle ModelHandle ModelHandle BaseModelHandle
ModelHandle NorthCoverHandle
ModelHandle EastCoverHandle
ModelHandle SouthCoverHandle
ModelHandle WestCoverHandle
CardSocket Sockets Arr(16)
TextureHandle ModelTextureHandle
TextureHandle BoardTextureHandle TextureHandle BoardTextureHandle
} }
@@ -98,6 +110,7 @@ type PuzzleVisualSettings
{ {
Vec4 TileBaseColor Vec4 TileBaseColor
Vec4 TileDotColor Vec4 TileDotColor
Vec3 Test
Vec4 DisabledCardTint Vec4 DisabledCardTint
} }
@@ -114,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
@@ -131,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)
@@ -152,3 +172,13 @@ type SavedEntityRenderData
ModelHandle Model ModelHandle Model
b Visible b Visible
} }
type SavedPlayerConfig
{
SavedEntityRenderData TabletBackgroundRenderData
SavedEntityRenderData TabletStatusRenderData
TextureHandle TabletStatusNotSolvedTexture
TextureHandle TabletStatusSolvedTexture
SavedEntityRenderData TabletResetRenderData
SavedEntityRenderData BackgroundLevelRenderData Arr(16)
}

View File

@@ -16,11 +16,12 @@ void DitherGen(DitherData& data, int32_t recursion)
for (int32_t i = 0; i < data.BrightnessBucketCount; ++i) 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;
@@ -84,21 +88,7 @@ void DitherGen(DitherData& data, int32_t recursion)
} }
// Upload textures // Upload textures
if (isValid(data.PreviewTex)) CleanupDitherData(data);
{
bgfx::destroy(data.PreviewTex);
data.PreviewTex = BGFX_INVALID_HANDLE;
}
if (isValid(data.FinalTex))
{
bgfx::destroy(data.FinalTex);
data.FinalTex = BGFX_INVALID_HANDLE;
}
if (isValid(data.RampTex))
{
bgfx::destroy(data.RampTex);
data.RampTex = BGFX_INVALID_HANDLE;
}
const bgfx::Memory* memPreview = bgfx::makeRef(data.DitherTex, texPixelCount * sizeof(Vec4)); const bgfx::Memory* memPreview = bgfx::makeRef(data.DitherTex, texPixelCount * sizeof(Vec4));
const bgfx::Memory* memFinal = bgfx::makeRef(data.DitherTex, texPixelCount * sizeof(Vec4)); const bgfx::Memory* memFinal = bgfx::makeRef(data.DitherTex, texPixelCount * sizeof(Vec4));
const bgfx::Memory* memRamp = bgfx::makeRef(data.BrightnessRamp, sizeof(data.BrightnessRamp)); const bgfx::Memory* memRamp = bgfx::makeRef(data.BrightnessRamp, sizeof(data.BrightnessRamp));
@@ -123,3 +113,22 @@ void DitherGen(DitherData& data, int32_t recursion)
data.RampSampler = bgfx::createUniform("s_rampSampler", bgfx::UniformType::Sampler); data.RampSampler = bgfx::createUniform("s_rampSampler", bgfx::UniformType::Sampler);
} }
} }
void CleanupDitherData(DitherData& data)
{
if (isValid(data.PreviewTex))
{
bgfx::destroy(data.PreviewTex);
data.PreviewTex = BGFX_INVALID_HANDLE;
}
if (isValid(data.FinalTex))
{
bgfx::destroy(data.FinalTex);
data.FinalTex = BGFX_INVALID_HANDLE;
}
if (isValid(data.RampTex))
{
bgfx::destroy(data.RampTex);
data.RampTex = BGFX_INVALID_HANDLE;
}
}

View File

@@ -24,3 +24,4 @@ struct DitherData
}; };
void DitherGen(DitherData& data, int32_t recursion); void DitherGen(DitherData& data, int32_t recursion);
void CleanupDitherData(DitherData& data);

View File

@@ -6,6 +6,7 @@
#include "../Tools.h" #include "../Tools.h"
#include "Rendering.h" #include "Rendering.h"
#include "Dither.h"
#include "SDL3/SDL_events.h" // IWYU pragma: keep #include "SDL3/SDL_events.h" // IWYU pragma: keep
#include "backends/imgui_impl_sdl3.h" #include "backends/imgui_impl_sdl3.h"
#include "bgfx/defines.h" #include "bgfx/defines.h"
@@ -32,15 +33,105 @@ namespace Game
{ {
namespace namespace
{ {
constexpr size_t ChunkSize = 1024;
constexpr size_t MaxFileSize = ChunkSize * 1024 * 1024;
constexpr size_t MaxChunkCount = MaxFileSize / ChunkSize;
bool BufferedFileRead(FILE* const file, uint8_t* const writePtrIn, size_t& outTotalReadCount)
{
uint8_t* writePtr = writePtrIn;
for (int32_t i = 0; i < MaxChunkCount; ++i)
{
size_t readCount = std::fread(writePtr, 1, ChunkSize, file);
writePtr += readCount;
outTotalReadCount += readCount;
if (readCount != ChunkSize)
{
if (std::feof(file))
{
return true;
}
int err = std::ferror(file);
if (err != 0)
{
LOG_ERROR("Error reading file: %i", err);
return false;
}
LOG_ERROR("This should never happen!");
return false;
}
}
if (!std::feof(file))
{
LOG_ERROR("File too big to be read!");
return false;
}
return true;
}
const bgfx::Memory* LoadBinaryFile(const char* path, int32_t retryCount = 1)
{
FILE* file = nullptr;
for (int32_t i = 0; i < retryCount; ++i)
{
file = std::fopen(path, "rb");
if (file == nullptr)
{
if (i < retryCount - 1)
{
std::this_thread::sleep_for(100ms);
LOG_WARN("Failed to open file, retrying...");
break;
}
else
{
LOG_ERROR("Failed to open file!");
return nullptr;
}
}
}
uint8_t* dataPtr = AllocateScratch(MaxFileSize);
if (dataPtr == nullptr)
{
LOG_ERROR("Failed to load file, exceeded scratch memory! %s", path);
return nullptr;
}
uint64_t totalReadCount = 0;
bool success = BufferedFileRead(file, dataPtr, totalReadCount);
std::fclose(file);
if (!success)
{
LOG_ERROR("Failed to read file %s", path);
ResizeLastScratchAlloc(0);
return nullptr;
}
if (!ResizeLastScratchAlloc(totalReadCount))
{
LOG_ERROR("This should never happen!");
return nullptr;
}
return bgfx::makeRef(dataPtr, totalReadCount);
}
const bgfx::Memory* loadFile(const char* path, bool appendZero = false, int32_t retryCount = 1) const bgfx::Memory* loadFile(const char* path, bool appendZero = false, int32_t retryCount = 1)
{ {
FILE* file; FILE* file;
for (int32_t i = 0; i < retryCount; ++i) for (int32_t i = 0; i < retryCount; ++i)
{ {
file = fopen(path, "rb"); file = std::fopen(path, "rb");
if (file == nullptr && i < retryCount - 1) if (file == nullptr && i < retryCount - 1)
{ {
std::this_thread::sleep_for(100ms); std::this_thread::sleep_for(100ms);
LOG_WARN("Failed to open file, retrying...");
break; break;
} }
@@ -48,11 +139,12 @@ namespace Game
long fileSize = ftell(file); long fileSize = ftell(file);
fseek(file, 0, SEEK_SET); fseek(file, 0, SEEK_SET);
long fileSizeX = appendZero ? fileSize + 1 : fileSize; long fileSizeX = appendZero ? (fileSize + 1) : fileSize;
void* rawMem = AllocateScratch(fileSizeX); void* rawMem = AllocateScratch(fileSizeX);
if (rawMem == nullptr) if (rawMem == nullptr)
{ {
LOG_ERROR("Failed to load file, exceeded scratch memory! %s", path); LOG_ERROR("Failed to load file, exceeded scratch memory! %s", path);
return nullptr;
} }
const bgfx::Memory* mem = bgfx::makeRef(rawMem, fileSizeX); const bgfx::Memory* mem = bgfx::makeRef(rawMem, fileSizeX);
fread(mem->data, 1, fileSize, file); fread(mem->data, 1, fileSize, file);
@@ -127,7 +219,7 @@ namespace Game
bgfx::TextureHandle handle = BGFX_INVALID_HANDLE; bgfx::TextureHandle handle = BGFX_INVALID_HANDLE;
bx::Error err; bx::Error err;
const bgfx::Memory* data = loadFile(_filePath.getCPtr()); const bgfx::Memory* data = LoadBinaryFile(_filePath.getCPtr());
if (data == nullptr || data->data == nullptr || data->size == 0) if (data == nullptr || data->data == nullptr || data->size == 0)
{ {
LOG_WARN("Failed to find image %s", _filePath.getCPtr()); LOG_WARN("Failed to find image %s", _filePath.getCPtr());
@@ -144,8 +236,18 @@ namespace Game
*_orientation = imageContainer.m_orientation; *_orientation = imageContainer.m_orientation;
} }
const bgfx::Memory* mem = // We're working with ktx textures, so the size should be in front of the actual data
bgfx::makeRef(data->data + imageContainer.m_offset, data->size - imageContainer.m_offset); const uint32_t* texSizePtr = reinterpret_cast<uint32_t*>(data->data + imageContainer.m_offset);
uint8_t* dataPtr = data->data + imageContainer.m_offset + sizeof(uint32_t);
uint32_t dataSize = data->size - imageContainer.m_offset - sizeof(uint32_t);
// Extra sanity check
if (*texSizePtr != dataSize)
{
LOG_WARN("Texture size sanity check failed! %u != %u", texSizePtr, dataSize);
return handle;
}
const bgfx::Memory* mem = bgfx::makeRef(dataPtr, dataSize);
if (NULL != _info) if (NULL != _info)
{ {
@@ -211,19 +313,24 @@ namespace Game
return *Instance; return *Instance;
} }
void GameRendering::Setup() void GameRendering::Setup(const RenderingSetup& setup)
{ {
LOG("--- RENDERING STARTUP ---"); LOG("--- RENDERING STARTUP ---");
ZoneScopedN("Setup"); ZoneScopedN("Setup");
SetupData = setup;
if (Instance != nullptr) LOG_WARN("old rendering wasn't destroyed!"); if (Instance != nullptr) LOG_WARN("old rendering wasn't destroyed!");
Instance = this; Instance = this;
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;
#else
init.debug = false;
#endif #endif
init.platformData.nwh = shared.Window.Handle; init.platformData.nwh = shared.Window.Handle;
init.platformData.ndt = nullptr; init.platformData.ndt = nullptr;
@@ -253,23 +360,26 @@ namespace Game
LoadModels(Models, ModelCount); LoadModels(Models, ModelCount);
ReloadShaders(); ReloadShaders();
imguiCreate();
SetImguiStyle();
if (!ImGui_ImplSDL3_InitForOther(shared.Window.SDLWindow)) if (SetupData.UseImgui)
{ {
LOG_ERROR("Failed to set up imgui implementation!"); imguiCreate();
return; SetImguiStyle();
} if (!ImGui_ImplSDL3_InitForOther(shared.Window.SDLWindow))
{
LOG_ERROR("Failed to set up imgui implementation!");
return;
}
// ImGui::GetIO().BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // ImGui::GetIO().BackendFlags |= ImGuiBackendFlags_RendererHasViewports;
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable; ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable;
// ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
// auto& platIO = ImGui::GetPlatformIO(); // auto& platIO = ImGui::GetPlatformIO();
// platIO.Renderer_CreateWindow = TODO; // platIO.Renderer_CreateWindow = TODO;
// platIO.Platform_DestroyWindow = TODO; // platIO.Platform_DestroyWindow = TODO;
// platIO.Platform_SetWindowSize = TODO; // platIO.Platform_SetWindowSize = TODO;
// platIO.Platform_RenderWindow = TODO; // platIO.Platform_RenderWindow = TODO;
}
GameInstance& inst = GetInstance(); GameInstance& inst = GetInstance();
if (!inst.IsInitialized) if (!inst.IsInitialized)
@@ -277,13 +387,16 @@ namespace Game
inst.Time.StartTime = bx::getHPCounter(); inst.Time.StartTime = bx::getHPCounter();
} }
if (inst.DebugData.ImguiIniSize > 0) if (SetupData.UseImgui)
{ {
ImGui::LoadIniSettingsFromMemory(inst.DebugData.ImguiIni, inst.DebugData.ImguiIniSize); if (inst.DebugData.ImguiIniSize > 0)
} {
else ImGui::LoadIniSettingsFromMemory(inst.DebugData.ImguiIni, inst.DebugData.ImguiIniSize);
{ }
ImGui::LoadIniSettingsFromDisk("imgui.ini"); else
{
ImGui::LoadIniSettingsFromDisk("imgui.ini");
}
} }
DitherGen(DitherTextures, DitherRecursion); DitherGen(DitherTextures, DitherRecursion);
} }
@@ -295,7 +408,10 @@ namespace Game
for (uint16_t i = 0; i < shared.Window.SDLEventCount; ++i) for (uint16_t i = 0; i < shared.Window.SDLEventCount; ++i)
{ {
ImGui_ImplSDL3_ProcessEvent(&shared.Window.SDLEvents[i]); if (SetupData.UseImgui)
{
ImGui_ImplSDL3_ProcessEvent(&shared.Window.SDLEvents[i]);
}
} }
shared.Window.SDLEventCount = 0; shared.Window.SDLEventCount = 0;
@@ -404,6 +520,7 @@ namespace Game
HandleEvents(); HandleEvents();
// Start Rendering // Start Rendering
if (SetupData.UseImgui)
{ {
ZoneScopedN("Imgui Start Frame"); ZoneScopedN("Imgui Start Frame");
imguiBeginFrame(20); imguiBeginFrame(20);
@@ -417,12 +534,13 @@ namespace Game
GetInstance().GameLevel.Render(MainViewID, Models, Materials, Textures); GetInstance().GameLevel.Render(MainViewID, Models, Materials, Textures);
// Finish Frame // Finish Frame
if (SetupData.UseImgui)
{ {
ZoneScopedN("Imgui End Frame"); ZoneScopedN("Imgui End Frame");
imguiEndFrame(); imguiEndFrame();
} }
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) if (SetupData.UseImgui && ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{ {
ZoneScopedN("Imgui Platform Update"); ZoneScopedN("Imgui Platform Update");
ImGui::UpdatePlatformWindows(); ImGui::UpdatePlatformWindows();
@@ -441,13 +559,34 @@ namespace Game
{ {
ZoneScopedN("Shutdown"); ZoneScopedN("Shutdown");
LOG("--- RENDERING_SHUTDOWN ---"); LOG("--- RENDERING_SHUTDOWN ---");
ImGui::SaveIniSettingsToDisk("imgui.ini");
auto& debug = GetInstance().DebugData; for (int32_t i = 0; i < BX_COUNTOF(Textures); ++i)
const char* iniData = ImGui::SaveIniSettingsToMemory(reinterpret_cast<uint64_t*>(&debug.ImguiIniSize)); {
assert(debug.ImguiIniSize <= BX_COUNTOF(InstanceDebugData::ImguiIni)); if (isValid(Textures[i].RenderHandle))
bx::memCopy(debug.ImguiIni, iniData, bx::min(debug.ImguiIniSize, BX_COUNTOF(InstanceDebugData::ImguiIni))); {
ImGui_ImplSDL3_Shutdown(); bgfx::destroy(Textures[i].RenderHandle);
imguiDestroy(); Textures[i].RenderHandle = {bgfx::kInvalidHandle};
}
}
for (int32_t i = 0; i < ModelCount; ++i)
{
bgfx::destroy(Models[i].VertexBuffer);
bgfx::destroy(Models[i].IndexBuffer);
}
ModelCount = 0;
CleanupDitherData(DitherTextures);
if (SetupData.UseImgui)
{
ImGui::SaveIniSettingsToDisk("imgui.ini");
auto& debug = GetInstance().DebugData;
const char* iniData = ImGui::SaveIniSettingsToMemory(reinterpret_cast<uint64_t*>(&debug.ImguiIniSize));
assert(debug.ImguiIniSize <= BX_COUNTOF(InstanceDebugData::ImguiIni));
bx::memCopy(debug.ImguiIni, iniData, bx::min(debug.ImguiIniSize, BX_COUNTOF(InstanceDebugData::ImguiIni)));
ImGui_ImplSDL3_Shutdown();
imguiDestroy();
}
bgfx::shutdown(); bgfx::shutdown();
Instance = nullptr; Instance = nullptr;
} }

View File

@@ -32,12 +32,36 @@ namespace Game
Gen::TextureHandle TexHandle; Gen::TextureHandle TexHandle;
}; };
struct ModelSocket
{
static constexpr uint16_t MaxSocketNameLength = 64;
Gen::Vec3 Pos;
Gen::Mat4 Rot;
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;
bgfx::VertexBufferHandle VertexBuffer = {bgfx::kInvalidHandle}; bgfx::VertexBufferHandle VertexBuffer = {bgfx::kInvalidHandle};
bgfx::IndexBufferHandle IndexBuffer = {bgfx::kInvalidHandle}; bgfx::IndexBufferHandle IndexBuffer = {bgfx::kInvalidHandle};
bgfx::VertexLayout VertLayout; bgfx::VertexLayout VertLayout;
Gen::ModelHandle Handle; 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 struct Material
@@ -64,6 +88,11 @@ namespace Game
Debug, Debug,
}; };
struct RenderingSetup
{
bool UseImgui = true;
};
class GameRendering class GameRendering
{ {
public: public:
@@ -76,6 +105,7 @@ namespace Game
DitherData DitherTextures; DitherData DitherTextures;
public: public:
RenderingSetup SetupData;
bgfx::UniformHandle DefaultSampler; bgfx::UniformHandle DefaultSampler;
Texture Textures[MaxTextures]; Texture Textures[MaxTextures];
Material Materials[8]; Material Materials[8];
@@ -89,7 +119,7 @@ namespace Game
int32_t DitherRecursion = 1; int32_t DitherRecursion = 1;
public: public:
void Setup(); void Setup(const RenderingSetup& setup);
void Update(); void Update();
void HandleEvents(); void HandleEvents();
void LoadTextures(); void LoadTextures();

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);
@@ -89,7 +89,9 @@ void main()
{ {
vec2 uv = vec2(1.0 - v_uv0.x, v_uv0.y); vec2 uv = vec2(1.0 - v_uv0.x, v_uv0.y);
vec3 rawTex = texture2D(s_texColor, uv).xyz; vec3 rawTex = texture2D(s_texColor, uv).xyz;
vec3 col = rawTex * u_dotColor.xyz; // float brightness = lerp(0.5, 0.9, 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)); vec3 col = rawTex;
if (uv.x < 0.1 || uv.y < 0.1 || uv.x > 0.9 || uv.y > 0.9) col *= u_dotColor.xyz;
float brightness = 1.0;
gl_FragColor = vec4(col * brightness, 1.0); gl_FragColor = vec4(col * brightness, 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, 0.0)).xyz);
} }

91
src/game/util/HashMap.h Normal file
View File

@@ -0,0 +1,91 @@
#include "bx/hash.h"
#include <cassert>
#include <cstdint>
template <typename T> struct HashMapInsertResult
{
T& Obj = nullptr;
bool ElementExists = false;
};
template <typename T> struct HashMapInsertResultConst
{
const T& Obj = nullptr;
bool ElementExists = false;
};
// BitSize 16 will make the HashTable ~200kb with 65k entries
template <typename T, uint32_t BitSize> struct HashMapCore
{
static constexpr uint32_t SlotCount = (1 << BitSize);
static constexpr uint32_t RequiredDataSize = SlotCount * sizeof(T);
T* Data = nullptr;
uint32_t HashTable[SlotCount]{0};
// External array that should be RequiredDataSize bytes big
void Init(T* data, uint64_t dataSize)
{
Data = data;
assert(data != nullptr);
assert(dataSize == RequiredDataSize);
}
bool Has(uint32_t hash) const
{
return HashTable[FindIdx(hash)] == hash;
}
HashMapInsertResult<T> Get(uint32_t hash)
{
uint16_t idx = FindIdx(hash);
return {Data[idx], HashTable[idx] == hash};
}
const T& Get(uint32_t hash) const
{
uint16_t idx = FindIdx(hash);
return {Data[idx], HashTable[idx] == hash};
}
bool Remove(uint32_t hash); // TODO: requires tombstones so later entries survive
private:
uint16_t FindIdx(uint32_t hash) const
{
uint32_t mask = SlotCount - 1;
uint32_t idx = hash & mask;
uint32_t tableEntry = HashTable[idx];
uint32_t stepCount = 0;
while (tableEntry != hash && tableEntry != 0 && stepCount < UINT16_MAX)
{
idx = (idx + 1) % SlotCount;
tableEntry = HashTable[idx];
++stepCount;
}
assert(stepCount < UINT16_MAX);
return idx;
}
};
namespace HashMapTests
{
struct AAA
{
int X = 3;
int Y = 42;
};
inline void Test()
{
HashMapCore<AAA, 16> testMap;
AAA* backingData = new AAA[testMap.RequiredDataSize]();
testMap.Init(backingData, testMap.RequiredDataSize);
AAA test{};
AAA test2{5, 6};
testMap.Get(bx::hash<bx::HashMurmur3>(test)).Obj = test;
testMap.Get(bx::hash<bx::HashMurmur3>(test2)).Obj = test2;
delete[] backingData;
}
} // namespace HashMapTests

View File

@@ -1,41 +1 @@
#include "Def.h" // #include "Def.h"
#define INST(T) \
template bool Save<T>(const T* obj, uint32_t count, Serializer& serializer); \
template bool Load<T>(T * obj, uint32_t count, Deserializer & serializer);
namespace Gen
{
template <typename T> bool Save(const T* obj, uint32_t count, Serializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
}
return isOk;
}
template <typename T> bool Load(T* obj, uint32_t count, Deserializer& serializer)
{
bool isOk = true;
for (uint32_t i = 0; i < count; ++i)
{
isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
}
return isOk;
}
INST(uint8_t)
INST(uint16_t)
INST(uint32_t)
INST(uint64_t)
INST(int8_t)
INST(int16_t)
INST(int32_t)
INST(int64_t)
INST(float)
INST(double)
INST(bool)
INST(char)
} // namespace Gen

View File

@@ -1,12 +1,83 @@
#pragma once #pragma once
#include "../game/Log.h" #include "../game/Log.h"
#include "Generated.h"
#include "bx/string.h" #include "bx/string.h"
#include <bx/file.h> #include <bx/file.h>
#include <cassert>
#include <cstdint> #include <cstdint>
namespace Gen namespace Gen
{ {
struct EmbeddedTypeTableBuffer
{
uint16_t DefCount = 0;
Meta::TypeDef Defs[64];
void AddDef(const Meta::TypeDef& def)
{
if (DefCount >= BX_COUNTOF(Defs))
{
LOG_WARN("Ran out of type definition space!");
return;
}
for (int32_t i = 0; i < DefCount; ++i)
{
if (Defs[i].Hash == def.Hash) return;
}
Defs[DefCount] = def;
++DefCount;
}
int32_t FindHash(uint32_t hash)
{
for (int32_t i = 0; i < DefCount; ++i)
{
if (Defs[i].Hash == hash)
{
return i;
}
}
return -1;
}
const int32_t FindDefByName(const char* name)
{
for (int32_t i = 0; i < DefCount; ++i)
{
if (bx::strCmp(name, Defs[i].Name) == 0)
{
return i;
}
}
return -1;
}
void PatchChildIndices()
{
for (int32_t i = 0; i < DefCount; ++i)
{
for (int32_t j = 0; j < Defs[i].ChildCount; ++j)
{
int32_t idx = FindHash(Meta::Metadata.TypeDefinitions[Defs[i].ChildIndices[j]].Hash);
assert(idx >= 0);
Defs[i].ChildIndices[j] = idx;
}
}
}
};
struct EmbeddedTypeInfoHeader
{
static constexpr uint32_t CurrentHeaderVersion = 1;
uint32_t HeaderVersion = CurrentHeaderVersion;
uint32_t BaseTypeHash = 0;
uint16_t BaseTypeIdx = 0;
uint16_t TypeCount = 0;
uint32_t TypeDataSize = 0;
uint32_t MemberDataSize = 0;
};
struct Serializer struct Serializer
{ {
bx::Error Err; bx::Error Err;
@@ -41,19 +112,43 @@ namespace Gen
template <typename T> bool WriteT(const T& data) template <typename T> bool WriteT(const T& data)
{ {
uint32_t hash = data.Hash; const Meta::TypeDef& baseDef = Meta::Metadata.TypeDefinitions[data.TypeIdx];
if (!Write(&hash, sizeof(hash))) return false;
uint32_t defSize = 0; EmbeddedTypeTableBuffer typeBuf;
if (!Write(&defSize, sizeof(defSize))) return false; typeBuf.AddDef(baseDef);
// auto& definitions = GetDefinitions(); // DefCount updates dynamically here!
// if (!Write(&definitions, sizeof(definitions))) return false; for (int32_t i = 0; i < typeBuf.DefCount; ++i)
{
const Meta::TypeDef& def = typeBuf.Defs[i];
for (int32_t j = 0; j < def.ChildCount; ++j)
{
typeBuf.AddDef(Meta::Metadata.TypeDefinitions[def.ChildIndices[j]]);
}
}
typeBuf.PatchChildIndices();
uint32_t size = sizeof(T); EmbeddedTypeInfoHeader header;
if (!Write(&size, sizeof(size))) return false; header.BaseTypeHash = baseDef.Hash;
header.BaseTypeIdx = 0;
header.TypeCount = typeBuf.DefCount;
header.TypeDataSize = header.TypeCount * sizeof(Meta::TypeDef);
header.MemberDataSize = bx::strLen(Meta::Metadata.MemberNameBuffer);
return Save(&data, 1, *this); if (!Write(&Meta::CurrentMetaVersion, sizeof(Meta::CurrentMetaVersion))) return false;
if (!Write(&header, sizeof(header))) return false;
for (int32_t i = 0; i < typeBuf.DefCount; ++i)
{
if (!Write(&typeBuf.Defs[i], sizeof(typeBuf.Defs[i]))) return false;
}
Write(Meta::Metadata.MemberNameBuffer, header.MemberDataSize);
if (!Save(&data, 1, *this))
{
LOG_ERROR("Failed to save!");
return false;
}
return true;
} }
bool Write(const void* data, uint32_t size) bool Write(const void* data, uint32_t size)
@@ -80,6 +175,9 @@ namespace Gen
bx::FilePath Path; bx::FilePath Path;
bx::FileReader Reader; bx::FileReader Reader;
char MemberNameBuf[64 * 64 * 64]{0};
EmbeddedTypeTableBuffer TypeBuf;
bool Init(const bx::FilePath& path, const char* _4cc) bool Init(const bx::FilePath& path, const char* _4cc)
{ {
Path = path; Path = path;
@@ -117,45 +215,55 @@ namespace Gen
template <typename T> bool ReadT(T& data) template <typename T> bool ReadT(T& data)
{ {
uint32_t hash = 0; uint16_t metadataVersion = 0;
if (!Read(&hash, sizeof(hash))) return false; if (!Read(&metadataVersion, sizeof(Meta::CurrentMetaVersion))) return false;
if (metadataVersion != Meta::CurrentMetaVersion)
uint32_t defSize = 0;
if (!Read(&defSize, sizeof(defSize))) return false;
if (data.Hash != hash)
{ {
LOG_WARN("Hash mismatch! %u != %u", data.Hash, hash); // TODO: upgrade?
LOG_ERROR("Metadata version mismatch: %u != %u", metadataVersion, Meta::CurrentMetaVersion);
// TODO: figure out upgrade data return false;
data = {};
return true;
} }
else
EmbeddedTypeInfoHeader header;
if (!Read(&header, sizeof(header))) return false;
if (header.HeaderVersion != EmbeddedTypeInfoHeader::CurrentHeaderVersion)
{ {
LOG("Hash match!"); // TODO: upgrade
LOG_ERROR("Header version mismatch: %u != %u",
header.HeaderVersion,
EmbeddedTypeInfoHeader::CurrentHeaderVersion);
return false;
}
// Skip definitions, we know they match const Meta::TypeDef& baseTypeDef = Meta::Metadata.TypeDefinitions[data.TypeIdx];
Reader.seek(defSize); if (header.BaseTypeHash != baseTypeDef.Hash)
{
LOG_WARN("Hash mismatch! %u != %u", header.BaseTypeHash, baseTypeDef.Hash);
}
uint32_t size = 0; TypeBuf.DefCount = header.TypeCount;
if (!Read(&size, sizeof(size))) return false; for (int32_t i = 0; i < TypeBuf.DefCount; ++i)
if (sizeof(T) != size) {
{ Read(&TypeBuf.Defs[i], sizeof(TypeBuf.Defs[i]));
LOG_ERROR("Size mismatch! %u != %u", sizeof(T), size); }
return false;
}
if (!Load(&data, 1, *this)) Read(MemberNameBuf, header.MemberDataSize);
{
LOG_ERROR("Failed to load: %s", Err.getMessage().getCPtr()); if (!Load(&data, 1, *this))
return false; {
} LOG_ERROR("Failed to load: %s", Err.getMessage().getCPtr());
return false;
} }
return true; return true;
} }
void Skip(uint32_t byteCount)
{
Reader.seek(byteCount);
}
void Finish() void Finish()
{ {
Reader.close(); Reader.close();
@@ -167,6 +275,18 @@ namespace Gen
} }
}; };
inline uint32_t FindNameInMetadata(const Meta::MetadataTable& meta, const char* name)
{
for (int32_t i = 0; i < BX_COUNTOF(meta.TypeDefinitions); ++i)
{
if (bx::strCmp(meta.TypeDefinitions[i].Name, name) == 0)
{
return i;
}
}
return -1;
}
template <typename T> bool Save(const T* obj, uint32_t count, Serializer& serializer); template <typename T> bool Save(const T* obj, uint32_t count, Serializer& serializer);
template <typename T> bool Load(T* obj, uint32_t count, Deserializer& serializer); template <typename T> bool Load(T* obj, uint32_t count, Deserializer& serializer);
} // namespace Gen } // namespace Gen

File diff suppressed because it is too large Load Diff

View File

@@ -7,9 +7,9 @@ namespace Gen
struct Deserializer; struct Deserializer;
struct PuzzleElementType struct PuzzleElementType
{ {
static constexpr uint16_t TypeIdx = 32;
static constexpr int32_t EntryCount = 8; static constexpr int32_t EntryCount = 8;
static constexpr uint32_t Hash = 2024002654; enum Enum : uint8_t
enum Enum : int32_t
{ {
None, None,
WaterIn, WaterIn,
@@ -54,10 +54,41 @@ namespace Gen
"#", "#",
}; };
}; };
struct PlacedPuzzleCardFlags
{
static constexpr uint16_t TypeIdx = 33;
static constexpr int32_t EntryCount = 2;
enum Enum : uint8_t
{
None = 0,
Locked = 1 << 0,
};
static constexpr char EntryNames[EntryCount][64]
{
"None",
"Locked",
};
};
inline PlacedPuzzleCardFlags::Enum operator| (const PlacedPuzzleCardFlags::Enum& a, const PlacedPuzzleCardFlags::Enum& b)
{
return a | b;
}
inline PlacedPuzzleCardFlags::Enum operator& (const PlacedPuzzleCardFlags::Enum& a, const PlacedPuzzleCardFlags::Enum& b)
{
return a & b;
}
inline PlacedPuzzleCardFlags::Enum operator|= (PlacedPuzzleCardFlags::Enum& a, const PlacedPuzzleCardFlags::Enum& b)
{
return a |= b;
}
inline PlacedPuzzleCardFlags::Enum operator&= (PlacedPuzzleCardFlags::Enum& a, const PlacedPuzzleCardFlags::Enum& b)
{
return a &= b;
}
struct EMaterial struct EMaterial
{ {
static constexpr uint16_t TypeIdx = 34;
static constexpr int32_t EntryCount = 2; static constexpr int32_t EntryCount = 2;
static constexpr uint32_t Hash = 2024002654;
enum Enum : int32_t enum Enum : int32_t
{ {
Default, Default,
@@ -71,20 +102,20 @@ namespace Gen
}; };
struct Vec2 struct Vec2
{ {
static constexpr uint32_t Hash = 2667033957; static constexpr uint16_t TypeIdx = 12;
float x = {}; float x = {};
float y = {}; float y = {};
}; };
struct Vec3 struct Vec3
{ {
static constexpr uint32_t Hash = 473740858; static constexpr uint16_t TypeIdx = 13;
float x = {}; float x = {};
float y = {}; float y = {};
float z = {}; float z = {};
}; };
struct Vec4 struct Vec4
{ {
static constexpr uint32_t Hash = 2507696603; static constexpr uint16_t TypeIdx = 14;
float x = {}; float x = {};
float y = {}; float y = {};
float z = {}; float z = {};
@@ -92,7 +123,7 @@ namespace Gen
}; };
struct Mat3 struct Mat3
{ {
static constexpr uint32_t Hash = 3364737048; static constexpr uint16_t TypeIdx = 15;
float M[9] = { float M[9] = {
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
@@ -101,7 +132,7 @@ namespace Gen
}; };
struct Mat4 struct Mat4
{ {
static constexpr uint32_t Hash = 1650094019; static constexpr uint16_t TypeIdx = 16;
float M[16] = { float M[16] = {
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
@@ -111,7 +142,7 @@ namespace Gen
}; };
struct Transform struct Transform
{ {
static constexpr uint32_t Hash = 4103530190; static constexpr uint16_t TypeIdx = 17;
Mat4 M = {}; Mat4 M = {};
Mat4 MI = {}; Mat4 MI = {};
Vec3 Position = {}; Vec3 Position = {};
@@ -120,70 +151,83 @@ namespace Gen
}; };
struct AssetHandle struct AssetHandle
{ {
static constexpr uint32_t Hash = 2609735487; static constexpr uint16_t TypeIdx = 18;
uint32_t Idx = UINT32_MAX; uint32_t Idx = UINT32_MAX;
}; };
struct ModelHandle struct ModelHandle
{ {
static constexpr uint32_t Hash = 298089627; static constexpr uint16_t TypeIdx = 19;
uint16_t ModelIdx = UINT16_MAX; uint16_t ModelIdx = UINT16_MAX;
AssetHandle Asset = {}; AssetHandle Asset = {};
}; };
struct TextureHandle struct TextureHandle
{ {
static constexpr uint32_t Hash = 1633273761; static constexpr uint16_t TypeIdx = 20;
uint16_t TextureIdx = UINT16_MAX; uint16_t TextureIdx = UINT16_MAX;
AssetHandle Asset = {}; AssetHandle Asset = {};
}; };
struct PuzPos struct PuzPos
{ {
static constexpr uint32_t Hash = 1834398141; static constexpr uint16_t TypeIdx = 21;
int8_t X = {}; int8_t X = {};
int8_t Y = {}; int8_t Y = {};
}; };
struct CardSocket
{
static constexpr uint16_t TypeIdx = 22;
ModelHandle Model = {};
uint8_t ConnectionDirection = {};
};
struct StaticPuzzleCard struct StaticPuzzleCard
{ {
static constexpr uint32_t Hash = 431895198; static constexpr uint16_t TypeIdx = 23;
PuzzleElementType::Enum Elements[4] = {}; PuzzleElementType::Enum Elements[4] = {};
ModelHandle ModelHandle = {}; ModelHandle BaseModelHandle = {};
ModelHandle NorthCoverHandle = {};
ModelHandle EastCoverHandle = {};
ModelHandle SouthCoverHandle = {};
ModelHandle WestCoverHandle = {};
CardSocket Sockets[16] = {};
TextureHandle ModelTextureHandle = {};
TextureHandle BoardTextureHandle = {}; TextureHandle BoardTextureHandle = {};
}; };
struct StaticPuzzleCardHandle struct StaticPuzzleCardHandle
{ {
static constexpr uint32_t Hash = 1742502768; static constexpr uint16_t TypeIdx = 24;
uint16_t Idx = UINT16_MAX; uint16_t Idx = UINT16_MAX;
}; };
struct PuzzleVisualSettings struct PuzzleVisualSettings
{ {
static constexpr uint32_t Hash = 4208425878; static constexpr uint16_t TypeIdx = 25;
Vec4 TileBaseColor = {}; Vec4 TileBaseColor = {};
Vec4 TileDotColor = {}; Vec4 TileDotColor = {};
Vec3 Test = {};
Vec4 DisabledCardTint = {}; Vec4 DisabledCardTint = {};
}; };
struct StaticPuzzleData struct StaticPuzzleData
{ {
static constexpr uint32_t Hash = 1076634601; static constexpr uint16_t TypeIdx = 26;
StaticPuzzleCard Cards[64] = {}; StaticPuzzleCard Cards[64] = {};
PuzzleVisualSettings Visuals = {}; PuzzleVisualSettings Visuals = {};
}; };
struct PuzzleCardStack struct PuzzleCardStack
{ {
static constexpr uint32_t Hash = 53538532; static constexpr uint16_t TypeIdx = 27;
StaticPuzzleCardHandle RefCard = {}; StaticPuzzleCardHandle RefCard = {};
uint8_t MaxAvailableCount = {}; uint8_t MaxAvailableCount = {};
uint8_t UsedCount = {}; uint8_t UsedCount = {};
}; };
struct PlacedPuzzleCard struct PlacedPuzzleCard
{ {
static constexpr uint32_t Hash = 3555575973; static constexpr uint16_t TypeIdx = 28;
StaticPuzzleCardHandle RefCard = {}; StaticPuzzleCardHandle RefCard = {};
PuzPos Position = {}; PuzPos Position = {};
uint8_t Rotation = {}; uint8_t Rotation = {};
bool IsLocked = {}; PlacedPuzzleCardFlags::Enum Flags = {};
}; };
struct PuzzleData struct PuzzleData
{ {
static constexpr uint32_t Hash = 657000000; static constexpr uint16_t TypeIdx = 29;
uint16_t ID = {}; uint16_t ID = {};
char PuzzleName[64] = {}; char PuzzleName[64] = {};
uint8_t WidthTiles = {}; uint8_t WidthTiles = {};
@@ -191,13 +235,14 @@ 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] = {};
}; };
struct SavedEntityRenderData struct SavedEntityRenderData
{ {
static constexpr uint32_t Hash = 3172756855; static constexpr uint16_t TypeIdx = 30;
Vec4 BaseColor = {}; Vec4 BaseColor = {};
Vec4 HighlightColor = {}; Vec4 HighlightColor = {};
Transform TF = {}; Transform TF = {};
@@ -206,10 +251,46 @@ namespace Gen
ModelHandle Model = {}; ModelHandle Model = {};
bool Visible = {}; bool Visible = {};
}; };
struct SavedPlayerConfig
{
static constexpr uint16_t TypeIdx = 31;
SavedEntityRenderData TabletBackgroundRenderData = {};
SavedEntityRenderData TabletStatusRenderData = {};
TextureHandle TabletStatusNotSolvedTexture = {};
TextureHandle TabletStatusSolvedTexture = {};
SavedEntityRenderData TabletResetRenderData = {};
SavedEntityRenderData BackgroundLevelRenderData[16] = {};
};
bool Save(const PuzzleElementType::Enum* obj, uint32_t count, Serializer& serializer); bool 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 Load(int8_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const int16_t* obj, uint32_t count, Serializer& serializer);
bool Load(int16_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const int32_t* obj, uint32_t count, Serializer& serializer);
bool Load(int32_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const int64_t* obj, uint32_t count, Serializer& serializer);
bool Load(int64_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const uint8_t* obj, uint32_t count, Serializer& serializer);
bool Load(uint8_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const uint16_t* obj, uint32_t count, Serializer& serializer);
bool Load(uint16_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const uint32_t* obj, uint32_t count, Serializer& serializer);
bool Load(uint32_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const uint64_t* obj, uint32_t count, Serializer& serializer);
bool Load(uint64_t* obj, uint32_t count, Deserializer& serializer);
bool Save(const bool* obj, uint32_t count, Serializer& serializer);
bool Load(bool* obj, uint32_t count, Deserializer& serializer);
bool Save(const float* obj, uint32_t count, Serializer& serializer);
bool Load(float* obj, uint32_t count, Deserializer& serializer);
bool Save(const double* obj, uint32_t count, Serializer& serializer);
bool Load(double* obj, uint32_t count, Deserializer& serializer);
bool Save(const char* obj, uint32_t count, Serializer& serializer);
bool Load(char* obj, uint32_t count, Deserializer& serializer);
bool Save(const Vec2* obj, uint32_t count, Serializer& serializer); bool Save(const Vec2* obj, uint32_t count, Serializer& serializer);
bool Load(Vec2* obj, uint32_t count, Deserializer& serializer); bool Load(Vec2* obj, uint32_t count, Deserializer& serializer);
bool Save(const Vec3* obj, uint32_t count, Serializer& serializer); bool Save(const Vec3* obj, uint32_t count, Serializer& serializer);
@@ -230,6 +311,8 @@ namespace Gen
bool Load(TextureHandle* obj, uint32_t count, Deserializer& serializer); bool Load(TextureHandle* obj, uint32_t count, Deserializer& serializer);
bool Save(const PuzPos* obj, uint32_t count, Serializer& serializer); bool Save(const PuzPos* obj, uint32_t count, Serializer& serializer);
bool Load(PuzPos* obj, uint32_t count, Deserializer& serializer); bool Load(PuzPos* obj, uint32_t count, Deserializer& serializer);
bool Save(const CardSocket* obj, uint32_t count, Serializer& serializer);
bool Load(CardSocket* obj, uint32_t count, Deserializer& serializer);
bool Save(const StaticPuzzleCard* obj, uint32_t count, Serializer& serializer); bool Save(const StaticPuzzleCard* obj, uint32_t count, Serializer& serializer);
bool Load(StaticPuzzleCard* obj, uint32_t count, Deserializer& serializer); bool Load(StaticPuzzleCard* obj, uint32_t count, Deserializer& serializer);
bool Save(const StaticPuzzleCardHandle* obj, uint32_t count, Serializer& serializer); bool Save(const StaticPuzzleCardHandle* obj, uint32_t count, Serializer& serializer);
@@ -246,4 +329,72 @@ namespace Gen
bool Load(PuzzleData* obj, uint32_t count, Deserializer& serializer); bool Load(PuzzleData* obj, uint32_t count, Deserializer& serializer);
bool Save(const SavedEntityRenderData* obj, uint32_t count, Serializer& serializer); bool Save(const SavedEntityRenderData* obj, uint32_t count, Serializer& serializer);
bool Load(SavedEntityRenderData* obj, uint32_t count, Deserializer& serializer); bool Load(SavedEntityRenderData* obj, uint32_t count, Deserializer& serializer);
bool Save(const SavedPlayerConfig* obj, uint32_t count, Serializer& serializer);
bool Load(SavedPlayerConfig* obj, uint32_t count, Deserializer& serializer);
namespace Meta {
constexpr uint16_t CurrentMetaVersion = 1;
struct StrRef
{
uint16_t Offset;
uint16_t Size;
};
struct TypeDef
{
uint32_t Size = 0;
uint32_t Hash = 0;
char Name[64]{"Dummy"};
uint16_t ChildCount = 0;
uint16_t ChildIndices[64]{0};
uint16_t ChildArraySizes[64]{0};
StrRef MemberNameIndices[64]{0};
};
struct MetadataTable
{
TypeDef TypeDefinitions[35]
{
TypeDef{sizeof(int8_t), 0, "i8", 0, {}, {}, {}},
TypeDef{sizeof(int16_t), 1, "i16", 0, {}, {}, {}},
TypeDef{sizeof(int32_t), 2, "i32", 0, {}, {}, {}},
TypeDef{sizeof(int64_t), 3, "i64", 0, {}, {}, {}},
TypeDef{sizeof(uint8_t), 4, "u8", 0, {}, {}, {}},
TypeDef{sizeof(uint16_t), 5, "u16", 0, {}, {}, {}},
TypeDef{sizeof(uint32_t), 6, "u32", 0, {}, {}, {}},
TypeDef{sizeof(uint64_t), 7, "u64", 0, {}, {}, {}},
TypeDef{sizeof(bool), 8, "b", 0, {}, {}, {}},
TypeDef{sizeof(float), 9, "f32", 0, {}, {}, {}},
TypeDef{sizeof(double), 10, "f64", 0, {}, {}, {}},
TypeDef{sizeof(char), 11, "str", 0, {}, {}, {}},
TypeDef{sizeof(Vec2), 2667033957, "Vec2", 2, {9, 9}, {0, 0}, {{0, 1}, {1, 1}}},
TypeDef{sizeof(Vec3), 473740858, "Vec3", 3, {9, 9, 9}, {0, 0, 0}, {{2, 1}, {3, 1}, {4, 1}}},
TypeDef{sizeof(Vec4), 2507696603, "Vec4", 4, {9, 9, 9, 9}, {0, 0, 0, 0}, {{5, 1}, {6, 1}, {7, 1}, {8, 1}}},
TypeDef{sizeof(Mat3), 3364737048, "Mat3", 1, {9}, {9}, {{9, 1}}},
TypeDef{sizeof(Mat4), 1650094019, "Mat4", 1, {9}, {16}, {{10, 1}}},
TypeDef{sizeof(Transform), 4103530190, "Transform", 5, {16, 16, 13, 16, 13}, {0, 0, 0, 0, 0}, {{11, 1}, {12, 2}, {14, 8}, {22, 8}, {30, 5}}},
TypeDef{sizeof(AssetHandle), 2609735487, "AssetHandle", 1, {6}, {0}, {{35, 3}}},
TypeDef{sizeof(ModelHandle), 298089627, "ModelHandle", 2, {5, 18}, {0, 0}, {{38, 8}, {46, 5}}},
TypeDef{sizeof(TextureHandle), 1633273761, "TextureHandle", 2, {5, 18}, {0, 0}, {{51, 10}, {61, 5}}},
TypeDef{sizeof(PuzPos), 1834398141, "PuzPos", 2, {0, 0}, {0, 0}, {{66, 1}, {67, 1}}},
TypeDef{sizeof(CardSocket), 2168907571, "CardSocket", 2, {19, 4}, {0, 0}, {{68, 5}, {73, 19}}},
TypeDef{sizeof(StaticPuzzleCard), 537913399, "StaticPuzzleCard", 9, {32, 19, 19, 19, 19, 19, 22, 20, 20}, {4, 0, 0, 0, 0, 0, 16, 0, 0}, {{92, 8}, {100, 15}, {115, 16}, {131, 15}, {146, 16}, {162, 15}, {177, 7}, {184, 18}, {202, 18}}},
TypeDef{sizeof(StaticPuzzleCardHandle), 1742502768, "StaticPuzzleCardHandle", 1, {5}, {0}, {{220, 3}}},
TypeDef{sizeof(PuzzleVisualSettings), 2302077481, "PuzzleVisualSettings", 4, {14, 14, 13, 14}, {0, 0, 0, 0}, {{223, 13}, {236, 12}, {248, 4}, {252, 16}}},
TypeDef{sizeof(StaticPuzzleData), 2637647137, "StaticPuzzleData", 2, {23, 25}, {64, 0}, {{268, 5}, {273, 7}}},
TypeDef{sizeof(PuzzleCardStack), 53538532, "PuzzleCardStack", 3, {24, 4, 4}, {0, 0, 0}, {{280, 7}, {287, 17}, {304, 9}}},
TypeDef{sizeof(PlacedPuzzleCard), 838818025, "PlacedPuzzleCard", 4, {24, 21, 4, 33}, {0, 0, 0, 0}, {{313, 7}, {320, 8}, {328, 8}, {336, 5}}},
TypeDef{sizeof(PuzzleData), 1562434765, "PuzzleData", 11, {5, 11, 4, 4, 6, 27, 28, 28, 32, 6, 21}, {0, 64, 0, 0, 0, 16, 256, 256, 1024, 0, 16}, {{341, 2}, {343, 10}, {353, 10}, {363, 11}, {374, 18}, {392, 14}, {406, 11}, {417, 18}, {435, 15}, {450, 17}, {467, 13}}},
TypeDef{sizeof(SavedEntityRenderData), 3172756855, "SavedEntityRenderData", 7, {14, 14, 17, 34, 20, 19, 8}, {0, 0, 0, 0, 0, 0, 0}, {{480, 9}, {489, 14}, {503, 2}, {505, 8}, {513, 7}, {520, 5}, {525, 7}}},
TypeDef{sizeof(SavedPlayerConfig), 1710757245, "SavedPlayerConfig", 6, {30, 30, 20, 20, 30, 30}, {0, 0, 0, 0, 0, 16}, {{532, 26}, {558, 22}, {580, 28}, {608, 25}, {633, 21}, {654, 25}}},
TypeDef{sizeof(PuzzleElementType::Enum), 2983807453, "PuzzleElementType", 0, {}, {}, {}},
TypeDef{sizeof(PlacedPuzzleCardFlags::Enum), 2983807453, "PlacedPuzzleCardFlags", 0, {}, {}, {}},
TypeDef{sizeof(EMaterial::Enum), 2024002654, "EMaterial", 0, {}, {}, {}},
};
char MemberNameBuffer[64*64*64]{"xyxyzxyzwMMMMIPositionRotationScaleIdxModelIdxAssetTextureIdxAssetXYModelConnectionDirectionElementsBaseModelHandleNorthCoverHandleEastCoverHandleSouthCoverHandleWestCoverHandleSocketsModelTextureHandleBoardTextureHandleIdxTileBaseColorTileDotColorTestDisabledCardTintCardsVisualsRefCardMaxAvailableCountUsedCountRefCardPositionRotationFlagsIDPuzzleNameWidthTilesHeightTilesAvailableCardCountAvailableCardsPlacedCardsInitialPlacedCardsBackgroundTilesGoalPositionCountGoalPositionsBaseColorHighlightColorTFMaterialTextureModelVisibleTabletBackgroundRenderDataTabletStatusRenderDataTabletStatusNotSolvedTextureTabletStatusSolvedTextureTabletResetRenderDataBackgroundLevelRenderData"};
};
constexpr MetadataTable Metadata;
}
} }

Binary file not shown.

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.

BIN
src/models/channel_cover_big.glb LFS Normal file

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.

13
src/notes.txt Normal file
View File

@@ -0,0 +1,13 @@
4 bytes: 4cc
File type idendifier
20 bytes: TypeInfoHeader
4 | 4 | 2 | 2 | 4 | 4
Version | Base Type Hash | Base Type Idx | Type Count | Type Data Size | Member Data Size
TypeDataSize bytes: TypeDefs
MemberDataSize bytes: Member data names, indexed from TypeDef
// todo: enum table for upgrading strings?
xxx bytes: actual data, Load/Save with BaseType

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

BIN
src/textures/bridge.ktx LFS Normal file

Binary file not shown.

BIN
src/textures/concrete_tile.ktx LFS Normal file

Binary file not shown.

BIN
src/textures/notsolved.ktx LFS Normal file

Binary file not shown.

BIN
src/textures/reset.ktx LFS Normal file

Binary file not shown.

BIN
src/textures/solved.ktx LFS Normal file

Binary file not shown.

BIN
src/textures/w corner long.ktx LFS Normal file

Binary file not shown.

Binary file not shown.

BIN
src/textures/w! corner short.ktx LFS Normal file

Binary file not shown.

BIN
src/textures/w+ corner short.ktx LFS Normal file

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
}

Some files were not shown because too many files have changed in this diff Show More