Compare commits
62 Commits
c244b997c1
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6e0cbf41c | ||
|
|
f95d9dee91 | ||
|
|
3c0af71470 | ||
|
|
7e89d93a7d | ||
|
|
05cf88d986 | ||
|
|
d6bec9e870 | ||
|
|
3ccbbf493f | ||
|
|
b47a0cf841 | ||
|
|
db47297ea4 | ||
|
|
6461b442de | ||
|
|
146bf4aa22 | ||
|
|
42c5b55f95 | ||
|
|
d7fc6b781e | ||
|
|
e15cd79e04 | ||
|
|
4e00355dbe | ||
|
|
ffcc5bd134 | ||
|
|
67c1489da0 | ||
|
|
59b8eea3a7 | ||
|
|
a936222711 | ||
|
|
3af10d120b | ||
|
|
6c8bead6ab | ||
|
|
faa36dd679 | ||
|
|
196d119338 | ||
|
|
383c6f975b | ||
|
|
4b230be2a8 | ||
|
|
87ce032833 | ||
|
|
cac2ef3330 | ||
|
|
410f401aef | ||
|
|
0c2d10d631 | ||
|
|
18e7085aeb | ||
|
|
bd2962fc38 | ||
|
|
15dc65530d | ||
|
|
70db6ca2aa | ||
|
|
1a8be39c19 | ||
|
|
ec7a709570 | ||
|
|
5cdc7d720e | ||
|
|
79fe91981b | ||
|
|
0d91ec1ebb | ||
|
|
1616704c50 | ||
|
|
5d1db591b7 | ||
|
|
234a9b1732 | ||
|
|
91e9566747 | ||
|
|
02c40aeea6 | ||
|
|
171e25ac76 | ||
|
|
32d89d8f77 | ||
|
|
4cdd80977c | ||
|
|
d75e5627f9 | ||
|
|
adbe518c6e | ||
|
|
c9db7e7e8f | ||
|
|
d252da6359 | ||
|
|
3fd8937b25 | ||
|
|
fd2654c944 | ||
|
|
d0f9051af7 | ||
|
|
e0016817dd | ||
|
|
c7edebaeb8 | ||
|
|
158d59e09e | ||
|
|
ab5c8a489f | ||
|
|
12c546b6dc | ||
|
|
ae069c4949 | ||
|
|
5a3739db0a | ||
|
|
4ba65713ef | ||
|
|
29a3aaf241 |
BIN
assets/blender/Channels.blend
LFS
BIN
assets/blender/Channels.blend
LFS
Binary file not shown.
BIN
assets/blender/cards.blend
LFS
Normal file
BIN
assets/blender/cards.blend
LFS
Normal file
Binary file not shown.
BIN
assets/blender/landscape.blend
LFS
Normal file
BIN
assets/blender/landscape.blend
LFS
Normal file
Binary file not shown.
BIN
assets/blender/tablet.blend
LFS
BIN
assets/blender/tablet.blend
LFS
Binary file not shown.
BIN
assets/textures/bridge.png
LFS
Normal file
BIN
assets/textures/bridge.png
LFS
Normal file
Binary file not shown.
BIN
assets/textures/concrete_tile.png
LFS
Normal file
BIN
assets/textures/concrete_tile.png
LFS
Normal file
Binary file not shown.
BIN
assets/textures/notsolved.png
LFS
Normal file
BIN
assets/textures/notsolved.png
LFS
Normal file
Binary file not shown.
BIN
assets/textures/reset.png
LFS
Normal file
BIN
assets/textures/reset.png
LFS
Normal file
Binary file not shown.
BIN
assets/textures/solved.png
LFS
Normal file
BIN
assets/textures/solved.png
LFS
Normal file
Binary file not shown.
BIN
assets/textures/w corner long.png
LFS
Normal file
BIN
assets/textures/w corner long.png
LFS
Normal file
Binary file not shown.
BIN
assets/textures/w straight.png
LFS
BIN
assets/textures/w straight.png
LFS
Binary file not shown.
BIN
assets/textures/w! corner short.png
LFS
Normal file
BIN
assets/textures/w! corner short.png
LFS
Normal file
Binary file not shown.
BIN
assets/textures/w+ corner short.png
LFS
Normal file
BIN
assets/textures/w+ corner short.png
LFS
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
|
||||
$texturecPath = ".\cmake-build\texturec.exe"
|
||||
$texturecPath = "..\tools\texturec.exe"
|
||||
$textureAssetDir = "..\assets\textures"
|
||||
$outputBaseDir = ".\textures"
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
cmake --build cmake-build-release
|
||||
@@ -1 +0,0 @@
|
||||
cmake --build cmake-build
|
||||
1
src/build_release.ps1
Normal file
1
src/build_release.ps1
Normal file
@@ -0,0 +1 @@
|
||||
cmake --build cmake-build-release --config Release
|
||||
1
src/buildnotes.txt
Normal file
1
src/buildnotes.txt
Normal file
@@ -0,0 +1 @@
|
||||
https://github.com/mstorsjo/llvm-mingw/releases
|
||||
2
src/debug.ps1
Normal file
2
src/debug.ps1
Normal file
@@ -0,0 +1,2 @@
|
||||
.\build.ps1
|
||||
& raddbg.exe --project:../tools/radsession.rad --auto_run -q
|
||||
@@ -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, ...);
|
||||
};
|
||||
@@ -32,7 +32,7 @@ namespace Gen
|
||||
constexpr char StructHeader2[] =
|
||||
R"END( struct %s
|
||||
{
|
||||
static constexpr uint32_t Hash = %u;
|
||||
static constexpr uint16_t TypeIdx = %u;
|
||||
)END";
|
||||
|
||||
constexpr char StructField4[] =
|
||||
@@ -46,8 +46,8 @@ namespace Gen
|
||||
constexpr char EnumHeader4[] =
|
||||
R"END( struct %s
|
||||
{
|
||||
static constexpr uint16_t TypeIdx = %u;
|
||||
static constexpr int32_t EntryCount = %u;
|
||||
static constexpr uint32_t Hash = %u;
|
||||
enum Enum : %s
|
||||
{
|
||||
)END";
|
||||
@@ -55,6 +55,9 @@ namespace Gen
|
||||
constexpr char EnumField1[] =
|
||||
R"END( %s,
|
||||
)END";
|
||||
constexpr char EnumFieldNumbered2[] =
|
||||
R"END( %s = %s,
|
||||
)END";
|
||||
|
||||
constexpr char EnumNamesStart2[] =
|
||||
R"END( };
|
||||
@@ -71,6 +74,25 @@ namespace Gen
|
||||
};
|
||||
)END";
|
||||
|
||||
constexpr char EnumFlagOperators12[] =
|
||||
R"END( inline %s::Enum operator| (const %s::Enum& a, const %s::Enum& b)
|
||||
{
|
||||
return a | b;
|
||||
}
|
||||
inline %s::Enum operator& (const %s::Enum& a, const %s::Enum& b)
|
||||
{
|
||||
return a & b;
|
||||
}
|
||||
inline %s::Enum operator|= (%s::Enum& a, const %s::Enum& b)
|
||||
{
|
||||
return a |= b;
|
||||
}
|
||||
inline %s::Enum operator&= (%s::Enum& a, const %s::Enum& b)
|
||||
{
|
||||
return a &= b;
|
||||
}
|
||||
)END";
|
||||
|
||||
constexpr char FileEnd[] =
|
||||
R"END(}
|
||||
)END";
|
||||
@@ -85,6 +107,8 @@ namespace Gen
|
||||
{
|
||||
)END";
|
||||
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";
|
||||
constexpr char SaveFuncBodyEnum1[] = R"END( auto val = (%s)obj[i];
|
||||
isOk = Save(&val, 1, serializer) && isOk;
|
||||
@@ -99,18 +123,148 @@ namespace Gen
|
||||
)END";
|
||||
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 LoadFuncBodyType3[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk;
|
||||
constexpr char LoadFuncBodyQuickLoad2[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk;
|
||||
)END";
|
||||
constexpr char LoadFuncBodyEnum2[] = R"END( %s& val = (%s&)obj[i];
|
||||
isOk = Load(&val, 1, serializer) && isOk;
|
||||
)END";
|
||||
constexpr char LoadFuncBodyEnd[] = R"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;
|
||||
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";
|
||||
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";
|
||||
constexpr char LoadFuncBodyTypeUpgradeEnd[] = R"END( assert(false);
|
||||
}
|
||||
}
|
||||
assert(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";
|
||||
} // namespace WriteTemplates
|
||||
|
||||
@@ -164,48 +318,69 @@ void CppFileWriter::WriteInternal(WriteBuffer& buf, const char* templateStr, va_
|
||||
buf.WrittenBytes += bx::vsnprintf(&buf.Data[buf.WrittenBytes], BufferRequestSize, templateStr, args);
|
||||
}
|
||||
|
||||
void CppFileWriter::PrintTypeName(char* buf,
|
||||
int32_t bufSize,
|
||||
const Def::FieldType& type,
|
||||
const Def::DefinitionFile& definitions)
|
||||
void CppFileWriter::PrintTypeName(
|
||||
char* buf, int32_t bufSize, Def::TypeRef type, const Def::DefinitionFile& definitions, PrintFlags flags)
|
||||
{
|
||||
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)
|
||||
{
|
||||
bx::strCopy(buf, bufSize, Gen::KnownType::CName[size_t(type.Native)]);
|
||||
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, t.NativeCName);
|
||||
}
|
||||
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)
|
||||
{
|
||||
bx::strCopy(buf, bufSize, definitions.Enums[type.TypeIdx].Name);
|
||||
if ((int32_t)flags & (int32_t)PrintFlags::PrintFullEnumName)
|
||||
{
|
||||
bx::strCat(buf, bufSize, "::Enum");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppFileWriter::WriteEnums(const Def::DefinitionFile& definitions)
|
||||
{
|
||||
for (int32_t enumIdx = 0; enumIdx < definitions.EnumCount; ++enumIdx)
|
||||
{
|
||||
const Def::Enum& e = definitions.Enums[enumIdx];
|
||||
bool isFlagsEnum = (uint32_t)e.EnumFlags & (uint32_t)Def::EEnumFlags::FlagsEnum;
|
||||
|
||||
Write(WriteTemplates::EnumHeader4,
|
||||
e.Name,
|
||||
e.EntryCount,
|
||||
e.Hash,
|
||||
Gen::KnownType::CName[(int32_t)e.EnumType.Native]);
|
||||
if (!IsValid(e.EnumType))
|
||||
{
|
||||
LOG_ERROR(0, "Invalid enum type (enum %i)", enumIdx);
|
||||
continue;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx)
|
||||
@@ -223,6 +398,23 @@ void CppFileWriter::WriteEnums(const Def::DefinitionFile& definitions)
|
||||
}
|
||||
|
||||
Write(WriteTemplates::EnumNamesEnd);
|
||||
|
||||
if (isFlagsEnum)
|
||||
{
|
||||
Write(WriteTemplates::EnumFlagOperators12,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name,
|
||||
e.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
void CppFileWriter::WriteTypes(const Def::DefinitionFile& definitions)
|
||||
@@ -230,15 +422,16 @@ void CppFileWriter::WriteTypes(const Def::DefinitionFile& definitions)
|
||||
for (int32_t typeIdx = 0; typeIdx < definitions.TypeCount; ++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)
|
||||
{
|
||||
char Type[64]{0};
|
||||
PrintTypeName(Type, sizeof(Type), t.FieldTypes[fieldIdx], definitions);
|
||||
char Array[32]{0};
|
||||
uint32_t ArraySize = t.FieldArraySizes[fieldIdx];
|
||||
if (ArraySize > 0)
|
||||
if (ArraySize > 0 && ArraySize != UINT32_MAX)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
PrintTypeName(fieldBuf, sizeof(fieldBuf), e.EnumType, definitions);
|
||||
|
||||
@@ -266,15 +464,23 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions)
|
||||
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyStart1, nameBuf);
|
||||
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];
|
||||
Write(WriteTemplates::SaveFuncHeader1, t.Name);
|
||||
Write(WriteTemplates::LoadFuncHeader1, t.Name);
|
||||
char typeName[Def::MaxNameLength]{0};
|
||||
PrintTypeName(typeName, sizeof(typeName), {typeIdx, Def::EFieldType::DefinedClass}, definitions);
|
||||
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyStart1, t.Name);
|
||||
Write(WriteTemplates::SaveFuncHeader1, typeName);
|
||||
Write(WriteTemplates::LoadFuncHeader1, typeName);
|
||||
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyStart1, typeName);
|
||||
if ((int32_t)t.TypeFlags & (int32_t)Def::ETypeFlags::IsNative)
|
||||
{
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyNative);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||
{
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyType3,
|
||||
@@ -282,19 +488,119 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions)
|
||||
t.FieldNames[fieldIdx],
|
||||
bx::max(1, t.FieldArraySizes[fieldIdx]));
|
||||
}
|
||||
}
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyEnd);
|
||||
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyStart1, t.Name);
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyStart1, typeName);
|
||||
if ((int32_t)t.TypeFlags & (int32_t)Def::ETypeFlags::IsNative)
|
||||
{
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyNative);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteCpp(WriteTemplates::LoadFuncBodySetupStart2, typeName, typeName);
|
||||
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||
{
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyType3,
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyQuickLoad2,
|
||||
t.FieldArraySizes[fieldIdx] > 0 ? "" : "&",
|
||||
t.FieldNames[fieldIdx],
|
||||
bx::max(1, t.FieldArraySizes[fieldIdx]));
|
||||
}
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyEnd);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
LOG(0, "Generating output files...");
|
||||
@@ -307,6 +613,7 @@ void CppFileWriter::GenerateCpp(const bx::FilePath& outDir, const Def::Definitio
|
||||
WriteEnums(definitions);
|
||||
WriteTypes(definitions);
|
||||
WriteSaveLoadMethods(definitions);
|
||||
WriteMetadata(definitions);
|
||||
Write(WriteTemplates::FileEnd);
|
||||
WriteCpp(WriteTemplates::FileEnd);
|
||||
|
||||
@@ -334,36 +641,3 @@ void CppFileWriter::WriteCpp(const char* templateStr, ...)
|
||||
WriteInternal(CppWrite, templateStr, 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;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,13 @@ struct WriteBuffer
|
||||
uint64_t WrittenBytes = 0;
|
||||
};
|
||||
|
||||
enum class PrintFlags : uint32_t
|
||||
{
|
||||
None = 0,
|
||||
PrintFullEnumName = 1 << 0,
|
||||
PrintNativeTypeName = 1 << 1,
|
||||
};
|
||||
|
||||
struct CppFileWriter
|
||||
{
|
||||
private:
|
||||
@@ -21,13 +28,18 @@ struct CppFileWriter
|
||||
void WriteInternal(WriteBuffer& buf, const char* templateStr, va_list args);
|
||||
|
||||
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 WriteTypes(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 Write(const char* templateStr, ...);
|
||||
void WriteCpp(const char* templateStr, ...);
|
||||
void WriteTypeDataFile(const bx::FilePath& outDir, const Def::DefinitionFile& definitions);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -8,7 +8,7 @@ namespace Gen
|
||||
bool isOk = true;
|
||||
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;
|
||||
}
|
||||
return isOk;
|
||||
@@ -18,17 +18,209 @@ namespace Gen
|
||||
bool isOk = true;
|
||||
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;
|
||||
}
|
||||
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 isOk = true;
|
||||
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;
|
||||
}
|
||||
@@ -37,7 +229,7 @@ namespace Gen
|
||||
bool isOk = true;
|
||||
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;
|
||||
}
|
||||
@@ -46,9 +238,9 @@ namespace Gen
|
||||
bool isOk = true;
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
isOk = Save(&obj[i].Width, 1, serializer) && isOk;
|
||||
isOk = Save(&obj[i].Height, 1, serializer) && isOk;
|
||||
isOk = Save(obj[i].StrTest, 3, serializer) && isOk;
|
||||
isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
|
||||
isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
|
||||
isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
|
||||
isOk = Save(&obj[i].T, 1, serializer) && isOk;
|
||||
}
|
||||
return isOk;
|
||||
@@ -58,9 +250,9 @@ namespace Gen
|
||||
bool isOk = true;
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
isOk = Load(&obj[i].Width, 1, serializer) && isOk;
|
||||
isOk = Load(&obj[i].Height, 1, serializer) && isOk;
|
||||
isOk = Load(obj[i].StrTest, 3, serializer) && isOk;
|
||||
isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
|
||||
isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
|
||||
isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
|
||||
isOk = Load(&obj[i].T, 1, serializer) && isOk;
|
||||
}
|
||||
return isOk;
|
||||
|
||||
@@ -7,9 +7,9 @@ namespace Gen
|
||||
struct Deserializer;
|
||||
struct KnownType
|
||||
{
|
||||
static constexpr uint16_t EnumIdx = 0;
|
||||
static constexpr int32_t EntryCount = 12;
|
||||
static constexpr uint32_t Hash = 2024002654;
|
||||
enum Enum : int32_t
|
||||
enum Enum : uint8_t
|
||||
{
|
||||
i8,
|
||||
i16,
|
||||
@@ -57,12 +57,12 @@ namespace Gen
|
||||
};
|
||||
struct Test
|
||||
{
|
||||
static constexpr uint32_t Hash = 273256278;
|
||||
static constexpr uint16_t TypeIdx = 12;
|
||||
uint32_t Number = {};
|
||||
};
|
||||
struct Texture
|
||||
{
|
||||
static constexpr uint32_t Hash = 992460010;
|
||||
static constexpr uint16_t TypeIdx = 13;
|
||||
uint32_t Width = {};
|
||||
uint32_t Height = {};
|
||||
char StrTest[3] = {};
|
||||
@@ -70,8 +70,76 @@ namespace Gen
|
||||
};
|
||||
bool Save(const KnownType::Enum* obj, uint32_t count, Serializer& 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 Load(Test* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const Texture* obj, uint32_t count, Serializer& 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;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -2,8 +2,8 @@
|
||||
#include "Gen/Generated.h"
|
||||
#include "Logging.h"
|
||||
#include "MiniDef.h"
|
||||
|
||||
#include "TypeDef.h"
|
||||
|
||||
#include "bx/hash.h"
|
||||
#include "bx/string.h"
|
||||
#include <bx/filepath.h>
|
||||
@@ -114,6 +114,8 @@ Parser::Result Parser::Parse()
|
||||
{
|
||||
ReadPtr = &Buffer[0];
|
||||
Parser::Result Res = Parser::OK;
|
||||
CHECK(LoadNativeTypes());
|
||||
|
||||
while (Res == Parser::OK)
|
||||
{
|
||||
Res = SkipWhitespace();
|
||||
@@ -136,6 +138,7 @@ Parser::Result Parser::Parse()
|
||||
Parser::Result Parser::HandleFileStart()
|
||||
{
|
||||
Result Res = OK;
|
||||
|
||||
if (CmpAdvance("type", Res, true) && Res == OK)
|
||||
{
|
||||
return HandleType();
|
||||
@@ -152,6 +155,20 @@ Parser::Result Parser::HandleFileStart()
|
||||
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()
|
||||
{
|
||||
Result Res = OK;
|
||||
@@ -200,6 +217,13 @@ Parser::Result Parser::HandleType()
|
||||
CHECK(ReadUint(t.FieldArraySizes[t.FieldCount]));
|
||||
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)
|
||||
{
|
||||
CHECK(ExpectChar("("));
|
||||
@@ -249,12 +273,21 @@ Parser::Result Parser::HandleEnum()
|
||||
if (CmpAdvance("(", Res) && Res == OK)
|
||||
{
|
||||
CHECK(SkipWhitespace());
|
||||
Def::FieldType field;
|
||||
CHECK(ReadNativeFieldType(field));
|
||||
CHECK(ReadDefinedFieldType(e.EnumType));
|
||||
CHECK(SkipWhitespace());
|
||||
CHECK(ExpectChar(")"));
|
||||
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(SkipWhitespace());
|
||||
@@ -338,29 +371,13 @@ Parser::Result Parser::ReadTypeToken()
|
||||
{
|
||||
Result Res = OK;
|
||||
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;
|
||||
LOG_ERROR(Line, "Unknown type token!");
|
||||
ErrorLine();
|
||||
return Error;
|
||||
}
|
||||
|
||||
Parser::Result Parser::ReadNativeFieldType(Def::FieldType& 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)
|
||||
Parser::Result Parser::ReadDefinedFieldType(Def::TypeRef& FieldT)
|
||||
{
|
||||
Result Res = OK;
|
||||
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]);
|
||||
|
||||
Def::EFieldType fieldType = t.FieldTypes[i].FieldKind;
|
||||
if (fieldType == Def::EFieldType::Native)
|
||||
{
|
||||
hash.add(t.FieldTypes[i].Native);
|
||||
}
|
||||
else if (fieldType == Def::EFieldType::DefinedClass)
|
||||
if (fieldType == Def::EFieldType::DefinedClass)
|
||||
{
|
||||
Def::Type& dependType = Definitions.Types[t.FieldTypes[i].TypeIdx];
|
||||
if (dependType.Hash == 0)
|
||||
@@ -456,7 +469,7 @@ uint32_t Parser::CalculateTypeHash(const Def::Type& t)
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(0, "TODO!");
|
||||
LOG_ERROR(Line, "TODO!");
|
||||
}
|
||||
}
|
||||
return hash.end();
|
||||
@@ -466,9 +479,14 @@ void Parser::CalculateHashes()
|
||||
for (int32_t i = 0; i < Definitions.EnumCount; ++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;
|
||||
hash.begin();
|
||||
hash.add(e.EnumType.Native);
|
||||
hash.add(Definitions.Types[e.EnumType.TypeIdx].Hash); // TODO: add enum entries?
|
||||
e.Hash = hash.end();
|
||||
}
|
||||
for (int32_t i = 0; i < Definitions.TypeCount; ++i)
|
||||
@@ -519,9 +537,5 @@ int main(int argc, const char** argv)
|
||||
FileParser.CalculateHashes();
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -86,12 +86,12 @@ class Parser
|
||||
Result ExpectChar(bx::StringView expect);
|
||||
Result Advance(int32_t Amount);
|
||||
Result HandleFileStart();
|
||||
Result LoadNativeTypes();
|
||||
Result HandleType();
|
||||
Result HandleEnum();
|
||||
Result ReadName(char* Target);
|
||||
Result ReadUint(uint32_t& Out);
|
||||
Result ReadNativeFieldType(Def::FieldType& FieldT);
|
||||
Result ReadDefinedFieldType(Def::FieldType& FieldT);
|
||||
Result ReadDefinedFieldType(Def::TypeRef& FieldT);
|
||||
Result ReadTypeToken();
|
||||
Result ReadOptionalEnumValues(Def::Enum& Enum, int32_t EntryIdx);
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include "Gen/Generated.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace Def
|
||||
@@ -7,39 +6,65 @@ namespace Def
|
||||
constexpr int32_t MaxNameLength = 64;
|
||||
constexpr int32_t MaxFields = 64;
|
||||
constexpr int32_t MaxExtraEnumFields = 2;
|
||||
enum class EFieldType
|
||||
|
||||
enum class EFieldType : uint8_t
|
||||
{
|
||||
Native,
|
||||
DefinedClass,
|
||||
DefinedEnum
|
||||
};
|
||||
struct FieldType
|
||||
|
||||
enum class ETypeFlags : uint32_t
|
||||
{
|
||||
EFieldType FieldKind = EFieldType::Native;
|
||||
Gen::KnownType::Enum Native = Gen::KnownType::Enum::i32;
|
||||
uint16_t TypeIdx = UINT16_MAX;
|
||||
None = 0,
|
||||
IsNative = 1 << 0,
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
int32_t FieldCount = 0;
|
||||
FieldType FieldTypes[MaxFields];
|
||||
TypeRef FieldTypes[MaxFields];
|
||||
char FieldNames[MaxFields][MaxNameLength];
|
||||
uint32_t FieldArraySizes[MaxFields]{0};
|
||||
char FieldValues[MaxFields][128]{0};
|
||||
ETypeFlags TypeFlags = ETypeFlags::None;
|
||||
ETypeFieldFlags FieldFlags[MaxFields]{ETypeFieldFlags::None};
|
||||
char Name[MaxNameLength]{0};
|
||||
char NativeCName[MaxNameLength]{0};
|
||||
uint32_t Hash = 0;
|
||||
};
|
||||
|
||||
struct Enum
|
||||
{
|
||||
FieldType EnumType;
|
||||
TypeRef EnumType;
|
||||
int32_t EntryCount = 0;
|
||||
char EntryNames[MaxFields][MaxNameLength];
|
||||
int32_t ExtraStringFieldCount = 0;
|
||||
char ExtraStringFieldNames[MaxExtraEnumFields][MaxNameLength];
|
||||
char ExtraStringFields[MaxFields][MaxExtraEnumFields][MaxNameLength];
|
||||
char Name[MaxNameLength]{0};
|
||||
EEnumFlags EnumFlags = EEnumFlags::None;
|
||||
uint32_t Hash = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -96,16 +96,19 @@ struct SharedDevData
|
||||
char ShaderLog[2048]{0};
|
||||
};
|
||||
|
||||
struct MemoryArena
|
||||
{
|
||||
uint8_t* Base = nullptr;
|
||||
uint64_t Used = 0;
|
||||
uint64_t MaxSize = 0;
|
||||
uint64_t LastAllocSize = 0;
|
||||
};
|
||||
|
||||
struct GameData
|
||||
{
|
||||
void* PermanentStorage = nullptr;
|
||||
uint64_t PermanentStorageSize = 0;
|
||||
|
||||
void* EntityStorage = nullptr;
|
||||
uint64_t EntityStorageSize = 0;
|
||||
|
||||
void* TransientStorage = nullptr;
|
||||
uint64_t TransientStorageSize = 0;
|
||||
MemoryArena PermanentArena;
|
||||
MemoryArena EntityArena;
|
||||
MemoryArena TransientArena;
|
||||
};
|
||||
|
||||
struct SharedData
|
||||
|
||||
@@ -23,6 +23,10 @@ constexpr const char* DLLPath = "libPuzGame.dll";
|
||||
constexpr const wchar_t* DLLWatch = L"libPuzGame2.dll";
|
||||
#endif
|
||||
|
||||
constexpr uint64_t KB = 1024LLU;
|
||||
constexpr uint64_t MB = 1024LLU * 1024LLU;
|
||||
constexpr uint64_t GB = 1024LLU * 1024LLU * 1024LLU;
|
||||
|
||||
namespace
|
||||
{
|
||||
bx::AllocatorI* defaultAllocator = new bx::DefaultAllocator{};
|
||||
@@ -260,6 +264,15 @@ bool ReloadDLL()
|
||||
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()
|
||||
{
|
||||
char PathBuf[512]{0};
|
||||
@@ -301,15 +314,9 @@ int main()
|
||||
HANDLE compiledShaderThread =
|
||||
CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.CompiledShaderWatcher, 0, &fileWatcherThreadId);
|
||||
|
||||
Shared.Game.PermanentStorageSize = 1024 * 1024;
|
||||
Shared.Game.PermanentStorage = VirtualAllocEx(
|
||||
GetCurrentProcess(), NULL, Shared.Game.PermanentStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
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);
|
||||
InitMemoryArena(Shared.Game.PermanentArena, MB);
|
||||
InitMemoryArena(Shared.Game.EntityArena, MB);
|
||||
InitMemoryArena(Shared.Game.TransientArena, 2 * GB);
|
||||
StartupFunc(Shared);
|
||||
|
||||
bool isRunning = true;
|
||||
|
||||
158
src/game/Entity.h
Normal file
158
src/game/Entity.h
Normal 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
|
||||
148
src/game/Gen.cpp
148
src/game/Gen.cpp
@@ -1,5 +1,7 @@
|
||||
#include "Gen.h"
|
||||
|
||||
#include "bx/math.h"
|
||||
|
||||
namespace Gen
|
||||
{
|
||||
bool IsValid(const ModelHandle& h)
|
||||
@@ -300,6 +302,32 @@ namespace Gen
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec3 EulerFromRotation(const Mat4& rotation)
|
||||
{
|
||||
const float r32 = rotation.M[9];
|
||||
const float r33 = rotation.M[10];
|
||||
float x = bx::atan2(r32, r33);
|
||||
float y = bx::atan2(-rotation.M[8], bx::sqrt(r32 * r32 + r33 * r33));
|
||||
float z = bx::atan2(rotation.M[4], rotation.M[0]);
|
||||
return {x, y, z};
|
||||
}
|
||||
|
||||
Mat4 RotationFromEuler(const Vec3& euler)
|
||||
{
|
||||
Mat4 mat;
|
||||
bx::Quaternion quat = bx::fromEuler({euler.x, euler.y, euler.z});
|
||||
bx::mtxFromQuaternion(mat.M, quat);
|
||||
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)
|
||||
{
|
||||
return bx::sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z + vec.w * vec.w);
|
||||
@@ -364,4 +392,124 @@ namespace Gen
|
||||
out = Vec3{l1.x + u * LbMinusLa.x, l1.y + u * LbMinusLa.y, l1.z + u * LbMinusLa.z};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RayTriangleIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out)
|
||||
{
|
||||
const float EPSILON = 1e-6f;
|
||||
Vec3 dir = l2 - l1; // Ray direction
|
||||
Vec3 edge1 = p2 - p1;
|
||||
Vec3 edge2 = p3 - p1;
|
||||
|
||||
Vec3 h = CrossProduct(dir, edge2);
|
||||
float a = DotProduct(edge1, h);
|
||||
|
||||
if (bx::abs(a) < EPSILON) return false; // Ray is parallel to the triangle
|
||||
|
||||
float f = 1.0f / a;
|
||||
Vec3 s = l1 - p1;
|
||||
float u = f * DotProduct(s, h);
|
||||
if (u < 0.0f || u > 1.0f) return false;
|
||||
|
||||
Vec3 q = CrossProduct(s, edge1);
|
||||
float v = f * DotProduct(dir, q);
|
||||
if (v < 0.0f || u + v > 1.0f) return false;
|
||||
|
||||
float t = f * DotProduct(edge2, q);
|
||||
if (t > EPSILON)
|
||||
{
|
||||
out = l1 + dir * t;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Translate(Transform& trans, Vec3 offset)
|
||||
{
|
||||
trans.Position += Vec3{offset.x, offset.y, offset.z};
|
||||
}
|
||||
|
||||
void TranslateLocal(Transform& trans, Vec3 offset)
|
||||
{
|
||||
Vec3 localOffset = GlobalToLocalDirection(trans, offset);
|
||||
trans.Position += Vec3{localOffset.x, localOffset.y, localOffset.z};
|
||||
}
|
||||
|
||||
void Rotate(Transform& trans, Vec3 rotation)
|
||||
{
|
||||
float rot[16]{0};
|
||||
bx::mtxRotateXYZ(rot, rotation.x, rotation.y, rotation.z);
|
||||
float temp[16]{0};
|
||||
bx::mtxMul(temp, rot, trans.Rotation.M);
|
||||
bx::memCopy(trans.Rotation.M, temp, sizeof(temp));
|
||||
}
|
||||
|
||||
void RotateLocal(Transform& trans, Vec3 rotation)
|
||||
{
|
||||
float rot[16]{0};
|
||||
bx::mtxRotateXYZ(rot, rotation.x, rotation.y, rotation.z);
|
||||
float temp[16]{0};
|
||||
bx::mtxMul(temp, trans.Rotation.M, rot);
|
||||
bx::memCopy(trans.Rotation.M, temp, sizeof(temp));
|
||||
}
|
||||
|
||||
Vec3 AxisRight(const Mat4& trans)
|
||||
{
|
||||
return {trans.M[0], trans.M[1], trans.M[2]};
|
||||
}
|
||||
|
||||
Vec3 AxisUp(const Mat4& trans)
|
||||
{
|
||||
return {trans.M[4], trans.M[5], trans.M[6]};
|
||||
}
|
||||
|
||||
Vec3 AxisForward(const Mat4& trans)
|
||||
{
|
||||
return {trans.M[8], trans.M[9], trans.M[10]};
|
||||
}
|
||||
|
||||
void UpdateMatrix(Transform& trans)
|
||||
{
|
||||
Mat4 pos;
|
||||
Mat4 scale;
|
||||
bx::mtxTranslate(pos.M, trans.Position.x, trans.Position.y, trans.Position.z);
|
||||
bx::mtxScale(scale.M, trans.Scale.x, trans.Scale.y, trans.Scale.z);
|
||||
Mat4 temp;
|
||||
bx::mtxMul(temp.M, scale.M, trans.Rotation.M);
|
||||
bx::mtxMul(trans.M.M, temp.M, pos.M);
|
||||
bx::mtxInverse(trans.MI.M, trans.M.M);
|
||||
}
|
||||
|
||||
Vec3 GlobalToLocalDirection(Transform& trans, Vec3 global)
|
||||
{
|
||||
UpdateMatrix(trans);
|
||||
float in[4]{global.x, global.y, global.z, 0.0f};
|
||||
float out[4]{0.0f};
|
||||
bx::vec4MulMtx(out, in, Transpose(trans.MI).M);
|
||||
return {out[0], out[1], out[2]};
|
||||
}
|
||||
Vec3 GlobalToLocalPoint(Transform& trans, Vec3 global)
|
||||
{
|
||||
UpdateMatrix(trans);
|
||||
float in[4]{global.x, global.y, global.z, 1.0f};
|
||||
float out[4]{0.0f};
|
||||
bx::vec4MulMtx(out, in, trans.MI.M);
|
||||
return {out[0], out[1], out[2]};
|
||||
}
|
||||
Vec3 LocalToGlobalDirection(Transform& trans, Vec3 local)
|
||||
{
|
||||
UpdateMatrix(trans);
|
||||
float in[4]{local.x, local.y, local.z, 0.0f};
|
||||
float out[4]{0.0f};
|
||||
bx::vec4MulMtx(out, in, Transpose(trans.M).M);
|
||||
return {out[0], out[1], out[2]};
|
||||
}
|
||||
Vec3 LocalToGlobalPoint(Transform& trans, Vec3 local)
|
||||
{
|
||||
UpdateMatrix(trans);
|
||||
float in[4]{local.x, local.y, local.z, 1.0f};
|
||||
float out[4]{0.0f};
|
||||
bx::vec4MulMtx(out, in, trans.M.M);
|
||||
return {out[0], out[1], out[2]};
|
||||
}
|
||||
} // namespace Gen
|
||||
|
||||
@@ -73,8 +73,26 @@ namespace Gen
|
||||
Mat4 Transpose(const Mat4& mat);
|
||||
Vec4 Mul(const Mat4& mat, const Vec4& vec);
|
||||
|
||||
Vec3 EulerFromRotation(const Mat4& rotation);
|
||||
Mat4 RotationFromEuler(const Vec3& euler);
|
||||
Mat4 RotationFromQuaternion(const Vec4& quaternion);
|
||||
|
||||
float DotProduct(Vec3 a, Vec3 b);
|
||||
Vec3 CrossProduct(Vec3 a, Vec3 b);
|
||||
Vec3 CrossProductFromPlane(Vec3 a, Vec3 b, Vec3 c);
|
||||
bool RayPlaneIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out);
|
||||
bool RayTriangleIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out);
|
||||
|
||||
void Translate(Transform& trans, Vec3 offset);
|
||||
void TranslateLocal(Transform& trans, Vec3 offset);
|
||||
void Rotate(Transform& trans, Vec3 rotation);
|
||||
void RotateLocal(Transform& trans, Vec3 rotation);
|
||||
Vec3 LocalToGlobalPoint(Transform& trans, Vec3 local);
|
||||
Vec3 LocalToGlobalDirection(Transform& trans, Vec3 local);
|
||||
Vec3 GlobalToLocalPoint(Transform& trans, Vec3 global);
|
||||
Vec3 GlobalToLocalDirection(Transform& trans, Vec3 global);
|
||||
Vec3 AxisRight(const Mat4& mat);
|
||||
Vec3 AxisUp(const Mat4& mat);
|
||||
Vec3 AxisForward(const Mat4& mat);
|
||||
void UpdateMatrix(Transform& trans);
|
||||
} // namespace Gen
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#include "../engine/Shared.h"
|
||||
#include "Gen.h"
|
||||
#include "Global.h"
|
||||
#include "Instance.h"
|
||||
|
||||
#include "bx/bx.h"
|
||||
#include "bx/math.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -40,127 +37,36 @@ namespace Game
|
||||
GameInst = &instance;
|
||||
}
|
||||
|
||||
void* AllocateScratch(size_t byteCount, size_t align)
|
||||
uint8_t* AllocateScratch(uint64_t byteCount, uint32_t align)
|
||||
{
|
||||
size_t offset = GetInstance().UsedScratchAmount;
|
||||
uint8_t* base = static_cast<uint8_t*>(GetShared().Game.TransientStorage);
|
||||
uint8_t* current = base + offset;
|
||||
size_t offsetAligned = ((offset + align - 1) / align) * align;
|
||||
uint8_t* ptrAligned = base + offsetAligned;
|
||||
size_t newOffset = offsetAligned + byteCount;
|
||||
if (newOffset > GetShared().Game.TransientStorageSize) return nullptr;
|
||||
GetInstance().UsedScratchAmount = newOffset;
|
||||
return reinterpret_cast<void*>(ptrAligned);
|
||||
assert(align <= 64); // The alignment of the arena limits the alignment that can be specified here!
|
||||
auto& arena = GetShared().Game.TransientArena;
|
||||
uint64_t offsetAligned = ((arena.Used + align - 1) / align) * align;
|
||||
uint8_t* ptrAligned = arena.Base + offsetAligned;
|
||||
uint64_t newOffset = offsetAligned + byteCount;
|
||||
if (newOffset > arena.MaxSize) return nullptr;
|
||||
arena.Used = newOffset;
|
||||
arena.LastAllocSize = byteCount;
|
||||
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
|
||||
|
||||
void Transform::CreateTransform(float* out, bx::Vec3 pos, bx::Quaternion rot, bx::Vec3 scale)
|
||||
{
|
||||
if (out == nullptr) return;
|
||||
float rMat[16]{0};
|
||||
float tMat[16]{0};
|
||||
float sMat[16]{0};
|
||||
bx::mtxFromQuaternion(rMat, bx::Quaternion{rot.x, rot.y, rot.z, rot.w});
|
||||
bx::mtxTranslate(tMat, pos.x, pos.y, pos.z);
|
||||
bx::mtxScale(sMat, scale.x, scale.y, scale.z);
|
||||
float buf[16]{0};
|
||||
bx::mtxMul(buf, rMat, sMat);
|
||||
bx::mtxMul(out, buf, tMat);
|
||||
}
|
||||
|
||||
void Transform::Translate(Vec3 offset)
|
||||
{
|
||||
Position = bx::add(Position, {offset.x, offset.y, offset.z});
|
||||
}
|
||||
|
||||
void Transform::TranslateLocal(Vec3 offset)
|
||||
{
|
||||
Vec3 localOffset = GlobalToLocalDirection(offset);
|
||||
Position = bx::add(Position, {localOffset.x, localOffset.y, localOffset.z});
|
||||
}
|
||||
|
||||
void Transform::Rotate(Vec3 rotation)
|
||||
{
|
||||
float rot[16]{0};
|
||||
bx::mtxRotateXYZ(rot, rotation.x, rotation.y, rotation.z);
|
||||
float temp[16]{0};
|
||||
bx::mtxMul(temp, rot, Rotation.M);
|
||||
bx::memCopy(Rotation.M, temp, sizeof(temp));
|
||||
}
|
||||
|
||||
void Transform::RotateLocal(Vec3 rotation)
|
||||
{
|
||||
float rot[16]{0};
|
||||
bx::mtxRotateXYZ(rot, rotation.x, rotation.y, rotation.z);
|
||||
float temp[16]{0};
|
||||
bx::mtxMul(temp, Rotation.M, rot);
|
||||
bx::memCopy(Rotation.M, temp, sizeof(temp));
|
||||
}
|
||||
|
||||
Vec3 Transform::Right() const
|
||||
{
|
||||
return {M.M[0], M.M[1], M.M[2]};
|
||||
}
|
||||
|
||||
Vec3 Transform::Up() const
|
||||
{
|
||||
return {M.M[4], M.M[5], M.M[6]};
|
||||
}
|
||||
|
||||
Vec3 Transform::Forward() const
|
||||
{
|
||||
return {M.M[8], M.M[9], M.M[10]};
|
||||
}
|
||||
|
||||
void Transform::UpdateMatrix()
|
||||
{
|
||||
Mat4 pos;
|
||||
Mat4 scale;
|
||||
bx::mtxTranslate(pos.M, Position.x, Position.y, Position.z);
|
||||
bx::mtxScale(scale.M, Scale.x, Scale.y, Scale.z);
|
||||
Mat4 temp;
|
||||
bx::mtxMul(temp.M, scale.M, Rotation.M);
|
||||
bx::mtxMul(M.M, temp.M, pos.M);
|
||||
bx::mtxInverse(MI.M, M.M);
|
||||
}
|
||||
|
||||
Vec3 Transform::GlobalToLocalDirection(Vec3 global)
|
||||
{
|
||||
UpdateMatrix();
|
||||
float in[4]{global.x, global.y, global.z, 0.0f};
|
||||
float out[4]{0.0f};
|
||||
bx::vec4MulMtx(out, in, Transpose(MI).M);
|
||||
return {out[0], out[1], out[2]};
|
||||
}
|
||||
Vec3 Transform::GlobalToLocalPoint(Vec3 global)
|
||||
{
|
||||
UpdateMatrix();
|
||||
float in[4]{global.x, global.y, global.z, 1.0f};
|
||||
float out[4]{0.0f};
|
||||
bx::vec4MulMtx(out, in, MI.M);
|
||||
return {out[0], out[1], out[2]};
|
||||
}
|
||||
Vec3 Transform::LocalToGlobalDirection(Vec3 local)
|
||||
{
|
||||
UpdateMatrix();
|
||||
float in[4]{local.x, local.y, local.z, 0.0f};
|
||||
float out[4]{0.0f};
|
||||
bx::vec4MulMtx(out, in, Transpose(M).M);
|
||||
return {out[0], out[1], out[2]};
|
||||
}
|
||||
Vec3 Transform::LocalToGlobalPoint(Vec3 local)
|
||||
{
|
||||
UpdateMatrix();
|
||||
float in[4]{local.x, local.y, local.z, 1.0f};
|
||||
float out[4]{0.0f};
|
||||
bx::vec4MulMtx(out, in, M.M);
|
||||
return {out[0], out[1], out[2]};
|
||||
}
|
||||
void Transform::SetPosition(Vec3 pos)
|
||||
{
|
||||
Position = {pos.x, pos.y, pos.z};
|
||||
}
|
||||
Vec3 Transform::GetPosition()
|
||||
{
|
||||
return {Position.x, Position.y, Position.z};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gen/Generated.h"
|
||||
#include "bx/math.h"
|
||||
#include <cstdint>
|
||||
|
||||
inline int32_t SetFlags(int32_t in, int32_t flags)
|
||||
{
|
||||
@@ -24,33 +23,6 @@ inline bool GetFlag(int32_t in, int32_t flags)
|
||||
return (in & flags) > 0;
|
||||
}
|
||||
|
||||
struct Transform
|
||||
{
|
||||
Gen::Mat4 M;
|
||||
Gen::Mat4 MI;
|
||||
bx::Vec3 Position{0.0f, 0.0f, 0.0f};
|
||||
Gen::Mat4 Rotation;
|
||||
bx::Vec3 Scale{1.0f, 1.0f, 1.0f};
|
||||
|
||||
static void CreateTransform(float* out, bx::Vec3 pos, bx::Quaternion rot, bx::Vec3 scale);
|
||||
void Translate(Gen::Vec3 offset);
|
||||
void TranslateLocal(Gen::Vec3 offset);
|
||||
void Rotate(Gen::Vec3 rotation);
|
||||
void RotateLocal(Gen::Vec3 rotation);
|
||||
Gen::Vec3 LocalToGlobalPoint(Gen::Vec3 local);
|
||||
Gen::Vec3 LocalToGlobalDirection(Gen::Vec3 local);
|
||||
Gen::Vec3 GlobalToLocalPoint(Gen::Vec3 global);
|
||||
Gen::Vec3 GlobalToLocalDirection(Gen::Vec3 global);
|
||||
Gen::Vec3 Right() const;
|
||||
Gen::Vec3 Up() const;
|
||||
Gen::Vec3 Forward() const;
|
||||
void SetPosition(Gen::Vec3 pos);
|
||||
Gen::Vec3 GetPosition();
|
||||
const float* GetPtr();
|
||||
void UpdateMatrix();
|
||||
void UpdateMatrixForCam();
|
||||
};
|
||||
|
||||
struct SharedData;
|
||||
|
||||
namespace Game
|
||||
@@ -61,5 +33,7 @@ namespace Game
|
||||
void SetShared(SharedData& instance);
|
||||
GameInstance& GetInstance();
|
||||
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
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Global.h"
|
||||
#include "Input.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
|
||||
namespace Game
|
||||
{
|
||||
@@ -9,12 +10,14 @@ namespace Game
|
||||
|
||||
bool IsKeyboardAllowed()
|
||||
{
|
||||
if (GImGui == nullptr) return true;
|
||||
auto& IO = ImGui::GetIO();
|
||||
return !IO.WantCaptureKeyboard || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
|
||||
}
|
||||
|
||||
bool IsMouseAllowed()
|
||||
{
|
||||
if (GImGui == nullptr) return true;
|
||||
auto& IO = ImGui::GetIO();
|
||||
return !IO.WantCaptureMouse || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoMouse);
|
||||
}
|
||||
@@ -60,6 +63,8 @@ namespace Game
|
||||
}
|
||||
Vec2 GetMousePos()
|
||||
{
|
||||
// TODO: fix this!!
|
||||
if (GImGui == nullptr) return {};
|
||||
ImVec2 pos = ImGui::GetMousePos();
|
||||
return {pos.x, pos.y};
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ namespace Game
|
||||
Game,
|
||||
};
|
||||
|
||||
enum class InteractionMode
|
||||
{
|
||||
Walk,
|
||||
ReadTablet,
|
||||
};
|
||||
|
||||
struct Time
|
||||
{
|
||||
double Now = 0.0;
|
||||
@@ -28,30 +34,34 @@ namespace Game
|
||||
|
||||
struct PlayerData
|
||||
{
|
||||
Transform PlayerCamTransform;
|
||||
Transform FreeflyCamTransform;
|
||||
Gen::Transform PlayerCamTransform;
|
||||
Gen::Transform FreeflyCamTransform;
|
||||
Gen::Mat4 Projection;
|
||||
Gen::Mat4 ProjectionInverse;
|
||||
float FreeflyXRot = 0.0f;
|
||||
float FreeflyYRot = 0.0f;
|
||||
float WalkXRot = 0.0f;
|
||||
float WalkYRot = 0.0f;
|
||||
CameraMode CameraM = CameraMode::Freefly;
|
||||
CameraMode CameraM = CameraMode::Walk;
|
||||
InputMode InputM = InputMode::Game;
|
||||
InteractionMode InteractionM = InteractionMode::Walk;
|
||||
float MouseSensitivity = 1.0f;
|
||||
float MovementSpeed = 10.0f;
|
||||
Gen::SavedPlayerConfig Config;
|
||||
};
|
||||
|
||||
struct InstanceDebugData
|
||||
{
|
||||
uint16_t SelectedDebugLevel = UINT16_MAX;
|
||||
static constexpr uint32_t MaxAssets = 128;
|
||||
uint16_t SelectedDebugLevel = 0;
|
||||
uint64_t ImguiIniSize = 0;
|
||||
char ImguiIni[4096]{0};
|
||||
static constexpr uint32_t MaxAssets = 128;
|
||||
uint32_t AssetCount = 0;
|
||||
Gen::AssetHandle AssetHandles[MaxAssets]{0};
|
||||
char AssetHandlePaths[MaxAssets][128];
|
||||
bool ShowImguiDemo = false;
|
||||
bool DebugBreakIDEnabled = false;
|
||||
int DebugBreakID = -1;
|
||||
uint8_t DebugCardRotation = 0;
|
||||
bool ShortenLogFileNames = true;
|
||||
bool ShowStats = true;
|
||||
@@ -61,7 +71,6 @@ namespace Game
|
||||
{
|
||||
bool IsInitialized = false;
|
||||
uint64_t Size = sizeof(GameInstance);
|
||||
uint64_t UsedScratchAmount = 0;
|
||||
Time Time;
|
||||
PlayerData Player;
|
||||
Level GameLevel;
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "Level.h"
|
||||
#include "Log.h"
|
||||
#include "Puzzle.h"
|
||||
#include "UI.h"
|
||||
#include "bx/bx.h"
|
||||
#include "bx/debug.h"
|
||||
#include "rendering/Rendering.h"
|
||||
|
||||
#include "SDL3/SDL_mouse.h"
|
||||
@@ -26,12 +29,19 @@ namespace Game
|
||||
{
|
||||
void EntityRenderData::Render(const Model* models, const Material* materials, const Texture* textures)
|
||||
{
|
||||
auto& debug = GetInstance().DebugData;
|
||||
if ((int32_t)debug.DebugBreakID == RenderID && debug.DebugBreakIDEnabled)
|
||||
{
|
||||
bx::debugBreak();
|
||||
debug.DebugBreakIDEnabled = false;
|
||||
}
|
||||
|
||||
if (models == nullptr || materials == nullptr || textures == nullptr) return;
|
||||
if (!Gen::IsValid(ModelH) || MaterialHandle == EMaterial::UNDEFINED) return;
|
||||
if (!Gen::IsValid(ModelH) || MaterialHandle >= EMaterial::EntryCount) return;
|
||||
if (!Visible) return;
|
||||
auto& rendering = GameRendering::Get();
|
||||
|
||||
Transform.UpdateMatrix();
|
||||
UpdateMatrix(Transform);
|
||||
bgfx::setTransform(Transform.M.M);
|
||||
|
||||
const Model& currentModel = models[ModelH.ModelIdx];
|
||||
@@ -74,29 +84,52 @@ namespace Game
|
||||
bgfx::submit(currentMaterial.ViewID, currentMaterial.Shader);
|
||||
}
|
||||
|
||||
void EntityRenderData::LoadFromSaved(const Gen::SavedEntityRenderData& saved)
|
||||
{
|
||||
DotColor = saved.HighlightColor;
|
||||
BaseColor = saved.BaseColor;
|
||||
Transform = saved.TF;
|
||||
// TODO: fix handle indices
|
||||
MaterialHandle = saved.Material;
|
||||
TextureHandle = saved.Texture;
|
||||
ModelH = saved.Model;
|
||||
Visible = saved.Visible;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void UpdatePlayerInputMode()
|
||||
{
|
||||
bool IsGaming = GetInstance().Player.InputM == InputMode::Game;
|
||||
SDL_SetWindowRelativeMouseMode(GetShared().Window.SDLWindow, IsGaming);
|
||||
bool captureMouse = IsGaming && GetInstance().Player.InteractionM == InteractionMode::Walk;
|
||||
SDL_SetWindowRelativeMouseMode(GetShared().Window.SDLWindow, captureMouse);
|
||||
|
||||
auto& rendering = GameRendering::Get();
|
||||
if (rendering.SetupData.UseImgui)
|
||||
{
|
||||
auto& IO = ImGui::GetIO();
|
||||
IO.ConfigFlags = FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, IsGaming);
|
||||
GameRendering::Get().UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug;
|
||||
IO.ConfigFlags =
|
||||
FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, captureMouse);
|
||||
}
|
||||
rendering.UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Level::Setup(GameData& data)
|
||||
{
|
||||
LOG("Level setup");
|
||||
void* storagePtr = data.EntityStorage;
|
||||
uint8_t* storagePtr = data.EntityArena.Base;
|
||||
bool needReset = false;
|
||||
needReset |= Cubes.Setup(storagePtr, needReset);
|
||||
needReset |= Tests.Setup(storagePtr, needReset);
|
||||
needReset |= PuzzleTiles.Setup(storagePtr, needReset);
|
||||
needReset |= PuzzleTileCovers.Setup(storagePtr, needReset);
|
||||
needReset |= UIQuads.Setup(storagePtr, needReset);
|
||||
needReset |= LevelEntities.Setup(storagePtr, needReset);
|
||||
|
||||
Puzzle::Setup();
|
||||
UIQuads.Count = 0;
|
||||
PuzzleTiles.Count = 0;
|
||||
|
||||
bx::Error err;
|
||||
bx::DirectoryReader dirIter;
|
||||
@@ -155,8 +188,16 @@ namespace Game
|
||||
Cubes.Get(PlayerOutsideViewCube).Setup();
|
||||
}
|
||||
|
||||
{
|
||||
Deserializer d;
|
||||
d.Init("game/data/static/uiconfig.dat", "UICO");
|
||||
d.ReadT(GetInstance().Player.Config);
|
||||
d.Finish();
|
||||
}
|
||||
|
||||
UIQuads.Count = 0;
|
||||
PuzzleTiles.Count = 0;
|
||||
PuzzleTileCovers.Count = 0;
|
||||
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
|
||||
{
|
||||
if (Puzzles[i].Data.ID != UINT16_MAX)
|
||||
@@ -164,8 +205,90 @@ namespace Game
|
||||
Puzzles[i].Setup();
|
||||
}
|
||||
}
|
||||
LOG("Tiles: %u", PuzzleTiles.Count);
|
||||
|
||||
PuzzleUI.Setup();
|
||||
|
||||
ReloadLevelEntities();
|
||||
|
||||
UpdatePlayerInputMode();
|
||||
|
||||
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
|
||||
{
|
||||
Puzzles[i].WorldPosition = {0.0f, 0.0f, i * 50.0f};
|
||||
}
|
||||
}
|
||||
|
||||
bool IsInPuzzle(WorldPuzzle& puz, Vec3 worldPos)
|
||||
{
|
||||
Vec3 offsetToPuzzle = worldPos - puz.WorldPosition + (Vec3{0.5f, 0.0f, 0.5f} * Puzzle::Config::CardScaleWorld);
|
||||
Vec3 scaledOffset = offsetToPuzzle / Puzzle::Config::CardScaleWorld;
|
||||
int32_t offsetX = (int32_t)bx::floor(scaledOffset.x);
|
||||
int32_t offsetY = (int32_t)bx::floor(scaledOffset.z);
|
||||
return (offsetX >= 0 && offsetX < puz.Data.WidthTiles / 2 && offsetY >= -1 &&
|
||||
offsetY < puz.Data.HeightTiles / 2);
|
||||
}
|
||||
|
||||
bool IsOnGround(Level& level, Vec3 worldPos)
|
||||
{
|
||||
for (auto& puz : level.Puzzles)
|
||||
{
|
||||
Vec3 offsetToPuzzle =
|
||||
worldPos - puz.WorldPosition + (Vec3{0.5f, 0.0f, 0.5f} * Puzzle::Config::CardScaleWorld);
|
||||
Vec3 scaledOffset = offsetToPuzzle / Puzzle::Config::CardScaleWorld;
|
||||
int32_t offsetX = (int32_t)bx::floor(scaledOffset.x);
|
||||
int32_t offsetY = puz.Data.HeightTiles / 2 - (int32_t)bx::floor(scaledOffset.z) - 1;
|
||||
float fracOffsetX = scaledOffset.x - offsetX;
|
||||
float fracOffsetY = scaledOffset.z - bx::floor(scaledOffset.z);
|
||||
|
||||
if (offsetX >= 0 && offsetX < puz.Data.WidthTiles / 2 && offsetY >= 0 && offsetY < puz.Data.HeightTiles / 2)
|
||||
{
|
||||
auto& card = puz.Data.PlacedCards[offsetY * Puzzle::Config::MaxPuzzleSizeCards + offsetX];
|
||||
if (card.RefCard.Idx == UINT16_MAX)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
auto& refCard = Puzzle::GetStaticPuzzleData().Cards[card.RefCard.Idx];
|
||||
if (!IsValid(refCard.BaseModelHandle))
|
||||
{
|
||||
LOG_WARN("missing base model! @ %i %i", offsetX, offsetY);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto& heightmap = GameRendering::Get().Models[refCard.BaseModelHandle.ModelIdx].Height;
|
||||
int32_t xPos = (int32_t)(fracOffsetX * heightmap.Width);
|
||||
int32_t yPos = (int32_t)(fracOffsetY * heightmap.Height);
|
||||
|
||||
uint8_t height = 0;
|
||||
switch (card.Rotation)
|
||||
{
|
||||
case 0:
|
||||
height = heightmap.Values[yPos * heightmap.Width + xPos];
|
||||
break;
|
||||
case 1:
|
||||
height = heightmap.Values[xPos * heightmap.Width + (heightmap.Height - yPos - 1)];
|
||||
break;
|
||||
case 2:
|
||||
height =
|
||||
heightmap
|
||||
.Values[(heightmap.Height - yPos - 1) * heightmap.Width + (heightmap.Width - xPos - 1)];
|
||||
break;
|
||||
default:
|
||||
height = heightmap.Values[(heightmap.Height - xPos - 1) * heightmap.Width + yPos];
|
||||
break;
|
||||
}
|
||||
return height >= 110 && height <= 125;
|
||||
}
|
||||
if (offsetX == 1 && offsetY == puz.Data.HeightTiles / Puzzle::Config::CardSize)
|
||||
{
|
||||
if (puz.IsSolved)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true; // TODO!
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Level::Update()
|
||||
@@ -214,20 +337,56 @@ namespace Game
|
||||
bx::mtxRotateXYZ(player.FreeflyCamTransform.Rotation.M, player.FreeflyXRot, player.FreeflyYRot, 0.0f);
|
||||
}
|
||||
|
||||
player.FreeflyCamTransform.TranslateLocal({0.0f, 0.0f, inputVec.z});
|
||||
player.FreeflyCamTransform.TranslateLocal({inputVec.x, 0.0f, 0.0f});
|
||||
TranslateLocal(player.FreeflyCamTransform, {0.0f, 0.0f, inputVec.z});
|
||||
TranslateLocal(player.FreeflyCamTransform, {inputVec.x, 0.0f, 0.0f});
|
||||
}
|
||||
else if (player.CameraM == CameraMode::Walk)
|
||||
{
|
||||
player.PlayerCamTransform.TranslateLocal({0.0f, 0.0f, inputVec.z});
|
||||
player.PlayerCamTransform.TranslateLocal({inputVec.x, 0.0f, 0.0f});
|
||||
player.PlayerCamTransform.Position.y = 3.0f;
|
||||
auto newTransform = player.PlayerCamTransform;
|
||||
// Global and local are inverted because camera
|
||||
Vec3 globalInput = GlobalToLocalDirection(newTransform, {inputVec.x, 0.0f, inputVec.z});
|
||||
Translate(newTransform, globalInput);
|
||||
newTransform.Position.y = 3.0f;
|
||||
|
||||
if (IsOnGround(*this, newTransform.Position))
|
||||
{
|
||||
player.PlayerCamTransform = newTransform;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto newTransform = player.PlayerCamTransform;
|
||||
Translate(newTransform, {globalInput.x, 0.0f, 0.0f});
|
||||
newTransform.Position.y = 3.0f;
|
||||
|
||||
if (IsOnGround(*this, newTransform.Position))
|
||||
{
|
||||
player.PlayerCamTransform = newTransform;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto newTransform = player.PlayerCamTransform;
|
||||
Translate(newTransform, {0.0f, 0.0f, globalInput.z});
|
||||
newTransform.Position.y = 3.0f;
|
||||
|
||||
if (IsOnGround(*this, newTransform.Position))
|
||||
{
|
||||
player.PlayerCamTransform = newTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player.WalkXRot += rotInput.x;
|
||||
player.WalkYRot += rotInput.y;
|
||||
bx::mtxRotateXYZ(player.PlayerCamTransform.Rotation.M, player.WalkXRot, player.WalkYRot, 0.0f);
|
||||
}
|
||||
|
||||
if (GetKeyPressedNow(ScanCode::SPACE))
|
||||
{
|
||||
player.InteractionM = player.InteractionM == InteractionMode::ReadTablet ? InteractionMode::Walk
|
||||
: InteractionMode::ReadTablet;
|
||||
UpdatePlayerInputMode();
|
||||
}
|
||||
|
||||
// Cubes
|
||||
for (uint16_t i = 0; i < Cubes.Count; ++i)
|
||||
{
|
||||
@@ -235,10 +394,20 @@ namespace Game
|
||||
}
|
||||
|
||||
// Puzzle tiles
|
||||
Puzzle::PuzzleSolver solver;
|
||||
uint16_t activeIdx = GetInstance().DebugData.SelectedDebugLevel;
|
||||
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
|
||||
{
|
||||
Puzzles[i].Update();
|
||||
if (IsInPuzzle(Puzzles[i], player.PlayerCamTransform.Position))
|
||||
{
|
||||
activeIdx = i;
|
||||
}
|
||||
Puzzles[i].IsActive = activeIdx == i;
|
||||
Puzzles[i].Update();
|
||||
Puzzles[i].IsSolved = solver.IsPuzzleSolved(Puzzles[i].Data);
|
||||
}
|
||||
|
||||
PuzzleUI.Update(Puzzles[activeIdx].Data, Puzzles[activeIdx].IsSolved);
|
||||
|
||||
END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter);
|
||||
}
|
||||
@@ -261,12 +430,12 @@ namespace Game
|
||||
Cubes.Get(PlayerOutsideViewCube).EData.Visible = isFreefly;
|
||||
if (isFreefly)
|
||||
{
|
||||
player.FreeflyCamTransform.UpdateMatrix();
|
||||
UpdateMatrix(player.FreeflyCamTransform);
|
||||
bgfx::setViewTransform(viewId, player.FreeflyCamTransform.MI.M, &player.Projection.M[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.PlayerCamTransform.UpdateMatrix();
|
||||
UpdateMatrix(player.PlayerCamTransform);
|
||||
bgfx::setViewTransform(viewId, player.PlayerCamTransform.MI.M, &player.Projection.M[0]);
|
||||
}
|
||||
|
||||
@@ -275,8 +444,13 @@ namespace Game
|
||||
Cubes.Render(models, materials, textures);
|
||||
Tests.Render(models, materials, textures);
|
||||
PuzzleTiles.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()
|
||||
{
|
||||
@@ -299,56 +473,59 @@ namespace Game
|
||||
|
||||
void WorldPuzzle::Setup()
|
||||
{
|
||||
auto& level = GetInstance().GameLevel;
|
||||
Level& level = GetInstance().GameLevel;
|
||||
for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i)
|
||||
{
|
||||
TileHandles[i] = level.PuzzleTiles.New();
|
||||
auto& tile = level.PuzzleTiles.Get(TileHandles[i]);
|
||||
PuzzleTileEntity& tile = level.PuzzleTiles.Get(TileHandles[i]);
|
||||
tile.EData.MaterialHandle = EMaterial::Default;
|
||||
tile.EData.Visible = false;
|
||||
|
||||
UIPlacedCards[i] = level.UIQuads.New();
|
||||
auto& quad = level.UIQuads.Get(UIPlacedCards[i]);
|
||||
quad.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/plane.glb");
|
||||
quad.EData.MaterialHandle = EMaterial::UI;
|
||||
quad.EData.Visible = false;
|
||||
for (int32_t j = 0; j < Puzzle::Config::MaxCoversInTile; ++j)
|
||||
{
|
||||
int32_t idx = i * Puzzle::Config::MaxCoversInTile + j;
|
||||
CoverHandles[idx] = level.PuzzleTileCovers.New();
|
||||
PuzzleTileCover& cover = level.PuzzleTileCovers.Get(CoverHandles[idx]);
|
||||
cover.EData.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < BX_COUNTOF(EndHandles); ++i)
|
||||
{
|
||||
EndHandles[i] = level.PuzzleTiles.New();
|
||||
PuzzleTileEntity& tile = level.PuzzleTiles.Get(EndHandles[i]);
|
||||
tile.EData.MaterialHandle = EMaterial::Default;
|
||||
}
|
||||
|
||||
WallHandle = level.PuzzleTiles.New();
|
||||
PuzzleTileEntity& wHandle = level.PuzzleTiles.Get(WallHandle);
|
||||
wHandle.EData.MaterialHandle = EMaterial::Default;
|
||||
wHandle.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/GateWall.glb");
|
||||
|
||||
DoorHandle = level.PuzzleTiles.New();
|
||||
PuzzleTileEntity& dHandle = level.PuzzleTiles.Get(DoorHandle);
|
||||
dHandle.EData.MaterialHandle = EMaterial::Default;
|
||||
dHandle.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/GateDoor.glb");
|
||||
|
||||
IsSetup = true;
|
||||
LOG("finished setup!");
|
||||
}
|
||||
|
||||
Vec3 PuzPosToWorldPos(const PuzzleData& data, int32_t x, int32_t y)
|
||||
{
|
||||
return {
|
||||
(float)x * Puzzle::Config::CardScaleWorld,
|
||||
-5.0f,
|
||||
(float)(data.HeightTiles / 2 - y - 1) * Puzzle::Config::CardScaleWorld,
|
||||
};
|
||||
}
|
||||
|
||||
void WorldPuzzle::Update()
|
||||
{
|
||||
Level& level = GetInstance().GameLevel;
|
||||
auto& window = GetShared().Window;
|
||||
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
|
||||
auto& visuals = Puzzle::GetStaticPuzzleData().Visuals;
|
||||
|
||||
Transform& camTransform = GetInstance().Player.PlayerCamTransform;
|
||||
camTransform.UpdateMatrix();
|
||||
Vec3 cameraPos = camTransform.GetPosition();
|
||||
|
||||
Transform boardTransform;
|
||||
boardTransform.Rotation = camTransform.Rotation;
|
||||
Vec3 fw = {camTransform.M.M[8], camTransform.M.M[9], camTransform.M.M[10]};
|
||||
Vec3 pos = cameraPos;
|
||||
pos += fw * 1.0f;
|
||||
boardTransform.SetPosition(pos);
|
||||
|
||||
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 = camTransform.LocalToGlobalPoint(mousePosCam);
|
||||
|
||||
// Board
|
||||
for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y)
|
||||
{
|
||||
for (int8_t x = 0; x < Data.WidthTiles / Puzzle::Config::CardSize; ++x)
|
||||
@@ -356,94 +533,96 @@ namespace Game
|
||||
int32_t cardIdx = y * Puzzle::Config::MaxPuzzleSizeCards + x;
|
||||
Gen::PlacedPuzzleCard& card = Data.PlacedCards[cardIdx];
|
||||
auto& tile = level.PuzzleTiles.Get(TileHandles[cardIdx]);
|
||||
auto& quad = level.UIQuads.Get(UIPlacedCards[cardIdx]);
|
||||
|
||||
bool isValid = Puzzle::IsValid(card.RefCard);
|
||||
auto& staticCard = isValid ? staticCards[card.RefCard.Idx] : staticCards[0];
|
||||
|
||||
// World Tile
|
||||
tile.EData.Visible = true;
|
||||
tile.EData.ModelH = isValid ? staticCards[card.RefCard.Idx].ModelHandle : staticCards[0].ModelHandle;
|
||||
tile.EData.ModelH = staticCard.BaseModelHandle;
|
||||
tile.EData.TextureHandle = staticCard.ModelTextureHandle;
|
||||
|
||||
Vec3 cardPos = {
|
||||
(float)card.Position.X * Puzzle::Config::CardScaleWorld,
|
||||
-5.0f,
|
||||
(float)card.Position.Y * Puzzle::Config::CardScaleWorld,
|
||||
};
|
||||
tile.EData.DotColor = visuals.TileDotColor;
|
||||
tile.EData.BaseColor = visuals.TileBaseColor;
|
||||
|
||||
Vec3 cardPos = PuzPosToWorldPos(Data, card.Position.X, card.Position.Y);
|
||||
if (!isValid)
|
||||
{
|
||||
cardPos = {x * Puzzle::Config::CardScaleWorld, -5.0f, y * Puzzle::Config::CardScaleWorld};
|
||||
cardPos = PuzPosToWorldPos(Data, x, y);
|
||||
}
|
||||
tile.EData.Transform.SetPosition(cardPos);
|
||||
bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * 0.5f);
|
||||
tile.EData.Transform.Position = cardPos + WorldPosition;
|
||||
bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * -0.5f);
|
||||
|
||||
quad.EData.Visible = isValid;
|
||||
quad.EData.TextureHandle =
|
||||
isValid ? staticCards[card.RefCard.Idx].BoardTextureHandle : Gen::TextureHandle{};
|
||||
quad.EData.DotColor = card.IsLocked ? Vec4{0.0f, 0.0f, 0.0f, 0.0f} : Vec4{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
quad.EData.Transform = boardTransform;
|
||||
quad.EData.Transform.TranslateLocal(Vec3{(float)card.Position.X, (float)card.Position.Y, 0.0f} *
|
||||
UICardOffset);
|
||||
quad.EData.Transform.Scale = {0.1f, 0.1f, 0.1f};
|
||||
quad.EData.Transform.Rotate(Vec3{bx::kPi * 0.5f, 0.0f, (1.0f - card.Rotation * 0.5f) * bx::kPi});
|
||||
|
||||
Vec3 quadPosWorld = quad.EData.Transform.GetPosition();
|
||||
Vec3 quadXWorld = quad.EData.Transform.LocalToGlobalPoint({1, 0, 0});
|
||||
Vec3 quadZWorld = quad.EData.Transform.LocalToGlobalPoint({0, 0, 1});
|
||||
Vec3 intersectPos;
|
||||
if (RayPlaneIntersect(
|
||||
camTransform.GetPosition(), mousePosWorld, quadPosWorld, quadXWorld, quadZWorld, intersectPos))
|
||||
// Covers
|
||||
if (IsValid(staticCard.BaseModelHandle))
|
||||
{
|
||||
Vec3 quadSpaceIntersect = quad.EData.Transform.GlobalToLocalPoint(intersectPos);
|
||||
if (quadSpaceIntersect.x >= -1.0f && quadSpaceIntersect.x <= 1.0f &&
|
||||
quadSpaceIntersect.z >= -1.0f && quadSpaceIntersect.z <= 1.0f)
|
||||
auto& model = GameRendering::Get().Models[staticCard.BaseModelHandle.ModelIdx];
|
||||
for (int32_t i = 0; i < model.SocketCount; ++i)
|
||||
{
|
||||
if (isValid && !card.IsLocked && DraggedCard.X == -1 &&
|
||||
GetMouseButtonPressedNow(MouseButton::Left))
|
||||
{
|
||||
DraggedCard.X = x;
|
||||
DraggedCard.Y = y;
|
||||
auto& cover =
|
||||
level.PuzzleTileCovers.Get(CoverHandles[cardIdx * Puzzle::Config::MaxCoversInTile + i]);
|
||||
cover.EData.Visible = IsActive;
|
||||
cover.EData.ModelH = staticCard.Sockets[i].Model;
|
||||
cover.EData.Transform = tile.EData.Transform;
|
||||
cover.EData.MaterialHandle = EMaterial::Default;
|
||||
cover.EData.BaseColor = {0.2f, 0.1f, 0.7f, 1.0f};
|
||||
cover.EData.DotColor = {0.2f, 0.2f, 0.8f, 1.0f};
|
||||
Gen::TranslateLocal(cover.EData.Transform, model.Sockets[i].Pos);
|
||||
Gen::RotateLocal(cover.EData.Transform, Gen::EulerFromRotation(model.Sockets[i].Rot));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DraggedCard.X == x && DraggedCard.Y == y)
|
||||
{
|
||||
Vec3 dragPos = intersectPos;
|
||||
dragPos -= fw * 0.01f;
|
||||
quad.EData.Transform.SetPosition(dragPos);
|
||||
|
||||
Vec3 boardPos = boardTransform.GlobalToLocalPoint(intersectPos);
|
||||
Vec3 boardTilePos = boardPos / UICardOffset;
|
||||
int32_t xPos = (int32_t)bx::round(boardTilePos.x);
|
||||
int32_t yPos = (int32_t)bx::round(boardTilePos.y);
|
||||
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))
|
||||
{
|
||||
srcCard.Rotation += 1;
|
||||
if (srcCard.Rotation >= 4) srcCard.Rotation = 0;
|
||||
}
|
||||
|
||||
if (!GetMouseButton(MouseButton::Left))
|
||||
// End
|
||||
for (int32_t i = 0; i < BX_COUNTOF(EndHandles); ++i)
|
||||
{
|
||||
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)
|
||||
auto& tile = level.PuzzleTiles.Get(EndHandles[i]);
|
||||
if (i < Data.WidthTiles / 2)
|
||||
{
|
||||
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))
|
||||
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
|
||||
{
|
||||
Puzzle::DragAvailableCardTo(Data, targetCardPos, 0, srcCard.Rotation);
|
||||
}
|
||||
}
|
||||
DraggedCard.X = -1;
|
||||
DraggedCard.Y = -1;
|
||||
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
|
||||
|
||||
151
src/game/Level.h
151
src/game/Level.h
@@ -1,148 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "../engine/Shared.h"
|
||||
#include "Global.h"
|
||||
#include "Log.h"
|
||||
#include "Entity.h"
|
||||
#include "Puzzle.h"
|
||||
#include "UI.h"
|
||||
#include "rendering/Rendering.h"
|
||||
|
||||
#include <bgfx/bgfx.h>
|
||||
#include <cstdint>
|
||||
|
||||
#define ENTITY_HANDLE(X) \
|
||||
struct X \
|
||||
{ \
|
||||
uint16_t Idx = UINT16_MAX; \
|
||||
}; \
|
||||
inline bool IsValid(X h) \
|
||||
{ \
|
||||
return h.Idx != UINT16_MAX; \
|
||||
}
|
||||
|
||||
namespace Game
|
||||
{
|
||||
struct EntityRenderData
|
||||
{
|
||||
Gen::Vec4 DotColor{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
Gen::Vec4 BaseColor{0.0f, 0.0f, 0.0f, 1.0f};
|
||||
Transform Transform;
|
||||
EMaterial MaterialHandle = EMaterial::UNDEFINED;
|
||||
Gen::TextureHandle TextureHandle;
|
||||
Gen::ModelHandle ModelH;
|
||||
bool Visible = true;
|
||||
|
||||
void Render(const Model* models, const Material* materials, const Texture* textures);
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
static constexpr Gen::Vec2 WorldCardSize{10.0f, 10.0f};
|
||||
static constexpr float UICardOffset = 0.21f;
|
||||
Gen::PuzzleData Data;
|
||||
Gen::Vec3 WorldPosition;
|
||||
PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle];
|
||||
UIQuadEntityHandle UIPlacedCards[Puzzle::Config::MaxCardsInPuzzle];
|
||||
Gen::PuzPos DraggedCard{-1, -1};
|
||||
PuzzleTileCoverHandle CoverHandles[Puzzle::Config::MaxCardsInPuzzle * Puzzle::Config::MaxCoversInTile];
|
||||
PuzzleTileEntityHandle EndHandles[Puzzle::Config::MaxPuzzleSizeCards];
|
||||
PuzzleTileEntityHandle WallHandle;
|
||||
PuzzleTileEntityHandle DoorHandle;
|
||||
bool IsSetup = false;
|
||||
bool IsActive = false;
|
||||
bool IsSolved = false;
|
||||
|
||||
void Setup();
|
||||
void Update();
|
||||
@@ -153,17 +34,23 @@ namespace Game
|
||||
public:
|
||||
EntityManager<Cube, CubeHandle, 1024> Cubes;
|
||||
EntityManager<TestEntity, TestEntityHandle, 32> Tests;
|
||||
EntityManager<PuzzleTileEntity, PuzzleTileEntityHandle, 1024> PuzzleTiles;
|
||||
EntityManager<UIQuadEntity, UIQuadEntityHandle, 1024> UIQuads;
|
||||
EntityManager<PuzzleTileEntity, PuzzleTileEntityHandle, Puzzle::Config::MaxTilesTotal> PuzzleTiles;
|
||||
EntityManager<PuzzleTileCover, PuzzleTileCoverHandle, Puzzle::Config::MaxCoversTotal> PuzzleTileCovers;
|
||||
UIQuadEntityManager UIQuads;
|
||||
EntityManager<LevelEntity, LevelEntityHandle, 64> LevelEntities;
|
||||
|
||||
CubeHandle PlayerOutsideViewCube;
|
||||
LevelEntityHandle BackgroundEntityHandles[16];
|
||||
|
||||
public:
|
||||
Gen::StaticPuzzleData PuzzleData;
|
||||
WorldPuzzle Puzzles[1];
|
||||
WorldPuzzle Puzzles[Puzzle::Config::MaxVisiblePuzzles];
|
||||
WorldPuzzleUI PuzzleUI;
|
||||
|
||||
public:
|
||||
void Setup(GameData& data);
|
||||
void Update();
|
||||
void Render(uint16_t ViewID, const Model* models, const Material* materials, const Texture* textures);
|
||||
void ReloadLevelEntities();
|
||||
};
|
||||
} // namespace Game
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace
|
||||
{
|
||||
char LineBuffer[LogInternal::MaxLineSize]{0};
|
||||
char OutBuffer[LogInternal::MaxLineSize]{0};
|
||||
char OutBufferUI[LogInternal::MaxLineSize]{0};
|
||||
bx::HandleHashMapT<1024> OnceMap;
|
||||
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::vprintf(LineBuffer, args);
|
||||
bx::vsnprintf(OutBuffer, sizeof(OutBuffer), LineBuffer, args);
|
||||
bx::vsnprintf(OutBufferUI, sizeof(OutBufferUI), format, args);
|
||||
va_end(args);
|
||||
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.WriteType[History.WriteIdx] = logType;
|
||||
bx::strCopy(&History.FileBuffer[History.WriteIdx * LogInternal::MaxLineSize], LogInternal::MaxLineSize, file);
|
||||
History.LineBuffer[History.WriteIdx] = line;
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ struct LogHistory
|
||||
uint32_t LineBuffer[LogInternal::LogHistorySize]{0};
|
||||
int32_t WriteIdx = 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, ...);
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
#include "Gen.h"
|
||||
#include "Global.h"
|
||||
#include "Log.h"
|
||||
#include "Mesh.h"
|
||||
#include "bgfx/bgfx.h"
|
||||
#include "bx/bx.h"
|
||||
#include "bx/error.h"
|
||||
#include "bx/file.h"
|
||||
#include "bx/filepath.h"
|
||||
#include "bx/hash.h"
|
||||
#include "bx/string.h"
|
||||
#include "bx/timer.h"
|
||||
#include "rendering/Rendering.h"
|
||||
|
||||
#include "Instance.h"
|
||||
#include <cstdint>
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
@@ -20,6 +24,7 @@ namespace Game
|
||||
{
|
||||
bool LoadMesh(Model& mesh, const char* path, bool isBinary)
|
||||
{
|
||||
bx::strCopy(mesh.Name, sizeof(mesh.Name), path);
|
||||
mesh.VertLayout.begin()
|
||||
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
|
||||
.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float)
|
||||
@@ -57,23 +62,23 @@ namespace Game
|
||||
|
||||
tinygltf::Primitive primitive = model.meshes[0].primitives[0];
|
||||
{
|
||||
tinygltf::Accessor accessor = model.accessors.at(primitive.indices);
|
||||
tinygltf::BufferView bufferView = model.bufferViews.at(accessor.bufferView);
|
||||
tinygltf::Buffer buffer = model.buffers[bufferView.buffer];
|
||||
const bgfx::Memory* ibMem = bgfx::alloc(bufferView.byteLength);
|
||||
bx::memCopy(ibMem->data, &buffer.data.at(bufferView.byteOffset), bufferView.byteLength);
|
||||
tinygltf::Accessor indexAccessor = model.accessors.at(primitive.indices);
|
||||
tinygltf::BufferView indexBufferView = model.bufferViews.at(indexAccessor.bufferView);
|
||||
int32_t indexStride = sizeof(uint16_t);
|
||||
tinygltf::Buffer indexBuffer = model.buffers[indexBufferView.buffer];
|
||||
const bgfx::Memory* ibMem = bgfx::alloc(indexBufferView.byteLength);
|
||||
bx::memCopy(ibMem->data, &indexBuffer.data.at(indexBufferView.byteOffset), indexBufferView.byteLength);
|
||||
mesh.IndexBuffer = bgfx::createIndexBuffer(ibMem);
|
||||
}
|
||||
{
|
||||
|
||||
tinygltf::Accessor posAccessor = model.accessors.at(primitive.attributes.at("POSITION"));
|
||||
tinygltf::Accessor normalAccessor = model.accessors.at(primitive.attributes.at("NORMAL"));
|
||||
tinygltf::Accessor uvAccessor = model.accessors.at(primitive.attributes.at("TEXCOORD_0"));
|
||||
tinygltf::BufferView posBufferView = model.bufferViews[posAccessor.bufferView];
|
||||
tinygltf::BufferView normalBufferView = model.bufferViews[normalAccessor.bufferView];
|
||||
tinygltf::BufferView uvBufferView = model.bufferViews[uvAccessor.bufferView];
|
||||
int posStride = posAccessor.ByteStride(posBufferView);
|
||||
int normalStride = normalAccessor.ByteStride(normalBufferView);
|
||||
int uvStride = uvAccessor.ByteStride(uvBufferView);
|
||||
int32_t posStride = posAccessor.ByteStride(posBufferView);
|
||||
int32_t normalStride = normalAccessor.ByteStride(normalBufferView);
|
||||
int32_t uvStride = uvAccessor.ByteStride(uvBufferView);
|
||||
tinygltf::Buffer posBuffer = model.buffers[posBufferView.buffer];
|
||||
tinygltf::Buffer normalBuffer = model.buffers[normalBufferView.buffer];
|
||||
tinygltf::Buffer uvBuffer = model.buffers[uvBufferView.buffer];
|
||||
@@ -91,7 +96,113 @@ namespace Game
|
||||
bx::memCopy(&v.uv_x, &uvBuffer.data.at(uvBufferView.byteOffset + i * uvStride), uvStride);
|
||||
}
|
||||
mesh.VertexBuffer = bgfx::createVertexBuffer(vbMem, mesh.VertLayout);
|
||||
|
||||
constexpr float SIZE_LIMIT = 1000.0f;
|
||||
mesh.MinPos = {SIZE_LIMIT, SIZE_LIMIT, SIZE_LIMIT};
|
||||
mesh.MaxPos = {-SIZE_LIMIT, -SIZE_LIMIT, -SIZE_LIMIT};
|
||||
|
||||
bx::memSet(mesh.Height.Values, 0, BX_COUNTOF(mesh.Height.Values));
|
||||
|
||||
int64_t startTime = bx::getHPCounter();
|
||||
for (int32_t i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
Gen::Vec3* pos =
|
||||
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + i * posStride]);
|
||||
if (pos->x < mesh.MinPos.x) mesh.MinPos.x = pos->x;
|
||||
if (pos->y < mesh.MinPos.y) mesh.MinPos.y = pos->y;
|
||||
if (pos->z < mesh.MinPos.z) mesh.MinPos.z = pos->z;
|
||||
if (pos->x > mesh.MaxPos.x) mesh.MaxPos.x = pos->x;
|
||||
if (pos->y > mesh.MaxPos.y) mesh.MaxPos.y = pos->y;
|
||||
if (pos->z > mesh.MaxPos.z) mesh.MaxPos.z = pos->z;
|
||||
}
|
||||
LOG("min/max: %lli", bx::getHPCounter() - startTime);
|
||||
|
||||
mesh.MinPos = {-5.0f, -5.0f, -5.0f};
|
||||
mesh.MaxPos = {5.0f, 5.0f, 5.0f};
|
||||
mesh.Size = mesh.MaxPos - mesh.MinPos;
|
||||
|
||||
startTime = bx::getHPCounter();
|
||||
for (uint32_t v = 0; v < HeightMap::Height; ++v)
|
||||
{
|
||||
float vPos = mesh.MinPos.z + (float)v / HeightMap::Height * mesh.Size.z;
|
||||
|
||||
for (uint32_t u = 0; u < HeightMap::Width; ++u)
|
||||
{
|
||||
float uPos = mesh.MinPos.x + (float)u / HeightMap::Width * mesh.Size.x;
|
||||
|
||||
Gen::Vec3 rayStart = {uPos, -100.0f, vPos};
|
||||
Gen::Vec3 rayEnd = {uPos, 100.0f, vPos};
|
||||
Gen::Vec3 ptOut;
|
||||
|
||||
for (int16_t i = 0; i < indexBufferView.byteLength; i += indexStride * 3)
|
||||
{
|
||||
uint16_t* idxA = reinterpret_cast<uint16_t*>(&indexBuffer.data[indexBufferView.byteOffset + i]);
|
||||
uint16_t* idxB = reinterpret_cast<uint16_t*>(
|
||||
&indexBuffer.data[indexBufferView.byteOffset + i + 1 * indexStride]);
|
||||
uint16_t* idxC = reinterpret_cast<uint16_t*>(
|
||||
&indexBuffer.data[indexBufferView.byteOffset + i + 2 * indexStride]);
|
||||
Gen::Vec3* triA =
|
||||
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + *idxA * posStride]);
|
||||
Gen::Vec3* triB =
|
||||
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + *idxB * posStride]);
|
||||
Gen::Vec3* triC =
|
||||
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + *idxC * posStride]);
|
||||
if (Gen::RayTriangleIntersect(rayStart, rayEnd, *triA, *triB, *triC, ptOut))
|
||||
{
|
||||
float len = ptOut.y - rayStart.y;
|
||||
uint8_t val = (uint8_t)(len / mesh.Size.y * UINT8_MAX);
|
||||
int32_t idx = v * HeightMap::Width + u;
|
||||
if (mesh.Height.Values[idx] < val)
|
||||
{
|
||||
mesh.Height.Values[idx] = val;
|
||||
}
|
||||
if (len < 0.0f)
|
||||
{
|
||||
LOG_ONCE("%f / %f = %u", len, mesh.Size.y, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG("heightmap: %lli", bx::getHPCounter() - startTime);
|
||||
}
|
||||
|
||||
const bgfx::Memory* mem = bgfx::makeRef(&mesh.Height.Values[0], sizeof(mesh.Height.Values));
|
||||
mesh.HeightMapTexture =
|
||||
bgfx::createTexture2D(HeightMap::Width, HeightMap::Height, false, 1, bgfx::TextureFormat::R8, 0, mem);
|
||||
|
||||
for (auto& node : model.nodes)
|
||||
{
|
||||
if (bx::strFindI(node.name.c_str(), "_slot_").getLength() > 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../gen/Def.h"
|
||||
#include "Gen.h"
|
||||
#include "Global.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "Puzzle.h"
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace
|
||||
|
||||
StaticPuzzleData StaticData;
|
||||
StaticPuzzleCard InvalidCard;
|
||||
PlacedPuzzleCard InvalidPlacedCard;
|
||||
} // namespace
|
||||
|
||||
namespace Puzzle
|
||||
@@ -103,6 +104,24 @@ namespace Puzzle
|
||||
return puz.BackgroundTiles[pos.Y * Puzzle::Config::MaxPuzzleSizeTiles + pos.X];
|
||||
}
|
||||
|
||||
PuzzleElementType::Enum GetInitialNodeAt(const PuzzleData& puz, PuzPos pos)
|
||||
{
|
||||
assert(pos.X < Puzzle::Config::MaxPuzzleSizeTiles && pos.Y < Puzzle::Config::MaxPuzzleSizeTiles && pos.X >= 0 &&
|
||||
pos.Y >= 0);
|
||||
int32_t cardIdxX = pos.X / Puzzle::Config::CardSize;
|
||||
int32_t cardIdxY = pos.Y / Puzzle::Config::CardSize;
|
||||
auto& card = puz.InitialPlacedCards[cardIdxY * Puzzle::Config::MaxPuzzleSizeCards + cardIdxX];
|
||||
int32_t offsetX = pos.X - (cardIdxX * Config::CardSize);
|
||||
int32_t offsetY = pos.Y - (cardIdxY * Config::CardSize);
|
||||
if (offsetX >= 0 && offsetX < Puzzle::Config::CardSize && offsetY >= 0 && offsetY < Puzzle::Config::CardSize &&
|
||||
IsValid(card.RefCard))
|
||||
{
|
||||
PuzzleElementType::Enum cardVal = GetCardNodeAt(GetCard(card.RefCard), card.Rotation, offsetX, offsetY);
|
||||
if (cardVal != PuzzleElementType::None) return cardVal;
|
||||
}
|
||||
return puz.BackgroundTiles[pos.Y * Puzzle::Config::MaxPuzzleSizeTiles + pos.X];
|
||||
}
|
||||
|
||||
PuzzleElementType::Enum GetCardNodeAt(const StaticPuzzleCard& card, uint8_t rotation, int8_t x, int8_t y)
|
||||
{
|
||||
assert(x >= 0 && x < Puzzle::Config::CardSize);
|
||||
@@ -172,6 +191,11 @@ namespace Puzzle
|
||||
bool PuzzleSolver::IsExitSatisfied(const PuzzleData& puzzle, PuzPos pos)
|
||||
{
|
||||
PuzzleElementType::Enum goalType = GetNodeAt(puzzle, pos);
|
||||
if (goalType == PuzzleElementType::None)
|
||||
{
|
||||
WARN_ONCE("TODO!");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t currentPositionQueueIdx = 0;
|
||||
uint32_t positionQueueCount = 0;
|
||||
@@ -234,7 +258,7 @@ namespace Puzzle
|
||||
return from == PuzzleElementType::ElectricIn || from == PuzzleElementType::ElectricGoal ||
|
||||
from == PuzzleElementType::None;
|
||||
}
|
||||
assert(false);
|
||||
// assert(false);
|
||||
return false;
|
||||
}
|
||||
bool PuzzleSolver::IsValidSource(PuzzleElementType::Enum sourceType, PuzzleElementType::Enum goalType)
|
||||
@@ -271,18 +295,43 @@ namespace Puzzle
|
||||
ImGui::InvisibleButton("cardbn",
|
||||
{Puzzle::Config::CardSize * UIPuzBoxSize, Puzzle::Config::CardSize * UIPuzBoxSize});
|
||||
}
|
||||
void RotateCard(PlacedPuzzleCard& card)
|
||||
{
|
||||
card.Rotation += 1;
|
||||
if (card.Rotation >= 4) card.Rotation = 0;
|
||||
}
|
||||
|
||||
void WritePuzzleFilePath(char* buf, int32_t bufSize, uint16_t 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)
|
||||
{
|
||||
auto& placedCard = obj.PlacedCards[targetPos.Y * Config::MaxPuzzleSizeCards + targetPos.X];
|
||||
PlacedPuzzleCard& placedCard = GetCardAt(obj, targetPos);
|
||||
if (IsValid(placedCard.RefCard))
|
||||
{
|
||||
if (placedCard.IsLocked)
|
||||
if (GetFlag(placedCard.Flags, PlacedPuzzleCardFlags::Locked))
|
||||
{
|
||||
LOG_WARN("Card at %i %i is locked!", targetPos.X, targetPos.Y);
|
||||
return false;
|
||||
@@ -319,19 +368,55 @@ namespace Puzzle
|
||||
auto& draggedCard = obj.AvailableCards[availIdx];
|
||||
draggedCard.UsedCount++;
|
||||
|
||||
auto& placedCard = obj.PlacedCards[targetPos.Y * Config::MaxPuzzleSizeCards + targetPos.X];
|
||||
PlacedPuzzleCard& placedCard = GetCardAt(obj, targetPos);
|
||||
placedCard.RefCard = draggedCard.RefCard;
|
||||
placedCard.IsLocked = false;
|
||||
placedCard.Flags = (PlacedPuzzleCardFlags::Enum)ClearFlags(placedCard.Flags, PlacedPuzzleCardFlags::Locked);
|
||||
placedCard.Position = targetPos;
|
||||
placedCard.Rotation = rotation;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecalculateInitialAvailable(PuzzleData& obj)
|
||||
{
|
||||
for (int32_t i = 0; i < obj.AvailableCardCount; ++i)
|
||||
{
|
||||
obj.AvailableCards[i].UsedCount = obj.AvailableCards[i].MaxAvailableCount;
|
||||
}
|
||||
|
||||
for (int32_t y = 0; y < obj.HeightTiles; ++y)
|
||||
{
|
||||
for (int32_t x = 0; x < obj.WidthTiles; ++x)
|
||||
{
|
||||
auto& placedCard = obj.PlacedCards[y * Puzzle::Config::MaxPuzzleSizeCards + x];
|
||||
if (Puzzle::IsValid(placedCard.RefCard))
|
||||
{
|
||||
bool found = false;
|
||||
for (int32_t i = 0; i < obj.AvailableCardCount; ++i)
|
||||
{
|
||||
if (obj.AvailableCards[i].RefCard.Idx == placedCard.RefCard.Idx)
|
||||
{
|
||||
found = true;
|
||||
obj.AvailableCards[i].MaxAvailableCount++;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
if (obj.AvailableCardCount == Puzzle::Config::MaxAvailableStacks)
|
||||
{
|
||||
LOG_ERROR("Read limit of available card stacks!");
|
||||
break;
|
||||
}
|
||||
obj.AvailableCards[obj.AvailableCardCount] = {};
|
||||
obj.AvailableCards[obj.AvailableCardCount].RefCard = placedCard.RefCard;
|
||||
obj.AvailableCards[obj.AvailableCardCount].MaxAvailableCount = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderDebugUI(PuzzleData& obj)
|
||||
{
|
||||
bool dataChanged = false;
|
||||
uint8_t debugRot = Game::GetInstance().DebugData.DebugCardRotation;
|
||||
|
||||
bool isVisible = true;
|
||||
if (ImGui::Begin("Puzzle", &isVisible))
|
||||
{
|
||||
@@ -345,17 +430,34 @@ namespace Puzzle
|
||||
return false;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reload"))
|
||||
if (ImGui::Button("Reset"))
|
||||
{
|
||||
// TODO
|
||||
ResetPuzzle(obj);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Save"))
|
||||
{
|
||||
ResetPuzzle(obj);
|
||||
char path[128]{0};
|
||||
WritePuzzleFilePath(path, sizeof(path), obj.ID);
|
||||
Serializer ser;
|
||||
if (ser.Init(path, "PZZL") && ser.WriteT(obj))
|
||||
{
|
||||
LOG("Saved to %s", path);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Failed to save to %s", path);
|
||||
}
|
||||
ser.Finish();
|
||||
}
|
||||
|
||||
int32_t val = obj.ID;
|
||||
if (ImGui::InputInt("ID", &val))
|
||||
{
|
||||
obj.ID = val;
|
||||
dataChanged = true;
|
||||
}
|
||||
dataChanged = ImGui::InputText("Name", obj.PuzzleName, sizeof(obj.PuzzleName)) || dataChanged;
|
||||
ImGui::InputText("Name", obj.PuzzleName, sizeof(obj.PuzzleName));
|
||||
|
||||
int32_t W = obj.WidthTiles;
|
||||
int32_t H = obj.HeightTiles;
|
||||
@@ -364,7 +466,6 @@ namespace Puzzle
|
||||
if (ImGui::DragInt("", &W, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
|
||||
{
|
||||
obj.WidthTiles = uint8_t(W);
|
||||
dataChanged = true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
ImGui::SameLine();
|
||||
@@ -375,7 +476,6 @@ namespace Puzzle
|
||||
if (ImGui::DragInt("", &H, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
|
||||
{
|
||||
obj.HeightTiles = uint8_t(H);
|
||||
dataChanged = true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
@@ -390,7 +490,7 @@ namespace Puzzle
|
||||
{
|
||||
ImGui::PushID(x);
|
||||
PuzPos nodePos = {int8_t(x), int8_t(y)};
|
||||
auto node = GetNodeAt(obj, nodePos);
|
||||
auto node = GetInitialNodeAt(obj, nodePos);
|
||||
if (node == PuzzleElementType::WaterGoal)
|
||||
{
|
||||
obj.GoalPositions[obj.GoalPositionCount] = nodePos;
|
||||
@@ -403,36 +503,30 @@ namespace Puzzle
|
||||
ImGui::SetCursorScreenPos(pos);
|
||||
if (x % Puzzle::Config::CardSize == 0 && y % Puzzle::Config::CardSize == 0)
|
||||
{
|
||||
int32_t cardX = x / Config::CardSize;
|
||||
int32_t cardY = y / Config::CardSize;
|
||||
PuzPos cardPos = {int8_t(cardX), int8_t(cardY)};
|
||||
auto& placedCard = obj.PlacedCards[cardY * Config::MaxPuzzleSizeCards + cardX];
|
||||
PuzPos cardPos = {int8_t(x / Config::CardSize), int8_t(y / Config::CardSize)};
|
||||
PlacedPuzzleCard& placedCard = GetInitialCardAt(obj, cardPos);
|
||||
bool isLocked = GetFlag(placedCard.Flags, PlacedPuzzleCardFlags::Locked);
|
||||
|
||||
ImGui::InvisibleButton("bn", {UIPuzBoxSize * 2, UIPuzBoxSize * 2});
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right))
|
||||
{
|
||||
placedCard.Rotation += 1;
|
||||
if (placedCard.Rotation >= 4) placedCard.Rotation = 0;
|
||||
dataChanged = true;
|
||||
}
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Middle) && IsValid(placedCard.RefCard))
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Middle))
|
||||
{
|
||||
if (placedCard.IsLocked)
|
||||
if (ImGui::IsKeyDown(ImGuiKey_LeftShift))
|
||||
{
|
||||
placedCard.IsLocked = false;
|
||||
placedCard.RefCard = {};
|
||||
dataChanged = true;
|
||||
placedCard = {};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ReturnPlacedCard(obj, cardPos))
|
||||
{
|
||||
placedCard.IsLocked = false;
|
||||
placedCard.RefCard = {};
|
||||
dataChanged = true;
|
||||
placedCard.Flags =
|
||||
(PlacedPuzzleCardFlags::Enum)(placedCard.Flags ^ PlacedPuzzleCardFlags::Locked);
|
||||
RecalculateInitialAvailable(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!placedCard.IsLocked && IsValid(placedCard.RefCard))
|
||||
if (!isLocked && IsValid(placedCard.RefCard))
|
||||
{
|
||||
ImVec2 s = {puzCursorStart.x + x * UIPuzBoxSize, puzCursorStart.y + y * UIPuzBoxSize};
|
||||
drawList.AddRectFilled(s,
|
||||
@@ -447,17 +541,11 @@ namespace Puzzle
|
||||
uint32_t CardIdx = *reinterpret_cast<uint32_t*>(payload->Data);
|
||||
placedCard = {};
|
||||
placedCard.RefCard = {(uint16_t)CardIdx};
|
||||
placedCard.Rotation = debugRot;
|
||||
placedCard.Rotation = 0;
|
||||
placedCard.Position = cardPos;
|
||||
placedCard.IsLocked = true;
|
||||
dataChanged = true;
|
||||
}
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("availcard", 0))
|
||||
{
|
||||
DragAvailableCardTo(obj,
|
||||
cardPos,
|
||||
*(int32_t*)payload->Data,
|
||||
Game::GetInstance().DebugData.DebugCardRotation);
|
||||
placedCard.Flags = (PlacedPuzzleCardFlags::Enum)SetFlags(placedCard.Flags,
|
||||
PlacedPuzzleCardFlags::Locked);
|
||||
RecalculateInitialAvailable(obj);
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
@@ -523,7 +611,6 @@ namespace Puzzle
|
||||
obj.AvailableCardCount++;
|
||||
}
|
||||
}
|
||||
dataChanged = true;
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
@@ -536,14 +623,8 @@ namespace Puzzle
|
||||
ImGui::SetCursorScreenPos(localPos);
|
||||
ImGui::PushID(i);
|
||||
auto& card = obj.AvailableCards[i];
|
||||
DrawCard(GetCard(card.RefCard), debugRot, ImGui::GetCursorScreenPos());
|
||||
DrawCard(GetCard(card.RefCard), 0, ImGui::GetCursorScreenPos());
|
||||
int displayCount = card.MaxAvailableCount - card.UsedCount;
|
||||
if (displayCount > 0 && ImGui::BeginDragDropSource())
|
||||
{
|
||||
ImGui::SetDragDropPayload("availcard", &i, sizeof(i));
|
||||
DrawCard(GetCard(card.RefCard), debugRot, ImGui::GetCursorScreenPos());
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
|
||||
ImGui::SetCursorScreenPos({localPos.x, localPos.y + 55.0f});
|
||||
ImGui::SetNextItemWidth(35);
|
||||
@@ -552,7 +633,6 @@ namespace Puzzle
|
||||
{
|
||||
int diff = displayCount - (card.MaxAvailableCount - card.UsedCount);
|
||||
card.MaxAvailableCount = bx::max(0, card.MaxAvailableCount + diff);
|
||||
dataChanged = true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
ImGui::SameLine(0, 3);
|
||||
@@ -571,22 +651,17 @@ namespace Puzzle
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
if (dataChanged)
|
||||
{
|
||||
char path[128]{0};
|
||||
WritePuzzleFilePath(path, sizeof(path), obj.ID);
|
||||
Serializer ser;
|
||||
if (ser.Init(path, "PZZL") && ser.WriteT(obj))
|
||||
{
|
||||
LOG("Saved to %s", path);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Failed to save to %s", path);
|
||||
}
|
||||
ser.Finish();
|
||||
}
|
||||
|
||||
return isVisible;
|
||||
}
|
||||
void ResetPuzzle(PuzzleData& puz)
|
||||
{
|
||||
for (int32_t i = 0; i < puz.AvailableCardCount; ++i)
|
||||
{
|
||||
puz.AvailableCards[i].UsedCount = 0;
|
||||
}
|
||||
for (int32_t i = 0; i < BX_COUNTOF(puz.PlacedCards); ++i)
|
||||
{
|
||||
puz.PlacedCards[i] = puz.InitialPlacedCards[i];
|
||||
}
|
||||
}
|
||||
} // namespace Puzzle
|
||||
|
||||
@@ -12,16 +12,20 @@ namespace Puzzle
|
||||
|
||||
struct Config
|
||||
{
|
||||
static constexpr uint32_t MaxVisiblePuzzles = 3;
|
||||
static constexpr uint32_t CardSize = 2;
|
||||
static constexpr uint32_t NodesPerCard = CardSize * CardSize;
|
||||
static constexpr uint32_t MaxElementsPerTile = 4;
|
||||
static constexpr uint32_t MaxPuzzleSizeCards = 16;
|
||||
static constexpr uint32_t MaxCardsInPuzzle = MaxPuzzleSizeCards * MaxPuzzleSizeCards;
|
||||
static constexpr uint32_t MaxPuzzleSizeTiles = 16 * CardSize;
|
||||
static constexpr uint32_t MaxTilesInPuzzle = MaxPuzzleSizeTiles * MaxPuzzleSizeTiles;
|
||||
static constexpr uint32_t MaxTilesTotal =
|
||||
MaxTilesInPuzzle * MaxVisiblePuzzles + MaxPuzzleSizeCards * MaxVisiblePuzzles + 64;
|
||||
static constexpr uint32_t MaxAvailableStacks = 16;
|
||||
static constexpr uint32_t MaxGoalPositions = 16;
|
||||
static constexpr float CardScaleWorld = 10.0f;
|
||||
static constexpr uint32_t MaxCoversInTile = 8;
|
||||
static constexpr uint32_t MaxCoversTotal = MaxCoversInTile * MaxTilesTotal;
|
||||
};
|
||||
|
||||
void Setup();
|
||||
@@ -32,14 +36,19 @@ namespace Puzzle
|
||||
bool IsValid(StaticPuzzleCardHandle h);
|
||||
uint8_t GetRemainingCount(const PuzzleCardStack& stack);
|
||||
PuzzleElementType::Enum GetNodeAt(const PuzzleData& puz, PuzPos pos);
|
||||
PuzzleElementType::Enum GetInitialNodeAt(const PuzzleData& puz, PuzPos pos);
|
||||
PuzzleElementType::Enum GetCardNodeAt(const StaticPuzzleCard& card, uint8_t rotation, int8_t x, int8_t y);
|
||||
PuzzleElementType::Enum& EditCardNodeAt(StaticPuzzleCard& card, uint8_t rotation, int8_t x, int8_t y);
|
||||
void DrawCard(const StaticPuzzleCard& card, uint8_t rotation, ImVec2 pos);
|
||||
void RotateCard(PlacedPuzzleCard& card);
|
||||
|
||||
PlacedPuzzleCard& GetCardAt(PuzzleData& obj, PuzPos pos);
|
||||
PlacedPuzzleCard& GetInitialCardAt(PuzzleData& obj, PuzPos pos);
|
||||
// TODO: targetPos is of type CardPos
|
||||
bool ReturnPlacedCard(PuzzleData& obj, PuzPos targetPos);
|
||||
// TODO: targetPos is of type CardPos
|
||||
bool DragAvailableCardTo(PuzzleData& obj, PuzPos targetPos, int32_t availIdx, uint8_t rotation);
|
||||
void ResetPuzzle(PuzzleData& puz);
|
||||
|
||||
struct PuzzleSolver
|
||||
{
|
||||
|
||||
@@ -33,32 +33,32 @@ namespace Game
|
||||
tracy::StartupProfiler();
|
||||
#endif
|
||||
|
||||
if (shared.Game.PermanentStorage == nullptr)
|
||||
if (shared.Game.PermanentArena.Base == nullptr)
|
||||
{
|
||||
LOG_ERROR("Game memory not initialized!!");
|
||||
return;
|
||||
}
|
||||
if (shared.Game.EntityStorage == nullptr)
|
||||
if (shared.Game.EntityArena.Base == nullptr)
|
||||
{
|
||||
LOG_ERROR("Entity memory not initialized!");
|
||||
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;
|
||||
}
|
||||
GameInstance& instance = *reinterpret_cast<GameInstance*>(shared.Game.PermanentStorage);
|
||||
GameInstance& instance = *reinterpret_cast<GameInstance*>(shared.Game.PermanentArena.Base);
|
||||
if (sizeof(GameInstance) != instance.Size)
|
||||
{
|
||||
LOG_WARN("Game instance size changed, resetting!");
|
||||
instance = {};
|
||||
}
|
||||
instance.UsedScratchAmount = 0;
|
||||
SetShared(shared);
|
||||
SetInstance(instance);
|
||||
ResetScratch();
|
||||
Puzzle::LoadStaticPuzzleData();
|
||||
SetupInstance.Rendering.Setup();
|
||||
SetupInstance.Rendering.Setup({});
|
||||
instance.GameLevel.Setup(shared.Game);
|
||||
instance.IsInitialized = true;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#include "../gen/Def.h"
|
||||
#include "Gen.h"
|
||||
#include "Global.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "Mesh.h"
|
||||
#include "Puzzle.h"
|
||||
#include "Tools.h"
|
||||
#include "bx/timer.h"
|
||||
|
||||
#include "bgfx/bgfx.h"
|
||||
#include "bx/filepath.h"
|
||||
#include "bx/string.h"
|
||||
#include "bx/timer.h"
|
||||
#include "rendering/Rendering.h"
|
||||
#include <imgui.h>
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
@@ -33,28 +39,47 @@ namespace Tools
|
||||
return "---";
|
||||
}
|
||||
|
||||
void ModelDropdown(Gen::ModelHandle& modelHandle)
|
||||
bool EntityDataSettings(Gen::SavedEntityRenderData& data)
|
||||
{
|
||||
ImGui::PushID(&data);
|
||||
bool changed = false;
|
||||
changed |= ModelDropdown(data.Model);
|
||||
changed |= MaterialDropdown(data.Material);
|
||||
changed |= TextureDropdown(data.Texture);
|
||||
changed |= TransformUI(data.TF);
|
||||
changed |= ImGui::Checkbox("Visible", &data.Visible);
|
||||
changed |= ImGui::ColorEdit4("Color 1", &data.BaseColor.x);
|
||||
changed |= ImGui::ColorEdit4("Color 2", &data.HighlightColor.x);
|
||||
ImGui::PopID();
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool ModelDropdown(Gen::ModelHandle& modelHandle, const char* title)
|
||||
{
|
||||
bool changed = false;
|
||||
auto& R = Game::GameRendering::Get();
|
||||
const char* name = GetAssetPath(modelHandle.Asset);
|
||||
if (ImGui::BeginCombo("Model", name))
|
||||
const char* assetName = GetAssetPath(modelHandle.Asset);
|
||||
if (ImGui::BeginCombo(title, assetName))
|
||||
{
|
||||
for (int32_t i = 0; i < R.ModelCount; ++i)
|
||||
{
|
||||
if (ImGui::Selectable(GetAssetPath(R.Models[i].Handle.Asset), i == modelHandle.ModelIdx))
|
||||
{
|
||||
modelHandle = R.Models[i].Handle;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void TextureDropdown(Gen::TextureHandle& texHandle)
|
||||
bool TextureDropdown(Gen::TextureHandle& texHandle, const char* title)
|
||||
{
|
||||
bool changed = false;
|
||||
auto& R = Game::GameRendering::Get();
|
||||
const char* name = GetAssetPath(texHandle.Asset);
|
||||
if (ImGui::BeginCombo("Texture", name))
|
||||
if (ImGui::BeginCombo(title, name))
|
||||
{
|
||||
for (int32_t i = 0; i < R.MaxTextures; ++i)
|
||||
{
|
||||
@@ -64,6 +89,7 @@ namespace Tools
|
||||
if (ImGui::Selectable("", i == texHandle.TextureIdx, ImGuiSelectableFlags_AllowOverlap, {0, 64}))
|
||||
{
|
||||
texHandle = R.Textures[i].TexHandle;
|
||||
changed = true;
|
||||
}
|
||||
ImGui::SetCursorScreenPos(pos);
|
||||
ImGui::Image(R.Textures[i].RenderHandle.idx, {64, 64});
|
||||
@@ -73,44 +99,123 @@ namespace Tools
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
void RenderDebugUI(Game::GameRendering& rendering)
|
||||
|
||||
bool MaterialDropdown(Gen::EMaterial::Enum& material)
|
||||
{
|
||||
bool changed = false;
|
||||
const char* selectedText = "---";
|
||||
if (material < Gen::EMaterial::EntryCount)
|
||||
{
|
||||
selectedText = Gen::EMaterial::EntryNames[material];
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Material", selectedText))
|
||||
{
|
||||
for (int32_t i = 0; i < Gen::EMaterial::EntryCount; ++i)
|
||||
{
|
||||
if (ImGui::Selectable(Gen::EMaterial::EntryNames[i], i == material))
|
||||
{
|
||||
material = (Gen::EMaterial::Enum)i;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
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 changed = false;
|
||||
changed |= ImGui::DragFloat3("Pos", &transform.Position.x, 0.1f);
|
||||
Vec3 euler = EulerFromRotation(transform.Rotation);
|
||||
if (ImGui::DragFloat3("Rot", &euler.x, 0.1f))
|
||||
{
|
||||
transform.Rotation = RotationFromEuler(euler);
|
||||
changed = true;
|
||||
}
|
||||
changed |= ImGui::DragFloat3("Scale", &transform.Scale.x, 0.01f);
|
||||
return changed;
|
||||
}
|
||||
|
||||
void RenderLogUI()
|
||||
{
|
||||
auto& time = Game::GetInstance().Time;
|
||||
auto& shared = Game::GetShared();
|
||||
auto& debug = Game::GetInstance().DebugData;
|
||||
auto& level = Game::GetInstance().GameLevel;
|
||||
auto& player = Game::GetInstance().Player;
|
||||
|
||||
if (rendering.UIVisible == Game::UIVisibilityState::Debug)
|
||||
{
|
||||
ZoneScopedN("DebugUI");
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right))
|
||||
{
|
||||
debug.DebugCardRotation++;
|
||||
if (debug.DebugCardRotation >= 4) debug.DebugCardRotation = 0;
|
||||
}
|
||||
if (ImGui::Begin("Log"))
|
||||
{
|
||||
ImGui::Checkbox("Shorten File Names", &debug.ShortenLogFileNames);
|
||||
ImGui::BeginTable(
|
||||
"tbl", 4, ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_SizingFixedFit);
|
||||
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();
|
||||
for (int32_t i = 0; i < bx::min(100, LogInternal::LogHistorySize); ++i)
|
||||
|
||||
auto& logs = GetLogHistory();
|
||||
|
||||
int32_t lineCount = bx::min(100, LogInternal::LogHistorySize);
|
||||
for (int32_t i = 0; i < lineCount; ++i)
|
||||
{
|
||||
int32_t idx = GetLogHistory().WriteIdx - i - 1;
|
||||
int32_t idx = logs.WriteIdx - i - 1;
|
||||
if (idx < 0) idx += LogInternal::LogHistorySize;
|
||||
const char* line = &GetLogHistory().LogBuffer[idx * LogInternal::MaxLineSize];
|
||||
const char* line = &logs.LogBuffer[idx * LogInternal::MaxLineSize];
|
||||
if (line[0] != 0)
|
||||
{
|
||||
int64_t timeOffset = GetLogHistory().WriteTime[idx] - time.StartTime;
|
||||
int64_t timeOffset = logs.WriteTime[idx] - time.StartTime;
|
||||
double writeTime = (double)timeOffset / bx::getHPFrequency();
|
||||
uint32_t fileLine = GetLogHistory().LineBuffer[idx];
|
||||
const char* filePath = &GetLogHistory().FileBuffer[idx * LogInternal::MaxLineSize];
|
||||
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;
|
||||
|
||||
@@ -127,11 +232,33 @@ namespace Tools
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", filePathRes);
|
||||
|
||||
if (i > 0) ImGui::PopStyleColor(2);
|
||||
ImVec4 bgCol = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
if (logs.WriteType[idx] == ELogType::Warn)
|
||||
bgCol = {0.2f, 0.2f, 0.0f, 1.0f};
|
||||
else if (logs.WriteType[idx] == ELogType::Error)
|
||||
bgCol = {0.2f, 0.0f, 0.0f, 1.0f};
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBg, bgCol);
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, bgCol);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
|
||||
if (lineCount > 0) ImGui::PopStyleColor(2);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void RenderRenderSettingsUI(Game::GameRendering& rendering)
|
||||
{
|
||||
auto& time = Game::GetInstance().Time;
|
||||
auto& shared = Game::GetShared();
|
||||
auto& debug = Game::GetInstance().DebugData;
|
||||
auto& level = Game::GetInstance().GameLevel;
|
||||
auto& player = Game::GetInstance().Player;
|
||||
|
||||
if (ImGui::Begin("Rendering"))
|
||||
{
|
||||
if (rendering.LastShaderLoadTime >= 0.0f)
|
||||
@@ -144,10 +271,6 @@ namespace Tools
|
||||
{
|
||||
ImGui::TextColored({0.9f, 0.2f, 0.2f, 1.0f}, "Shader load Failiure!");
|
||||
}
|
||||
if (ImGui::Button("Reload Meshes"))
|
||||
{
|
||||
LoadModels(rendering.Models, rendering.ModelCount);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reload Level"))
|
||||
{
|
||||
@@ -155,19 +278,65 @@ namespace Tools
|
||||
level.Setup(shared.Game);
|
||||
}
|
||||
|
||||
ImGui::DragFloat3("Player Pos", &player.PlayerCamTransform.Position.x);
|
||||
ImGui::DragFloat3("Puz0 Pos", &level.Puzzles[0].WorldPosition.x);
|
||||
ImGui::SliderFloat("Mouse Sensitivity", &player.MouseSensitivity, 0.1f, 5.0f);
|
||||
ImGui::SliderFloat("Player Speed", &player.MovementSpeed, 1.0f, 30.0f);
|
||||
|
||||
ImGui::Checkbox("Show ImGui Demo", &debug.ShowImguiDemo);
|
||||
ImGui::Checkbox("Show Stats", &debug.ShowStats);
|
||||
if (debug.ShowImguiDemo) ImGui::ShowDemoWindow(&debug.ShowImguiDemo);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNodeEx("Entity Groups"))
|
||||
{
|
||||
ImGui::Checkbox("Cubes", &level.Cubes.IsEnabled);
|
||||
ImGui::Checkbox("Tests", &level.Tests.IsEnabled);
|
||||
ImGui::Checkbox("PuzzleTiles", &level.PuzzleTiles.IsEnabled);
|
||||
ImGui::Checkbox("UIQuads", &level.UIQuads.IsEnabled);
|
||||
ImGui::Checkbox("Level", &level.LevelEntities.IsEnabled);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
bool uiconfigChanged = false;
|
||||
if (ImGui::TreeNodeEx("Game Tablet"))
|
||||
{
|
||||
uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletBackgroundRenderData);
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Status");
|
||||
uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletStatusRenderData);
|
||||
uiconfigChanged |= Tools::TextureDropdown(player.Config.TabletStatusSolvedTexture, "Solved Texture");
|
||||
uiconfigChanged |=
|
||||
Tools::TextureDropdown(player.Config.TabletStatusNotSolvedTexture, "Not Solved Texture");
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Reset");
|
||||
uiconfigChanged |= Tools::EntityDataSettings(player.Config.TabletResetRenderData);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNodeEx("Background Level"))
|
||||
{
|
||||
for (int32_t i = 0; i < BX_COUNTOF(player.Config.BackgroundLevelRenderData); ++i)
|
||||
{
|
||||
if (i > 0) ImGui::Separator();
|
||||
uiconfigChanged |= Tools::EntityDataSettings(player.Config.BackgroundLevelRenderData[i]);
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (uiconfigChanged)
|
||||
{
|
||||
Serializer s;
|
||||
s.Init("game/data/static/uiconfig.dat", "UICO");
|
||||
s.WriteT(player.Config);
|
||||
s.Finish();
|
||||
level.PuzzleUI.Reset();
|
||||
level.ReloadLevelEntities();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNodeEx("Dithering"))
|
||||
{
|
||||
if (ImGui::Button("Dithergen"))
|
||||
{
|
||||
DitherGen(rendering.DitherTextures, rendering.DitherRecursion);
|
||||
@@ -194,31 +363,20 @@ namespace Tools
|
||||
ImGui::Image(rendering.DitherTextures.RampTex.idx,
|
||||
{BX_COUNTOF(rendering.DitherTextures.BrightnessRamp), 8});
|
||||
}
|
||||
Vec3 quadPos = level.UIQuads.Get({0}).EData.Transform.GetPosition();
|
||||
ImGui::Text("%f %f %f", quadPos.x, quadPos.y, quadPos.z);
|
||||
|
||||
auto& puzzleVisuals = Puzzle::GetStaticPuzzleData().Visuals;
|
||||
if (ImGui::ColorEdit3("Tile Base Color", &puzzleVisuals.TileBaseColor.x))
|
||||
{
|
||||
auto& tiles = level.PuzzleTiles;
|
||||
for (int32_t i = 0; i < tiles.Count; ++i)
|
||||
{
|
||||
tiles.Data[i].EData.BaseColor = puzzleVisuals.TileBaseColor;
|
||||
}
|
||||
}
|
||||
if (ImGui::ColorEdit3("Tile Dot Color", &puzzleVisuals.TileDotColor.x))
|
||||
{
|
||||
auto& tiles = level.PuzzleTiles;
|
||||
for (int32_t i = 0; i < tiles.Count; ++i)
|
||||
{
|
||||
tiles.Data[i].EData.DotColor = puzzleVisuals.TileDotColor;
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::Text("Shader log:");
|
||||
if (ImGui::TreeNodeEx("Shader log"))
|
||||
{
|
||||
ImGui::TextWrapped("%s", Game::GetShared().Dev.ShaderLog);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void RenderTexturesUI(Game::GameRendering& rendering)
|
||||
{
|
||||
if (ImGui::Begin("Textures"))
|
||||
{
|
||||
if (ImGui::Button("Reload"))
|
||||
@@ -235,43 +393,63 @@ namespace Tools
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void RenderModelsUI(Game::GameRendering& rendering)
|
||||
{
|
||||
if (ImGui::Begin("Models"))
|
||||
{
|
||||
if (ImGui::Button("Reload"))
|
||||
{
|
||||
LoadModels(rendering.Models, rendering.ModelCount);
|
||||
}
|
||||
for (int32_t i = 0; i < rendering.ModelCount; ++i)
|
||||
{
|
||||
auto& mdl = rendering.Models[i];
|
||||
if (bgfx::isValid(mdl.HeightMapTexture))
|
||||
{
|
||||
ImGui::Text("%s", mdl.Name);
|
||||
ImGui::Image(mdl.HeightMapTexture.idx,
|
||||
ImVec2{(float)Game::HeightMap::Height, (float)Game::HeightMap::Width});
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Text("Invalid Handle!");
|
||||
}
|
||||
ImGui::Spacing();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void RenderPuzzlesUI()
|
||||
{
|
||||
auto& debug = Game::GetInstance().DebugData;
|
||||
auto& level = Game::GetInstance().GameLevel;
|
||||
|
||||
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();
|
||||
char nameBuf[64]{0};
|
||||
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
|
||||
{
|
||||
ImGui::PushID(i);
|
||||
auto& puzzleData = level.Puzzles[i].Data;
|
||||
if (puzzleData.ID == UINT16_MAX) continue;
|
||||
|
||||
bool isSelected = debug.SelectedDebugLevel == i;
|
||||
ImGui::PushID("selectable");
|
||||
if (ImGui::Selectable(puzzleData.PuzzleName, isSelected))
|
||||
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))
|
||||
@@ -279,9 +457,16 @@ namespace Tools
|
||||
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();
|
||||
@@ -292,6 +477,12 @@ namespace Tools
|
||||
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();
|
||||
@@ -308,8 +499,30 @@ namespace Tools
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
|
||||
Tools::ModelDropdown(card.ModelHandle);
|
||||
Tools::TextureDropdown(card.BoardTextureHandle);
|
||||
Tools::ModelDropdown(card.BaseModelHandle);
|
||||
Tools::TextureDropdown(card.ModelTextureHandle, "World Texture");
|
||||
Tools::TextureDropdown(card.BoardTextureHandle, "UI Texture");
|
||||
if (IsValid(card.BaseModelHandle))
|
||||
{
|
||||
auto& mdl = rendering.Models[card.BaseModelHandle.ModelIdx];
|
||||
if (mdl.SocketCount > 0 && ImGui::TreeNodeEx("Slots"))
|
||||
{
|
||||
for (int32_t sIdx = 0; sIdx < mdl.SocketCount; ++sIdx)
|
||||
{
|
||||
Tools::ModelDropdown(card.Sockets[sIdx].Model, mdl.Sockets[sIdx].Name);
|
||||
int val = card.Sockets[sIdx].ConnectionDirection;
|
||||
ImGui::PushID(sIdx);
|
||||
if (ImGui::Combo("Connection Direction", &val, "North\0East\0South\0West\0"))
|
||||
{
|
||||
card.Sockets[sIdx].ConnectionDirection = val;
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Text("Card");
|
||||
for (int8_t y = 0; y < Puzzle::Config::CardSize; ++y)
|
||||
{
|
||||
ImGui::PushID(y);
|
||||
@@ -336,6 +549,61 @@ namespace Tools
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void RenderEntitiesUI()
|
||||
{
|
||||
auto& level = Game::GetInstance().GameLevel;
|
||||
|
||||
if (ImGui::Begin("Entities"))
|
||||
{
|
||||
if (ImGui::TreeNodeEx("UIQuads"))
|
||||
{
|
||||
ImGui::Text("Count: %u", level.UIQuads.Count);
|
||||
for (uint16_t i = 0; i < level.UIQuads.Count; ++i)
|
||||
{
|
||||
ImGui::Separator();
|
||||
ImGui::PushID(i);
|
||||
ImGui::Text("%u", i);
|
||||
ImGui::SameLine();
|
||||
auto& quad = level.UIQuads.Get({i});
|
||||
ImGui::Checkbox("Visible", &quad.EData.Visible);
|
||||
TextureDropdown(quad.EData.TextureHandle);
|
||||
MaterialDropdown(quad.EData.MaterialHandle);
|
||||
ImGui::DragFloat3("Pos", &quad.EData.Transform.Position.x);
|
||||
ImGui::DragFloat3("UI Pos", &quad.UIPos.x);
|
||||
ImGui::Text("RenderID: %i", quad.EData.RenderID);
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNodeEx("Level"))
|
||||
{
|
||||
ImGui::Text("Count: %u", level.LevelEntities.Count);
|
||||
for (uint16_t i = 0; i < level.LevelEntities.Count; ++i)
|
||||
{
|
||||
ImGui::Separator();
|
||||
ImGui::PushID(i);
|
||||
ImGui::Text("%u", i);
|
||||
ImGui::SameLine();
|
||||
auto& levelEnt = level.LevelEntities.Get({i});
|
||||
ImGui::Checkbox("Visible", &levelEnt.EData.Visible);
|
||||
TextureDropdown(levelEnt.EData.TextureHandle);
|
||||
MaterialDropdown(levelEnt.EData.MaterialHandle);
|
||||
ImGui::DragFloat3("Pos", &levelEnt.EData.Transform.Position.x);
|
||||
ImGui::Text("RenderID: %i", levelEnt.EData.RenderID);
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void RenderStatsUI()
|
||||
{
|
||||
auto& time = Game::GetInstance().Time;
|
||||
auto& debug = Game::GetInstance().DebugData;
|
||||
|
||||
if (debug.ShowStats)
|
||||
{
|
||||
ImGui::SetNextWindowPos({0, 0});
|
||||
@@ -354,7 +622,7 @@ namespace Tools
|
||||
ImGui::Text("FPS: %.0f", 1.0 / time.Delta);
|
||||
|
||||
constexpr ImVec2 FpsPlotSize{200, 60};
|
||||
if (ImGui::BeginChild("FpsPlot", FpsPlotSize))
|
||||
if (ImGui::BeginChild("FpsPlot", FpsPlotSize, 0, ImGuiWindowFlags_NoInputs))
|
||||
{
|
||||
auto& drawList = *ImGui::GetWindowDrawList();
|
||||
ImVec2 pos = ImGui::GetWindowPos();
|
||||
@@ -384,6 +652,105 @@ namespace Tools
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderDebugUI(Game::GameRendering& rendering)
|
||||
{
|
||||
if (!rendering.SetupData.UseImgui) return;
|
||||
ZoneScopedN("DebugUI");
|
||||
|
||||
auto& time = Game::GetInstance().Time;
|
||||
auto& shared = Game::GetShared();
|
||||
auto& debug = Game::GetInstance().DebugData;
|
||||
auto& level = Game::GetInstance().GameLevel;
|
||||
auto& player = Game::GetInstance().Player;
|
||||
|
||||
if (ImGui::Begin("Hilfe"))
|
||||
{
|
||||
if (ImGui::Button("Spiel Neustarten"))
|
||||
{
|
||||
player.PlayerCamTransform.Position = {0.0f, 3.0f, 0.0f};
|
||||
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
|
||||
{
|
||||
Puzzle::ResetPuzzle(level.Puzzles[i].Data);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Zurück zum Anfang"))
|
||||
{
|
||||
player.PlayerCamTransform.Position = {0.0f, 3.0f, 0.0f};
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Anleitung:");
|
||||
ImGui::Text("Bewege dich mit");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored({1.0f, 0.6f, 0.6f, 1.0f}, "W, A, S, D");
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("und schau dich um mit der");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored({1.0f, 0.6f, 0.6f, 1.0f}, "Maus.");
|
||||
ImGui::Text("Drücke");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored({1.0f, 0.6f, 0.6f, 1.0f}, "Leertaste");
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("um den Spielplan zu öffnen.");
|
||||
ImGui::Text("Auf dem Spielplan kannst du Karten verschieben.");
|
||||
ImGui::Text("Mit");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored({1.0f, 0.6f, 0.6f, 1.0f}, "Rechter Maustaste");
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("kannst du Karten drehen.");
|
||||
ImGui::Text("");
|
||||
ImGui::Text("Dein Ziel: Verbinde die Pumpe mit dem Abfluss, um das");
|
||||
ImGui::Text("Tor zum nächsten Level zu öffnen!");
|
||||
ImGui::Text("");
|
||||
auto& inflowTexture = rendering.Textures[10];
|
||||
auto& outflowTexture = rendering.Textures[9];
|
||||
auto& connectionTexture = rendering.Textures[8];
|
||||
ImGui::Text("Pumpe (Wasserquelle):");
|
||||
ImGui::Image(inflowTexture.RenderHandle.idx, {64.0f, 64.0f});
|
||||
ImGui::Text("Abfluss (Ziel):");
|
||||
ImGui::Image(outflowTexture.RenderHandle.idx, {64.0f, 64.0f});
|
||||
ImGui::Text("Verbindung:");
|
||||
ImGui::Image(connectionTexture.RenderHandle.idx, {64.0f, 64.0f});
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
if (rendering.UIVisible == Game::UIVisibilityState::Debug)
|
||||
{
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right))
|
||||
{
|
||||
debug.DebugCardRotation++;
|
||||
if (debug.DebugCardRotation >= 4) debug.DebugCardRotation = 0;
|
||||
}
|
||||
|
||||
if (ImGui::Begin("Debug"))
|
||||
{
|
||||
ImGui::Checkbox("ImGui Demo", &debug.ShowImguiDemo);
|
||||
ImGui::SliderFloat("Font Scale", &ImGui::GetIO().FontGlobalScale, 0.5f, 4.0f);
|
||||
ImGui::Checkbox("Break on ID", &debug.DebugBreakIDEnabled);
|
||||
ImGui::SameLine();
|
||||
ImGui::PushID("@#$");
|
||||
ImGui::InputInt("", &debug.DebugBreakID);
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Arenas");
|
||||
ProgressBar("Permanent", shared.Game.PermanentArena.Used, shared.Game.PermanentArena.MaxSize);
|
||||
ProgressBar("Entity", shared.Game.EntityArena.Used, shared.Game.EntityArena.MaxSize);
|
||||
ProgressBar("Transient", shared.Game.TransientArena.Used, shared.Game.TransientArena.MaxSize);
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
RenderLogUI();
|
||||
RenderRenderSettingsUI(rendering);
|
||||
RenderTexturesUI(rendering);
|
||||
RenderModelsUI(rendering);
|
||||
RenderPuzzlesUI();
|
||||
RenderCardsUI(rendering);
|
||||
RenderEntitiesUI();
|
||||
}
|
||||
RenderStatsUI();
|
||||
}
|
||||
void MeasureFrameEnd()
|
||||
{
|
||||
FrameTimes[FrameTimeIdx] = bx::getHPCounter();
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
|
||||
namespace Tools
|
||||
{
|
||||
void ModelDropdown(Gen::ModelHandle& modelHandle);
|
||||
void TextureDropdown(Gen::TextureHandle& texHandle);
|
||||
bool EntityDataSettings(Gen::SavedEntityRenderData& data);
|
||||
bool ModelDropdown(Gen::ModelHandle& modelHandle, const char* title = "Model");
|
||||
bool TextureDropdown(Gen::TextureHandle& texHandle, const char* title = "Texture");
|
||||
bool MaterialDropdown(Gen::EMaterial::Enum& material);
|
||||
bool TransformUI(Gen::Transform& transform);
|
||||
void RenderDebugUI(Game::GameRendering& rendering);
|
||||
void MeasureFrameEnd();
|
||||
} // namespace Tools
|
||||
|
||||
382
src/game/UI.cpp
Normal file
382
src/game/UI.cpp
Normal 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
44
src/game/UI.h
Normal 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.
BIN
src/game/compiled-shaders/glsl/dither/frag.bin
LFS
Normal file
BIN
src/game/compiled-shaders/glsl/dither/frag.bin
LFS
Normal file
Binary file not shown.
BIN
src/game/compiled-shaders/glsl/dither/vert.bin
LFS
Normal file
BIN
src/game/compiled-shaders/glsl/dither/vert.bin
LFS
Normal file
Binary file not shown.
BIN
src/game/compiled-shaders/glsl/normal/frag.bin
LFS
Normal file
BIN
src/game/compiled-shaders/glsl/normal/frag.bin
LFS
Normal file
Binary file not shown.
BIN
src/game/compiled-shaders/glsl/normal/vert.bin
LFS
Normal file
BIN
src/game/compiled-shaders/glsl/normal/vert.bin
LFS
Normal file
Binary file not shown.
BIN
src/game/data/puzzles/0.pzl
LFS
BIN
src/game/data/puzzles/0.pzl
LFS
Binary file not shown.
BIN
src/game/data/puzzles/1.pzl
LFS
Normal file
BIN
src/game/data/puzzles/1.pzl
LFS
Normal file
Binary file not shown.
BIN
src/game/data/puzzles/2.pzl
LFS
Normal file
BIN
src/game/data/puzzles/2.pzl
LFS
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/game/data/static/uiconfig.dat
Normal file
BIN
src/game/data/static/uiconfig.dat
Normal file
Binary file not shown.
@@ -38,6 +38,15 @@ type Mat4
|
||||
}")
|
||||
}
|
||||
|
||||
type Transform
|
||||
{
|
||||
Mat4 M
|
||||
Mat4 MI
|
||||
Vec3 Position
|
||||
Mat4 Rotation
|
||||
Vec3 Scale Default("{1.0f, 1.0f, 1.0f}")
|
||||
}
|
||||
|
||||
type AssetHandle
|
||||
{
|
||||
u32 Idx Default("UINT32_MAX")
|
||||
@@ -73,10 +82,22 @@ enum PuzzleElementType(u8)
|
||||
Bridge GameName("Bridge") ShortName("#")
|
||||
}
|
||||
|
||||
type CardSocket
|
||||
{
|
||||
ModelHandle Model
|
||||
u8 ConnectionDirection
|
||||
}
|
||||
|
||||
type StaticPuzzleCard
|
||||
{
|
||||
PuzzleElementType Elements Arr(4)
|
||||
ModelHandle ModelHandle
|
||||
ModelHandle BaseModelHandle
|
||||
ModelHandle NorthCoverHandle
|
||||
ModelHandle EastCoverHandle
|
||||
ModelHandle SouthCoverHandle
|
||||
ModelHandle WestCoverHandle
|
||||
CardSocket Sockets Arr(16)
|
||||
TextureHandle ModelTextureHandle
|
||||
TextureHandle BoardTextureHandle
|
||||
}
|
||||
|
||||
@@ -89,6 +110,7 @@ type PuzzleVisualSettings
|
||||
{
|
||||
Vec4 TileBaseColor
|
||||
Vec4 TileDotColor
|
||||
Vec3 Test
|
||||
Vec4 DisabledCardTint
|
||||
}
|
||||
|
||||
@@ -105,12 +127,18 @@ type PuzzleCardStack
|
||||
u8 UsedCount
|
||||
}
|
||||
|
||||
enum PlacedPuzzleCardFlags(u8) Flags
|
||||
{
|
||||
None
|
||||
Locked
|
||||
}
|
||||
|
||||
type PlacedPuzzleCard
|
||||
{
|
||||
StaticPuzzleCardHandle RefCard
|
||||
PuzPos Position
|
||||
u8 Rotation
|
||||
b IsLocked
|
||||
PlacedPuzzleCardFlags Flags
|
||||
}
|
||||
|
||||
type PuzzleData
|
||||
@@ -122,7 +150,35 @@ type PuzzleData
|
||||
u32 AvailableCardCount
|
||||
PuzzleCardStack AvailableCards Arr(16)
|
||||
PlacedPuzzleCard PlacedCards Arr(256)
|
||||
PlacedPuzzleCard InitialPlacedCards Arr(256)
|
||||
PuzzleElementType BackgroundTiles Arr(1024)
|
||||
u32 GoalPositionCount
|
||||
PuzPos GoalPositions Arr(16)
|
||||
}
|
||||
|
||||
enum EMaterial
|
||||
{
|
||||
Default
|
||||
UI
|
||||
}
|
||||
|
||||
type SavedEntityRenderData
|
||||
{
|
||||
Vec4 BaseColor
|
||||
Vec4 HighlightColor
|
||||
Transform TF
|
||||
EMaterial Material
|
||||
TextureHandle Texture
|
||||
ModelHandle Model
|
||||
b Visible
|
||||
}
|
||||
|
||||
type SavedPlayerConfig
|
||||
{
|
||||
SavedEntityRenderData TabletBackgroundRenderData
|
||||
SavedEntityRenderData TabletStatusRenderData
|
||||
TextureHandle TabletStatusNotSolvedTexture
|
||||
TextureHandle TabletStatusSolvedTexture
|
||||
SavedEntityRenderData TabletResetRenderData
|
||||
SavedEntityRenderData BackgroundLevelRenderData Arr(16)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "../Log.h"
|
||||
#include "Dither.h"
|
||||
|
||||
#include "bx/math.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
void DitherGen(DitherData& data, int32_t recursion)
|
||||
@@ -14,11 +16,12 @@ void DitherGen(DitherData& data, int32_t recursion)
|
||||
for (int32_t i = 0; i < data.BrightnessBucketCount; ++i)
|
||||
data.BrightnessBuckets[i] = 0;
|
||||
|
||||
for (int32_t recursionLevel = 0; recursionLevel < recursion; ++recursionLevel)
|
||||
// add "subdivided" beyer matrix layers
|
||||
for (int32_t recursionLevel = 0; recursionLevel < recursion - 1; ++recursionLevel)
|
||||
{
|
||||
int32_t startCount = data.PointCount;
|
||||
float offset = bx::pow(0.5f, recursionLevel + 1);
|
||||
for (int32_t i = 0; i < 4; ++i)
|
||||
for (int32_t i = 1; i < 4; ++i)
|
||||
{
|
||||
for (int32_t j = 0; j < startCount; ++j)
|
||||
{
|
||||
@@ -28,6 +31,7 @@ void DitherGen(DitherData& data, int32_t recursion)
|
||||
}
|
||||
}
|
||||
|
||||
// Texture info setup
|
||||
uint64_t dotsPerSide = bx::round(bx::pow(2, recursion));
|
||||
data.DitherTexDepth = dotsPerSide * dotsPerSide;
|
||||
data.DitherTexWH = 16 * dotsPerSide;
|
||||
@@ -39,6 +43,7 @@ void DitherGen(DitherData& data, int32_t recursion)
|
||||
return;
|
||||
}
|
||||
|
||||
// What does this do?
|
||||
float invRes = 1.0f / data.DitherTexWH;
|
||||
for (int32_t z = 0; z < data.DitherTexDepth; ++z)
|
||||
{
|
||||
@@ -46,7 +51,7 @@ void DitherGen(DitherData& data, int32_t recursion)
|
||||
float dotArea = 0.5f / dotCount;
|
||||
float dotRadius = bx::sqrt(dotArea / bx::kPi);
|
||||
|
||||
int zOffset = z * data.DitherTexWH * data.DitherTexWH;
|
||||
int32_t zOffset = z * data.DitherTexWH * data.DitherTexWH;
|
||||
for (int32_t y = 0; y < data.DitherTexWH; ++y)
|
||||
{
|
||||
int32_t yOffset = y * data.DitherTexWH;
|
||||
@@ -57,7 +62,9 @@ void DitherGen(DitherData& data, int32_t recursion)
|
||||
for (int32_t i = 0; i < dotCount; ++i)
|
||||
{
|
||||
Vec2 vec = point - data.Points[i];
|
||||
Vec2 wrappedVec{bx::mod(vec.x + 0.5f, 1.0f) - 0.5f, bx::mod(vec.y + 0.5f, 1.0f) - 0.5f};
|
||||
float wrapX = bx::wrap(vec.x + 0.5f, 1.0f) - 0.5f;
|
||||
float wrapY = bx::wrap(vec.y + 0.5f, 1.0f) - 0.5f;
|
||||
Vec2 wrappedVec = {wrapX, wrapY};
|
||||
float curDist = Magnitude(wrappedVec);
|
||||
dist = bx::min(dist, curDist);
|
||||
}
|
||||
@@ -65,7 +72,6 @@ void DitherGen(DitherData& data, int32_t recursion)
|
||||
dist = dist / (dotRadius * 2.4f);
|
||||
float val = bx::clamp(1.0f - dist, 0.0f, 1.0f);
|
||||
data.DitherTex[x + yOffset + zOffset] = Vec4{val, val, val, 1.0f};
|
||||
// data.DitherTex[x + yOffset + zOffset] = Vec4{1.0, 0.0f, 0.0f, 1.0f};
|
||||
int32_t bucket = bx::clamp(
|
||||
uint32_t(val * DitherData::BrightnessBucketCount), 0, DitherData::BrightnessBucketCount - 1);
|
||||
data.BrightnessBuckets[bucket] += 1;
|
||||
@@ -82,21 +88,7 @@ void DitherGen(DitherData& data, int32_t recursion)
|
||||
}
|
||||
|
||||
// Upload textures
|
||||
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;
|
||||
}
|
||||
CleanupDitherData(data);
|
||||
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* memRamp = bgfx::makeRef(data.BrightnessRamp, sizeof(data.BrightnessRamp));
|
||||
@@ -121,3 +113,22 @@ void DitherGen(DitherData& data, int32_t recursion)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +24,4 @@ struct DitherData
|
||||
};
|
||||
|
||||
void DitherGen(DitherData& data, int32_t recursion);
|
||||
void CleanupDitherData(DitherData& data);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "../Tools.h"
|
||||
#include "Rendering.h"
|
||||
|
||||
#include "Dither.h"
|
||||
#include "SDL3/SDL_events.h" // IWYU pragma: keep
|
||||
#include "backends/imgui_impl_sdl3.h"
|
||||
#include "bgfx/defines.h"
|
||||
@@ -32,15 +33,105 @@ namespace Game
|
||||
{
|
||||
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)
|
||||
{
|
||||
FILE* file;
|
||||
for (int32_t i = 0; i < retryCount; ++i)
|
||||
{
|
||||
file = fopen(path, "rb");
|
||||
file = std::fopen(path, "rb");
|
||||
if (file == nullptr && i < retryCount - 1)
|
||||
{
|
||||
std::this_thread::sleep_for(100ms);
|
||||
LOG_WARN("Failed to open file, retrying...");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -48,11 +139,12 @@ namespace Game
|
||||
long fileSize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
long fileSizeX = appendZero ? fileSize + 1 : fileSize;
|
||||
long fileSizeX = appendZero ? (fileSize + 1) : fileSize;
|
||||
void* rawMem = AllocateScratch(fileSizeX);
|
||||
if (rawMem == nullptr)
|
||||
{
|
||||
LOG_ERROR("Failed to load file, exceeded scratch memory! %s", path);
|
||||
return nullptr;
|
||||
}
|
||||
const bgfx::Memory* mem = bgfx::makeRef(rawMem, fileSizeX);
|
||||
fread(mem->data, 1, fileSize, file);
|
||||
@@ -127,7 +219,7 @@ namespace Game
|
||||
bgfx::TextureHandle handle = BGFX_INVALID_HANDLE;
|
||||
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)
|
||||
{
|
||||
LOG_WARN("Failed to find image %s", _filePath.getCPtr());
|
||||
@@ -144,8 +236,18 @@ namespace Game
|
||||
*_orientation = imageContainer.m_orientation;
|
||||
}
|
||||
|
||||
const bgfx::Memory* mem =
|
||||
bgfx::makeRef(data->data + imageContainer.m_offset, data->size - imageContainer.m_offset);
|
||||
// We're working with ktx textures, so the size should be in front of the actual data
|
||||
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)
|
||||
{
|
||||
@@ -211,19 +313,24 @@ namespace Game
|
||||
return *Instance;
|
||||
}
|
||||
|
||||
void GameRendering::Setup()
|
||||
void GameRendering::Setup(const RenderingSetup& setup)
|
||||
{
|
||||
LOG("--- RENDERING STARTUP ---");
|
||||
ZoneScopedN("Setup");
|
||||
|
||||
SetupData = setup;
|
||||
|
||||
if (Instance != nullptr) LOG_WARN("old rendering wasn't destroyed!");
|
||||
Instance = this;
|
||||
SharedData& shared = GetShared();
|
||||
|
||||
bgfx::Init init;
|
||||
init.type = bgfx::RendererType::Direct3D12;
|
||||
init.type = bgfx::RendererType::Direct3D11;
|
||||
#ifdef _DEBUG
|
||||
// init.debug = true;
|
||||
init.debug = true;
|
||||
// init.debug = false;
|
||||
#else
|
||||
init.debug = false;
|
||||
#endif
|
||||
init.platformData.nwh = shared.Window.Handle;
|
||||
init.platformData.ndt = nullptr;
|
||||
@@ -253,9 +360,11 @@ namespace Game
|
||||
LoadModels(Models, ModelCount);
|
||||
|
||||
ReloadShaders();
|
||||
|
||||
if (SetupData.UseImgui)
|
||||
{
|
||||
imguiCreate();
|
||||
SetImguiStyle();
|
||||
|
||||
if (!ImGui_ImplSDL3_InitForOther(shared.Window.SDLWindow))
|
||||
{
|
||||
LOG_ERROR("Failed to set up imgui implementation!");
|
||||
@@ -270,6 +379,7 @@ namespace Game
|
||||
// platIO.Platform_DestroyWindow = TODO;
|
||||
// platIO.Platform_SetWindowSize = TODO;
|
||||
// platIO.Platform_RenderWindow = TODO;
|
||||
}
|
||||
|
||||
GameInstance& inst = GetInstance();
|
||||
if (!inst.IsInitialized)
|
||||
@@ -277,6 +387,8 @@ namespace Game
|
||||
inst.Time.StartTime = bx::getHPCounter();
|
||||
}
|
||||
|
||||
if (SetupData.UseImgui)
|
||||
{
|
||||
if (inst.DebugData.ImguiIniSize > 0)
|
||||
{
|
||||
ImGui::LoadIniSettingsFromMemory(inst.DebugData.ImguiIni, inst.DebugData.ImguiIniSize);
|
||||
@@ -285,6 +397,7 @@ namespace Game
|
||||
{
|
||||
ImGui::LoadIniSettingsFromDisk("imgui.ini");
|
||||
}
|
||||
}
|
||||
DitherGen(DitherTextures, DitherRecursion);
|
||||
}
|
||||
|
||||
@@ -294,9 +407,12 @@ namespace Game
|
||||
SharedData& shared = GetShared();
|
||||
|
||||
for (uint16_t i = 0; i < shared.Window.SDLEventCount; ++i)
|
||||
{
|
||||
if (SetupData.UseImgui)
|
||||
{
|
||||
ImGui_ImplSDL3_ProcessEvent(&shared.Window.SDLEvents[i]);
|
||||
}
|
||||
}
|
||||
shared.Window.SDLEventCount = 0;
|
||||
|
||||
// Resize if necessary
|
||||
@@ -391,8 +507,8 @@ namespace Game
|
||||
|
||||
void GameRendering::ReloadShaders()
|
||||
{
|
||||
Materials[(uint16_t)EMaterial::Default] = Material::LoadFromShader("dither/vert", "dither/frag", MainViewID);
|
||||
Materials[(uint16_t)EMaterial::UI] = Material::LoadFromShader("normal/vert", "normal/frag", MainViewID);
|
||||
Materials[Gen::EMaterial::Default] = Material::LoadFromShader("dither/vert", "dither/frag", MainViewID);
|
||||
Materials[Gen::EMaterial::UI] = Material::LoadFromShader("normal/vert", "normal/frag", MainViewID);
|
||||
}
|
||||
|
||||
void GameRendering::Update()
|
||||
@@ -404,6 +520,7 @@ namespace Game
|
||||
HandleEvents();
|
||||
|
||||
// Start Rendering
|
||||
if (SetupData.UseImgui)
|
||||
{
|
||||
ZoneScopedN("Imgui Start Frame");
|
||||
imguiBeginFrame(20);
|
||||
@@ -417,12 +534,13 @@ namespace Game
|
||||
GetInstance().GameLevel.Render(MainViewID, Models, Materials, Textures);
|
||||
|
||||
// Finish Frame
|
||||
if (SetupData.UseImgui)
|
||||
{
|
||||
ZoneScopedN("Imgui End Frame");
|
||||
imguiEndFrame();
|
||||
}
|
||||
|
||||
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
if (SetupData.UseImgui && ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
ZoneScopedN("Imgui Platform Update");
|
||||
ImGui::UpdatePlatformWindows();
|
||||
@@ -441,6 +559,25 @@ namespace Game
|
||||
{
|
||||
ZoneScopedN("Shutdown");
|
||||
LOG("--- RENDERING_SHUTDOWN ---");
|
||||
|
||||
for (int32_t i = 0; i < BX_COUNTOF(Textures); ++i)
|
||||
{
|
||||
if (isValid(Textures[i].RenderHandle))
|
||||
{
|
||||
bgfx::destroy(Textures[i].RenderHandle);
|
||||
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));
|
||||
@@ -448,6 +585,8 @@ namespace Game
|
||||
bx::memCopy(debug.ImguiIni, iniData, bx::min(debug.ImguiIniSize, BX_COUNTOF(InstanceDebugData::ImguiIni)));
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
imguiDestroy();
|
||||
}
|
||||
|
||||
bgfx::shutdown();
|
||||
Instance = nullptr;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,36 @@ namespace Game
|
||||
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
|
||||
{
|
||||
static constexpr uint16_t MaxSocketCount = 16;
|
||||
bgfx::VertexBufferHandle VertexBuffer = {bgfx::kInvalidHandle};
|
||||
bgfx::IndexBufferHandle IndexBuffer = {bgfx::kInvalidHandle};
|
||||
bgfx::VertexLayout VertLayout;
|
||||
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
|
||||
@@ -64,11 +88,9 @@ namespace Game
|
||||
Debug,
|
||||
};
|
||||
|
||||
enum class EMaterial : uint16_t
|
||||
struct RenderingSetup
|
||||
{
|
||||
Default = 0,
|
||||
UI = 1,
|
||||
UNDEFINED = UINT16_MAX
|
||||
bool UseImgui = true;
|
||||
};
|
||||
|
||||
class GameRendering
|
||||
@@ -83,6 +105,7 @@ namespace Game
|
||||
DitherData DitherTextures;
|
||||
|
||||
public:
|
||||
RenderingSetup SetupData;
|
||||
bgfx::UniformHandle DefaultSampler;
|
||||
Texture Textures[MaxTextures];
|
||||
Material Materials[8];
|
||||
@@ -96,7 +119,7 @@ namespace Game
|
||||
int32_t DitherRecursion = 1;
|
||||
|
||||
public:
|
||||
void Setup();
|
||||
void Setup(const RenderingSetup& setup);
|
||||
void Update();
|
||||
void HandleEvents();
|
||||
void LoadTextures();
|
||||
|
||||
@@ -32,7 +32,7 @@ vec3 desaturate(vec3 color)
|
||||
|
||||
float dither(float brightness, vec2 inputUv)
|
||||
{
|
||||
float globalScale = 8;
|
||||
float globalScale = 6;
|
||||
|
||||
// constants
|
||||
float xRes = u_texInfo.z;
|
||||
@@ -42,31 +42,30 @@ float dither(float brightness, vec2 inputUv)
|
||||
float zRes = dotsTotal;
|
||||
float invZRes = 1 / zRes;
|
||||
|
||||
float2 rampLookupUv = vec2((0.5 * invXRes + (1 - invXRes) * brightness), 0.5);
|
||||
vec2 rampLookupUv = vec2((0.5 * invXRes + (1 - invXRes) * brightness), 0.5);
|
||||
float brightnessCurve = texture2D(s_rampSampler, rampLookupUv).r;
|
||||
|
||||
// Magic dot frequency calculation
|
||||
float2 dx = ddx(inputUv);
|
||||
float2 dy = ddy(inputUv);
|
||||
float2x2 mat = float2x2(dx, dy);
|
||||
float4 vectorized = float4(dx, dy);
|
||||
vec2 dx = dFdx(inputUv);
|
||||
vec2 dy = dFdy(inputUv);
|
||||
mat2 mat = mat2(dx, dy);
|
||||
vec4 vectorized = vec4(dx, dy);
|
||||
float qq = dot(vectorized, vectorized);
|
||||
float rr = determinant(mat);
|
||||
float discriminantSqr = max(0.0, qq*qq - 4.0*rr*rr);
|
||||
float discriminant = sqrt(discriminantSqr);
|
||||
float2 freq = sqrt(float2(qq + discriminant, qq - discriminant) / 2.0);
|
||||
vec2 freq = sqrt(vec2(qq + discriminant, qq - discriminant) / 2.0);
|
||||
|
||||
// Figuring out how many dots we want
|
||||
float scaleExp = exp2(globalScale);
|
||||
float spacing = freq.y * scaleExp;
|
||||
spacing *= dotsPerSide * 0.125;
|
||||
spacing *= dotsPerSide * (1 / globalScale); // todo: just guessed that globalScale is the right variable here
|
||||
|
||||
float brightnessSpacingMultiplier = pow(brightnessCurve * 2 + 0.001, -(1 - 0.5));
|
||||
// float brightnessSpacingMultiplier = 1;
|
||||
spacing *= brightnessSpacingMultiplier;
|
||||
|
||||
float spacingLog = log2(spacing);
|
||||
int patternScaleLevel = floor(spacingLog);
|
||||
int patternScaleLevel = int(floor(spacingLog));
|
||||
float patternFractional = spacingLog - patternScaleLevel;
|
||||
vec2 uv = inputUv / exp2(patternScaleLevel);
|
||||
|
||||
@@ -77,35 +76,72 @@ float dither(float brightness, vec2 inputUv)
|
||||
|
||||
float pattern = texture3D(s_ditherSampler, vec3(uv, subLayer)).r;
|
||||
|
||||
float contrast = 2 * scaleExp * brightnessSpacingMultiplier * 0.1;
|
||||
float contrast = 0.5 * scaleExp * brightnessSpacingMultiplier * 0.1;
|
||||
contrast *= pow(freq.y / freq.x, 1.0);
|
||||
float baseVal = lerp(0.5, brightness, saturate(1.05 / (1 + contrast)));
|
||||
float threshold = 1 - brightnessCurve + 0.6;
|
||||
float threshold = 1 - brightnessCurve;
|
||||
|
||||
return saturate((pattern - threshold) * contrast + baseVal);
|
||||
}
|
||||
|
||||
vec4 rgbToCmyk(vec3 rgb)
|
||||
{
|
||||
float k = min(1.0 - rgb.r, min(1.0 - rgb.g, 1.0 - rgb.b));
|
||||
vec3 cmy = vec3(0.0, 0.0, 0.0);
|
||||
float invK = 1.0 - k;
|
||||
if (invK != 0.0)
|
||||
{
|
||||
cmy.x = 1.0 - rgb.r - k;
|
||||
cmy.y = 1.0 - rgb.g - k;
|
||||
cmy.z = 1.0 - rgb.b - k;
|
||||
cmy /= invK;
|
||||
}
|
||||
return saturate(vec4(cmy, k));
|
||||
}
|
||||
|
||||
vec3 cmykToRgb(vec4 cmyk)
|
||||
{
|
||||
float invK = 1.0 - cmyk.w;
|
||||
float r = 1.0 - min(1.0, cmyk.x * invK + cmyk.w);
|
||||
float g = 1.0 - min(1.0, cmyk.y * invK + cmyk.w);
|
||||
float b = 1.0 - min(1.0, cmyk.z * invK + cmyk.w);
|
||||
return saturate(vec3(r,g,b));
|
||||
}
|
||||
|
||||
vec2 rotateUV(vec2 uv, vec2 angle)
|
||||
{
|
||||
return uv;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// setup
|
||||
bool isTextured = u_dotColor.x < 0.02;
|
||||
float testRadius = 30.0;
|
||||
float testSpeed = 1.0;
|
||||
vec3 testOffset = vec3(0.0, 0.0, 50.0);
|
||||
float3 lightPos = vec3(sin(u_time.x * testSpeed) * testRadius, 5.0, cos(u_time.x * testSpeed) * testRadius);
|
||||
vec3 texColor = u_dotColor.x > 0.1 ? u_dotColor.xyz : texture2D(s_texColor, v_uv0).xyz;
|
||||
vec3 lightPos = vec3(sin(u_time.x * testSpeed) * testRadius, 5.0, cos(u_time.x * testSpeed) * testRadius);
|
||||
vec3 baseColor = u_baseColor.xyz;
|
||||
vec3 texColor = isTextured ? texture2D(s_texColor, v_uv0).xyz : u_dotColor.xyz;
|
||||
|
||||
// lighting
|
||||
// float brightness = calcBrightness(lightPos, v_wpos, v_normal);
|
||||
float brightness = lerp(0.5, 0.9, calcBrightnessDirectional(vec3(0.5, 0.3, 1.0), v_normal));
|
||||
// float brightness = 0.5;
|
||||
// brightness = lerp(0.2, 1.0, sin(u_time.x) * 0.5 + 0.5);
|
||||
float brightness = lerp(0.2, 0.8, calcBrightnessDirectional(vec3(0.5, 0.3, 1.0), v_normal));
|
||||
|
||||
float r = dither(brightness * texColor.r, v_uv0);
|
||||
float g = dither(brightness * texColor.g, v_uv0);
|
||||
float b = dither(brightness * texColor.b, v_uv0);
|
||||
// float3 finalColor = vec3(r, g, b);
|
||||
float3 ditheredColor = dither(brightness, v_uv0);
|
||||
float3 finalColor = mix(u_baseColor, texColor, ditheredColor);
|
||||
gl_FragColor = vec4(finalColor, 1.0);
|
||||
// dither
|
||||
float r = dither(texColor.r * brightness, v_uv0);
|
||||
float g = dither(texColor.g * brightness, v_uv0);
|
||||
float b = dither(texColor.b * brightness, v_uv0);
|
||||
// vec3 ditheredColor = vec3(r,g,b);
|
||||
|
||||
vec4 cmyk = rgbToCmyk(texColor * brightness);
|
||||
cmyk.x = dither(cmyk.x, rotateUV(v_uv0, float2(0.966, 0.259)));
|
||||
cmyk.y = dither(cmyk.y, rotateUV(v_uv0, float2(0.259, 0.966)));
|
||||
cmyk.z = dither(cmyk.z, rotateUV(v_uv0, float2(1.000, 0.000)));
|
||||
cmyk.w = dither(cmyk.w, rotateUV(v_uv0, float2(0.707, 0.707)));
|
||||
vec3 ditheredColor = cmykToRgb(cmyk);
|
||||
|
||||
// finalize
|
||||
vec3 finalColor = mix(baseColor, ditheredColor, ditheredColor);
|
||||
gl_FragColor = vec4(finalColor.rg, finalColor.b * 0.99, 1.0);
|
||||
// gl_FragColor = vec4(ditheredColor, 1.0);
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ void main()
|
||||
v_color0 = a_color0;
|
||||
v_uv0 = a_texcoord0;
|
||||
v_wpos = mul(u_model[0], vec4(a_position, 1.0)).xyz;
|
||||
v_normal = normalize(mul(u_model[0], a_normal));
|
||||
v_normal = normalize(mul(u_model[0], vec4(a_normal, 1.0)).xyz);
|
||||
}
|
||||
|
||||
@@ -42,19 +42,19 @@ float dither(float brightness, vec2 inputUv)
|
||||
float zRes = dotsTotal;
|
||||
float invZRes = 1 / zRes;
|
||||
|
||||
float2 rampLookupUv = vec2((0.5 * invXRes + (1 - invXRes) * brightness), 0.5);
|
||||
vec2 rampLookupUv = vec2((0.5 * invXRes + (1 - invXRes) * brightness), 0.5);
|
||||
float brightnessCurve = texture2D(s_rampSampler, rampLookupUv).r;
|
||||
|
||||
// Magic dot frequency calculation
|
||||
float2 dx = ddx(inputUv);
|
||||
float2 dy = ddy(inputUv);
|
||||
float2x2 mat = float2x2(dx, dy);
|
||||
float4 vectorized = float4(dx, dy);
|
||||
vec2 dx = dFdx(inputUv);
|
||||
vec2 dy = dFdy(inputUv);
|
||||
mat2 mat = mat2(dx, dy);
|
||||
vec4 vectorized = vec4(dx, dy);
|
||||
float qq = dot(vectorized, vectorized);
|
||||
float rr = determinant(mat);
|
||||
float discriminantSqr = max(0.0, qq*qq - 4.0*rr*rr);
|
||||
float discriminant = sqrt(discriminantSqr);
|
||||
float2 freq = sqrt(float2(qq + discriminant, qq - discriminant) / 2.0);
|
||||
vec2 freq = sqrt(vec2(qq + discriminant, qq - discriminant) / 2.0);
|
||||
|
||||
// Figuring out how many dots we want
|
||||
float scaleExp = exp2(globalScale);
|
||||
@@ -66,7 +66,7 @@ float dither(float brightness, vec2 inputUv)
|
||||
spacing *= brightnessSpacingMultiplier;
|
||||
|
||||
float spacingLog = log2(spacing);
|
||||
int patternScaleLevel = floor(spacingLog);
|
||||
int patternScaleLevel = int(floor(spacingLog));
|
||||
float patternFractional = spacingLog - patternScaleLevel;
|
||||
vec2 uv = inputUv / exp2(patternScaleLevel);
|
||||
|
||||
@@ -89,7 +89,9 @@ void main()
|
||||
{
|
||||
vec2 uv = vec2(1.0 - v_uv0.x, v_uv0.y);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ void main()
|
||||
v_color0 = a_color0;
|
||||
v_uv0 = a_texcoord0;
|
||||
v_wpos = mul(u_model[0], vec4(a_position, 1.0)).xyz;
|
||||
v_normal = normalize(mul(u_model[0], a_normal));
|
||||
v_normal = normalize(mul(u_model[0], vec4(a_normal, 0.0)).xyz);
|
||||
}
|
||||
|
||||
91
src/game/util/HashMap.h
Normal file
91
src/game/util/HashMap.h
Normal 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
|
||||
@@ -1,41 +1 @@
|
||||
#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
|
||||
// #include "Def.h"
|
||||
|
||||
190
src/gen/Def.h
190
src/gen/Def.h
@@ -1,12 +1,83 @@
|
||||
#pragma once
|
||||
#include "../game/Log.h"
|
||||
|
||||
#include "Generated.h"
|
||||
#include "bx/string.h"
|
||||
#include <bx/file.h>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
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
|
||||
{
|
||||
bx::Error Err;
|
||||
@@ -41,19 +112,43 @@ namespace Gen
|
||||
|
||||
template <typename T> bool WriteT(const T& data)
|
||||
{
|
||||
uint32_t hash = data.Hash;
|
||||
if (!Write(&hash, sizeof(hash))) return false;
|
||||
const Meta::TypeDef& baseDef = Meta::Metadata.TypeDefinitions[data.TypeIdx];
|
||||
|
||||
uint32_t defSize = 0;
|
||||
if (!Write(&defSize, sizeof(defSize))) return false;
|
||||
EmbeddedTypeTableBuffer typeBuf;
|
||||
typeBuf.AddDef(baseDef);
|
||||
|
||||
// auto& definitions = GetDefinitions();
|
||||
// if (!Write(&definitions, sizeof(definitions))) return false;
|
||||
// DefCount updates dynamically here!
|
||||
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);
|
||||
if (!Write(&size, sizeof(size))) return false;
|
||||
EmbeddedTypeInfoHeader header;
|
||||
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)
|
||||
@@ -80,6 +175,9 @@ namespace Gen
|
||||
bx::FilePath Path;
|
||||
bx::FileReader Reader;
|
||||
|
||||
char MemberNameBuf[64 * 64 * 64]{0};
|
||||
EmbeddedTypeTableBuffer TypeBuf;
|
||||
|
||||
bool Init(const bx::FilePath& path, const char* _4cc)
|
||||
{
|
||||
Path = path;
|
||||
@@ -117,45 +215,55 @@ namespace Gen
|
||||
|
||||
template <typename T> bool ReadT(T& data)
|
||||
{
|
||||
uint32_t hash = 0;
|
||||
if (!Read(&hash, sizeof(hash))) return false;
|
||||
|
||||
uint32_t defSize = 0;
|
||||
if (!Read(&defSize, sizeof(defSize))) return false;
|
||||
|
||||
if (data.Hash != hash)
|
||||
uint16_t metadataVersion = 0;
|
||||
if (!Read(&metadataVersion, sizeof(Meta::CurrentMetaVersion))) return false;
|
||||
if (metadataVersion != Meta::CurrentMetaVersion)
|
||||
{
|
||||
LOG_WARN("Hash mismatch! %u != %u", data.Hash, hash);
|
||||
|
||||
// TODO: figure out upgrade data
|
||||
data = {};
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Hash match!");
|
||||
|
||||
// Skip definitions, we know they match
|
||||
Reader.seek(defSize);
|
||||
|
||||
uint32_t size = 0;
|
||||
if (!Read(&size, sizeof(size))) return false;
|
||||
if (sizeof(T) != size)
|
||||
{
|
||||
LOG_ERROR("Size mismatch! %u != %u", sizeof(T), size);
|
||||
// TODO: upgrade?
|
||||
LOG_ERROR("Metadata version mismatch: %u != %u", metadataVersion, Meta::CurrentMetaVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
EmbeddedTypeInfoHeader header;
|
||||
if (!Read(&header, sizeof(header))) return false;
|
||||
|
||||
if (header.HeaderVersion != EmbeddedTypeInfoHeader::CurrentHeaderVersion)
|
||||
{
|
||||
// TODO: upgrade
|
||||
LOG_ERROR("Header version mismatch: %u != %u",
|
||||
header.HeaderVersion,
|
||||
EmbeddedTypeInfoHeader::CurrentHeaderVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
const Meta::TypeDef& baseTypeDef = Meta::Metadata.TypeDefinitions[data.TypeIdx];
|
||||
if (header.BaseTypeHash != baseTypeDef.Hash)
|
||||
{
|
||||
LOG_WARN("Hash mismatch! %u != %u", header.BaseTypeHash, baseTypeDef.Hash);
|
||||
}
|
||||
|
||||
TypeBuf.DefCount = header.TypeCount;
|
||||
for (int32_t i = 0; i < TypeBuf.DefCount; ++i)
|
||||
{
|
||||
Read(&TypeBuf.Defs[i], sizeof(TypeBuf.Defs[i]));
|
||||
}
|
||||
|
||||
Read(MemberNameBuf, header.MemberDataSize);
|
||||
|
||||
if (!Load(&data, 1, *this))
|
||||
{
|
||||
LOG_ERROR("Failed to load: %s", Err.getMessage().getCPtr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Skip(uint32_t byteCount)
|
||||
{
|
||||
Reader.seek(byteCount);
|
||||
}
|
||||
|
||||
void Finish()
|
||||
{
|
||||
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 Load(T* obj, uint32_t count, Deserializer& serializer);
|
||||
} // namespace Gen
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,15 @@
|
||||
#pragma once
|
||||
#include "Def.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace Gen
|
||||
{
|
||||
struct Serializer;
|
||||
struct Deserializer;
|
||||
struct PuzzleElementType
|
||||
{
|
||||
static constexpr uint32_t Hash = 2024002654;
|
||||
static constexpr uint16_t TypeIdx = 32;
|
||||
static constexpr int32_t EntryCount = 8;
|
||||
enum Enum : int32_t
|
||||
enum Enum : uint8_t
|
||||
{
|
||||
None,
|
||||
WaterIn,
|
||||
@@ -18,7 +20,8 @@ namespace Gen
|
||||
Blocked,
|
||||
Bridge,
|
||||
};
|
||||
static constexpr char EntryNames[EntryCount][64]{
|
||||
static constexpr char EntryNames[EntryCount][64]
|
||||
{
|
||||
"None",
|
||||
"WaterIn",
|
||||
"WaterGoal",
|
||||
@@ -28,7 +31,8 @@ namespace Gen
|
||||
"Blocked",
|
||||
"Bridge",
|
||||
};
|
||||
static constexpr char GameName[EntryCount][64]{
|
||||
static constexpr char GameName[EntryCount][64]
|
||||
{
|
||||
"Empty",
|
||||
"Water Source",
|
||||
"Water Goal",
|
||||
@@ -38,7 +42,8 @@ namespace Gen
|
||||
"Blocked",
|
||||
"Bridge",
|
||||
};
|
||||
static constexpr char ShortName[EntryCount][64]{
|
||||
static constexpr char ShortName[EntryCount][64]
|
||||
{
|
||||
" ",
|
||||
"~+",
|
||||
"~!",
|
||||
@@ -49,22 +54,68 @@ 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
|
||||
{
|
||||
static constexpr uint16_t TypeIdx = 34;
|
||||
static constexpr int32_t EntryCount = 2;
|
||||
enum Enum : int32_t
|
||||
{
|
||||
Default,
|
||||
UI,
|
||||
};
|
||||
static constexpr char EntryNames[EntryCount][64]
|
||||
{
|
||||
"Default",
|
||||
"UI",
|
||||
};
|
||||
};
|
||||
struct Vec2
|
||||
{
|
||||
static constexpr uint32_t Hash = 2667033957;
|
||||
static constexpr uint16_t TypeIdx = 12;
|
||||
float x = {};
|
||||
float y = {};
|
||||
};
|
||||
struct Vec3
|
||||
{
|
||||
static constexpr uint32_t Hash = 473740858;
|
||||
static constexpr uint16_t TypeIdx = 13;
|
||||
float x = {};
|
||||
float y = {};
|
||||
float z = {};
|
||||
};
|
||||
struct Vec4
|
||||
{
|
||||
static constexpr uint32_t Hash = 2507696603;
|
||||
static constexpr uint16_t TypeIdx = 14;
|
||||
float x = {};
|
||||
float y = {};
|
||||
float z = {};
|
||||
@@ -72,80 +123,111 @@ namespace Gen
|
||||
};
|
||||
struct Mat3
|
||||
{
|
||||
static constexpr uint32_t Hash = 3364737048;
|
||||
float M[9] = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};
|
||||
static constexpr uint16_t TypeIdx = 15;
|
||||
float M[9] = {
|
||||
1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f
|
||||
};
|
||||
};
|
||||
struct Mat4
|
||||
{
|
||||
static constexpr uint32_t Hash = 1650094019;
|
||||
float M[16] = {1.0f, 0.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, 0.0f, 1.0f};
|
||||
static constexpr uint16_t TypeIdx = 16;
|
||||
float M[16] = {
|
||||
1.0f, 0.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, 0.0f, 1.0f
|
||||
};
|
||||
};
|
||||
struct Transform
|
||||
{
|
||||
static constexpr uint16_t TypeIdx = 17;
|
||||
Mat4 M = {};
|
||||
Mat4 MI = {};
|
||||
Vec3 Position = {};
|
||||
Mat4 Rotation = {};
|
||||
Vec3 Scale = {1.0f, 1.0f, 1.0f};
|
||||
};
|
||||
struct AssetHandle
|
||||
{
|
||||
static constexpr uint32_t Hash = 2609735487;
|
||||
static constexpr uint16_t TypeIdx = 18;
|
||||
uint32_t Idx = UINT32_MAX;
|
||||
};
|
||||
struct ModelHandle
|
||||
{
|
||||
static constexpr uint32_t Hash = 298089627;
|
||||
static constexpr uint16_t TypeIdx = 19;
|
||||
uint16_t ModelIdx = UINT16_MAX;
|
||||
AssetHandle Asset = {};
|
||||
};
|
||||
struct TextureHandle
|
||||
{
|
||||
static constexpr uint32_t Hash = 1633273761;
|
||||
static constexpr uint16_t TypeIdx = 20;
|
||||
uint16_t TextureIdx = UINT16_MAX;
|
||||
AssetHandle Asset = {};
|
||||
};
|
||||
struct PuzPos
|
||||
{
|
||||
static constexpr uint32_t Hash = 1834398141;
|
||||
static constexpr uint16_t TypeIdx = 21;
|
||||
int8_t X = {};
|
||||
int8_t Y = {};
|
||||
};
|
||||
struct CardSocket
|
||||
{
|
||||
static constexpr uint16_t TypeIdx = 22;
|
||||
ModelHandle Model = {};
|
||||
uint8_t ConnectionDirection = {};
|
||||
};
|
||||
struct StaticPuzzleCard
|
||||
{
|
||||
static constexpr uint32_t Hash = 431895198;
|
||||
static constexpr uint16_t TypeIdx = 23;
|
||||
PuzzleElementType::Enum Elements[4] = {};
|
||||
ModelHandle ModelHandle = {};
|
||||
ModelHandle BaseModelHandle = {};
|
||||
ModelHandle NorthCoverHandle = {};
|
||||
ModelHandle EastCoverHandle = {};
|
||||
ModelHandle SouthCoverHandle = {};
|
||||
ModelHandle WestCoverHandle = {};
|
||||
CardSocket Sockets[16] = {};
|
||||
TextureHandle ModelTextureHandle = {};
|
||||
TextureHandle BoardTextureHandle = {};
|
||||
};
|
||||
struct StaticPuzzleCardHandle
|
||||
{
|
||||
static constexpr uint32_t Hash = 1742502768;
|
||||
static constexpr uint16_t TypeIdx = 24;
|
||||
uint16_t Idx = UINT16_MAX;
|
||||
};
|
||||
struct PuzzleVisualSettings
|
||||
{
|
||||
static constexpr uint32_t Hash = 4208425878;
|
||||
static constexpr uint16_t TypeIdx = 25;
|
||||
Vec4 TileBaseColor = {};
|
||||
Vec4 TileDotColor = {};
|
||||
Vec3 Test = {};
|
||||
Vec4 DisabledCardTint = {};
|
||||
};
|
||||
struct StaticPuzzleData
|
||||
{
|
||||
static constexpr uint32_t Hash = 1076634601;
|
||||
static constexpr uint16_t TypeIdx = 26;
|
||||
StaticPuzzleCard Cards[64] = {};
|
||||
PuzzleVisualSettings Visuals = {};
|
||||
};
|
||||
struct PuzzleCardStack
|
||||
{
|
||||
static constexpr uint32_t Hash = 53538532;
|
||||
static constexpr uint16_t TypeIdx = 27;
|
||||
StaticPuzzleCardHandle RefCard = {};
|
||||
uint8_t MaxAvailableCount = {};
|
||||
uint8_t UsedCount = {};
|
||||
};
|
||||
struct PlacedPuzzleCard
|
||||
{
|
||||
static constexpr uint32_t Hash = 3555575973;
|
||||
static constexpr uint16_t TypeIdx = 28;
|
||||
StaticPuzzleCardHandle RefCard = {};
|
||||
PuzPos Position = {};
|
||||
uint8_t Rotation = {};
|
||||
bool IsLocked = {};
|
||||
PlacedPuzzleCardFlags::Enum Flags = {};
|
||||
};
|
||||
struct PuzzleData
|
||||
{
|
||||
static constexpr uint32_t Hash = 657000000;
|
||||
static constexpr uint16_t TypeIdx = 29;
|
||||
uint16_t ID = {};
|
||||
char PuzzleName[64] = {};
|
||||
uint8_t WidthTiles = {};
|
||||
@@ -153,12 +235,62 @@ namespace Gen
|
||||
uint32_t AvailableCardCount = {};
|
||||
PuzzleCardStack AvailableCards[16] = {};
|
||||
PlacedPuzzleCard PlacedCards[256] = {};
|
||||
PlacedPuzzleCard InitialPlacedCards[256] = {};
|
||||
PuzzleElementType::Enum BackgroundTiles[1024] = {};
|
||||
uint32_t GoalPositionCount = {};
|
||||
PuzPos GoalPositions[16] = {};
|
||||
};
|
||||
struct SavedEntityRenderData
|
||||
{
|
||||
static constexpr uint16_t TypeIdx = 30;
|
||||
Vec4 BaseColor = {};
|
||||
Vec4 HighlightColor = {};
|
||||
Transform TF = {};
|
||||
EMaterial::Enum Material = {};
|
||||
TextureHandle Texture = {};
|
||||
ModelHandle Model = {};
|
||||
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 Load(PuzzleElementType::Enum* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const PlacedPuzzleCardFlags::Enum* obj, uint32_t count, Serializer& serializer);
|
||||
bool Load(PlacedPuzzleCardFlags::Enum* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const EMaterial::Enum* obj, uint32_t count, Serializer& serializer);
|
||||
bool Load(EMaterial::Enum* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const int8_t* obj, uint32_t count, Serializer& serializer);
|
||||
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 Load(Vec2* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const Vec3* obj, uint32_t count, Serializer& serializer);
|
||||
@@ -169,6 +301,8 @@ namespace Gen
|
||||
bool Load(Mat3* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const Mat4* obj, uint32_t count, Serializer& serializer);
|
||||
bool Load(Mat4* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const Transform* obj, uint32_t count, Serializer& serializer);
|
||||
bool Load(Transform* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const AssetHandle* obj, uint32_t count, Serializer& serializer);
|
||||
bool Load(AssetHandle* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const ModelHandle* obj, uint32_t count, Serializer& serializer);
|
||||
@@ -177,6 +311,8 @@ namespace Gen
|
||||
bool Load(TextureHandle* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const PuzPos* obj, uint32_t count, Serializer& 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 Load(StaticPuzzleCard* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const StaticPuzzleCardHandle* obj, uint32_t count, Serializer& serializer);
|
||||
@@ -191,4 +327,74 @@ namespace Gen
|
||||
bool Load(PlacedPuzzleCard* obj, uint32_t count, Deserializer& serializer);
|
||||
bool Save(const PuzzleData* obj, uint32_t count, Serializer& serializer);
|
||||
bool Load(PuzzleData* obj, uint32_t count, Deserializer& serializer);
|
||||
} // namespace Gen
|
||||
bool Save(const SavedEntityRenderData* obj, uint32_t count, Serializer& 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;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/gen/TypeData.bin
LFS
BIN
src/gen/TypeData.bin
LFS
Binary file not shown.
BIN
src/models/ConcretePlane.glb
LFS
BIN
src/models/ConcretePlane.glb
LFS
Binary file not shown.
BIN
src/models/GateDoor.glb
LFS
Normal file
BIN
src/models/GateDoor.glb
LFS
Normal file
Binary file not shown.
BIN
src/models/GateWall.glb
LFS
Normal file
BIN
src/models/GateWall.glb
LFS
Normal file
Binary file not shown.
BIN
src/models/channel_cover_big.glb
LFS
Normal file
BIN
src/models/channel_cover_big.glb
LFS
Normal file
Binary file not shown.
BIN
src/models/channel_cover_small.glb
LFS
Normal file
BIN
src/models/channel_cover_small.glb
LFS
Normal file
Binary file not shown.
BIN
src/models/landscape.glb
LFS
Normal file
BIN
src/models/landscape.glb
LFS
Normal file
Binary file not shown.
BIN
src/models/river.glb
LFS
Normal file
BIN
src/models/river.glb
LFS
Normal file
Binary file not shown.
BIN
src/models/tablet.glb
LFS
BIN
src/models/tablet.glb
LFS
Binary file not shown.
BIN
src/models/w straight.glb
LFS
BIN
src/models/w straight.glb
LFS
Binary file not shown.
BIN
src/models/w! corner short.glb
LFS
BIN
src/models/w! corner short.glb
LFS
Binary file not shown.
BIN
src/models/w+ corner short.glb
LFS
BIN
src/models/w+ corner short.glb
LFS
Binary file not shown.
BIN
src/models/z_water_cover.glb
LFS
Normal file
BIN
src/models/z_water_cover.glb
LFS
Normal file
Binary file not shown.
13
src/notes.txt
Normal file
13
src/notes.txt
Normal 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
|
||||
@@ -1,4 +0,0 @@
|
||||
cd dependency/bgfx.cmake
|
||||
cmake -G "Ninja" -S . -B cmake-build-release -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DBGFX_BUILD_TOOLS=OFF -DBGFX_BUILD_EXAMPLES=OFF
|
||||
cd ..\..
|
||||
cmake -G "Ninja" -S . -B cmake-build-release -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
@@ -3,15 +3,21 @@ $shadersDir = ".\game\shaders"
|
||||
$outputBaseDir = ".\game\compiled-shaders"
|
||||
$includeDir = ".\dependency\bgfx.cmake\bgfx\src"
|
||||
|
||||
function CompileForAPI {
|
||||
param ([string]$API, [string]$ShaderProfile)
|
||||
$outDir = "$outputBaseDir\$API\$DirectoryName"
|
||||
New-Item -ItemType Directory -Path $outDir -Force -ErrorAction Stop | Out-Null
|
||||
Write-Host "Frag: $API $ShaderProfile"
|
||||
& $shadercPath -f "$DirectoryFull\vert.sc" -o "$outDir\vert.bin" -i $includeDir --type v --platform windows --profile $ShaderProfile
|
||||
Write-Host "Vert: $API $ShaderProfile"
|
||||
& $shadercPath -f "$DirectoryFull\frag.sc" -o "$outDir\frag.bin" -i $includeDir --type f --platform windows --profile $ShaderProfile
|
||||
}
|
||||
|
||||
function Process-Directory {
|
||||
param ([string]$DirectoryFull, [string]$DirectoryName)
|
||||
Write-Host "Dir: $DirectoryName"
|
||||
$outDir = "$outputBaseDir\dx11\$DirectoryName"
|
||||
New-Item -ItemType Directory -Path $outDir -Force -ErrorAction Stop | Out-Null
|
||||
Write-Host "Frag"
|
||||
& $shadercPath -f "$DirectoryFull\vert.sc" -o "$outDir\vert.bin" -i $includeDir --type v --platform windows --profile s_5_0
|
||||
Write-Host "Vert"
|
||||
& $shadercPath -f "$DirectoryFull\frag.sc" -o "$outDir\frag.bin" -i $includeDir --type f --platform windows --profile s_5_0
|
||||
CompileForAPI -API "dx11" -ShaderProfile "s_5_0"
|
||||
CompileForAPI -API "glsl" -ShaderProfile "430"
|
||||
}
|
||||
|
||||
$subdirectories = Get-ChildItem -Path $shadersDir -Directory -Recurse -ErrorAction Stop
|
||||
|
||||
BIN
src/textures/bridge.ktx
LFS
Normal file
BIN
src/textures/bridge.ktx
LFS
Normal file
Binary file not shown.
BIN
src/textures/concrete_tile.ktx
LFS
Normal file
BIN
src/textures/concrete_tile.ktx
LFS
Normal file
Binary file not shown.
BIN
src/textures/notsolved.ktx
LFS
Normal file
BIN
src/textures/notsolved.ktx
LFS
Normal file
Binary file not shown.
BIN
src/textures/reset.ktx
LFS
Normal file
BIN
src/textures/reset.ktx
LFS
Normal file
Binary file not shown.
BIN
src/textures/solved.ktx
LFS
Normal file
BIN
src/textures/solved.ktx
LFS
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user