Compare commits
101 Commits
29bb1d0208
...
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 | ||
|
|
c244b997c1 | ||
|
|
6d170be57a | ||
|
|
052fc2cc07 | ||
|
|
b006d14197 | ||
|
|
e5076b0c3b | ||
|
|
3ce1acc633 | ||
|
|
cd03f89465 | ||
|
|
39164bffa5 | ||
|
|
ef7833caa6 | ||
|
|
dbc65fec9a | ||
|
|
cdf6a83af6 | ||
|
|
77a6a0a510 | ||
|
|
fc67ff62be | ||
|
|
365805537c | ||
|
|
f56ffdaa13 | ||
|
|
26ba03b7fe | ||
|
|
90d4c3df1b | ||
|
|
2ff08d7258 | ||
|
|
24a724a021 | ||
|
|
aafa5e966e | ||
|
|
fa93abe1ec | ||
|
|
551796e7ad | ||
|
|
e16c9e0a2f | ||
|
|
ffd2e45d81 | ||
|
|
93bb1553be | ||
|
|
ebf29b058a | ||
|
|
442fd23a0b | ||
|
|
a0af22cea6 | ||
|
|
a5e32c414e | ||
|
|
a3e22b7b05 | ||
|
|
f14add70b6 | ||
|
|
de88190c47 | ||
|
|
97146664f2 | ||
|
|
155339917d | ||
|
|
f3f994fd8b | ||
|
|
ffad8f8460 | ||
|
|
c7377c3452 | ||
|
|
ff00119e5b | ||
|
|
e2b94b826d |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -4,3 +4,7 @@
|
|||||||
*.png filter=lfs diff=lfs merge=lfs -text
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||||
*.blend filter=lfs diff=lfs merge=lfs -text
|
*.blend filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.pzl filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.exe filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.glb filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ktx filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -11,3 +11,6 @@
|
|||||||
path = src/dependency/imgui
|
path = src/dependency/imgui
|
||||||
url = https://github.com/ocornut/imgui
|
url = https://github.com/ocornut/imgui
|
||||||
branch = docking
|
branch = docking
|
||||||
|
[submodule "src/dependency/tracy"]
|
||||||
|
path = src/dependency/tracy
|
||||||
|
url = https://github.com/wolfpld/tracy
|
||||||
|
|||||||
BIN
assets/blender/Channels.blend
LFS
Normal file
BIN
assets/blender/Channels.blend
LFS
Normal file
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
Normal file
BIN
assets/blender/tablet.blend
LFS
Normal file
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/test.png
LFS
Normal file
BIN
assets/textures/test.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
Normal file
BIN
assets/textures/w straight.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.
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
src/.gitattributes
vendored
1
src/.gitattributes
vendored
@@ -1 +0,0 @@
|
|||||||
*.glb filter=lfs diff=lfs merge=lfs -text
|
|
||||||
1
src/.gitignore
vendored
1
src/.gitignore
vendored
@@ -33,5 +33,6 @@
|
|||||||
|
|
||||||
# build dirs
|
# build dirs
|
||||||
cmake-build/
|
cmake-build/
|
||||||
|
cmake-build-release/
|
||||||
out/
|
out/
|
||||||
.vs/
|
.vs/
|
||||||
@@ -2,12 +2,14 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
project(PuzGameProj)
|
project(PuzGameProj)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
|
||||||
else()
|
else()
|
||||||
add_compile_options(-g -gcodeview)
|
add_compile_options(-g -gcodeview)
|
||||||
add_link_options(-fuse-ld=lld -g -Wl,--pdb=)
|
add_link_options(-fuse-ld=lld -g -Wl,--pdb=)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
|
add_compile_definitions("$<$<CONFIG:DEBUG>:DEBUG>")
|
||||||
|
|
||||||
# set the output directory for built objects.
|
# set the output directory for built objects.
|
||||||
# This makes sure that the dynamic library goes into the build directory automatically.
|
# This makes sure that the dynamic library goes into the build directory automatically.
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
|
||||||
@@ -24,15 +26,34 @@ add_subdirectory("${CMAKE_SOURCE_DIR}/dependency/minidef")
|
|||||||
# Engine
|
# Engine
|
||||||
file(GLOB_RECURSE sources_engine engine/*.cpp engine/*.h)
|
file(GLOB_RECURSE sources_engine engine/*.cpp engine/*.h)
|
||||||
add_executable(PuzGameEngine ${sources_engine})
|
add_executable(PuzGameEngine ${sources_engine})
|
||||||
|
target_compile_definitions(PuzGameEngine PUBLIC "_AMD64_")
|
||||||
set_property(TARGET PuzGameEngine PROPERTY CXX_STANDARD 17)
|
set_property(TARGET PuzGameEngine PROPERTY CXX_STANDARD 17)
|
||||||
target_include_directories(PuzGameEngine PUBLIC)
|
|
||||||
|
|
||||||
# Game
|
# Game
|
||||||
file(GLOB_RECURSE sources_game game/*.cpp game/*.h gen/*.cpp gen/*.h)
|
add_custom_command(
|
||||||
|
COMMAND "${CMAKE_SOURCE_DIR}/../tools/minidef.exe" "${CMAKE_SOURCE_DIR}/game/mini.def" "${CMAKE_SOURCE_DIR}/gen/"
|
||||||
|
DEPENDS "${CMAKE_SOURCE_DIR}/game/mini.def"
|
||||||
|
OUTPUT "${CMAKE_SOURCE_DIR}/gen/Generated.h" "${CMAKE_SOURCE_DIR}/gen/Generated.cpp"
|
||||||
|
COMMENT "Genrating from minidef"
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE sources_game game/*.cpp game/*.h gen/Generated.cpp gen/Generated.h gen/Def.h gen/Def.cpp)
|
||||||
file(GLOB source_singleheader dependency/tinygltf/stb_image.h dependency/tinygltf/stb_image_write.h dependency/tinygltf/json.hpp dependency/tinygltf/tiny_gltf.h)
|
file(GLOB source_singleheader dependency/tinygltf/stb_image.h dependency/tinygltf/stb_image_write.h dependency/tinygltf/json.hpp dependency/tinygltf/tiny_gltf.h)
|
||||||
add_library(PuzGame SHARED ${sources_game} ${source_singleheader} ${imgui_sources} ${imgui_backend_sdl})
|
file(GLOB sources_imgui_helper dependency/imgui-bgfx/imgui-helper.h dependency/imgui-bgfx/imgui-helper.cpp)
|
||||||
|
add_library(PuzGame SHARED ${sources_game} ${source_singleheader} ${imgui_sources} ${imgui_backend_sdl} ${sources_imgui_helper})
|
||||||
set_property(TARGET PuzGame PROPERTY CXX_STANDARD 17)
|
set_property(TARGET PuzGame PROPERTY CXX_STANDARD 17)
|
||||||
target_include_directories(PuzGame PUBLIC dependency/imgui)
|
target_include_directories(PuzGame PUBLIC dependency/imgui)
|
||||||
|
target_include_directories(PuzGame PUBLIC dependency/tracy/public)
|
||||||
|
target_include_directories(PuzGame PUBLIC dependency/imgui-bgfx)
|
||||||
|
|
||||||
|
# Profiling
|
||||||
|
option(TRACY_ENABLE "" OFF)
|
||||||
|
if (TRACY_ENABLE)
|
||||||
|
option(TRACY_ON_DEMAND "" ON)
|
||||||
|
set(TRACY_DELAYED_INIT ON)
|
||||||
|
set(TRACY_MANUAL_LIFETIME ON)
|
||||||
|
add_subdirectory("${CMAKE_SOURCE_DIR}/dependency/tracy")
|
||||||
|
endif()
|
||||||
|
|
||||||
# SDL
|
# SDL
|
||||||
add_subdirectory("${CMAKE_SOURCE_DIR}/dependency/SDL" EXCLUDE_FROM_ALL)
|
add_subdirectory("${CMAKE_SOURCE_DIR}/dependency/SDL" EXCLUDE_FROM_ALL)
|
||||||
@@ -43,6 +64,11 @@ SET(BGFX_BUILD_EXAMPLES OFF)
|
|||||||
add_subdirectory("${CMAKE_SOURCE_DIR}/dependency/bgfx.cmake")
|
add_subdirectory("${CMAKE_SOURCE_DIR}/dependency/bgfx.cmake")
|
||||||
|
|
||||||
# Link
|
# Link
|
||||||
|
if (TRACY_ENABLE)
|
||||||
|
target_link_libraries(PuzGame bx bimg bgfx SDL3::SDL3 Tracy::TracyClient)
|
||||||
|
target_link_libraries(PuzGameEngine bx SDL3::SDL3 Tracy::TracyClient)
|
||||||
|
else()
|
||||||
target_link_libraries(PuzGame bx bimg bgfx SDL3::SDL3)
|
target_link_libraries(PuzGame bx bimg bgfx SDL3::SDL3)
|
||||||
target_link_libraries(PuzGameEngine bx SDL3::SDL3)
|
target_link_libraries(PuzGameEngine bx SDL3::SDL3)
|
||||||
|
endif()
|
||||||
set_target_properties(PuzGame PROPERTIES OUTPUT_NAME "PuzGame2")
|
set_target_properties(PuzGame PROPERTIES OUTPUT_NAME "PuzGame2")
|
||||||
|
|||||||
10
src/assetcompile.ps1
Normal file
10
src/assetcompile.ps1
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
$texturecPath = "..\tools\texturec.exe"
|
||||||
|
$textureAssetDir = "..\assets\textures"
|
||||||
|
$outputBaseDir = ".\textures"
|
||||||
|
|
||||||
|
Get-ChildItem -Path $textureAssetDir -File | ForEach-Object {
|
||||||
|
$outName = Join-Path -Path $outputBaseDir -ChildPath ($_.BaseName + ".ktx")
|
||||||
|
Write-Host $_.FullName $outName
|
||||||
|
& "$texturecPath" -f $_.FullName -o $outName -t RGBA8
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
cd dependency/bgfx.cmake
|
cd dependency/bgfx.cmake
|
||||||
|
cmake -G "Ninja" -S . -B cmake-build -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DBGFX_BUILD_TOOLS=OFF -DBGFX_BUILD_EXAMPLES=OFF
|
||||||
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
|
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 ..\..
|
cd ..\..
|
||||||
|
cmake -G "Ninja" -S . -B cmake-build -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||||
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
|
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
|
||||||
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,4 +1,6 @@
|
|||||||
SDL/*
|
SDL/*
|
||||||
# !SDL/src
|
bgfx.cmake/*
|
||||||
# bgfx.cmake/*
|
|
||||||
tinygltf/*
|
tinygltf/*
|
||||||
|
imgui/*
|
||||||
|
iconfontheaders/*
|
||||||
|
tracy/*
|
||||||
|
|||||||
Submodule src/dependency/imgui updated: afd659bb92...126d004f9e
@@ -1,9 +1,15 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(MiniDefProj)
|
project(MiniDefProj)
|
||||||
add_executable(minidef "${CMAKE_CURRENT_SOURCE_DIR}/src/MiniDef.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/Logging.cpp")
|
|
||||||
|
file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h")
|
||||||
|
file(GLOB sources "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
|
||||||
|
|
||||||
|
add_executable(minidef ${headers} ${sources})
|
||||||
|
set_property(TARGET minidef PROPERTY CXX_STANDARD 17)
|
||||||
target_include_directories(minidef PRIVATE
|
target_include_directories(minidef PRIVATE
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../bgfx.cmake/bx/include/"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../bgfx.cmake/bx/include/"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../bgfx.cmake/bx/include/compat/msvc/"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../bgfx.cmake/bx/include/compat/msvc/"
|
||||||
)
|
)
|
||||||
target_link_libraries(minidef bx)
|
target_link_libraries(minidef bx)
|
||||||
target_compile_definitions(minidef PRIVATE "$<$<CONFIG:DEBUG>:BX_CONFIG_DEBUG=1>$<$<CONFIG:RELEASE>:BX_CONFIG_DEBUG=0>")
|
target_compile_definitions(minidef PRIVATE "$<$<CONFIG:DEBUG>:BX_CONFIG_DEBUG=1>$<$<CONFIG:RELEASE>:BX_CONFIG_DEBUG=0>")
|
||||||
|
target_compile_definitions(minidef PUBLIC "_AMD64_")
|
||||||
|
|||||||
@@ -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, ...);
|
|
||||||
};
|
|
||||||
643
src/dependency/minidef/src/CppGen.cpp
Normal file
643
src/dependency/minidef/src/CppGen.cpp
Normal file
@@ -0,0 +1,643 @@
|
|||||||
|
#include "CppGen.h"
|
||||||
|
#include "Logging.h"
|
||||||
|
#include "TypeDef.h"
|
||||||
|
#include "bx/string.h"
|
||||||
|
|
||||||
|
#include <bx/file.h>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <memoryapi.h>
|
||||||
|
#include <winnt.h>
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include "Windows.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
namespace WriteTemplates
|
||||||
|
{
|
||||||
|
constexpr char FileHeaderStart[] =
|
||||||
|
R"END(#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Gen
|
||||||
|
{
|
||||||
|
struct Serializer;
|
||||||
|
struct Deserializer;
|
||||||
|
)END";
|
||||||
|
constexpr char FileCppStart[] = R"END(#include "Def.h"
|
||||||
|
#include "Generated.h"
|
||||||
|
|
||||||
|
namespace Gen
|
||||||
|
{
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char StructHeader2[] =
|
||||||
|
R"END( struct %s
|
||||||
|
{
|
||||||
|
static constexpr uint16_t TypeIdx = %u;
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char StructField4[] =
|
||||||
|
R"END( %s %s%s = %s;
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char StructEnd[] =
|
||||||
|
R"END( };
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char EnumHeader4[] =
|
||||||
|
R"END( struct %s
|
||||||
|
{
|
||||||
|
static constexpr uint16_t TypeIdx = %u;
|
||||||
|
static constexpr int32_t EntryCount = %u;
|
||||||
|
enum Enum : %s
|
||||||
|
{
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char EnumField1[] =
|
||||||
|
R"END( %s,
|
||||||
|
)END";
|
||||||
|
constexpr char EnumFieldNumbered2[] =
|
||||||
|
R"END( %s = %s,
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char EnumNamesStart2[] =
|
||||||
|
R"END( };
|
||||||
|
static constexpr char %s[EntryCount][%u]
|
||||||
|
{
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char EnumNamesEntry1[] =
|
||||||
|
R"END( "%s",
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char EnumNamesEnd[] =
|
||||||
|
R"END( };
|
||||||
|
};
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char EnumFlagOperators12[] =
|
||||||
|
R"END( inline %s::Enum operator| (const %s::Enum& a, const %s::Enum& b)
|
||||||
|
{
|
||||||
|
return a | b;
|
||||||
|
}
|
||||||
|
inline %s::Enum operator& (const %s::Enum& a, const %s::Enum& b)
|
||||||
|
{
|
||||||
|
return a & b;
|
||||||
|
}
|
||||||
|
inline %s::Enum operator|= (%s::Enum& a, const %s::Enum& b)
|
||||||
|
{
|
||||||
|
return a |= b;
|
||||||
|
}
|
||||||
|
inline %s::Enum operator&= (%s::Enum& a, const %s::Enum& b)
|
||||||
|
{
|
||||||
|
return a &= b;
|
||||||
|
}
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char FileEnd[] =
|
||||||
|
R"END(}
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char SaveFuncHeader1[] =
|
||||||
|
R"END( bool Save(const %s* obj, uint32_t count, Serializer& serializer);
|
||||||
|
)END";
|
||||||
|
constexpr char SaveFuncBodyStart1[] = R"END( bool Save(const %s* obj, uint32_t count, Serializer& serializer)
|
||||||
|
{
|
||||||
|
bool isOk = true;
|
||||||
|
for (uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
)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;
|
||||||
|
)END";
|
||||||
|
constexpr char SaveFuncBodyEnd[] = R"END( }
|
||||||
|
return isOk;
|
||||||
|
}
|
||||||
|
)END";
|
||||||
|
|
||||||
|
constexpr char LoadFuncHeader1[] =
|
||||||
|
R"END( bool Load(%s* obj, uint32_t count, Deserializer& serializer);
|
||||||
|
)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 LoadFuncBodyQuickLoad2[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk;
|
||||||
|
)END";
|
||||||
|
constexpr char LoadFuncBodySetupEnd[] = R"END( }
|
||||||
|
// if we're not ok here, something went really wrong
|
||||||
|
assert(isOk);
|
||||||
|
return isOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed to resolve hash, the type definition chaned since the file was saved! try to match by name.
|
||||||
|
*obj = {};
|
||||||
|
int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName);
|
||||||
|
if (nameMatchIdx < 0)
|
||||||
|
{
|
||||||
|
// Name match failed, caller has to handle this and potentially skip some bytes
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully matched name, but we need to follow the definition of the file now!
|
||||||
|
const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx];
|
||||||
|
|
||||||
|
// Figure out new member mapping
|
||||||
|
uint64_t WriteDestinations[64];
|
||||||
|
for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i)
|
||||||
|
{
|
||||||
|
WriteDestinations[i] = UINT64_MAX;
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < matchedDef.ChildCount; ++i)
|
||||||
|
{
|
||||||
|
const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size};
|
||||||
|
const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name;
|
||||||
|
)END";
|
||||||
|
constexpr char LoadFuncBodyMemberCheck4[] =
|
||||||
|
R"END( if (bx::strCmp(memberName, "%s") == 0 && bx::strCmp(memberTypeName, "%s") == 0)
|
||||||
|
{
|
||||||
|
WriteDestinations[i] = offsetof(%s, %s);
|
||||||
|
}
|
||||||
|
)END";
|
||||||
|
constexpr char LoadFuncBodyTypeUpgradeStart[] = R"END( }
|
||||||
|
|
||||||
|
// Start reading in file order, skipping things that we don't know by name and type
|
||||||
|
bool isOk = true;
|
||||||
|
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
|
||||||
|
|
||||||
|
void CppFileWriter::InitBuffer(WriteBuffer& buf)
|
||||||
|
{
|
||||||
|
if (buf.Data != nullptr)
|
||||||
|
{
|
||||||
|
LOG_ERROR(0, "Multiple writes not supported yet!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buf.Data =
|
||||||
|
reinterpret_cast<char*>(VirtualAlloc(nullptr, BufferRequestSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||||
|
if (buf.Data == nullptr)
|
||||||
|
{
|
||||||
|
LOG_ERROR(0, "Failed to allocate write memory!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buf.WrittenBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CppFileWriter::WriteBufferToDisk(const bx::FilePath& path, const WriteBuffer& buf)
|
||||||
|
{
|
||||||
|
bx::Error error;
|
||||||
|
bx::FileWriter writer;
|
||||||
|
|
||||||
|
LOG(0, "Writing to %s", path.getCPtr());
|
||||||
|
if (!writer.open(path, false, &error))
|
||||||
|
{
|
||||||
|
LOG_ERROR(0, "Failed to open output file: %s", error.getMessage().getCPtr());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.write(buf.Data, buf.WrittenBytes, &error);
|
||||||
|
if (!error.isOk())
|
||||||
|
{
|
||||||
|
LOG_ERROR(0, "Failed to write to output file: %s", error.getMessage().getCPtr());
|
||||||
|
}
|
||||||
|
writer.close();
|
||||||
|
LOG(0, "Finished writing!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppFileWriter::WriteInternal(WriteBuffer& buf, const char* templateStr, va_list args)
|
||||||
|
{
|
||||||
|
if (buf.Data == nullptr)
|
||||||
|
{
|
||||||
|
LOG_ERROR(0, "Wrote too early!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WrittenBytes += bx::vsnprintf(&buf.Data[buf.WrittenBytes], BufferRequestSize, templateStr, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppFileWriter::PrintTypeName(
|
||||||
|
char* buf, int32_t bufSize, Def::TypeRef type, const Def::DefinitionFile& definitions, PrintFlags flags)
|
||||||
|
{
|
||||||
|
if (buf == nullptr || bufSize == 0 || !IsValid(type))
|
||||||
|
{
|
||||||
|
LOG_ERROR(0, "Invalid PrintTypeName call!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type.FieldKind == Def::EFieldType::DefinedClass)
|
||||||
|
{
|
||||||
|
auto& t = definitions.Types[type.TypeIdx];
|
||||||
|
if (((uint32_t)t.TypeFlags & (uint32_t)Def::ETypeFlags::IsNative) &&
|
||||||
|
((uint32_t)flags & (uint32_t)PrintFlags::PrintNativeTypeName))
|
||||||
|
{
|
||||||
|
bx::strCopy(buf, bufSize, t.NativeCName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bx::strCopy(buf, bufSize, t.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;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Write(WriteTemplates::EnumNamesEntry1, e.EntryNames[entryIdx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t extraIdx = 0; extraIdx < e.ExtraStringFieldCount; ++extraIdx)
|
||||||
|
{
|
||||||
|
Write(WriteTemplates::EnumNamesStart2, e.ExtraStringFieldNames[extraIdx], Def::MaxNameLength);
|
||||||
|
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx)
|
||||||
|
{
|
||||||
|
Write(WriteTemplates::EnumNamesEntry1, e.ExtraStringFields[entryIdx][extraIdx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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, 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 && ArraySize != UINT32_MAX)
|
||||||
|
{
|
||||||
|
bx::snprintf(Array, sizeof(Array), "[%u]", ArraySize);
|
||||||
|
}
|
||||||
|
Write(WriteTemplates::StructField4, Type, t.FieldNames[fieldIdx], Array, t.FieldValues[fieldIdx]);
|
||||||
|
}
|
||||||
|
Write(WriteTemplates::StructEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions)
|
||||||
|
{
|
||||||
|
char nameBuf[64]{0};
|
||||||
|
char fieldBuf[64]{0};
|
||||||
|
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);
|
||||||
|
|
||||||
|
Write(WriteTemplates::SaveFuncHeader1, nameBuf);
|
||||||
|
Write(WriteTemplates::LoadFuncHeader1, nameBuf);
|
||||||
|
|
||||||
|
WriteCpp(WriteTemplates::SaveFuncBodyStart1, nameBuf);
|
||||||
|
WriteCpp(WriteTemplates::SaveFuncBodyEnum1, fieldBuf);
|
||||||
|
WriteCpp(WriteTemplates::SaveFuncBodyEnd);
|
||||||
|
|
||||||
|
WriteCpp(WriteTemplates::LoadFuncBodyStart1, nameBuf);
|
||||||
|
WriteCpp(WriteTemplates::LoadFuncBodyEnum2, fieldBuf, fieldBuf);
|
||||||
|
}
|
||||||
|
for (uint16_t typeIdx = 0; typeIdx < definitions.TypeCount; ++typeIdx)
|
||||||
|
{
|
||||||
|
const Def::Type& t = definitions.Types[typeIdx];
|
||||||
|
char typeName[Def::MaxNameLength]{0};
|
||||||
|
PrintTypeName(typeName, sizeof(typeName), {typeIdx, Def::EFieldType::DefinedClass}, definitions);
|
||||||
|
|
||||||
|
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,
|
||||||
|
t.FieldArraySizes[fieldIdx] > 0 ? "" : "&",
|
||||||
|
t.FieldNames[fieldIdx],
|
||||||
|
bx::max(1, t.FieldArraySizes[fieldIdx]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WriteCpp(WriteTemplates::SaveFuncBodyEnd);
|
||||||
|
|
||||||
|
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::LoadFuncBodyQuickLoad2,
|
||||||
|
t.FieldArraySizes[fieldIdx] > 0 ? "" : "&",
|
||||||
|
t.FieldNames[fieldIdx],
|
||||||
|
bx::max(1, t.FieldArraySizes[fieldIdx]));
|
||||||
|
}
|
||||||
|
WriteCpp(WriteTemplates::LoadFuncBodySetupEnd);
|
||||||
|
char fieldTypeName[Def::MaxNameLength]{0};
|
||||||
|
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||||
|
{
|
||||||
|
const char* fieldName = t.FieldNames[fieldIdx];
|
||||||
|
// This prints native type name, seems wrong??
|
||||||
|
// Havent i already fixed this???
|
||||||
|
PrintTypeName(
|
||||||
|
fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions, PrintFlags::None);
|
||||||
|
WriteCpp(WriteTemplates::LoadFuncBodyMemberCheck4, fieldName, fieldTypeName, typeName, fieldName);
|
||||||
|
}
|
||||||
|
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeStart);
|
||||||
|
for (uint32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||||
|
{
|
||||||
|
const char* fieldName = t.FieldNames[fieldIdx];
|
||||||
|
PrintTypeName(fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions);
|
||||||
|
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeMember3,
|
||||||
|
fieldName,
|
||||||
|
fieldTypeName,
|
||||||
|
bx::max(1, t.FieldArraySizes[fieldIdx]));
|
||||||
|
}
|
||||||
|
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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...");
|
||||||
|
|
||||||
|
InitBuffer(HeaderWrite);
|
||||||
|
InitBuffer(CppWrite);
|
||||||
|
|
||||||
|
Write(WriteTemplates::FileHeaderStart);
|
||||||
|
WriteCpp(WriteTemplates::FileCppStart);
|
||||||
|
WriteEnums(definitions);
|
||||||
|
WriteTypes(definitions);
|
||||||
|
WriteSaveLoadMethods(definitions);
|
||||||
|
WriteMetadata(definitions);
|
||||||
|
Write(WriteTemplates::FileEnd);
|
||||||
|
WriteCpp(WriteTemplates::FileEnd);
|
||||||
|
|
||||||
|
// std::filesystem::create_directory(outDir.getCPtr());
|
||||||
|
bx::FilePath writePathHeader = outDir;
|
||||||
|
bx::FilePath writePathCpp = outDir;
|
||||||
|
writePathHeader.join("Generated.h");
|
||||||
|
writePathCpp.join("Generated.cpp");
|
||||||
|
WriteBufferToDisk(writePathHeader, HeaderWrite);
|
||||||
|
WriteBufferToDisk(writePathCpp, CppWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppFileWriter::Write(const char* templateStr, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, templateStr);
|
||||||
|
WriteInternal(HeaderWrite, templateStr, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppFileWriter::WriteCpp(const char* templateStr, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, templateStr);
|
||||||
|
WriteInternal(CppWrite, templateStr, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
45
src/dependency/minidef/src/CppGen.h
Normal file
45
src/dependency/minidef/src/CppGen.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "TypeDef.h"
|
||||||
|
|
||||||
|
#include "bx/filepath.h"
|
||||||
|
|
||||||
|
struct WriteBuffer
|
||||||
|
{
|
||||||
|
char* Data = nullptr;
|
||||||
|
uint64_t WrittenBytes = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PrintFlags : uint32_t
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
PrintFullEnumName = 1 << 0,
|
||||||
|
PrintNativeTypeName = 1 << 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CppFileWriter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static constexpr size_t BufferRequestSize = 1024 * 1024 * 1024;
|
||||||
|
WriteBuffer HeaderWrite;
|
||||||
|
WriteBuffer CppWrite;
|
||||||
|
void InitBuffer(WriteBuffer& buf);
|
||||||
|
bool WriteBufferToDisk(const bx::FilePath& path, const WriteBuffer& buf);
|
||||||
|
void WriteInternal(WriteBuffer& buf, const char* templateStr, va_list args);
|
||||||
|
|
||||||
|
public:
|
||||||
|
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, ...);
|
||||||
|
};
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <cstdint>
|
|
||||||
260
src/dependency/minidef/src/Gen/Generated.cpp
Normal file
260
src/dependency/minidef/src/Gen/Generated.cpp
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
#include "Def.h"
|
||||||
|
#include "Generated.h"
|
||||||
|
|
||||||
|
namespace Gen
|
||||||
|
{
|
||||||
|
bool Save(const KnownType::Enum* obj, uint32_t count, Serializer& serializer)
|
||||||
|
{
|
||||||
|
bool isOk = true;
|
||||||
|
for (uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
auto val = (uint8_t)obj[i];
|
||||||
|
isOk = Save(&val, 1, serializer) && isOk;
|
||||||
|
}
|
||||||
|
return isOk;
|
||||||
|
}
|
||||||
|
bool Load(KnownType::Enum* obj, uint32_t count, Deserializer& serializer)
|
||||||
|
{
|
||||||
|
bool isOk = true;
|
||||||
|
for (uint32_t i = 0; i < count; ++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 = serializer.Write(&obj[i], sizeof(obj[i])) && isOk;
|
||||||
|
}
|
||||||
|
return isOk;
|
||||||
|
}
|
||||||
|
bool Load(Test* 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;
|
||||||
|
}
|
||||||
|
bool Save(const Texture* 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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
bool Load(Texture* 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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Def.h"
|
#include <cstdint>
|
||||||
|
|
||||||
namespace Generated
|
namespace Gen
|
||||||
{
|
{
|
||||||
struct Test
|
struct Serializer;
|
||||||
{
|
struct Deserializer;
|
||||||
uint32_t Number = {};
|
|
||||||
};
|
|
||||||
struct Texture
|
|
||||||
{
|
|
||||||
uint32_t Width = {};
|
|
||||||
uint32_t Height = {};
|
|
||||||
char StrTest[3] = {};
|
|
||||||
Test T = {};
|
|
||||||
};
|
|
||||||
struct KnownType
|
struct KnownType
|
||||||
{
|
{
|
||||||
|
static constexpr uint16_t EnumIdx = 0;
|
||||||
static constexpr int32_t EntryCount = 12;
|
static constexpr int32_t EntryCount = 12;
|
||||||
enum class Enum : int32_t
|
enum Enum : uint8_t
|
||||||
{
|
{
|
||||||
i8,
|
i8,
|
||||||
i16,
|
i16,
|
||||||
@@ -63,4 +55,91 @@ namespace Generated
|
|||||||
"char",
|
"char",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
struct Test
|
||||||
|
{
|
||||||
|
static constexpr uint16_t TypeIdx = 12;
|
||||||
|
uint32_t Number = {};
|
||||||
|
};
|
||||||
|
struct Texture
|
||||||
|
{
|
||||||
|
static constexpr uint16_t TypeIdx = 13;
|
||||||
|
uint32_t Width = {};
|
||||||
|
uint32_t Height = {};
|
||||||
|
char StrTest[3] = {};
|
||||||
|
Test T = {};
|
||||||
|
};
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,163 +1,13 @@
|
|||||||
|
#include "CppGen.h"
|
||||||
#include "Gen/Generated.h"
|
#include "Gen/Generated.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "MiniDef.h"
|
#include "MiniDef.h"
|
||||||
|
#include "TypeDef.h"
|
||||||
|
|
||||||
|
#include "bx/hash.h"
|
||||||
#include "bx/string.h"
|
#include "bx/string.h"
|
||||||
#include <bx/filepath.h>
|
#include <bx/filepath.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
namespace WriteTemplates
|
|
||||||
{
|
|
||||||
constexpr char FileHeader[] =
|
|
||||||
R"END(#pragma once
|
|
||||||
#include "Def.h"
|
|
||||||
|
|
||||||
namespace Generated
|
|
||||||
{
|
|
||||||
)END";
|
|
||||||
|
|
||||||
constexpr char StructHeader1[] =
|
|
||||||
R"END( struct %s
|
|
||||||
{
|
|
||||||
)END";
|
|
||||||
|
|
||||||
constexpr char StructField4[] =
|
|
||||||
R"END( %s %s%s = %s;
|
|
||||||
)END";
|
|
||||||
|
|
||||||
constexpr char StructEnd[] =
|
|
||||||
R"END( };
|
|
||||||
)END";
|
|
||||||
|
|
||||||
constexpr char EnumHeader3[] =
|
|
||||||
R"END( struct %s
|
|
||||||
{
|
|
||||||
static constexpr int32_t EntryCount = %u;
|
|
||||||
enum class Enum : %s
|
|
||||||
{
|
|
||||||
)END";
|
|
||||||
|
|
||||||
constexpr char EnumField1[] =
|
|
||||||
R"END( %s,
|
|
||||||
)END";
|
|
||||||
|
|
||||||
constexpr char EnumNamesStart2[] =
|
|
||||||
R"END( };
|
|
||||||
static constexpr char %s[EntryCount][%u]
|
|
||||||
{
|
|
||||||
)END";
|
|
||||||
|
|
||||||
constexpr char EnumNamesEntry1[] =
|
|
||||||
R"END( "%s",
|
|
||||||
)END";
|
|
||||||
|
|
||||||
constexpr char EnumNamesEnd[] =
|
|
||||||
R"END( };
|
|
||||||
};
|
|
||||||
)END";
|
|
||||||
|
|
||||||
constexpr char FileEnd[] =
|
|
||||||
R"END(}
|
|
||||||
)END";
|
|
||||||
} // namespace WriteTemplates
|
|
||||||
|
|
||||||
void DefinitionFile::PrintTypeName(char* buf, int32_t bufSize, const Def::FieldType& type)
|
|
||||||
{
|
|
||||||
if (type.FieldKind == Def::EFieldType::Native)
|
|
||||||
{
|
|
||||||
if (int32_t(type.Native) < Generated::KnownType::EntryCount)
|
|
||||||
{
|
|
||||||
bx::strCopy(buf, bufSize, Generated::KnownType::CName[size_t(type.Native)]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR(0, "Unknown native type index: %u", type.Native);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type.FieldKind == Def::EFieldType::DefinedClass)
|
|
||||||
{
|
|
||||||
bx::strCopy(buf, bufSize, Types[type.TypeIdx].Name);
|
|
||||||
}
|
|
||||||
else if (type.FieldKind == Def::EFieldType::DefinedEnum)
|
|
||||||
{
|
|
||||||
bx::strCopy(buf, bufSize, Enums[type.TypeIdx].Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DefinitionFile::WriteEnums(TemplateWriter& Template)
|
|
||||||
{
|
|
||||||
for (int32_t enumIdx = 0; enumIdx < EnumCount; ++enumIdx)
|
|
||||||
{
|
|
||||||
Def::Enum& e = Enums[enumIdx];
|
|
||||||
|
|
||||||
Template.Write(
|
|
||||||
WriteTemplates::EnumHeader3, e.Name, e.EntryCount, Generated::KnownType::CName[(int32_t)e.EnumType.Native]);
|
|
||||||
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx)
|
|
||||||
{
|
|
||||||
Template.Write(WriteTemplates::EnumField1, e.EntryNames[entryIdx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Template.Write(WriteTemplates::EnumNamesStart2, "EntryNames", Def::MaxNameLength);
|
|
||||||
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx)
|
|
||||||
{
|
|
||||||
Template.Write(WriteTemplates::EnumNamesEntry1, e.EntryNames[entryIdx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32_t extraIdx = 0; extraIdx < e.ExtraStringFieldCount; ++extraIdx)
|
|
||||||
{
|
|
||||||
Template.Write(WriteTemplates::EnumNamesStart2, e.ExtraStringFieldNames[extraIdx], Def::MaxNameLength);
|
|
||||||
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx)
|
|
||||||
{
|
|
||||||
Template.Write(WriteTemplates::EnumNamesEntry1, e.ExtraStringFields[entryIdx][extraIdx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Template.Write(WriteTemplates::EnumNamesEnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void DefinitionFile::WriteTypes(TemplateWriter& Template)
|
|
||||||
{
|
|
||||||
for (int32_t typeIdx = 0; typeIdx < TypeCount; ++typeIdx)
|
|
||||||
{
|
|
||||||
Def::Type& t = Types[typeIdx];
|
|
||||||
|
|
||||||
Template.Write(WriteTemplates::StructHeader1, t.Name);
|
|
||||||
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
|
||||||
{
|
|
||||||
char Type[64]{0};
|
|
||||||
PrintTypeName(Type, sizeof(Type), t.FieldTypes[fieldIdx]);
|
|
||||||
char Array[32]{0};
|
|
||||||
uint32_t ArraySize = t.FieldArraySizes[fieldIdx];
|
|
||||||
if (ArraySize > 0)
|
|
||||||
{
|
|
||||||
bx::snprintf(Array, sizeof(Array), "[%u]", ArraySize);
|
|
||||||
}
|
|
||||||
Template.Write(WriteTemplates::StructField4, Type, t.FieldNames[fieldIdx], Array, "{}");
|
|
||||||
}
|
|
||||||
Template.Write(WriteTemplates::StructEnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void DefinitionFile::GenerateCpp(const bx::FilePath& outDir)
|
|
||||||
{
|
|
||||||
LOG(0, "Generating...");
|
|
||||||
|
|
||||||
bx::Error error;
|
|
||||||
bx::FileWriter writer;
|
|
||||||
bx::FilePath writePath = outDir;
|
|
||||||
std::filesystem::create_directory(outDir.getCPtr());
|
|
||||||
writePath.join("Generated.h");
|
|
||||||
writer.open(writePath, false, &error);
|
|
||||||
|
|
||||||
TemplateWriter Template{writer, error};
|
|
||||||
Template.Write(WriteTemplates::FileHeader);
|
|
||||||
|
|
||||||
WriteEnums(Template);
|
|
||||||
WriteTypes(Template);
|
|
||||||
|
|
||||||
Template.Write(WriteTemplates::FileEnd);
|
|
||||||
writer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Parser::CmpAdvance(bx::StringView expect, Result& Res, bool RequireGap)
|
bool Parser::CmpAdvance(bx::StringView expect, Result& Res, bool RequireGap)
|
||||||
{
|
{
|
||||||
@@ -264,6 +114,8 @@ Parser::Result Parser::Parse()
|
|||||||
{
|
{
|
||||||
ReadPtr = &Buffer[0];
|
ReadPtr = &Buffer[0];
|
||||||
Parser::Result Res = Parser::OK;
|
Parser::Result Res = Parser::OK;
|
||||||
|
CHECK(LoadNativeTypes());
|
||||||
|
|
||||||
while (Res == Parser::OK)
|
while (Res == Parser::OK)
|
||||||
{
|
{
|
||||||
Res = SkipWhitespace();
|
Res = SkipWhitespace();
|
||||||
@@ -286,6 +138,7 @@ Parser::Result Parser::Parse()
|
|||||||
Parser::Result Parser::HandleFileStart()
|
Parser::Result Parser::HandleFileStart()
|
||||||
{
|
{
|
||||||
Result Res = OK;
|
Result Res = OK;
|
||||||
|
|
||||||
if (CmpAdvance("type", Res, true) && Res == OK)
|
if (CmpAdvance("type", Res, true) && Res == OK)
|
||||||
{
|
{
|
||||||
return HandleType();
|
return HandleType();
|
||||||
@@ -302,22 +155,41 @@ Parser::Result Parser::HandleFileStart()
|
|||||||
return Error;
|
return Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Parser::Result Parser::LoadNativeTypes()
|
||||||
|
{
|
||||||
|
for (int32_t i = 0; i < Gen::KnownType::EntryCount; ++i)
|
||||||
|
{
|
||||||
|
auto& t = Definitions.Types[i];
|
||||||
|
t.Hash = i; // TODO!
|
||||||
|
bx::strCopy(t.Name, sizeof(t.Name), Gen::KnownType::EntryNames[i]);
|
||||||
|
bx::strCopy(t.NativeCName, sizeof(t.NativeCName), Gen::KnownType::CName[i]);
|
||||||
|
t.TypeFlags = Def::ETypeFlags::IsNative;
|
||||||
|
++Definitions.TypeCount;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
Parser::Result Parser::HandleType()
|
Parser::Result Parser::HandleType()
|
||||||
{
|
{
|
||||||
Result Res = OK;
|
Result Res = OK;
|
||||||
if (!Stack.Push(TokenType::TypeKeyword)) return Error;
|
if (!Stack.Push(TokenType::TypeKeyword)) return Error;
|
||||||
CHECK(SkipWhitespace());
|
CHECK(SkipWhitespace());
|
||||||
|
|
||||||
if (Definitions.TypeCount >= DefinitionFile::MaxTypes)
|
if (Definitions.TypeCount >= Def::DefinitionFile::MaxTypes)
|
||||||
{
|
{
|
||||||
LOG_ERROR(Line, "Too many types!");
|
LOG_ERROR(Line, "Too many types!");
|
||||||
ErrorLine();
|
ErrorLine();
|
||||||
return Error;
|
return Error;
|
||||||
}
|
}
|
||||||
Def::Type& t = Definitions.Types[Definitions.TypeCount];
|
Def::Type& t = Definitions.Types[Definitions.TypeCount];
|
||||||
CHECK(ReadName(t.Name));
|
for (int32_t i = 0; i < Def::MaxFields; ++i)
|
||||||
|
{
|
||||||
|
bx::strCopy(t.FieldValues[i], sizeof(t.FieldValues[i]), "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(ReadName(t.Name));
|
||||||
CHECK(SkipWhitespace());
|
CHECK(SkipWhitespace());
|
||||||
|
|
||||||
CHECK(ExpectChar("{"));
|
CHECK(ExpectChar("{"));
|
||||||
CHECK(SkipWhitespace());
|
CHECK(SkipWhitespace());
|
||||||
|
|
||||||
@@ -336,7 +208,7 @@ Parser::Result Parser::HandleType()
|
|||||||
bool NewLine = false;
|
bool NewLine = false;
|
||||||
CHECK(SkipWhitespace(&NewLine));
|
CHECK(SkipWhitespace(&NewLine));
|
||||||
|
|
||||||
if (!NewLine)
|
while (!NewLine)
|
||||||
{
|
{
|
||||||
Result Res;
|
Result Res;
|
||||||
if (CmpAdvance("Arr", Res, true) && Res == Result::OK)
|
if (CmpAdvance("Arr", Res, true) && Res == Result::OK)
|
||||||
@@ -345,9 +217,37 @@ Parser::Result Parser::HandleType()
|
|||||||
CHECK(ReadUint(t.FieldArraySizes[t.FieldCount]));
|
CHECK(ReadUint(t.FieldArraySizes[t.FieldCount]));
|
||||||
CHECK(ExpectChar(")"));
|
CHECK(ExpectChar(")"));
|
||||||
}
|
}
|
||||||
|
else if (CmpAdvance("ArrDynamic", Res, true) && Res == Result::OK)
|
||||||
|
{
|
||||||
|
CHECK(ExpectChar("("));
|
||||||
|
CHECK(ReadUint(t.FieldArraySizes[t.FieldCount]));
|
||||||
|
t.FieldFlags[t.FieldCount] = Def::ETypeFieldFlags::DynamicArray;
|
||||||
|
CHECK(ExpectChar(")"));
|
||||||
|
}
|
||||||
|
else if (CmpAdvance("Default", Res, true) && Res == OK)
|
||||||
|
{
|
||||||
|
CHECK(ExpectChar("("));
|
||||||
|
CHECK(ExpectChar("\""));
|
||||||
|
|
||||||
|
int32_t Remaining = bx::min(GetRemaining(), (int32_t)BX_COUNTOF(Def::Type::FieldValues[0]));
|
||||||
|
for (int32_t i = 0; i < Remaining; ++i)
|
||||||
|
{
|
||||||
|
if (*ReadPtr != '\\' && CmpAdvance("\"", Res)) break;
|
||||||
|
t.FieldValues[t.FieldCount][i] = *ReadPtr;
|
||||||
|
ReadPtr++;
|
||||||
|
}
|
||||||
|
if (Res != OK) return Res;
|
||||||
|
CHECK(ExpectChar(")"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR(Line, "Unknown token!");
|
||||||
|
ErrorLine();
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
CHECK(SkipWhitespace(&NewLine));
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(SkipWhitespace());
|
|
||||||
t.FieldCount++;
|
t.FieldCount++;
|
||||||
}
|
}
|
||||||
Definitions.TypeCount++;
|
Definitions.TypeCount++;
|
||||||
@@ -360,7 +260,7 @@ Parser::Result Parser::HandleEnum()
|
|||||||
if (!Stack.Push(TokenType::EnumKeyword)) return Error;
|
if (!Stack.Push(TokenType::EnumKeyword)) return Error;
|
||||||
CHECK(SkipWhitespace());
|
CHECK(SkipWhitespace());
|
||||||
|
|
||||||
if (Definitions.EnumCount >= DefinitionFile::MaxTypes)
|
if (Definitions.EnumCount >= Def::DefinitionFile::MaxTypes)
|
||||||
{
|
{
|
||||||
LOG_ERROR(Line, "Too many enums!");
|
LOG_ERROR(Line, "Too many enums!");
|
||||||
ErrorLine();
|
ErrorLine();
|
||||||
@@ -373,12 +273,21 @@ Parser::Result Parser::HandleEnum()
|
|||||||
if (CmpAdvance("(", Res) && Res == OK)
|
if (CmpAdvance("(", Res) && Res == OK)
|
||||||
{
|
{
|
||||||
CHECK(SkipWhitespace());
|
CHECK(SkipWhitespace());
|
||||||
Def::FieldType field;
|
CHECK(ReadDefinedFieldType(e.EnumType));
|
||||||
CHECK(ReadNativeFieldType(field));
|
|
||||||
CHECK(SkipWhitespace());
|
CHECK(SkipWhitespace());
|
||||||
CHECK(ExpectChar(")"));
|
CHECK(ExpectChar(")"));
|
||||||
CHECK(SkipWhitespace());
|
CHECK(SkipWhitespace());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e.EnumType = {(uint16_t)Gen::KnownType::i32, Def::EFieldType::DefinedClass};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CmpAdvance("Flags", Res) && Res == OK)
|
||||||
|
{
|
||||||
|
e.EnumFlags = (Def::EEnumFlags)((uint32_t)e.EnumFlags | (uint32_t)Def::EEnumFlags::FlagsEnum);
|
||||||
|
CHECK(SkipWhitespace());
|
||||||
|
}
|
||||||
|
|
||||||
CHECK(ExpectChar("{"));
|
CHECK(ExpectChar("{"));
|
||||||
CHECK(SkipWhitespace());
|
CHECK(SkipWhitespace());
|
||||||
@@ -462,29 +371,13 @@ Parser::Result Parser::ReadTypeToken()
|
|||||||
{
|
{
|
||||||
Result Res = OK;
|
Result Res = OK;
|
||||||
Def::Type& t = Definitions.Types[Definitions.TypeCount];
|
Def::Type& t = Definitions.Types[Definitions.TypeCount];
|
||||||
if (ReadNativeFieldType(t.FieldTypes[t.FieldCount]) == OK) return OK;
|
|
||||||
if (ReadDefinedFieldType(t.FieldTypes[t.FieldCount]) == OK) return OK;
|
if (ReadDefinedFieldType(t.FieldTypes[t.FieldCount]) == OK) return OK;
|
||||||
LOG_ERROR(Line, "Unknown type token!");
|
LOG_ERROR(Line, "Unknown type token!");
|
||||||
ErrorLine();
|
ErrorLine();
|
||||||
return Error;
|
return Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser::Result Parser::ReadNativeFieldType(Def::FieldType& FieldT)
|
Parser::Result Parser::ReadDefinedFieldType(Def::TypeRef& FieldT)
|
||||||
{
|
|
||||||
Result Res = OK;
|
|
||||||
for (int32_t i = 0; i < Generated::KnownType::EntryCount; ++i)
|
|
||||||
{
|
|
||||||
if (CmpAdvance(Generated::KnownType::EntryNames[i], Res, true) && Res == OK)
|
|
||||||
{
|
|
||||||
FieldT.FieldKind = Def::EFieldType::Native;
|
|
||||||
FieldT.Native = Generated::KnownType::Enum(i);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
Parser::Result Parser::ReadDefinedFieldType(Def::FieldType& FieldT)
|
|
||||||
{
|
{
|
||||||
Result Res = OK;
|
Result Res = OK;
|
||||||
for (uint16_t i = 0; i < Definitions.TypeCount; ++i)
|
for (uint16_t i = 0; i < Definitions.TypeCount; ++i)
|
||||||
@@ -529,9 +422,8 @@ Parser::Result Parser::ReadOptionalEnumValues(Def::Enum& Enum, int32_t EntryIdx)
|
|||||||
int32_t Remaining = GetRemaining();
|
int32_t Remaining = GetRemaining();
|
||||||
for (int32_t i = 0; i < Remaining; ++i)
|
for (int32_t i = 0; i < Remaining; ++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (CmpAdvance("\"", Res)) break;
|
if (CmpAdvance("\"", Res)) break;
|
||||||
Enum.ExtraStringFields[extraIdx][EntryIdx][i] = *ReadPtr;
|
Enum.ExtraStringFields[EntryIdx][extraIdx][i] = *ReadPtr;
|
||||||
ReadPtr++;
|
ReadPtr++;
|
||||||
}
|
}
|
||||||
if (Res != OK) return Res;
|
if (Res != OK) return Res;
|
||||||
@@ -552,22 +444,65 @@ int32_t Parser::GetRemaining()
|
|||||||
{
|
{
|
||||||
return &Buffer[BufferSize] - ReadPtr;
|
return &Buffer[BufferSize] - ReadPtr;
|
||||||
}
|
}
|
||||||
|
uint32_t Parser::CalculateTypeHash(const Def::Type& t)
|
||||||
char WriteBuffer[1024 * 1024]{0};
|
|
||||||
void TemplateWriter::Write(const char* Template, ...)
|
|
||||||
{
|
{
|
||||||
va_list ArgList;
|
bx::HashMurmur2A hash;
|
||||||
va_start(ArgList, Template);
|
hash.begin();
|
||||||
int32_t Count = bx::vsnprintf(WriteBuffer, sizeof(WriteBuffer), Template, ArgList);
|
for (int32_t i = 0; i < t.FieldCount; ++i)
|
||||||
va_end(ArgList);
|
{
|
||||||
bx::write(&Writer, WriteBuffer, Count, &Error);
|
hash.add(t.FieldNames[i]);
|
||||||
|
hash.add(t.FieldArraySizes[i]);
|
||||||
|
|
||||||
|
Def::EFieldType fieldType = t.FieldTypes[i].FieldKind;
|
||||||
|
if (fieldType == Def::EFieldType::DefinedClass)
|
||||||
|
{
|
||||||
|
Def::Type& dependType = Definitions.Types[t.FieldTypes[i].TypeIdx];
|
||||||
|
if (dependType.Hash == 0)
|
||||||
|
{
|
||||||
|
CalculateTypeHash(dependType);
|
||||||
|
}
|
||||||
|
hash.add(dependType.Hash);
|
||||||
|
}
|
||||||
|
else if (fieldType == Def::EFieldType::DefinedEnum)
|
||||||
|
{
|
||||||
|
hash.add(Definitions.Enums[t.FieldTypes[i].TypeIdx].Hash);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR(Line, "TODO!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hash.end();
|
||||||
|
}
|
||||||
|
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(Definitions.Types[e.EnumType.TypeIdx].Hash); // TODO: add enum entries?
|
||||||
|
e.Hash = hash.end();
|
||||||
|
}
|
||||||
|
for (int32_t i = 0; i < Definitions.TypeCount; ++i)
|
||||||
|
{
|
||||||
|
Def::Type& t = Definitions.Types[i];
|
||||||
|
if (t.Hash == 0)
|
||||||
|
{
|
||||||
|
t.Hash = CalculateTypeHash(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser TestParser;
|
Parser FileParser;
|
||||||
|
CppFileWriter Writer;
|
||||||
int main(int argc, const char** argv)
|
int main(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
LOG(0, "Hello");
|
|
||||||
|
|
||||||
if (argc != 3)
|
if (argc != 3)
|
||||||
{
|
{
|
||||||
LOG(0, "invalid number of arguments!");
|
LOG(0, "invalid number of arguments!");
|
||||||
@@ -584,8 +519,9 @@ int main(int argc, const char** argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestParser.BufferSize = bx::read(&reader, TestParser.Buffer, Parser::MaxBufferSize, &error);
|
LOG(0, "Reading from %s", defPath.getCPtr());
|
||||||
Parser::Result Res = TestParser.Parse();
|
FileParser.BufferSize = bx::read(&reader, FileParser.Buffer, Parser::MaxBufferSize, &error);
|
||||||
|
Parser::Result Res = FileParser.Parse();
|
||||||
|
|
||||||
if (Res == Parser::OK)
|
if (Res == Parser::OK)
|
||||||
{
|
{
|
||||||
@@ -597,7 +533,9 @@ int main(int argc, const char** argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
LOG(0, "Finished parsing!");
|
LOG(0, "Finished parsing!");
|
||||||
TestParser.Definitions.GenerateCpp(outPath);
|
|
||||||
|
FileParser.CalculateHashes();
|
||||||
|
Writer.GenerateCpp(outPath, FileParser.Definitions);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "bx/string.h"
|
||||||
#include <bx/file.h>
|
#include <bx/file.h>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "Gen/Generated.h"
|
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "bx/string.h"
|
#include "TypeDef.h"
|
||||||
|
|
||||||
enum class TokenType : uint8_t
|
enum class TokenType : uint8_t
|
||||||
{
|
{
|
||||||
@@ -50,73 +49,6 @@ struct ParseStack
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TemplateWriter
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
bx::WriterI& Writer;
|
|
||||||
bx::Error& Error;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TemplateWriter(bx::WriterI& W, bx::Error& E) : Writer(W), Error(E)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Write(const char* Template, ...);
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Def
|
|
||||||
{
|
|
||||||
constexpr int32_t MaxNameLength = 64;
|
|
||||||
constexpr int32_t MaxFields = 64;
|
|
||||||
constexpr int32_t MaxExtraEnumFields = 1;
|
|
||||||
enum class EFieldType
|
|
||||||
{
|
|
||||||
Native,
|
|
||||||
DefinedClass,
|
|
||||||
DefinedEnum
|
|
||||||
};
|
|
||||||
struct FieldType
|
|
||||||
{
|
|
||||||
EFieldType FieldKind = EFieldType::Native;
|
|
||||||
Generated::KnownType::Enum Native = Generated::KnownType::Enum::i32;
|
|
||||||
uint16_t TypeIdx = UINT16_MAX;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Type
|
|
||||||
{
|
|
||||||
int32_t FieldCount = 0;
|
|
||||||
FieldType FieldTypes[MaxFields];
|
|
||||||
char FieldNames[MaxFields][MaxNameLength];
|
|
||||||
uint32_t FieldArraySizes[MaxFields]{0};
|
|
||||||
char Name[MaxNameLength]{0};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Enum
|
|
||||||
{
|
|
||||||
FieldType 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};
|
|
||||||
};
|
|
||||||
} // namespace Def
|
|
||||||
|
|
||||||
struct DefinitionFile
|
|
||||||
{
|
|
||||||
static constexpr int32_t MaxTypes = 256;
|
|
||||||
void PrintTypeName(char* buf, int32_t bufSize, const Def::FieldType& type);
|
|
||||||
void WriteEnums(TemplateWriter& Template);
|
|
||||||
void WriteTypes(TemplateWriter& Template);
|
|
||||||
void GenerateCpp(const bx::FilePath& outDir);
|
|
||||||
|
|
||||||
Def::Type Types[MaxTypes];
|
|
||||||
uint16_t TypeCount = 0;
|
|
||||||
Def::Enum Enums[MaxTypes];
|
|
||||||
int32_t EnumCount = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Parser
|
class Parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -139,11 +71,12 @@ class Parser
|
|||||||
char* ReadPtr = &Buffer[0];
|
char* ReadPtr = &Buffer[0];
|
||||||
uint32_t Line = 0;
|
uint32_t Line = 0;
|
||||||
|
|
||||||
DefinitionFile Definitions;
|
Def::DefinitionFile Definitions;
|
||||||
ParseStack Stack;
|
ParseStack Stack;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Result Parse();
|
Result Parse();
|
||||||
|
void CalculateHashes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32_t GetRemaining();
|
int32_t GetRemaining();
|
||||||
@@ -153,15 +86,17 @@ class Parser
|
|||||||
Result ExpectChar(bx::StringView expect);
|
Result ExpectChar(bx::StringView expect);
|
||||||
Result Advance(int32_t Amount);
|
Result Advance(int32_t Amount);
|
||||||
Result HandleFileStart();
|
Result HandleFileStart();
|
||||||
|
Result LoadNativeTypes();
|
||||||
Result HandleType();
|
Result HandleType();
|
||||||
Result HandleEnum();
|
Result HandleEnum();
|
||||||
Result ReadName(char* Target);
|
Result ReadName(char* Target);
|
||||||
Result ReadUint(uint32_t& Out);
|
Result ReadUint(uint32_t& Out);
|
||||||
Result ReadNativeFieldType(Def::FieldType& FieldT);
|
Result ReadDefinedFieldType(Def::TypeRef& FieldT);
|
||||||
Result ReadDefinedFieldType(Def::FieldType& FieldT);
|
|
||||||
Result ReadTypeToken();
|
Result ReadTypeToken();
|
||||||
Result ReadOptionalEnumValues(Def::Enum& Enum, int32_t EntryIdx);
|
Result ReadOptionalEnumValues(Def::Enum& Enum, int32_t EntryIdx);
|
||||||
|
|
||||||
|
uint32_t CalculateTypeHash(const Def::Type& t);
|
||||||
|
|
||||||
void ErrorLine()
|
void ErrorLine()
|
||||||
{
|
{
|
||||||
char line[64]{0};
|
char line[64]{0};
|
||||||
|
|||||||
79
src/dependency/minidef/src/TypeDef.h
Normal file
79
src/dependency/minidef/src/TypeDef.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Def
|
||||||
|
{
|
||||||
|
constexpr int32_t MaxNameLength = 64;
|
||||||
|
constexpr int32_t MaxFields = 64;
|
||||||
|
constexpr int32_t MaxExtraEnumFields = 2;
|
||||||
|
|
||||||
|
enum class EFieldType : uint8_t
|
||||||
|
{
|
||||||
|
DefinedClass,
|
||||||
|
DefinedEnum
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ETypeFlags : uint32_t
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DefinitionFile
|
||||||
|
{
|
||||||
|
static constexpr int32_t MaxTypes = 256;
|
||||||
|
Def::Type Types[MaxTypes];
|
||||||
|
uint16_t TypeCount = 0;
|
||||||
|
Def::Enum Enums[MaxTypes];
|
||||||
|
int32_t EnumCount = 0;
|
||||||
|
};
|
||||||
|
} // namespace Def
|
||||||
1
src/dependency/tracy
Submodule
1
src/dependency/tracy
Submodule
Submodule src/dependency/tracy added at 5d542dc09f
@@ -96,16 +96,19 @@ struct SharedDevData
|
|||||||
char ShaderLog[2048]{0};
|
char ShaderLog[2048]{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MemoryArena
|
||||||
|
{
|
||||||
|
uint8_t* Base = nullptr;
|
||||||
|
uint64_t Used = 0;
|
||||||
|
uint64_t MaxSize = 0;
|
||||||
|
uint64_t LastAllocSize = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct GameData
|
struct GameData
|
||||||
{
|
{
|
||||||
void* PermanentStorage = nullptr;
|
MemoryArena PermanentArena;
|
||||||
uint64_t PermanentStorageSize = 0;
|
MemoryArena EntityArena;
|
||||||
|
MemoryArena TransientArena;
|
||||||
void* EntityStorage = nullptr;
|
|
||||||
uint64_t EntityStorageSize = 0;
|
|
||||||
|
|
||||||
void* TransientStorage = nullptr;
|
|
||||||
uint64_t TransientStorageSize = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SharedData
|
struct SharedData
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "bx/filepath.h"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -14,9 +15,7 @@
|
|||||||
#include "Shared.h"
|
#include "Shared.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
|
|
||||||
// #define VISUAL_STUDIO
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
#ifdef VISUAL_STUDIO
|
|
||||||
constexpr const char* DLLPath = "PuzGame.dll";
|
constexpr const char* DLLPath = "PuzGame.dll";
|
||||||
constexpr const wchar_t* DLLWatch = L"PuzGame2.dll";
|
constexpr const wchar_t* DLLWatch = L"PuzGame2.dll";
|
||||||
#else
|
#else
|
||||||
@@ -24,6 +23,10 @@ constexpr const char* DLLPath = "libPuzGame.dll";
|
|||||||
constexpr const wchar_t* DLLWatch = L"libPuzGame2.dll";
|
constexpr const wchar_t* DLLWatch = L"libPuzGame2.dll";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
constexpr uint64_t KB = 1024LLU;
|
||||||
|
constexpr uint64_t MB = 1024LLU * 1024LLU;
|
||||||
|
constexpr uint64_t GB = 1024LLU * 1024LLU * 1024LLU;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bx::AllocatorI* defaultAllocator = new bx::DefaultAllocator{};
|
bx::AllocatorI* defaultAllocator = new bx::DefaultAllocator{};
|
||||||
@@ -99,6 +102,10 @@ void FileChangeCheck(HANDLE dirHandle, FileChangeType changeType, const wchar_t*
|
|||||||
{
|
{
|
||||||
if (compName == nullptr || compName[0] == 0 || wcscmp(notifyData->FileName, compName) == 0)
|
if (compName == nullptr || compName[0] == 0 || wcscmp(notifyData->FileName, compName) == 0)
|
||||||
{
|
{
|
||||||
|
char buf[1024]{0};
|
||||||
|
wcstombs(buf, notifyData->FileName, sizeof(buf));
|
||||||
|
printf("file change of type %u: %s\n", changeType, buf);
|
||||||
|
|
||||||
FileChangeNotification notif;
|
FileChangeNotification notif;
|
||||||
wcscpy(notif.FileName, notifyData->FileName);
|
wcscpy(notif.FileName, notifyData->FileName);
|
||||||
if (changeType == FileChangeType::DLL)
|
if (changeType == FileChangeType::DLL)
|
||||||
@@ -107,23 +114,25 @@ void FileChangeCheck(HANDLE dirHandle, FileChangeType changeType, const wchar_t*
|
|||||||
}
|
}
|
||||||
else if (changeType == FileChangeType::Shader)
|
else if (changeType == FileChangeType::Shader)
|
||||||
{
|
{
|
||||||
std::system("shadercompile.bat > shadercompile.log");
|
printf("shader source change!\n");
|
||||||
|
std::system("powershell.exe .\\shadercompile.ps1 > shadercompile.log");
|
||||||
Sleep(1000);
|
Sleep(1000);
|
||||||
std::ifstream shaderLogFile("shadercompile.log");
|
std::ifstream shaderLogFile("shadercompile.log");
|
||||||
if (shaderLogFile.is_open())
|
if (shaderLogFile.is_open())
|
||||||
{
|
{
|
||||||
shaderLogFile.seekg(0, std::ios::end);
|
shaderLogFile.seekg(0, std::ios::end);
|
||||||
uint32_t size = bx::min(BX_COUNTOF(Shared.Dev.ShaderLog), shaderLogFile.tellg());
|
uint32_t size = bx::min(BX_COUNTOF(Shared.Dev.ShaderLog) - 1, shaderLogFile.tellg());
|
||||||
shaderLogFile.seekg(0);
|
shaderLogFile.seekg(0);
|
||||||
shaderLogFile.read(Shared.Dev.ShaderLog, size);
|
shaderLogFile.read(Shared.Dev.ShaderLog, size);
|
||||||
shaderLogFile.close();
|
shaderLogFile.close();
|
||||||
|
Shared.Dev.ShaderLog[size] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (changeType == FileChangeType::CompiledShader)
|
else if (changeType == FileChangeType::CompiledShader)
|
||||||
{
|
{
|
||||||
|
printf("compiled shader change!\n");
|
||||||
DevData.FileWatcher.ShaderQueue.push(¬if);
|
DevData.FileWatcher.ShaderQueue.push(¬if);
|
||||||
}
|
}
|
||||||
printf("detected file change of type %u!\n", changeType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,40 +189,52 @@ bool ReloadDLL()
|
|||||||
{
|
{
|
||||||
FreeLibrary(DevData.GameLib);
|
FreeLibrary(DevData.GameLib);
|
||||||
}
|
}
|
||||||
#ifdef VISUAL_STUDIO
|
|
||||||
if (!CopyFile("PuzGame2.dll", "PuzGame.dll", false))
|
char exePath[1024];
|
||||||
{
|
GetModuleFileName(nullptr, exePath, BX_COUNTOF(exePath));
|
||||||
printf("Failed to copy game DLL!\n");
|
bx::FilePath exeFilePath{exePath};
|
||||||
return false;
|
bx::FilePath exeDir{exeFilePath.getPath()};
|
||||||
}
|
bx::FilePath libPath = exeDir;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
libPath.join("PuzGame.dll");
|
||||||
#else
|
#else
|
||||||
if (!CopyFile("cmake-build\\libPuzGame2.dll", "cmake-build\\libPuzGame.dll", false))
|
libPath.join("libPuzGame.dll");
|
||||||
|
#endif
|
||||||
|
bx::FilePath lib2Path = exeDir;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
lib2Path.join("PuzGame2.dll");
|
||||||
|
#else
|
||||||
|
lib2Path.join("libPuzGame2.dll");
|
||||||
|
#endif
|
||||||
|
if (!CopyFile(lib2Path.getCPtr(), libPath.getCPtr(), false))
|
||||||
{
|
{
|
||||||
printf("Failed to copy game DLL!\n");
|
DWORD err = GetLastError();
|
||||||
|
printf("[%lu] Failed to copy game DLL from %s to %s!\n", err, libPath.getCPtr(), lib2Path.getCPtr());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
HMODULE gameLibReloaded = LoadLibraryEx(DLLPath, NULL, 0);
|
HMODULE gameLibReloaded = LoadLibraryEx(DLLPath, NULL, 0);
|
||||||
if (gameLibReloaded == NULL)
|
if (gameLibReloaded == NULL)
|
||||||
{
|
{
|
||||||
printf("Failed to load game DLL from %s!\n", DLLPath);
|
DWORD err = GetLastError();
|
||||||
|
printf("[%lu] Failed to load game DLL from %s!\n", err, DLLPath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DevData.GameLib = gameLibReloaded;
|
DevData.GameLib = gameLibReloaded;
|
||||||
|
|
||||||
#ifdef VISUAL_STUDIO
|
#ifdef _MSC_VER
|
||||||
Startup StartupReloaded = (Startup)GetProcAddress(DevData.GameLib, "?Setup@Game@@YAXPEAX@Z");
|
Startup StartupReloaded = (Startup)GetProcAddress(DevData.GameLib, "?Setup@Game@@YAXAEAUSharedData@@@Z");
|
||||||
#else
|
#else
|
||||||
Startup StartupReloaded = (Startup)GetProcAddress(DevData.GameLib, "_ZN4Game5SetupER10SharedData");
|
Startup StartupReloaded = (Startup)GetProcAddress(DevData.GameLib, "_ZN4Game5SetupER10SharedData");
|
||||||
#endif
|
#endif
|
||||||
if (StartupReloaded == NULL)
|
if (StartupReloaded == NULL)
|
||||||
{
|
{
|
||||||
printf("Failed to load startup function from game DLL!\n");
|
DWORD err = GetLastError();
|
||||||
|
printf("[%lu] Failed to load startup function from game DLL!\n", err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VISUAL_STUDIO
|
#ifdef _MSC_VER
|
||||||
Update UpdateReloaded = (Update)GetProcAddress(DevData.GameLib, "?Update@Game@@YAXXZ");
|
Update UpdateReloaded = (Update)GetProcAddress(DevData.GameLib, "?Update@Game@@YAXXZ");
|
||||||
#else
|
#else
|
||||||
Update UpdateReloaded = (Update)GetProcAddress(DevData.GameLib, "_ZN4Game6UpdateEv");
|
Update UpdateReloaded = (Update)GetProcAddress(DevData.GameLib, "_ZN4Game6UpdateEv");
|
||||||
@@ -224,7 +245,7 @@ bool ReloadDLL()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VISUAL_STUDIO
|
#ifdef _MSC_VER
|
||||||
Shutdown ShutdownReloaded = (Shutdown)GetProcAddress(DevData.GameLib, "?Shutdown@Game@@YAXXZ");
|
Shutdown ShutdownReloaded = (Shutdown)GetProcAddress(DevData.GameLib, "?Shutdown@Game@@YAXXZ");
|
||||||
#else
|
#else
|
||||||
Shutdown ShutdownReloaded = (Shutdown)GetProcAddress(DevData.GameLib, "_ZN4Game8ShutdownEv");
|
Shutdown ShutdownReloaded = (Shutdown)GetProcAddress(DevData.GameLib, "_ZN4Game8ShutdownEv");
|
||||||
@@ -243,6 +264,15 @@ bool ReloadDLL()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InitMemoryArena(MemoryArena& arena, uint64_t size)
|
||||||
|
{
|
||||||
|
arena.MaxSize = size;
|
||||||
|
arena.Base = reinterpret_cast<uint8_t*>(
|
||||||
|
VirtualAllocEx(GetCurrentProcess(), NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||||
|
arena.Used = 0;
|
||||||
|
arena.LastAllocSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
char PathBuf[512]{0};
|
char PathBuf[512]{0};
|
||||||
@@ -262,7 +292,12 @@ int main()
|
|||||||
DevData.FileWatcher.ShaderWatcher.ChangeType = FileChangeType::Shader;
|
DevData.FileWatcher.ShaderWatcher.ChangeType = FileChangeType::Shader;
|
||||||
DevData.FileWatcher.CompiledShaderWatcher.ChangeType = FileChangeType::CompiledShader;
|
DevData.FileWatcher.CompiledShaderWatcher.ChangeType = FileChangeType::CompiledShader;
|
||||||
|
|
||||||
bx::strCopy(DevData.FileWatcher.DLLWatcher.DirPath, sizeof(DevData.FileWatcher.DLLWatcher.DirPath), "cmake-build");
|
char exePath[1024];
|
||||||
|
GetModuleFileName(nullptr, exePath, BX_COUNTOF(exePath));
|
||||||
|
bx::FilePath exeFilePath{exePath};
|
||||||
|
bx::FilePath exeDir{exeFilePath.getPath()};
|
||||||
|
bx::strCopy(
|
||||||
|
DevData.FileWatcher.DLLWatcher.DirPath, sizeof(DevData.FileWatcher.DLLWatcher.DirPath), exeDir.getCPtr());
|
||||||
bx::strCopy(
|
bx::strCopy(
|
||||||
DevData.FileWatcher.ShaderWatcher.DirPath, sizeof(DevData.FileWatcher.ShaderWatcher.DirPath), "game/shaders");
|
DevData.FileWatcher.ShaderWatcher.DirPath, sizeof(DevData.FileWatcher.ShaderWatcher.DirPath), "game/shaders");
|
||||||
bx::strCopy(DevData.FileWatcher.CompiledShaderWatcher.DirPath,
|
bx::strCopy(DevData.FileWatcher.CompiledShaderWatcher.DirPath,
|
||||||
@@ -279,15 +314,9 @@ int main()
|
|||||||
HANDLE compiledShaderThread =
|
HANDLE compiledShaderThread =
|
||||||
CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.CompiledShaderWatcher, 0, &fileWatcherThreadId);
|
CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.CompiledShaderWatcher, 0, &fileWatcherThreadId);
|
||||||
|
|
||||||
Shared.Game.PermanentStorageSize = 1024 * 1024;
|
InitMemoryArena(Shared.Game.PermanentArena, MB);
|
||||||
Shared.Game.PermanentStorage = VirtualAllocEx(
|
InitMemoryArena(Shared.Game.EntityArena, MB);
|
||||||
GetCurrentProcess(), NULL, Shared.Game.PermanentStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
InitMemoryArena(Shared.Game.TransientArena, 2 * GB);
|
||||||
Shared.Game.EntityStorageSize = 1024 * 1024;
|
|
||||||
Shared.Game.EntityStorage = VirtualAllocEx(
|
|
||||||
GetCurrentProcess(), NULL, Shared.Game.EntityStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
||||||
Shared.Game.TransientStorageSize = 1024 * 1024 * 100;
|
|
||||||
Shared.Game.TransientStorage = VirtualAllocEx(
|
|
||||||
GetCurrentProcess(), NULL, Shared.Game.TransientStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
||||||
StartupFunc(Shared);
|
StartupFunc(Shared);
|
||||||
|
|
||||||
bool isRunning = true;
|
bool isRunning = true;
|
||||||
|
|||||||
158
src/game/Entity.h
Normal file
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
|
||||||
515
src/game/Gen.cpp
Normal file
515
src/game/Gen.cpp
Normal file
@@ -0,0 +1,515 @@
|
|||||||
|
#include "Gen.h"
|
||||||
|
|
||||||
|
#include "bx/math.h"
|
||||||
|
|
||||||
|
namespace Gen
|
||||||
|
{
|
||||||
|
bool IsValid(const ModelHandle& h)
|
||||||
|
{
|
||||||
|
return h.ModelIdx != UINT16_MAX && IsValid(h.Asset);
|
||||||
|
}
|
||||||
|
bool IsValid(const AssetHandle& h)
|
||||||
|
{
|
||||||
|
return h.Idx != UINT32_MAX;
|
||||||
|
}
|
||||||
|
bool IsValid(const TextureHandle& h)
|
||||||
|
{
|
||||||
|
return h.TextureIdx != UINT16_MAX && IsValid(h.Asset);
|
||||||
|
}
|
||||||
|
bool operator==(const AssetHandle& lhs, const AssetHandle& rhs)
|
||||||
|
{
|
||||||
|
return lhs.Idx == rhs.Idx;
|
||||||
|
}
|
||||||
|
bool operator==(const ModelHandle& lhs, const ModelHandle& rhs)
|
||||||
|
{
|
||||||
|
if (!IsValid(lhs) || !IsValid(rhs)) return IsValid(lhs) == IsValid(rhs);
|
||||||
|
return lhs.ModelIdx == rhs.ModelIdx && lhs.Asset == rhs.Asset;
|
||||||
|
}
|
||||||
|
PuzPos operator+=(PuzPos lhs, const PuzPos& rhs)
|
||||||
|
{
|
||||||
|
lhs.X += rhs.X;
|
||||||
|
lhs.Y += rhs.Y;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
PuzPos operator+(PuzPos lhs, const PuzPos& rhs)
|
||||||
|
{
|
||||||
|
PuzPos res = lhs;
|
||||||
|
res.X += rhs.X;
|
||||||
|
res.Y += rhs.Y;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PuzPos operator-=(PuzPos lhs, const PuzPos& rhs)
|
||||||
|
{
|
||||||
|
lhs.X -= rhs.X;
|
||||||
|
lhs.Y -= rhs.Y;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
PuzPos operator-(PuzPos lhs, const PuzPos& rhs)
|
||||||
|
{
|
||||||
|
PuzPos res = lhs;
|
||||||
|
res.X += rhs.X;
|
||||||
|
res.Y += rhs.Y;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vec4
|
||||||
|
Vec4& operator+=(Vec4& lhs, const Vec4& rhs)
|
||||||
|
{
|
||||||
|
lhs.x += rhs.x;
|
||||||
|
lhs.y += rhs.y;
|
||||||
|
lhs.z += rhs.z;
|
||||||
|
lhs.w += rhs.w;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec4 operator+(const Vec4& lhs, const Vec4& rhs)
|
||||||
|
{
|
||||||
|
Vec4 out = lhs;
|
||||||
|
return out += rhs;
|
||||||
|
}
|
||||||
|
Vec4& operator+=(Vec4& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x += rhs;
|
||||||
|
lhs.y += rhs;
|
||||||
|
lhs.z += rhs;
|
||||||
|
lhs.w += rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec4 operator+(Vec4& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec4 out = lhs;
|
||||||
|
return out += rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec4& operator-=(Vec4& lhs, const Vec4& rhs)
|
||||||
|
{
|
||||||
|
lhs.x -= rhs.x;
|
||||||
|
lhs.y -= rhs.y;
|
||||||
|
lhs.z -= rhs.z;
|
||||||
|
lhs.w -= rhs.w;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec4 operator-(const Vec4& lhs, const Vec4& rhs)
|
||||||
|
{
|
||||||
|
Vec4 out = lhs;
|
||||||
|
return out -= rhs;
|
||||||
|
}
|
||||||
|
Vec4& operator-=(Vec4& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x -= rhs;
|
||||||
|
lhs.y -= rhs;
|
||||||
|
lhs.z -= rhs;
|
||||||
|
lhs.w -= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec4 operator-(const Vec4& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec4 out = lhs;
|
||||||
|
return out -= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec4& operator*=(Vec4& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x *= rhs;
|
||||||
|
lhs.y *= rhs;
|
||||||
|
lhs.z *= rhs;
|
||||||
|
lhs.w *= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec4 operator*(const Vec4& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec4 out = lhs;
|
||||||
|
return out *= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec4& operator/=(Vec4& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x /= rhs;
|
||||||
|
lhs.y /= rhs;
|
||||||
|
lhs.z /= rhs;
|
||||||
|
lhs.w /= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec4 operator/(const Vec4& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec4 out = lhs;
|
||||||
|
return out /= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vec3
|
||||||
|
Vec3& operator+=(Vec3& lhs, const Vec3& rhs)
|
||||||
|
{
|
||||||
|
lhs.x += rhs.x;
|
||||||
|
lhs.y += rhs.y;
|
||||||
|
lhs.z += rhs.z;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec3 operator+(const Vec3& lhs, const Vec3& rhs)
|
||||||
|
{
|
||||||
|
Vec3 out = lhs;
|
||||||
|
return out += rhs;
|
||||||
|
}
|
||||||
|
Vec3& operator+=(Vec3& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x += rhs;
|
||||||
|
lhs.y += rhs;
|
||||||
|
lhs.z += rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec3 operator+(Vec3& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec3 out = lhs;
|
||||||
|
return out += rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3& operator-=(Vec3& lhs, const Vec3& rhs)
|
||||||
|
{
|
||||||
|
lhs.x -= rhs.x;
|
||||||
|
lhs.y -= rhs.y;
|
||||||
|
lhs.z -= rhs.z;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec3 operator-(const Vec3& lhs, const Vec3& rhs)
|
||||||
|
{
|
||||||
|
Vec3 out = lhs;
|
||||||
|
return out -= rhs;
|
||||||
|
}
|
||||||
|
Vec3& operator-=(Vec3& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x -= rhs;
|
||||||
|
lhs.y -= rhs;
|
||||||
|
lhs.z -= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec3 operator-(const Vec3& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec3 out = lhs;
|
||||||
|
return out -= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3& operator*=(Vec3& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x *= rhs;
|
||||||
|
lhs.y *= rhs;
|
||||||
|
lhs.z *= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec3 operator*(const Vec3& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec3 out = lhs;
|
||||||
|
return out *= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3& operator/=(Vec3& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x /= rhs;
|
||||||
|
lhs.y /= rhs;
|
||||||
|
lhs.z /= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec3 operator/(const Vec3& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec3 out = lhs;
|
||||||
|
return out /= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vec2
|
||||||
|
Vec2& operator+=(Vec2& lhs, const Vec2& rhs)
|
||||||
|
{
|
||||||
|
lhs.x += rhs.x;
|
||||||
|
lhs.y += rhs.y;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec2 operator+(const Vec2& lhs, const Vec2& rhs)
|
||||||
|
{
|
||||||
|
Vec2 out = lhs;
|
||||||
|
return out += rhs;
|
||||||
|
}
|
||||||
|
Vec2& operator+=(Vec2& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x += rhs;
|
||||||
|
lhs.y += rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec2 operator+(Vec2& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec2 out = lhs;
|
||||||
|
return out += rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2& operator-=(Vec2& lhs, const Vec2& rhs)
|
||||||
|
{
|
||||||
|
lhs.x -= rhs.x;
|
||||||
|
lhs.y -= rhs.y;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec2 operator-(const Vec2& lhs, const Vec2& rhs)
|
||||||
|
{
|
||||||
|
Vec2 out = lhs;
|
||||||
|
return out -= rhs;
|
||||||
|
}
|
||||||
|
Vec2& operator-=(Vec2& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x -= rhs;
|
||||||
|
lhs.y -= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec2 operator-(const Vec2& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec2 out = lhs;
|
||||||
|
return out -= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2& operator*=(Vec2& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x *= rhs;
|
||||||
|
lhs.y *= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec2 operator*(const Vec2& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec2 out = lhs;
|
||||||
|
return out *= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2& operator/=(Vec2& lhs, float rhs)
|
||||||
|
{
|
||||||
|
lhs.x /= rhs;
|
||||||
|
lhs.y /= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
Vec2 operator/(const Vec2& lhs, float rhs)
|
||||||
|
{
|
||||||
|
Vec2 out = lhs;
|
||||||
|
return out /= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4 Inverse(const Mat4& mat)
|
||||||
|
{
|
||||||
|
Mat4 result;
|
||||||
|
bx::mtxInverse(result.M, &mat.M[0]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Mat4 Transpose(const Mat4& mat)
|
||||||
|
{
|
||||||
|
Mat4 result;
|
||||||
|
bx::mtxTranspose(result.M, &mat.M[0]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Vec4 Mul(const Mat4& mat, const Vec4& vec)
|
||||||
|
{
|
||||||
|
Vec4 out;
|
||||||
|
bx::vec4MulMtx(&out.x, &vec.x, &mat.M[0]);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
float Magnitude(const Vec3& vec)
|
||||||
|
{
|
||||||
|
return bx::sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z);
|
||||||
|
}
|
||||||
|
float Magnitude(const Vec2& vec)
|
||||||
|
{
|
||||||
|
return bx::sqrt(vec.x * vec.x + vec.y * vec.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec4 Normalized(const Vec4& vec)
|
||||||
|
{
|
||||||
|
Vec4 res = vec;
|
||||||
|
return res /= Magnitude(vec);
|
||||||
|
}
|
||||||
|
Vec3 Normalized(const Vec3& vec)
|
||||||
|
{
|
||||||
|
Vec3 res = vec;
|
||||||
|
return res /= Magnitude(vec);
|
||||||
|
}
|
||||||
|
Vec2 Normalized(const Vec2& vec)
|
||||||
|
{
|
||||||
|
Vec2 res = vec;
|
||||||
|
return res /= Magnitude(vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
float DotProduct(Vec3 a, Vec3 b)
|
||||||
|
{
|
||||||
|
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||||
|
}
|
||||||
|
Vec3 CrossProduct(Vec3 a, Vec3 b)
|
||||||
|
{
|
||||||
|
float x = a.y * b.z - a.z * b.y;
|
||||||
|
float y = a.z * b.x - a.x * b.z;
|
||||||
|
float z = a.x * b.y - a.y * b.x;
|
||||||
|
return {x, y, z};
|
||||||
|
}
|
||||||
|
Vec3 CrossProductFromPlane(Vec3 a, Vec3 b, Vec3 c)
|
||||||
|
{
|
||||||
|
// TODO: normalize might not be necessary
|
||||||
|
Vec3 lineA = Normalized(b - a);
|
||||||
|
Vec3 lineB = Normalized(c - a);
|
||||||
|
return CrossProduct(lineA, lineB);
|
||||||
|
}
|
||||||
|
bool RayPlaneIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out)
|
||||||
|
{
|
||||||
|
// thanks to Paul Bourke and Bryan Hanson
|
||||||
|
// l1,l2 constitute the line. P1,P2,P3 constitute the plane
|
||||||
|
out = {};
|
||||||
|
Vec3 N = CrossProductFromPlane(p1, p2, p3); // N is the normal of the plane
|
||||||
|
float n = DotProduct(N, Vec3{p3.x - l1.x, p3.y - l1.y, p3.z - l1.z});
|
||||||
|
Vec3 LbMinusLa = Vec3{l2.x - l1.x, l2.y - l1.y, l2.z - l1.z};
|
||||||
|
float d = DotProduct(N, LbMinusLa);
|
||||||
|
if (d == 0) return false; // Line is parallel to or in the plane
|
||||||
|
float u = n / d;
|
||||||
|
if ((u >= 0.0) && (u <= 1.0))
|
||||||
|
{ // Plane is between the two points
|
||||||
|
} // can be used for checking but does not influence the outcome
|
||||||
|
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
|
||||||
98
src/game/Gen.h
Normal file
98
src/game/Gen.h
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../gen/Generated.h"
|
||||||
|
|
||||||
|
namespace Gen
|
||||||
|
{
|
||||||
|
bool IsValid(const AssetHandle& h);
|
||||||
|
bool IsValid(const ModelHandle& h);
|
||||||
|
bool IsValid(const TextureHandle& h);
|
||||||
|
|
||||||
|
bool operator==(const AssetHandle& lhs, const AssetHandle& rhs);
|
||||||
|
bool operator==(const ModelHandle& lhs, const ModelHandle& rhs);
|
||||||
|
|
||||||
|
PuzPos operator+=(PuzPos lhs, const PuzPos& rhs);
|
||||||
|
PuzPos operator+(PuzPos lhs, const PuzPos& rhs);
|
||||||
|
|
||||||
|
Vec4& operator+=(Vec4& lhs, const Vec4& rhs);
|
||||||
|
Vec4 operator+(const Vec4& lhs, const Vec4& rhs);
|
||||||
|
Vec4& operator+=(Vec4& lhs, float rhs);
|
||||||
|
Vec4 operator+(Vec4& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec4& operator-=(Vec4& lhs, const Vec4& rhs);
|
||||||
|
Vec4 operator-(const Vec4& lhs, const Vec4& rhs);
|
||||||
|
Vec4& operator-=(Vec4& lhs, float rhs);
|
||||||
|
Vec4 operator-(const Vec4& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec4& operator*=(Vec4& lhs, float rhs);
|
||||||
|
Vec4 operator*(const Vec4& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec4& operator/=(Vec4& lhs, float rhs);
|
||||||
|
Vec4 operator/(const Vec4& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec3& operator+=(Vec3& lhs, const Vec3& rhs);
|
||||||
|
Vec3 operator+(const Vec3& lhs, const Vec3& rhs);
|
||||||
|
Vec3& operator+=(Vec3& lhs, float rhs);
|
||||||
|
Vec3 operator+(Vec3& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec3& operator-=(Vec3& lhs, const Vec3& rhs);
|
||||||
|
Vec3 operator-(const Vec3& lhs, const Vec3& rhs);
|
||||||
|
Vec3& operator-=(Vec3& lhs, float rhs);
|
||||||
|
Vec3 operator-(const Vec3& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec3& operator*=(Vec3& lhs, float rhs);
|
||||||
|
Vec3 operator*(const Vec3& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec3& operator/=(Vec3& lhs, float rhs);
|
||||||
|
Vec3 operator/(const Vec3& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec2& operator+=(Vec2& lhs, const Vec2& rhs);
|
||||||
|
Vec2 operator+(const Vec2& lhs, const Vec2& rhs);
|
||||||
|
Vec2& operator+=(Vec2& lhs, float rhs);
|
||||||
|
Vec2 operator+(Vec2& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec2& operator-=(Vec2& lhs, const Vec2& rhs);
|
||||||
|
Vec2 operator-(const Vec2& lhs, const Vec2& rhs);
|
||||||
|
Vec2& operator-=(Vec2& lhs, float rhs);
|
||||||
|
Vec2 operator-(const Vec2& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec2& operator*=(Vec2& lhs, float rhs);
|
||||||
|
Vec2 operator*(const Vec2& lhs, float rhs);
|
||||||
|
|
||||||
|
Vec2& operator/=(Vec2& lhs, float rhs);
|
||||||
|
Vec2 operator/(const Vec2& lhs, float rhs);
|
||||||
|
|
||||||
|
float Magnitude(const Vec4& vec);
|
||||||
|
float Magnitude(const Vec3& vec);
|
||||||
|
float Magnitude(const Vec2& vec);
|
||||||
|
|
||||||
|
Vec4 Normalized(const Vec4& vec);
|
||||||
|
Vec3 Normalized(const Vec3& vec);
|
||||||
|
Vec2 Normalized(const Vec2& vec);
|
||||||
|
|
||||||
|
Mat4 Inverse(const Mat4& mat);
|
||||||
|
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,87 +1,18 @@
|
|||||||
#include "../engine/Shared.h"
|
#include "../engine/Shared.h"
|
||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "bx/bx.h"
|
|
||||||
#include "bx/math.h"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
using namespace Gen;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
SharedData* SharedInstance = nullptr;
|
SharedData* SharedInstance = nullptr;
|
||||||
Game::GameInstance* GameInst = nullptr;
|
Game::GameInstance* GameInst = nullptr;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
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(bx::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(bx::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, pos.M, temp.M);
|
|
||||||
bx::mtxInverse(MI.M, M.M);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
{
|
{
|
||||||
SharedData& GetShared()
|
SharedData& GetShared()
|
||||||
@@ -106,69 +37,36 @@ namespace Game
|
|||||||
GameInst = &instance;
|
GameInst = &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* AllocateScratch(size_t byteCount, size_t align)
|
uint8_t* AllocateScratch(uint64_t byteCount, uint32_t align)
|
||||||
{
|
{
|
||||||
size_t offset = GetInstance().UsedScratchAmount;
|
assert(align <= 64); // The alignment of the arena limits the alignment that can be specified here!
|
||||||
uint8_t* base = static_cast<uint8_t*>(GetShared().Game.TransientStorage);
|
auto& arena = GetShared().Game.TransientArena;
|
||||||
uint8_t* current = base + offset;
|
uint64_t offsetAligned = ((arena.Used + align - 1) / align) * align;
|
||||||
size_t offsetAligned = ((offset + align - 1) / align) * align;
|
uint8_t* ptrAligned = arena.Base + offsetAligned;
|
||||||
uint8_t* ptrAligned = base + offsetAligned;
|
uint64_t newOffset = offsetAligned + byteCount;
|
||||||
size_t newOffset = offsetAligned + byteCount;
|
if (newOffset > arena.MaxSize) return nullptr;
|
||||||
if (newOffset > GetShared().Game.TransientStorageSize) return nullptr;
|
arena.Used = newOffset;
|
||||||
GetInstance().UsedScratchAmount = newOffset;
|
arena.LastAllocSize = byteCount;
|
||||||
return reinterpret_cast<void*>(ptrAligned);
|
return ptrAligned;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResizeLastScratchAlloc(uint64_t newByteCount)
|
||||||
|
{
|
||||||
|
auto& arena = GetShared().Game.TransientArena;
|
||||||
|
if (newByteCount > arena.LastAllocSize)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Can't resize to more than previous size!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
arena.Used -= arena.LastAllocSize;
|
||||||
|
arena.Used += newByteCount;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetScratch()
|
||||||
|
{
|
||||||
|
auto& arena = GetShared().Game.TransientArena;
|
||||||
|
arena.Used = 0;
|
||||||
|
arena.LastAllocSize = 0;
|
||||||
}
|
}
|
||||||
} // namespace Game
|
} // namespace Game
|
||||||
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, MI.M);
|
|
||||||
return {out[0], out[1], out[2]};
|
|
||||||
}
|
|
||||||
bx::Vec3 Transform::GlobalToLocalPoint(bx::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};
|
|
||||||
Mat4 test = M.Transpose();
|
|
||||||
bx::vec4MulMtx(out, in, test.M);
|
|
||||||
return {out[0], out[1], out[2]};
|
|
||||||
}
|
|
||||||
bx::Vec3 Transform::LocalToGlobalPoint(bx::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};
|
|
||||||
}
|
|
||||||
Mat4 Mat4::Inverse()
|
|
||||||
{
|
|
||||||
Mat4 result;
|
|
||||||
bx::mtxInverse(result.M, M);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
Mat4 Mat4::Transpose()
|
|
||||||
{
|
|
||||||
Mat4 result;
|
|
||||||
bx::mtxTranspose(result.M, M);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,186 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "bx/math.h"
|
#include <cstdint>
|
||||||
#include <cfloat>
|
|
||||||
|
|
||||||
struct Vec2
|
|
||||||
{
|
|
||||||
float x = 0.0f;
|
|
||||||
float y = 0.0f;
|
|
||||||
|
|
||||||
Vec2& operator+=(const Vec2& rhs)
|
|
||||||
{
|
|
||||||
x += rhs.x;
|
|
||||||
y += rhs.y;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec2 operator+(Vec2 lhs, const Vec2& rhs)
|
|
||||||
{
|
|
||||||
lhs += rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2& operator-=(const Vec2& rhs)
|
|
||||||
{
|
|
||||||
x -= rhs.x;
|
|
||||||
y -= rhs.y;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec2 operator-(Vec2 lhs, const Vec2& rhs)
|
|
||||||
{
|
|
||||||
lhs -= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2& operator*=(const float rhs)
|
|
||||||
{
|
|
||||||
x *= rhs;
|
|
||||||
y *= rhs;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec2 operator*(Vec2 lhs, const float rhs)
|
|
||||||
{
|
|
||||||
lhs *= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2& operator/=(const float rhs)
|
|
||||||
{
|
|
||||||
x /= rhs;
|
|
||||||
y /= rhs;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec2 operator/(Vec2 lhs, const float rhs)
|
|
||||||
{
|
|
||||||
lhs /= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Magnitude()
|
|
||||||
{
|
|
||||||
return bx::sqrt(x * x + y * y);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2 Normalize()
|
|
||||||
{
|
|
||||||
float mag = Magnitude();
|
|
||||||
if (mag < FLT_EPSILON) return {};
|
|
||||||
return {x / mag, y / mag};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vec3
|
|
||||||
{
|
|
||||||
float x = 0.0f;
|
|
||||||
float y = 0.0f;
|
|
||||||
float z = 0.0f;
|
|
||||||
|
|
||||||
Vec3& operator+=(const Vec3& rhs)
|
|
||||||
{
|
|
||||||
x += rhs.x;
|
|
||||||
y += rhs.y;
|
|
||||||
z += rhs.z;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec3 operator+(Vec3 lhs, const Vec3& rhs)
|
|
||||||
{
|
|
||||||
lhs += rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3& operator-=(const Vec3& rhs)
|
|
||||||
{
|
|
||||||
x -= rhs.x;
|
|
||||||
y -= rhs.y;
|
|
||||||
z -= rhs.z;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec3 operator-(Vec3 lhs, const Vec3& rhs)
|
|
||||||
{
|
|
||||||
lhs -= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3& operator*=(const float rhs)
|
|
||||||
{
|
|
||||||
x *= rhs;
|
|
||||||
y *= rhs;
|
|
||||||
z *= rhs;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec3 operator*(Vec3 lhs, const float rhs)
|
|
||||||
{
|
|
||||||
lhs *= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3& operator/=(const float rhs)
|
|
||||||
{
|
|
||||||
x /= rhs;
|
|
||||||
y /= rhs;
|
|
||||||
z /= rhs;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec3 operator/(Vec3 lhs, const float rhs)
|
|
||||||
{
|
|
||||||
lhs /= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Magnitude()
|
|
||||||
{
|
|
||||||
return bx::sqrt(x * x + y * y + z * z);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3 Normalize()
|
|
||||||
{
|
|
||||||
float mag = Magnitude();
|
|
||||||
if (mag < FLT_EPSILON) return {};
|
|
||||||
return {x / mag, y / mag, z / mag};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vec4
|
|
||||||
{
|
|
||||||
float x = 0.0f;
|
|
||||||
float y = 0.0f;
|
|
||||||
float z = 0.0f;
|
|
||||||
float w = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Mat3
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
float M[9]{
|
|
||||||
1.0f, 0.0f, 0.0f,
|
|
||||||
0.0f, 1.0f, 0.0f,
|
|
||||||
0.0f, 0.0f, 1.0f,
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Mat4
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
float M[16]{
|
|
||||||
1.0, 0.0, 0.0, 0.0,
|
|
||||||
0.0, 1.0, 0.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0, 0.0,
|
|
||||||
0.0, 0.0, 0.0, 1.0,
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
Mat4 Inverse();
|
|
||||||
Mat4 Transpose();
|
|
||||||
};
|
|
||||||
|
|
||||||
inline int32_t SetFlags(int32_t in, int32_t flags)
|
inline int32_t SetFlags(int32_t in, int32_t flags)
|
||||||
{
|
{
|
||||||
@@ -203,32 +23,6 @@ inline bool GetFlag(int32_t in, int32_t flags)
|
|||||||
return (in & flags) > 0;
|
return (in & flags) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Transform
|
|
||||||
{
|
|
||||||
Mat4 M;
|
|
||||||
Mat4 MI;
|
|
||||||
bx::Vec3 Position{0.0f, 0.0f, 0.0f};
|
|
||||||
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(Vec3 offset);
|
|
||||||
void TranslateLocal(Vec3 offset);
|
|
||||||
void Rotate(bx::Vec3 rotation);
|
|
||||||
void RotateLocal(bx::Vec3 rotation);
|
|
||||||
bx::Vec3 LocalToGlobalPoint(bx::Vec3 local);
|
|
||||||
Vec3 LocalToGlobalDirection(Vec3 local);
|
|
||||||
bx::Vec3 GlobalToLocalPoint(bx::Vec3 global);
|
|
||||||
Vec3 GlobalToLocalDirection(Vec3 global);
|
|
||||||
Vec3 Right() const;
|
|
||||||
Vec3 Up() const;
|
|
||||||
Vec3 Forward() const;
|
|
||||||
void SetPosition(Vec3 pos);
|
|
||||||
Vec3 GetPosition();
|
|
||||||
const float* GetPtr();
|
|
||||||
void UpdateMatrix();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SharedData;
|
struct SharedData;
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
@@ -239,5 +33,7 @@ namespace Game
|
|||||||
void SetShared(SharedData& instance);
|
void SetShared(SharedData& instance);
|
||||||
GameInstance& GetInstance();
|
GameInstance& GetInstance();
|
||||||
void SetInstance(GameInstance& instance);
|
void SetInstance(GameInstance& instance);
|
||||||
void* AllocateScratch(size_t byteCount, size_t align = 16);
|
uint8_t* AllocateScratch(uint64_t byteCount, uint32_t align = 16);
|
||||||
|
bool ResizeLastScratchAlloc(uint64_t newByteCount);
|
||||||
|
void ResetScratch();
|
||||||
} // namespace Game
|
} // namespace Game
|
||||||
|
|||||||
@@ -2,17 +2,22 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
#include "Input.h"
|
#include "Input.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
{
|
{
|
||||||
|
using namespace Gen;
|
||||||
|
|
||||||
bool IsKeyboardAllowed()
|
bool IsKeyboardAllowed()
|
||||||
{
|
{
|
||||||
|
if (GImGui == nullptr) return true;
|
||||||
auto& IO = ImGui::GetIO();
|
auto& IO = ImGui::GetIO();
|
||||||
return !IO.WantCaptureKeyboard || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
|
return !IO.WantCaptureKeyboard || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsMouseAllowed()
|
bool IsMouseAllowed()
|
||||||
{
|
{
|
||||||
|
if (GImGui == nullptr) return true;
|
||||||
auto& IO = ImGui::GetIO();
|
auto& IO = ImGui::GetIO();
|
||||||
return !IO.WantCaptureMouse || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoMouse);
|
return !IO.WantCaptureMouse || GetFlag(IO.ConfigFlags, ImGuiConfigFlags_NoMouse);
|
||||||
}
|
}
|
||||||
@@ -56,4 +61,11 @@ namespace Game
|
|||||||
if (!IsMouseAllowed()) return {};
|
if (!IsMouseAllowed()) return {};
|
||||||
return {GetShared().Window.MouseDeltaX, GetShared().Window.MouseDeltaY};
|
return {GetShared().Window.MouseDeltaX, GetShared().Window.MouseDeltaY};
|
||||||
}
|
}
|
||||||
|
Vec2 GetMousePos()
|
||||||
|
{
|
||||||
|
// TODO: fix this!!
|
||||||
|
if (GImGui == nullptr) return {};
|
||||||
|
ImVec2 pos = ImGui::GetMousePos();
|
||||||
|
return {pos.x, pos.y};
|
||||||
|
}
|
||||||
} // namespace Game
|
} // namespace Game
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Global.h"
|
#include "../gen/Generated.h"
|
||||||
|
|
||||||
enum class MouseButton
|
enum class MouseButton
|
||||||
{
|
{
|
||||||
@@ -393,5 +393,6 @@ namespace Game
|
|||||||
bool GetMouseButton(MouseButton button);
|
bool GetMouseButton(MouseButton button);
|
||||||
bool GetMouseButtonPressedNow(MouseButton button);
|
bool GetMouseButtonPressedNow(MouseButton button);
|
||||||
bool GetMouseButtonReleasedNow(MouseButton button);
|
bool GetMouseButtonReleasedNow(MouseButton button);
|
||||||
Vec2 GetMouseMovement();
|
Gen::Vec2 GetMouseMovement();
|
||||||
|
Gen::Vec2 GetMousePos();
|
||||||
} // namespace Game
|
} // namespace Game
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ namespace Game
|
|||||||
Game,
|
Game,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class InteractionMode
|
||||||
|
{
|
||||||
|
Walk,
|
||||||
|
ReadTablet,
|
||||||
|
};
|
||||||
|
|
||||||
struct Time
|
struct Time
|
||||||
{
|
{
|
||||||
double Now = 0.0;
|
double Now = 0.0;
|
||||||
@@ -28,28 +34,43 @@ namespace Game
|
|||||||
|
|
||||||
struct PlayerData
|
struct PlayerData
|
||||||
{
|
{
|
||||||
Transform FreeflyCamTransform;
|
Gen::Transform PlayerCamTransform;
|
||||||
|
Gen::Transform FreeflyCamTransform;
|
||||||
|
Gen::Mat4 Projection;
|
||||||
|
Gen::Mat4 ProjectionInverse;
|
||||||
float FreeflyXRot = 0.0f;
|
float FreeflyXRot = 0.0f;
|
||||||
float FreeflyYRot = 0.0f;
|
float FreeflyYRot = 0.0f;
|
||||||
float WalkXRot = 0.0f;
|
float WalkXRot = 0.0f;
|
||||||
float WalkYRot = 0.0f;
|
float WalkYRot = 0.0f;
|
||||||
Transform PlayerCamTransform;
|
CameraMode CameraM = CameraMode::Walk;
|
||||||
CameraMode CameraM = CameraMode::Freefly;
|
|
||||||
InputMode InputM = InputMode::Game;
|
InputMode InputM = InputMode::Game;
|
||||||
|
InteractionMode InteractionM = InteractionMode::Walk;
|
||||||
|
float MouseSensitivity = 1.0f;
|
||||||
|
float MovementSpeed = 10.0f;
|
||||||
|
Gen::SavedPlayerConfig Config;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InstanceDebugData
|
struct InstanceDebugData
|
||||||
{
|
{
|
||||||
uint16_t SelectedDebugLevel = UINT16_MAX;
|
static constexpr uint32_t MaxAssets = 128;
|
||||||
|
uint16_t SelectedDebugLevel = 0;
|
||||||
uint64_t ImguiIniSize = 0;
|
uint64_t ImguiIniSize = 0;
|
||||||
char ImguiIni[4096]{0};
|
char ImguiIni[4096]{0};
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GameInstance
|
struct GameInstance
|
||||||
{
|
{
|
||||||
bool IsInitialized = false;
|
bool IsInitialized = false;
|
||||||
uint64_t Size = sizeof(GameInstance);
|
uint64_t Size = sizeof(GameInstance);
|
||||||
uint64_t UsedScratchAmount = 0;
|
|
||||||
Time Time;
|
Time Time;
|
||||||
PlayerData Player;
|
PlayerData Player;
|
||||||
Level GameLevel;
|
Level GameLevel;
|
||||||
|
|||||||
@@ -1,30 +1,55 @@
|
|||||||
|
#include "../gen/Def.h"
|
||||||
|
#include "Gen.h"
|
||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
#include "Input.h"
|
#include "Input.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "Level.h"
|
#include "Level.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Puzzle.h"
|
#include "Puzzle.h"
|
||||||
|
#include "UI.h"
|
||||||
|
#include "bx/bx.h"
|
||||||
|
#include "bx/debug.h"
|
||||||
|
#include "rendering/Rendering.h"
|
||||||
|
|
||||||
#include "SDL3/SDL_mouse.h"
|
#include "SDL3/SDL_mouse.h"
|
||||||
#include "bgfx/bgfx.h"
|
#include "bgfx/bgfx.h"
|
||||||
|
#include "bx/error.h"
|
||||||
|
#include "bx/file.h"
|
||||||
|
#include "bx/filepath.h"
|
||||||
|
#include "bx/string.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "rendering/Rendering.h"
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <bx/math.h>
|
#include <bx/math.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <tracy/Tracy.hpp>
|
||||||
|
|
||||||
|
using namespace Gen;
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
{
|
{
|
||||||
void EntityRenderData::Render(const Model* models, const Material* materials)
|
void EntityRenderData::Render(const Model* models, const Material* materials, const Texture* textures)
|
||||||
{
|
{
|
||||||
if (ModelHandle == UINT16_MAX || MaterialHandle == UINT16_MAX) return;
|
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::EntryCount) return;
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
auto& rendering = GameRendering::Get();
|
auto& rendering = GameRendering::Get();
|
||||||
|
|
||||||
Transform.UpdateMatrix();
|
UpdateMatrix(Transform);
|
||||||
bgfx::setTransform(Transform.M.M);
|
bgfx::setTransform(Transform.M.M);
|
||||||
|
|
||||||
const Model& currentModel = models[ModelHandle];
|
const Model& currentModel = models[ModelH.ModelIdx];
|
||||||
const Material& currentMaterial = materials[MaterialHandle];
|
const Material& currentMaterial = materials[(uint16_t)MaterialHandle];
|
||||||
|
|
||||||
|
if (!isValid(currentModel.IndexBuffer) || !isValid(currentModel.VertexBuffer)) return;
|
||||||
|
if (!isValid(currentMaterial.Shader)) return;
|
||||||
|
|
||||||
bgfx::setVertexBuffer(0, currentModel.VertexBuffer);
|
bgfx::setVertexBuffer(0, currentModel.VertexBuffer);
|
||||||
bgfx::setIndexBuffer(currentModel.IndexBuffer);
|
bgfx::setIndexBuffer(currentModel.IndexBuffer);
|
||||||
bgfx::setState(currentMaterial.State);
|
bgfx::setState(currentMaterial.State);
|
||||||
@@ -33,84 +58,249 @@ namespace Game
|
|||||||
timeValues[0] = GetInstance().Time.Now;
|
timeValues[0] = GetInstance().Time.Now;
|
||||||
|
|
||||||
float texInfo[4]{0.0f};
|
float texInfo[4]{0.0f};
|
||||||
texInfo[0] = currentMaterial.Textures[0].Info.width;
|
texInfo[0] = textures[0].Info.width;
|
||||||
texInfo[1] = currentMaterial.Textures[0].Info.height;
|
texInfo[1] = textures[0].Info.height;
|
||||||
texInfo[2] = rendering.DitherTextures.DitherTexWH;
|
texInfo[2] = rendering.DitherTextures.DitherTexWH;
|
||||||
texInfo[3] = rendering.DitherTextures.DitherTexDepth;
|
texInfo[3] = rendering.DitherTextures.DitherTexDepth;
|
||||||
|
|
||||||
bgfx::setTexture(0, currentMaterial.Textures[0].SamplerHandle, currentMaterial.Textures[0].Handle);
|
bgfx::UniformHandle sampler = rendering.DefaultSampler;
|
||||||
|
bgfx::TextureHandle tex = rendering.Textures[0].RenderHandle;
|
||||||
|
if (IsValid(TextureHandle))
|
||||||
|
{
|
||||||
|
sampler = textures[TextureHandle.TextureIdx].SamplerHandle;
|
||||||
|
tex = textures[TextureHandle.TextureIdx].RenderHandle;
|
||||||
|
texInfo[0] = textures[TextureHandle.TextureIdx].Info.width;
|
||||||
|
texInfo[1] = textures[TextureHandle.TextureIdx].Info.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
bgfx::setTexture(0, sampler, tex);
|
||||||
bgfx::setTexture(1, rendering.DitherTextures.DitherSampler, rendering.DitherTextures.FinalTex);
|
bgfx::setTexture(1, rendering.DitherTextures.DitherSampler, rendering.DitherTextures.FinalTex);
|
||||||
bgfx::setTexture(2, rendering.DitherTextures.RampSampler, rendering.DitherTextures.RampTex);
|
bgfx::setTexture(2, rendering.DitherTextures.RampSampler, rendering.DitherTextures.RampTex);
|
||||||
bgfx::setUniform(currentMaterial.Uniforms[Material::UTime], timeValues);
|
bgfx::setUniform(currentMaterial.Uniforms[Material::UTime], timeValues);
|
||||||
bgfx::setUniform(currentMaterial.Uniforms[Material::UDotColor], TestColor);
|
bgfx::setUniform(currentMaterial.Uniforms[Material::UDotColor], &DotColor.x);
|
||||||
bgfx::setUniform(currentMaterial.Uniforms[Material::UTexInfo], texInfo);
|
bgfx::setUniform(currentMaterial.Uniforms[Material::UTexInfo], texInfo);
|
||||||
|
bgfx::setUniform(currentMaterial.Uniforms[Material::UBaseColor], &BaseColor.x);
|
||||||
|
|
||||||
bgfx::submit(currentMaterial.ViewID, currentMaterial.Shader);
|
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
|
namespace
|
||||||
{
|
{
|
||||||
void UpdatePlayerInputMode()
|
void UpdatePlayerInputMode()
|
||||||
{
|
{
|
||||||
bool IsGaming = GetInstance().Player.InputM == InputMode::Game;
|
bool IsGaming = GetInstance().Player.InputM == InputMode::Game;
|
||||||
SDL_SetWindowRelativeMouseMode(GetShared().Window.SDLWindow, IsGaming);
|
bool captureMouse = IsGaming && GetInstance().Player.InteractionM == InteractionMode::Walk;
|
||||||
|
SDL_SetWindowRelativeMouseMode(GetShared().Window.SDLWindow, captureMouse);
|
||||||
|
|
||||||
|
auto& rendering = GameRendering::Get();
|
||||||
|
if (rendering.SetupData.UseImgui)
|
||||||
|
{
|
||||||
auto& IO = ImGui::GetIO();
|
auto& IO = ImGui::GetIO();
|
||||||
IO.ConfigFlags = FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, IsGaming);
|
IO.ConfigFlags =
|
||||||
GameRendering::Get().UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug;
|
FlagBool(IO.ConfigFlags, ImGuiConfigFlags_NoMouse | ImGuiConfigFlags_NoKeyboard, captureMouse);
|
||||||
|
}
|
||||||
|
rendering.UIVisible = IsGaming ? UIVisibilityState::Game : UIVisibilityState::Debug;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void Level::Setup(GameData& data)
|
void Level::Setup(GameData& data)
|
||||||
{
|
{
|
||||||
LOG("Level setup");
|
LOG("Level setup");
|
||||||
void* storagePtr = data.EntityStorage;
|
uint8_t* storagePtr = data.EntityArena.Base;
|
||||||
bool needReset = false;
|
bool needReset = false;
|
||||||
needReset |= Cubes.Setup(storagePtr, needReset);
|
needReset |= Cubes.Setup(storagePtr, needReset);
|
||||||
needReset |= Tests.Setup(storagePtr, needReset);
|
needReset |= Tests.Setup(storagePtr, needReset);
|
||||||
needReset |= PuzzleTiles.Setup(storagePtr, needReset);
|
needReset |= PuzzleTiles.Setup(storagePtr, needReset);
|
||||||
|
needReset |= PuzzleTileCovers.Setup(storagePtr, needReset);
|
||||||
needReset |= UIQuads.Setup(storagePtr, needReset);
|
needReset |= UIQuads.Setup(storagePtr, needReset);
|
||||||
|
needReset |= LevelEntities.Setup(storagePtr, needReset);
|
||||||
|
|
||||||
PuzzleData.Setup();
|
Puzzle::Setup();
|
||||||
|
UIQuads.Count = 0;
|
||||||
|
PuzzleTiles.Count = 0;
|
||||||
|
|
||||||
if (Cubes.Count == 0)
|
bx::Error err;
|
||||||
|
bx::DirectoryReader dirIter;
|
||||||
|
bx::FileInfo info;
|
||||||
|
bx::FilePath puzzleDirPath{Puzzle::PuzzleFileDir};
|
||||||
|
if (dirIter.open(puzzleDirPath, &err))
|
||||||
{
|
{
|
||||||
for (uint32_t yy = 0; yy < 11; ++yy)
|
while (true)
|
||||||
{
|
{
|
||||||
for (uint32_t xx = 0; xx < 11; ++xx)
|
int32_t readCount = dirIter.read(&info, sizeof(info), &err);
|
||||||
|
if (readCount == 0) break;
|
||||||
|
if (err.isOk())
|
||||||
{
|
{
|
||||||
Cube& c = Cubes.Get(Cubes.New());
|
if (info.type != bx::FileType::File) continue;
|
||||||
c.TestX = xx;
|
bx::StringView pathEnd = info.filePath.getExt();
|
||||||
c.TestY = yy;
|
if (bx::strCmpI(pathEnd, ".pzl") != 0) continue;
|
||||||
c.Setup();
|
|
||||||
|
bx::FilePath fullPath = puzzleDirPath;
|
||||||
|
fullPath.join(info.filePath);
|
||||||
|
LOG("Loading %s", fullPath.getCPtr());
|
||||||
|
|
||||||
|
Gen::Deserializer ser;
|
||||||
|
Gen::PuzzleData dataBuf;
|
||||||
|
if (ser.Init(fullPath, "PZZL") && ser.ReadT(dataBuf))
|
||||||
|
{
|
||||||
|
if (dataBuf.ID >= BX_COUNTOF(Puzzles))
|
||||||
|
{
|
||||||
|
LOG_ERROR("Puzzle ID out of bounds: %u", dataBuf.ID);
|
||||||
|
ser.Finish();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Puzzles[dataBuf.ID].Data = dataBuf;
|
||||||
|
Puzzles[dataBuf.ID].Setup();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_WARN("Failed to load puzzle!");
|
||||||
|
}
|
||||||
|
ser.Finish();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("Failed parsing file name at %s:\n%s", puzzleDirPath.getCPtr(), err.getMessage());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cubes.New(); // Floor
|
|
||||||
}
|
}
|
||||||
if (Tests.Count == 0)
|
else
|
||||||
{
|
{
|
||||||
Tests.Get(Tests.New()).Setup();
|
LOG_ERROR("Failed to open puzzle dir at %s:\n%s", puzzleDirPath.getCPtr(), err.getMessage().getCPtr());
|
||||||
}
|
}
|
||||||
if (PuzzleTiles.Count == 0)
|
|
||||||
|
if (!IsValid(PlayerOutsideViewCube))
|
||||||
{
|
{
|
||||||
for (uint32_t puzI = 0; puzI < BX_COUNTOF(Puzzles); ++puzI)
|
PlayerOutsideViewCube = Cubes.New();
|
||||||
|
Cubes.Get(PlayerOutsideViewCube).Setup();
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Puzzles[puzI].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)
|
||||||
|
{
|
||||||
|
Puzzles[i].Setup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PuzzleUI.Setup();
|
||||||
|
|
||||||
|
ReloadLevelEntities();
|
||||||
|
|
||||||
UpdatePlayerInputMode();
|
UpdatePlayerInputMode();
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
|
||||||
|
{
|
||||||
|
Puzzles[i].WorldPosition = {0.0f, 0.0f, i * 50.0f};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInPuzzle(WorldPuzzle& puz, Vec3 worldPos)
|
||||||
|
{
|
||||||
|
Vec3 offsetToPuzzle = worldPos - puz.WorldPosition + (Vec3{0.5f, 0.0f, 0.5f} * Puzzle::Config::CardScaleWorld);
|
||||||
|
Vec3 scaledOffset = offsetToPuzzle / Puzzle::Config::CardScaleWorld;
|
||||||
|
int32_t offsetX = (int32_t)bx::floor(scaledOffset.x);
|
||||||
|
int32_t offsetY = (int32_t)bx::floor(scaledOffset.z);
|
||||||
|
return (offsetX >= 0 && offsetX < puz.Data.WidthTiles / 2 && offsetY >= -1 &&
|
||||||
|
offsetY < puz.Data.HeightTiles / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsOnGround(Level& level, Vec3 worldPos)
|
||||||
|
{
|
||||||
|
for (auto& puz : level.Puzzles)
|
||||||
|
{
|
||||||
|
Vec3 offsetToPuzzle =
|
||||||
|
worldPos - puz.WorldPosition + (Vec3{0.5f, 0.0f, 0.5f} * Puzzle::Config::CardScaleWorld);
|
||||||
|
Vec3 scaledOffset = offsetToPuzzle / Puzzle::Config::CardScaleWorld;
|
||||||
|
int32_t offsetX = (int32_t)bx::floor(scaledOffset.x);
|
||||||
|
int32_t offsetY = puz.Data.HeightTiles / 2 - (int32_t)bx::floor(scaledOffset.z) - 1;
|
||||||
|
float fracOffsetX = scaledOffset.x - offsetX;
|
||||||
|
float fracOffsetY = scaledOffset.z - bx::floor(scaledOffset.z);
|
||||||
|
|
||||||
|
if (offsetX >= 0 && offsetX < puz.Data.WidthTiles / 2 && offsetY >= 0 && offsetY < puz.Data.HeightTiles / 2)
|
||||||
|
{
|
||||||
|
auto& card = puz.Data.PlacedCards[offsetY * Puzzle::Config::MaxPuzzleSizeCards + offsetX];
|
||||||
|
if (card.RefCard.Idx == UINT16_MAX)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& refCard = Puzzle::GetStaticPuzzleData().Cards[card.RefCard.Idx];
|
||||||
|
if (!IsValid(refCard.BaseModelHandle))
|
||||||
|
{
|
||||||
|
LOG_WARN("missing base model! @ %i %i", offsetX, offsetY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& heightmap = GameRendering::Get().Models[refCard.BaseModelHandle.ModelIdx].Height;
|
||||||
|
int32_t xPos = (int32_t)(fracOffsetX * heightmap.Width);
|
||||||
|
int32_t yPos = (int32_t)(fracOffsetY * heightmap.Height);
|
||||||
|
|
||||||
|
uint8_t height = 0;
|
||||||
|
switch (card.Rotation)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
height = heightmap.Values[yPos * heightmap.Width + xPos];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
height = heightmap.Values[xPos * heightmap.Width + (heightmap.Height - yPos - 1)];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
height =
|
||||||
|
heightmap
|
||||||
|
.Values[(heightmap.Height - yPos - 1) * heightmap.Width + (heightmap.Width - xPos - 1)];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
height = heightmap.Values[(heightmap.Height - xPos - 1) * heightmap.Width + yPos];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return height >= 110 && height <= 125;
|
||||||
|
}
|
||||||
|
if (offsetX == 1 && offsetY == puz.Data.HeightTiles / Puzzle::Config::CardSize)
|
||||||
|
{
|
||||||
|
if (puz.IsSolved)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true; // TODO!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Level::Update()
|
void Level::Update()
|
||||||
{
|
{
|
||||||
|
ZoneScopedN("Level update");
|
||||||
START_PERF();
|
START_PERF();
|
||||||
PlayerData& player = GetInstance().Player;
|
PlayerData& player = GetInstance().Player;
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
float delta = GetInstance().Time.Delta;
|
float delta = GetInstance().Time.Delta;
|
||||||
delta = 1.0f / 144.0f;
|
float moveSpeed = player.MovementSpeed;
|
||||||
constexpr float moveSpeed = 10.0f;
|
float rotSpeed = player.MouseSensitivity;
|
||||||
constexpr float rotSpeed = 0.6f;
|
|
||||||
|
|
||||||
float forwardInput = (GetKey(ScanCode::W) ? 1.0f : 0.0f) + (GetKey(ScanCode::S) ? -1.0f : 0.0f);
|
float forwardInput = (GetKey(ScanCode::W) ? 1.0f : 0.0f) + (GetKey(ScanCode::S) ? -1.0f : 0.0f);
|
||||||
float rightInput = (GetKey(ScanCode::D) ? 1.0f : 0.0f) + (GetKey(ScanCode::A) ? -1.0f : 0.0f);
|
float rightInput = (GetKey(ScanCode::D) ? 1.0f : 0.0f) + (GetKey(ScanCode::A) ? -1.0f : 0.0f);
|
||||||
@@ -118,7 +308,7 @@ namespace Game
|
|||||||
moveInput = bx::normalize(moveInput);
|
moveInput = bx::normalize(moveInput);
|
||||||
bx::Vec3 inputVec = {moveInput.x * delta * moveSpeed, 0.0f, moveInput.y * delta * moveSpeed};
|
bx::Vec3 inputVec = {moveInput.x * delta * moveSpeed, 0.0f, moveInput.y * delta * moveSpeed};
|
||||||
Vec2 mouseMovement = GetMouseMovement();
|
Vec2 mouseMovement = GetMouseMovement();
|
||||||
bx::Vec3 rotInput = {mouseMovement.y * delta * rotSpeed, mouseMovement.x * delta * rotSpeed, 0.0f};
|
bx::Vec3 rotInput = {mouseMovement.y * delta * -rotSpeed, mouseMovement.x * delta * -rotSpeed, 0.0f};
|
||||||
|
|
||||||
if (GetKeyPressedNow(ScanCode::F1))
|
if (GetKeyPressedNow(ScanCode::F1))
|
||||||
{
|
{
|
||||||
@@ -144,23 +334,57 @@ namespace Game
|
|||||||
{
|
{
|
||||||
player.FreeflyXRot += rotInput.x;
|
player.FreeflyXRot += rotInput.x;
|
||||||
player.FreeflyYRot += rotInput.y;
|
player.FreeflyYRot += rotInput.y;
|
||||||
bx::mtxRotateY(player.FreeflyCamTransform.Rotation.M, player.FreeflyYRot);
|
bx::mtxRotateXYZ(player.FreeflyCamTransform.Rotation.M, player.FreeflyXRot, player.FreeflyYRot, 0.0f);
|
||||||
player.FreeflyCamTransform.RotateLocal({player.FreeflyXRot, 0.0f, 0.0f});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
player.FreeflyCamTransform.TranslateLocal({0.0f, 0.0f, -inputVec.z});
|
TranslateLocal(player.FreeflyCamTransform, {0.0f, 0.0f, inputVec.z});
|
||||||
player.FreeflyCamTransform.TranslateLocal({-inputVec.x, 0.0f, 0.0f});
|
TranslateLocal(player.FreeflyCamTransform, {inputVec.x, 0.0f, 0.0f});
|
||||||
}
|
}
|
||||||
else if (player.CameraM == CameraMode::Walk)
|
else if (player.CameraM == CameraMode::Walk)
|
||||||
{
|
{
|
||||||
player.PlayerCamTransform.TranslateLocal({0.0f, 0.0f, -inputVec.z});
|
auto newTransform = player.PlayerCamTransform;
|
||||||
player.PlayerCamTransform.TranslateLocal({-inputVec.x, 0.0f, 0.0f});
|
// Global and local are inverted because camera
|
||||||
player.PlayerCamTransform.Position.y = -3.0f;
|
Vec3 globalInput = GlobalToLocalDirection(newTransform, {inputVec.x, 0.0f, inputVec.z});
|
||||||
|
Translate(newTransform, globalInput);
|
||||||
|
newTransform.Position.y = 3.0f;
|
||||||
|
|
||||||
|
if (IsOnGround(*this, newTransform.Position))
|
||||||
|
{
|
||||||
|
player.PlayerCamTransform = newTransform;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto newTransform = player.PlayerCamTransform;
|
||||||
|
Translate(newTransform, {globalInput.x, 0.0f, 0.0f});
|
||||||
|
newTransform.Position.y = 3.0f;
|
||||||
|
|
||||||
|
if (IsOnGround(*this, newTransform.Position))
|
||||||
|
{
|
||||||
|
player.PlayerCamTransform = newTransform;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto newTransform = player.PlayerCamTransform;
|
||||||
|
Translate(newTransform, {0.0f, 0.0f, globalInput.z});
|
||||||
|
newTransform.Position.y = 3.0f;
|
||||||
|
|
||||||
|
if (IsOnGround(*this, newTransform.Position))
|
||||||
|
{
|
||||||
|
player.PlayerCamTransform = newTransform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
player.WalkXRot += rotInput.x;
|
player.WalkXRot += rotInput.x;
|
||||||
player.WalkYRot += rotInput.y;
|
player.WalkYRot += rotInput.y;
|
||||||
bx::mtxRotateY(player.PlayerCamTransform.Rotation.M, player.WalkYRot);
|
bx::mtxRotateXYZ(player.PlayerCamTransform.Rotation.M, player.WalkXRot, player.WalkYRot, 0.0f);
|
||||||
player.PlayerCamTransform.RotateLocal({player.WalkXRot, 0.0f, 0.0f});
|
}
|
||||||
|
|
||||||
|
if (GetKeyPressedNow(ScanCode::SPACE))
|
||||||
|
{
|
||||||
|
player.InteractionM = player.InteractionM == InteractionMode::ReadTablet ? InteractionMode::Walk
|
||||||
|
: InteractionMode::ReadTablet;
|
||||||
|
UpdatePlayerInputMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cubes
|
// Cubes
|
||||||
@@ -170,129 +394,235 @@ namespace Game
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Puzzle tiles
|
// Puzzle tiles
|
||||||
|
Puzzle::PuzzleSolver solver;
|
||||||
|
uint16_t activeIdx = GetInstance().DebugData.SelectedDebugLevel;
|
||||||
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
|
for (int32_t i = 0; i < BX_COUNTOF(Puzzles); ++i)
|
||||||
{
|
{
|
||||||
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);
|
END_PERF(GetShared().Window.PerfCounters, PerfCounterType::GameLevelUpdate, GetShared().Window.FrameCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Level::Render(uint16_t viewId, const Model* models, const Material* materials)
|
void Level::Render(uint16_t viewId, const Model* models, const Material* materials, const Texture* textures)
|
||||||
{
|
{
|
||||||
|
ZoneScopedN("Level Render");
|
||||||
auto& shared = GetShared();
|
auto& shared = GetShared();
|
||||||
|
auto& player = GetInstance().Player;
|
||||||
|
|
||||||
float proj[16];
|
bx::mtxProj(&player.Projection.M[0],
|
||||||
bx::mtxProj(proj,
|
|
||||||
75.0f,
|
75.0f,
|
||||||
float(shared.Window.WindowWidth) / float(shared.Window.WindowHeight),
|
float(shared.Window.WindowWidth) / float(shared.Window.WindowHeight),
|
||||||
0.1f,
|
0.1f,
|
||||||
1000.0f,
|
1000.0f,
|
||||||
bgfx::getCaps()->homogeneousDepth);
|
bgfx::getCaps()->homogeneousDepth);
|
||||||
|
bx::mtxInverse(&player.ProjectionInverse.M[0], &player.Projection.M[0]);
|
||||||
|
|
||||||
auto& player = GetInstance().Player;
|
bool isFreefly = player.CameraM == CameraMode::Freefly;
|
||||||
if (player.CameraM == CameraMode::Freefly)
|
Cubes.Get(PlayerOutsideViewCube).EData.Visible = isFreefly;
|
||||||
|
if (isFreefly)
|
||||||
{
|
{
|
||||||
player.FreeflyCamTransform.UpdateMatrix();
|
UpdateMatrix(player.FreeflyCamTransform);
|
||||||
bgfx::setViewTransform(viewId, player.FreeflyCamTransform.M.M, proj);
|
bgfx::setViewTransform(viewId, player.FreeflyCamTransform.MI.M, &player.Projection.M[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
player.PlayerCamTransform.UpdateMatrix();
|
UpdateMatrix(player.PlayerCamTransform);
|
||||||
bgfx::setViewTransform(viewId, player.PlayerCamTransform.M.M, proj);
|
bgfx::setViewTransform(viewId, player.PlayerCamTransform.MI.M, &player.Projection.M[0]);
|
||||||
bgfx::dbgTextPrintf(1, 0, 0b1100, " ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cubes.Render(models, materials);
|
bgfx::touch(viewId);
|
||||||
Tests.Render(models, materials);
|
|
||||||
PuzzleTiles.Render(models, materials);
|
Cubes.Render(models, materials, textures);
|
||||||
UIQuads.Render(models, materials);
|
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()
|
void Cube::Setup()
|
||||||
{
|
{
|
||||||
EData.MaterialHandle = 0;
|
EData.MaterialHandle = EMaterial::UI;
|
||||||
EData.ModelHandle = GameRendering::Get().GetModelHandleFromPath("models/cube.gltf");
|
EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/cube.gltf");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cube::Update()
|
void Cube::Update()
|
||||||
{
|
{
|
||||||
if (TestX >= 0 && TestY >= 0)
|
EData.Transform.Position = GetInstance().Player.PlayerCamTransform.Position;
|
||||||
{
|
EData.Transform.Rotation = GetInstance().Player.PlayerCamTransform.Rotation;
|
||||||
double globalTime = GetInstance().Time.Now;
|
EData.Transform.Scale = {0.2f, 0.2f, 0.2f};
|
||||||
double time = TestY <= 5 ? globalTime * 1.0f : 0.0f;
|
|
||||||
float scale = 1.0f + TestX * 0.4f;
|
|
||||||
EData.Transform.Position = bx::Vec3{TestX * 2.0f, TestY * 2.0f, 0.0f};
|
|
||||||
EData.Transform.Scale = {scale, scale, scale};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EData.Transform.Position = {0.0f, -1.0f, 0.0f};
|
|
||||||
EData.Transform.Scale = {100.0f, 1.0f, 100.0f};
|
|
||||||
EData.TestColor[0] = 0.3f;
|
|
||||||
EData.TestColor[1] = 0.325f;
|
|
||||||
EData.TestColor[2] = 0.3f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestEntity::Setup()
|
void TestEntity::Setup()
|
||||||
{
|
{
|
||||||
EData.MaterialHandle = 0;
|
EData.MaterialHandle = EMaterial::Default;
|
||||||
EData.ModelHandle = GameRendering::Get().GetModelHandleFromPath("models/zurg.gltf");
|
EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/cube.gltf");
|
||||||
|
|
||||||
EData.Transform.Position = {0.0f, 0.0f, 0.0f};
|
|
||||||
EData.TestColor[0] = 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldPuzzle::Setup()
|
void WorldPuzzle::Setup()
|
||||||
{
|
{
|
||||||
Data.PlacedCardCount = 16;
|
|
||||||
for (int32_t i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
Data.PlacedCards[i].RefCard = {0};
|
|
||||||
Data.PlacedCards[i].Position = {int8_t(i % 4), int8_t(i / 4)};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t cardI = 0; cardI < Data.PlacedCardCount; ++cardI)
|
|
||||||
{
|
|
||||||
const Puzzle::PlacedPuzzleCard& card = Data.PlacedCards[cardI];
|
|
||||||
Level& level = GetInstance().GameLevel;
|
Level& level = GetInstance().GameLevel;
|
||||||
TileHandles[cardI] = level.PuzzleTiles.New();
|
for (int32_t i = 0; i < Puzzle::Config::MaxCardsInPuzzle; ++i)
|
||||||
UIPlacedCards[cardI] = level.UIQuads.New();
|
{
|
||||||
|
TileHandles[i] = level.PuzzleTiles.New();
|
||||||
|
PuzzleTileEntity& tile = level.PuzzleTiles.Get(TileHandles[i]);
|
||||||
|
tile.EData.MaterialHandle = EMaterial::Default;
|
||||||
|
|
||||||
bx::Vec3 Pos = {
|
for (int32_t j = 0; j < Puzzle::Config::MaxCoversInTile; ++j)
|
||||||
WorldPosition.x + card.Position.X * WorldCardSize.x,
|
{
|
||||||
WorldPosition.y,
|
int32_t idx = i * Puzzle::Config::MaxCoversInTile + j;
|
||||||
WorldPosition.z + card.Position.Y * WorldCardSize.y,
|
CoverHandles[idx] = level.PuzzleTileCovers.New();
|
||||||
};
|
PuzzleTileCover& cover = level.PuzzleTileCovers.Get(CoverHandles[idx]);
|
||||||
PuzzleTileEntity& tile = level.PuzzleTiles.Get(TileHandles[cardI]);
|
cover.EData.Visible = false;
|
||||||
tile.EData.Transform.Position = Pos;
|
|
||||||
tile.EData.MaterialHandle = 0;
|
|
||||||
|
|
||||||
UIQuadEntity& quad = level.UIQuads.Get(UIPlacedCards[cardI]);
|
|
||||||
quad.EData.MaterialHandle = 0;
|
|
||||||
quad.EData.ModelHandle = GameRendering::Get().GetModelHandleFromPath("models/plane.glb");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
void WorldPuzzle::Update()
|
||||||
{
|
{
|
||||||
Transform& camTransform = GetInstance().Player.PlayerCamTransform;
|
|
||||||
Vec3 cameraPos = camTransform.GetPosition() * -1;
|
|
||||||
Level& level = GetInstance().GameLevel;
|
Level& level = GetInstance().GameLevel;
|
||||||
|
auto& staticCards = Puzzle::GetStaticPuzzleData().Cards;
|
||||||
|
auto& visuals = Puzzle::GetStaticPuzzleData().Visuals;
|
||||||
|
|
||||||
for (int32_t cardI = 0; cardI < Data.PlacedCardCount; ++cardI)
|
// Board
|
||||||
|
for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y)
|
||||||
{
|
{
|
||||||
Puzzle::PlacedPuzzleCard& card = Data.PlacedCards[cardI];
|
for (int8_t x = 0; x < Data.WidthTiles / Puzzle::Config::CardSize; ++x)
|
||||||
if (!card.RefCard.IsValid()) continue;
|
{
|
||||||
const Puzzle::StaticPuzzleCard& cData = Puzzle::StaticPuzzleData::Get().GetCard(card.RefCard);
|
int32_t cardIdx = y * Puzzle::Config::MaxPuzzleSizeCards + x;
|
||||||
level.PuzzleTiles.Get(TileHandles[cardI]).EData.ModelHandle = cData.ModelHandle;
|
Gen::PlacedPuzzleCard& card = Data.PlacedCards[cardIdx];
|
||||||
|
auto& tile = level.PuzzleTiles.Get(TileHandles[cardIdx]);
|
||||||
|
|
||||||
auto& quad = level.UIQuads.Get(UIPlacedCards[cardI]);
|
bool isValid = Puzzle::IsValid(card.RefCard);
|
||||||
Vec3 fw = {0, -1, 0};
|
auto& staticCard = isValid ? staticCards[card.RefCard.Idx] : staticCards[0];
|
||||||
// quad.EData.Transform.SetPosition(cameraPos + Vec3{0, -2, 0});
|
|
||||||
quad.EData.Transform.SetPosition({});
|
// World Tile
|
||||||
quad.EData.Transform.Rotation = camTransform.Rotation;
|
tile.EData.Visible = true;
|
||||||
|
tile.EData.ModelH = staticCard.BaseModelHandle;
|
||||||
|
tile.EData.TextureHandle = staticCard.ModelTextureHandle;
|
||||||
|
|
||||||
|
tile.EData.DotColor = visuals.TileDotColor;
|
||||||
|
tile.EData.BaseColor = visuals.TileBaseColor;
|
||||||
|
|
||||||
|
Vec3 cardPos = PuzPosToWorldPos(Data, card.Position.X, card.Position.Y);
|
||||||
|
if (!isValid)
|
||||||
|
{
|
||||||
|
cardPos = PuzPosToWorldPos(Data, x, y);
|
||||||
}
|
}
|
||||||
|
tile.EData.Transform.Position = cardPos + WorldPosition;
|
||||||
|
bx::mtxRotateY(tile.EData.Transform.Rotation.M, card.Rotation * bx::kPi * -0.5f);
|
||||||
|
|
||||||
|
// Covers
|
||||||
|
if (IsValid(staticCard.BaseModelHandle))
|
||||||
|
{
|
||||||
|
auto& model = GameRendering::Get().Models[staticCard.BaseModelHandle.ModelIdx];
|
||||||
|
for (int32_t i = 0; i < model.SocketCount; ++i)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// End
|
||||||
|
for (int32_t i = 0; i < BX_COUNTOF(EndHandles); ++i)
|
||||||
|
{
|
||||||
|
auto& tile = level.PuzzleTiles.Get(EndHandles[i]);
|
||||||
|
if (i < Data.WidthTiles / 2)
|
||||||
|
{
|
||||||
|
tile.EData.Visible = true;
|
||||||
|
tile.EData.ModelH = staticCards[0].BaseModelHandle;
|
||||||
|
tile.EData.TextureHandle = staticCards[0].ModelTextureHandle;
|
||||||
|
tile.EData.DotColor = visuals.TileDotColor;
|
||||||
|
tile.EData.BaseColor = visuals.TileBaseColor + Vec4{0.1f, 0.1f, 0.1f, 0.0f};
|
||||||
|
tile.EData.Transform.Position = WorldPosition + Vec3{
|
||||||
|
i * Puzzle::Config::CardScaleWorld,
|
||||||
|
-5.0f,
|
||||||
|
(float)Data.HeightTiles / Puzzle::Config::CardSize *
|
||||||
|
Puzzle::Config::CardScaleWorld,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tile.EData.Visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto& wall = level.PuzzleTiles.Get(WallHandle);
|
||||||
|
wall.EData.Visible = true;
|
||||||
|
wall.EData.Transform.Position =
|
||||||
|
WorldPosition + Vec3{0.0f, 0.0f, Data.HeightTiles * 5.0f} + Vec3{30.0f, -5.0f, 0.2f};
|
||||||
|
|
||||||
|
auto& door = level.PuzzleTiles.Get(DoorHandle);
|
||||||
|
door.EData.Visible = !IsSolved;
|
||||||
|
door.EData.Transform.Position =
|
||||||
|
WorldPosition + Vec3{0.0f, 0.0f, Data.HeightTiles * 5.0f} + Vec3{30.0f, -5.0f, 0.2f};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Level::ReloadLevelEntities()
|
||||||
|
{
|
||||||
|
LevelEntities.Count = 0;
|
||||||
|
for (int32_t i = 0; i < BX_COUNTOF(BackgroundEntityHandles); ++i)
|
||||||
|
{
|
||||||
|
BackgroundEntityHandles[i] = LevelEntities.New();
|
||||||
|
auto& levelBgEntity = LevelEntities.Get(BackgroundEntityHandles[i]);
|
||||||
|
levelBgEntity.EData.LoadFromSaved(GetInstance().Player.Config.BackgroundLevelRenderData[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t GetNextRenderID()
|
||||||
|
{
|
||||||
|
static int32_t RenderIDCounter = 0;
|
||||||
|
RenderIDCounter++;
|
||||||
|
return RenderIDCounter;
|
||||||
}
|
}
|
||||||
} // namespace Game
|
} // namespace Game
|
||||||
|
|||||||
153
src/game/Level.h
153
src/game/Level.h
@@ -1,137 +1,29 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../engine/Shared.h"
|
#include "../engine/Shared.h"
|
||||||
#include "Global.h"
|
#include "Entity.h"
|
||||||
#include "Log.h"
|
|
||||||
#include "Puzzle.h"
|
#include "Puzzle.h"
|
||||||
|
#include "UI.h"
|
||||||
#include "rendering/Rendering.h"
|
#include "rendering/Rendering.h"
|
||||||
|
|
||||||
#include <bgfx/bgfx.h>
|
#include <bgfx/bgfx.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#define ENTITY_HANDLE(X) \
|
|
||||||
struct X \
|
|
||||||
{ \
|
|
||||||
uint16_t Idx = UINT16_MAX; \
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
{
|
{
|
||||||
struct EntityRenderData
|
|
||||||
{
|
|
||||||
float TestColor[4]{1.0f, 1.0f, 1.0f, 1.0f};
|
|
||||||
Transform Transform;
|
|
||||||
uint16_t MaterialHandle = UINT16_MAX;
|
|
||||||
uint16_t ModelHandle = UINT16_MAX;
|
|
||||||
bool Visible = true;
|
|
||||||
|
|
||||||
void Render(const Model* models, const Material* materials);
|
|
||||||
};
|
|
||||||
|
|
||||||
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{};
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
for (uint16_t i = 0; i < Count; ++i)
|
|
||||||
{
|
|
||||||
Get({i}).EData.Render(models, materials);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WorldPuzzle
|
struct WorldPuzzle
|
||||||
{
|
{
|
||||||
static constexpr Vec2 WorldCardSize{10.0f, 10.0f};
|
static constexpr Gen::Vec2 WorldCardSize{10.0f, 10.0f};
|
||||||
Puzzle::PuzzleData Data;
|
Gen::PuzzleData Data;
|
||||||
Vec3 WorldPosition;
|
Gen::Vec3 WorldPosition;
|
||||||
PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle];
|
PuzzleTileEntityHandle TileHandles[Puzzle::Config::MaxCardsInPuzzle];
|
||||||
UIQuadEntityHandle UIPlacedCards[Puzzle::Config::MaxCardsInPuzzle];
|
PuzzleTileCoverHandle CoverHandles[Puzzle::Config::MaxCardsInPuzzle * Puzzle::Config::MaxCoversInTile];
|
||||||
|
PuzzleTileEntityHandle EndHandles[Puzzle::Config::MaxPuzzleSizeCards];
|
||||||
|
PuzzleTileEntityHandle WallHandle;
|
||||||
|
PuzzleTileEntityHandle DoorHandle;
|
||||||
|
bool IsSetup = false;
|
||||||
|
bool IsActive = false;
|
||||||
|
bool IsSolved = false;
|
||||||
|
|
||||||
void Setup();
|
void Setup();
|
||||||
void Update();
|
void Update();
|
||||||
@@ -142,16 +34,23 @@ namespace Game
|
|||||||
public:
|
public:
|
||||||
EntityManager<Cube, CubeHandle, 1024> Cubes;
|
EntityManager<Cube, CubeHandle, 1024> Cubes;
|
||||||
EntityManager<TestEntity, TestEntityHandle, 32> Tests;
|
EntityManager<TestEntity, TestEntityHandle, 32> Tests;
|
||||||
EntityManager<PuzzleTileEntity, PuzzleTileEntityHandle, 1024> PuzzleTiles;
|
EntityManager<PuzzleTileEntity, PuzzleTileEntityHandle, Puzzle::Config::MaxTilesTotal> PuzzleTiles;
|
||||||
EntityManager<UIQuadEntity, UIQuadEntityHandle, 1024> UIQuads;
|
EntityManager<PuzzleTileCover, PuzzleTileCoverHandle, Puzzle::Config::MaxCoversTotal> PuzzleTileCovers;
|
||||||
|
UIQuadEntityManager UIQuads;
|
||||||
|
EntityManager<LevelEntity, LevelEntityHandle, 64> LevelEntities;
|
||||||
|
|
||||||
|
CubeHandle PlayerOutsideViewCube;
|
||||||
|
LevelEntityHandle BackgroundEntityHandles[16];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Puzzle::StaticPuzzleData PuzzleData;
|
Gen::StaticPuzzleData PuzzleData;
|
||||||
WorldPuzzle Puzzles[1];
|
WorldPuzzle Puzzles[Puzzle::Config::MaxVisiblePuzzles];
|
||||||
|
WorldPuzzleUI PuzzleUI;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Setup(GameData& data);
|
void Setup(GameData& data);
|
||||||
void Update();
|
void Update();
|
||||||
void Render(uint16_t ViewID, const Model* models, const Material* materials);
|
void Render(uint16_t ViewID, const Model* models, const Material* materials, const Texture* textures);
|
||||||
|
void ReloadLevelEntities();
|
||||||
};
|
};
|
||||||
} // namespace Game
|
} // namespace Game
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "bx/handlealloc.h"
|
#include "bx/handlealloc.h"
|
||||||
#include "bx/hash.h"
|
#include "bx/hash.h"
|
||||||
|
#include "bx/timer.h"
|
||||||
#include <bx/string.h>
|
#include <bx/string.h>
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include "Windows.h"
|
#include "Windows.h"
|
||||||
|
|
||||||
|
#include "Instance.h"
|
||||||
|
|
||||||
#define ESC "\x1B["
|
#define ESC "\x1B["
|
||||||
#define YELLOW ESC "33m"
|
#define YELLOW ESC "33m"
|
||||||
#define RED ESC "31m"
|
#define RED ESC "31m"
|
||||||
@@ -12,9 +15,12 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
char LineBuffer[1024]{0};
|
char LineBuffer[LogInternal::MaxLineSize]{0};
|
||||||
char OutBuffer[1024]{0};
|
char OutBuffer[LogInternal::MaxLineSize]{0};
|
||||||
|
char OutBufferUI[LogInternal::MaxLineSize]{0};
|
||||||
bx::HandleHashMapT<1024> OnceMap;
|
bx::HandleHashMapT<1024> OnceMap;
|
||||||
|
LogHistory History;
|
||||||
|
|
||||||
constexpr char LogFormat[]{"%s\n"};
|
constexpr char LogFormat[]{"%s\n"};
|
||||||
constexpr char WarnFormat[]{YELLOW "%s" END "\n"};
|
constexpr char WarnFormat[]{YELLOW "%s" END "\n"};
|
||||||
constexpr char ErrorFormat[]{RED "%s" END "\n"};
|
constexpr char ErrorFormat[]{RED "%s" END "\n"};
|
||||||
@@ -31,8 +37,18 @@ void Log(ELogType logType, const char* file, uint32_t line, const char* format,
|
|||||||
bx::snprintf(LineBuffer, sizeof(LineBuffer), LineFormat, format);
|
bx::snprintf(LineBuffer, sizeof(LineBuffer), LineFormat, format);
|
||||||
bx::vprintf(LineBuffer, args);
|
bx::vprintf(LineBuffer, args);
|
||||||
bx::vsnprintf(OutBuffer, sizeof(OutBuffer), LineBuffer, args);
|
bx::vsnprintf(OutBuffer, sizeof(OutBuffer), LineBuffer, args);
|
||||||
|
bx::vsnprintf(OutBufferUI, sizeof(OutBufferUI), format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
OutputDebugStringA(OutBuffer);
|
OutputDebugStringA(OutBuffer);
|
||||||
|
|
||||||
|
bx::strCopy(&History.LogBuffer[History.WriteIdx * LogInternal::MaxLineSize], LogInternal::MaxLineSize, 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;
|
||||||
|
|
||||||
|
++History.WriteIdx;
|
||||||
|
if (History.WriteIdx >= LogInternal::LogHistorySize) History.WriteIdx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WasLogged(ELogType logType, const char* file, uint32_t line, const char* format)
|
bool WasLogged(ELogType logType, const char* file, uint32_t line, const char* format)
|
||||||
@@ -48,3 +64,8 @@ bool WasLogged(ELogType logType, const char* file, uint32_t line, const char* fo
|
|||||||
OnceMap.insert(hash, {});
|
OnceMap.insert(hash, {});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogHistory& GetLogHistory()
|
||||||
|
{
|
||||||
|
return History;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,5 +27,22 @@ enum class ELogType
|
|||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace LogInternal
|
||||||
|
{
|
||||||
|
constexpr int32_t MaxLineSize = 1024;
|
||||||
|
constexpr int32_t LogHistorySize = 1024;
|
||||||
|
} // namespace LogInternal
|
||||||
|
|
||||||
|
struct LogHistory
|
||||||
|
{
|
||||||
|
char LogBuffer[LogInternal::MaxLineSize * LogInternal::LogHistorySize]{0};
|
||||||
|
char FileBuffer[LogInternal::MaxLineSize * LogInternal::LogHistorySize]{0};
|
||||||
|
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, ...);
|
void Log(ELogType logType, const char* file, uint32_t line, const char* format, ...);
|
||||||
bool WasLogged(ELogType logType, const char* file, uint32_t line, const char* format);
|
bool WasLogged(ELogType logType, const char* file, uint32_t line, const char* format);
|
||||||
|
LogHistory& GetLogHistory();
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
|
#include "Gen.h"
|
||||||
|
#include "Global.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Mesh.h"
|
#include "Mesh.h"
|
||||||
|
#include "bgfx/bgfx.h"
|
||||||
#include "bx/bx.h"
|
#include "bx/bx.h"
|
||||||
#include "bx/error.h"
|
#include "bx/error.h"
|
||||||
#include "bx/file.h"
|
#include "bx/file.h"
|
||||||
#include "bx/filepath.h"
|
#include "bx/filepath.h"
|
||||||
#include "bx/hash.h"
|
#include "bx/hash.h"
|
||||||
#include "bx/string.h"
|
#include "bx/string.h"
|
||||||
|
#include "bx/timer.h"
|
||||||
#include "rendering/Rendering.h"
|
#include "rendering/Rendering.h"
|
||||||
|
|
||||||
|
#include "Instance.h"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#define TINYGLTF_IMPLEMENTATION
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
@@ -17,6 +24,7 @@ namespace Game
|
|||||||
{
|
{
|
||||||
bool LoadMesh(Model& mesh, const char* path, bool isBinary)
|
bool LoadMesh(Model& mesh, const char* path, bool isBinary)
|
||||||
{
|
{
|
||||||
|
bx::strCopy(mesh.Name, sizeof(mesh.Name), path);
|
||||||
mesh.VertLayout.begin()
|
mesh.VertLayout.begin()
|
||||||
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
|
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
|
||||||
.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float)
|
.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float)
|
||||||
@@ -54,23 +62,23 @@ namespace Game
|
|||||||
|
|
||||||
tinygltf::Primitive primitive = model.meshes[0].primitives[0];
|
tinygltf::Primitive primitive = model.meshes[0].primitives[0];
|
||||||
{
|
{
|
||||||
tinygltf::Accessor accessor = model.accessors.at(primitive.indices);
|
tinygltf::Accessor indexAccessor = model.accessors.at(primitive.indices);
|
||||||
tinygltf::BufferView bufferView = model.bufferViews.at(accessor.bufferView);
|
tinygltf::BufferView indexBufferView = model.bufferViews.at(indexAccessor.bufferView);
|
||||||
tinygltf::Buffer buffer = model.buffers[bufferView.buffer];
|
int32_t indexStride = sizeof(uint16_t);
|
||||||
const bgfx::Memory* ibMem = bgfx::alloc(bufferView.byteLength);
|
tinygltf::Buffer indexBuffer = model.buffers[indexBufferView.buffer];
|
||||||
bx::memCopy(ibMem->data, &buffer.data.at(bufferView.byteOffset), bufferView.byteLength);
|
const bgfx::Memory* ibMem = bgfx::alloc(indexBufferView.byteLength);
|
||||||
|
bx::memCopy(ibMem->data, &indexBuffer.data.at(indexBufferView.byteOffset), indexBufferView.byteLength);
|
||||||
mesh.IndexBuffer = bgfx::createIndexBuffer(ibMem);
|
mesh.IndexBuffer = bgfx::createIndexBuffer(ibMem);
|
||||||
}
|
|
||||||
{
|
|
||||||
tinygltf::Accessor posAccessor = model.accessors.at(primitive.attributes.at("POSITION"));
|
tinygltf::Accessor posAccessor = model.accessors.at(primitive.attributes.at("POSITION"));
|
||||||
tinygltf::Accessor normalAccessor = model.accessors.at(primitive.attributes.at("NORMAL"));
|
tinygltf::Accessor normalAccessor = model.accessors.at(primitive.attributes.at("NORMAL"));
|
||||||
tinygltf::Accessor uvAccessor = model.accessors.at(primitive.attributes.at("TEXCOORD_0"));
|
tinygltf::Accessor uvAccessor = model.accessors.at(primitive.attributes.at("TEXCOORD_0"));
|
||||||
tinygltf::BufferView posBufferView = model.bufferViews[posAccessor.bufferView];
|
tinygltf::BufferView posBufferView = model.bufferViews[posAccessor.bufferView];
|
||||||
tinygltf::BufferView normalBufferView = model.bufferViews[normalAccessor.bufferView];
|
tinygltf::BufferView normalBufferView = model.bufferViews[normalAccessor.bufferView];
|
||||||
tinygltf::BufferView uvBufferView = model.bufferViews[uvAccessor.bufferView];
|
tinygltf::BufferView uvBufferView = model.bufferViews[uvAccessor.bufferView];
|
||||||
int posStride = posAccessor.ByteStride(posBufferView);
|
int32_t posStride = posAccessor.ByteStride(posBufferView);
|
||||||
int normalStride = normalAccessor.ByteStride(normalBufferView);
|
int32_t normalStride = normalAccessor.ByteStride(normalBufferView);
|
||||||
int uvStride = uvAccessor.ByteStride(uvBufferView);
|
int32_t uvStride = uvAccessor.ByteStride(uvBufferView);
|
||||||
tinygltf::Buffer posBuffer = model.buffers[posBufferView.buffer];
|
tinygltf::Buffer posBuffer = model.buffers[posBufferView.buffer];
|
||||||
tinygltf::Buffer normalBuffer = model.buffers[normalBufferView.buffer];
|
tinygltf::Buffer normalBuffer = model.buffers[normalBufferView.buffer];
|
||||||
tinygltf::Buffer uvBuffer = model.buffers[uvBufferView.buffer];
|
tinygltf::Buffer uvBuffer = model.buffers[uvBufferView.buffer];
|
||||||
@@ -88,7 +96,113 @@ namespace Game
|
|||||||
bx::memCopy(&v.uv_x, &uvBuffer.data.at(uvBufferView.byteOffset + i * uvStride), uvStride);
|
bx::memCopy(&v.uv_x, &uvBuffer.data.at(uvBufferView.byteOffset + i * uvStride), uvStride);
|
||||||
}
|
}
|
||||||
mesh.VertexBuffer = bgfx::createVertexBuffer(vbMem, mesh.VertLayout);
|
mesh.VertexBuffer = bgfx::createVertexBuffer(vbMem, mesh.VertLayout);
|
||||||
|
|
||||||
|
constexpr float SIZE_LIMIT = 1000.0f;
|
||||||
|
mesh.MinPos = {SIZE_LIMIT, SIZE_LIMIT, SIZE_LIMIT};
|
||||||
|
mesh.MaxPos = {-SIZE_LIMIT, -SIZE_LIMIT, -SIZE_LIMIT};
|
||||||
|
|
||||||
|
bx::memSet(mesh.Height.Values, 0, BX_COUNTOF(mesh.Height.Values));
|
||||||
|
|
||||||
|
int64_t startTime = bx::getHPCounter();
|
||||||
|
for (int32_t i = 0; i < vertexCount; ++i)
|
||||||
|
{
|
||||||
|
Gen::Vec3* pos =
|
||||||
|
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + i * posStride]);
|
||||||
|
if (pos->x < mesh.MinPos.x) mesh.MinPos.x = pos->x;
|
||||||
|
if (pos->y < mesh.MinPos.y) mesh.MinPos.y = pos->y;
|
||||||
|
if (pos->z < mesh.MinPos.z) mesh.MinPos.z = pos->z;
|
||||||
|
if (pos->x > mesh.MaxPos.x) mesh.MaxPos.x = pos->x;
|
||||||
|
if (pos->y > mesh.MaxPos.y) mesh.MaxPos.y = pos->y;
|
||||||
|
if (pos->z > mesh.MaxPos.z) mesh.MaxPos.z = pos->z;
|
||||||
}
|
}
|
||||||
|
LOG("min/max: %lli", bx::getHPCounter() - startTime);
|
||||||
|
|
||||||
|
mesh.MinPos = {-5.0f, -5.0f, -5.0f};
|
||||||
|
mesh.MaxPos = {5.0f, 5.0f, 5.0f};
|
||||||
|
mesh.Size = mesh.MaxPos - mesh.MinPos;
|
||||||
|
|
||||||
|
startTime = bx::getHPCounter();
|
||||||
|
for (uint32_t v = 0; v < HeightMap::Height; ++v)
|
||||||
|
{
|
||||||
|
float vPos = mesh.MinPos.z + (float)v / HeightMap::Height * mesh.Size.z;
|
||||||
|
|
||||||
|
for (uint32_t u = 0; u < HeightMap::Width; ++u)
|
||||||
|
{
|
||||||
|
float uPos = mesh.MinPos.x + (float)u / HeightMap::Width * mesh.Size.x;
|
||||||
|
|
||||||
|
Gen::Vec3 rayStart = {uPos, -100.0f, vPos};
|
||||||
|
Gen::Vec3 rayEnd = {uPos, 100.0f, vPos};
|
||||||
|
Gen::Vec3 ptOut;
|
||||||
|
|
||||||
|
for (int16_t i = 0; i < indexBufferView.byteLength; i += indexStride * 3)
|
||||||
|
{
|
||||||
|
uint16_t* idxA = reinterpret_cast<uint16_t*>(&indexBuffer.data[indexBufferView.byteOffset + i]);
|
||||||
|
uint16_t* idxB = reinterpret_cast<uint16_t*>(
|
||||||
|
&indexBuffer.data[indexBufferView.byteOffset + i + 1 * indexStride]);
|
||||||
|
uint16_t* idxC = reinterpret_cast<uint16_t*>(
|
||||||
|
&indexBuffer.data[indexBufferView.byteOffset + i + 2 * indexStride]);
|
||||||
|
Gen::Vec3* triA =
|
||||||
|
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + *idxA * posStride]);
|
||||||
|
Gen::Vec3* triB =
|
||||||
|
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + *idxB * posStride]);
|
||||||
|
Gen::Vec3* triC =
|
||||||
|
reinterpret_cast<Gen::Vec3*>(&posBuffer.data[posBufferView.byteOffset + *idxC * posStride]);
|
||||||
|
if (Gen::RayTriangleIntersect(rayStart, rayEnd, *triA, *triB, *triC, ptOut))
|
||||||
|
{
|
||||||
|
float len = ptOut.y - rayStart.y;
|
||||||
|
uint8_t val = (uint8_t)(len / mesh.Size.y * UINT8_MAX);
|
||||||
|
int32_t idx = v * HeightMap::Width + u;
|
||||||
|
if (mesh.Height.Values[idx] < val)
|
||||||
|
{
|
||||||
|
mesh.Height.Values[idx] = val;
|
||||||
|
}
|
||||||
|
if (len < 0.0f)
|
||||||
|
{
|
||||||
|
LOG_ONCE("%f / %f = %u", len, mesh.Size.y, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG("heightmap: %lli", bx::getHPCounter() - startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bgfx::Memory* mem = bgfx::makeRef(&mesh.Height.Values[0], sizeof(mesh.Height.Values));
|
||||||
|
mesh.HeightMapTexture =
|
||||||
|
bgfx::createTexture2D(HeightMap::Width, HeightMap::Height, false, 1, bgfx::TextureFormat::R8, 0, mem);
|
||||||
|
|
||||||
|
for (auto& node : model.nodes)
|
||||||
|
{
|
||||||
|
if (bx::strFindI(node.name.c_str(), "_slot_").getLength() > 0)
|
||||||
|
{
|
||||||
|
if (mesh.SocketCount >= mesh.MaxSocketCount)
|
||||||
|
{
|
||||||
|
LOG_WARN("Too many sockets on mesh!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto& socket = mesh.Sockets[mesh.SocketCount];
|
||||||
|
if (node.translation.size() >= 3)
|
||||||
|
{
|
||||||
|
socket.Pos.x = node.translation[0];
|
||||||
|
socket.Pos.y = node.translation[1];
|
||||||
|
socket.Pos.z = node.translation[2];
|
||||||
|
}
|
||||||
|
if (node.rotation.size() >= 4)
|
||||||
|
{
|
||||||
|
socket.Rot = Gen::RotationFromQuaternion({static_cast<float>(node.rotation[0]),
|
||||||
|
static_cast<float>(node.rotation[1]),
|
||||||
|
static_cast<float>(node.rotation[2]),
|
||||||
|
static_cast<float>(node.rotation[3])});
|
||||||
|
}
|
||||||
|
if (node.matrix.size() >= 0)
|
||||||
|
{
|
||||||
|
LOG_WARN("TODO: support matrix!");
|
||||||
|
}
|
||||||
|
bx::strCopy(&socket.Name[0], socket.MaxSocketNameLength, node.name.c_str());
|
||||||
|
++mesh.SocketCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +244,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
LOG("Found %u models!", modelFilePathCount);
|
LOG("Found %u models!", modelFilePathCount);
|
||||||
|
|
||||||
|
auto& inst = GetInstance();
|
||||||
int32_t writeI = 0;
|
int32_t writeI = 0;
|
||||||
for (int32_t i = 0; i < modelFilePathCount; ++i)
|
for (int32_t i = 0; i < modelFilePathCount; ++i)
|
||||||
{
|
{
|
||||||
@@ -138,7 +253,16 @@ namespace Game
|
|||||||
Model& mod = models[writeI];
|
Model& mod = models[writeI];
|
||||||
if (LoadMesh(mod, fullPath.getCPtr(), modelFileIsBinary[i]))
|
if (LoadMesh(mod, fullPath.getCPtr(), modelFileIsBinary[i]))
|
||||||
{
|
{
|
||||||
mod.AssetHandle = CrcPath(fullPath.getCPtr());
|
mod.Handle.Asset.Idx = CrcPath(fullPath.getCPtr());
|
||||||
|
mod.Handle.ModelIdx = writeI;
|
||||||
|
if (inst.DebugData.AssetCount < inst.DebugData.MaxAssets)
|
||||||
|
{
|
||||||
|
inst.DebugData.AssetHandles[inst.DebugData.AssetCount] = mod.Handle.Asset;
|
||||||
|
bx::strCopy(inst.DebugData.AssetHandlePaths[inst.DebugData.AssetCount],
|
||||||
|
sizeof(inst.DebugData.AssetHandlePaths[inst.DebugData.AssetCount]),
|
||||||
|
fullPath.getCPtr());
|
||||||
|
++inst.DebugData.AssetCount;
|
||||||
|
}
|
||||||
++writeI;
|
++writeI;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,82 +1,177 @@
|
|||||||
|
#include "../gen/Def.h"
|
||||||
|
#include "Gen.h"
|
||||||
|
#include "Global.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Puzzle.h"
|
#include "Puzzle.h"
|
||||||
#include "bx/string.h"
|
|
||||||
#include "imgui.h"
|
|
||||||
#include "rendering/Rendering.h"
|
|
||||||
|
|
||||||
#include "bx/bx.h"
|
#include "bx/bx.h"
|
||||||
|
#include "bx/string.h"
|
||||||
|
#include "imgui.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
static constexpr Puzzle::PuzPos Dirs[4]{
|
using namespace Gen;
|
||||||
|
static constexpr PuzPos Dirs[4]{
|
||||||
{-1, 0},
|
{-1, 0},
|
||||||
{0, -1},
|
{0, -1},
|
||||||
{0, 1},
|
{0, 1},
|
||||||
{1, 0},
|
{1, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
Puzzle::StaticPuzzleData* StaticDataInstance = nullptr;
|
StaticPuzzleData StaticData;
|
||||||
|
StaticPuzzleCard InvalidCard;
|
||||||
|
PlacedPuzzleCard InvalidPlacedCard;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace Puzzle
|
namespace Puzzle
|
||||||
{
|
{
|
||||||
void StaticPuzzleData::Setup()
|
constexpr float UIPuzBoxSize = 26;
|
||||||
|
using namespace Gen;
|
||||||
|
|
||||||
|
void Setup()
|
||||||
{
|
{
|
||||||
StaticDataInstance = this;
|
|
||||||
LOG("Setting up static puzzle data");
|
LOG("Setting up static puzzle data");
|
||||||
for (int32_t i = 0; i < BX_COUNTOF(Cards); ++i)
|
LoadStaticPuzzleData();
|
||||||
{
|
|
||||||
Cards[i].ModelHandle = Game::GameRendering::Get().GetModelHandleFromPath("models/w straight.glb");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticPuzzleData& StaticPuzzleData::Get()
|
StaticPuzzleData& GetStaticPuzzleData()
|
||||||
{
|
{
|
||||||
assert(StaticDataInstance != nullptr);
|
return StaticData;
|
||||||
return *StaticDataInstance;
|
|
||||||
}
|
|
||||||
const StaticPuzzleCard& StaticPuzzleData::GetCard(StaticPuzzleCardHandle H) const
|
|
||||||
{
|
|
||||||
assert(H.IsValid());
|
|
||||||
return Cards[H.Idx];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PuzzleNode::HasElement(PuzzleElementType search) const
|
void LoadStaticPuzzleData()
|
||||||
{
|
{
|
||||||
for (int32_t i = 0; i < Config::MaxElementsPerTile; ++i)
|
Deserializer ser;
|
||||||
|
if (ser.Init("game/data/static/puzzle.dat", "SPUZ") && ser.ReadT(StaticData))
|
||||||
{
|
{
|
||||||
if (PlacedTypes[i] == search) return true;
|
LOG("Successfully loaded static puzzle data!");
|
||||||
}
|
}
|
||||||
return false;
|
ser.Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PuzzleNode::IsEmpty() const
|
void SaveStaticPuzzleData()
|
||||||
{
|
{
|
||||||
for (int32_t i = 0; i < Config::MaxElementsPerTile; ++i)
|
auto& data = GetStaticPuzzleData();
|
||||||
|
Serializer ser;
|
||||||
|
if (ser.Init("game/data/static/puzzle.dat", "SPUZ") && ser.WriteT(GetStaticPuzzleData()))
|
||||||
{
|
{
|
||||||
if (PlacedTypes[i] != PuzzleElementType::None) return false;
|
LOG("Successfully saved static puzzle data!");
|
||||||
}
|
}
|
||||||
return true;
|
ser.Finish();
|
||||||
|
}
|
||||||
|
const StaticPuzzleCard& GetCard(StaticPuzzleCardHandle H)
|
||||||
|
{
|
||||||
|
if (H.Idx == UINT16_MAX)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Invalid static card handle!");
|
||||||
|
return InvalidCard;
|
||||||
|
}
|
||||||
|
return GetStaticPuzzleData().Cards[H.Idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t PuzzleCardStack::GetRemainingCount()
|
bool IsValid(StaticPuzzleCardHandle h)
|
||||||
{
|
{
|
||||||
assert(MaxAvailableCount >= UsedCount);
|
return h.Idx != UINT16_MAX;
|
||||||
return MaxAvailableCount - UsedCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PuzzleNode& PuzzleData::GetNodeAt(PuzPos pos) const
|
const char* GetShortNodeName(const PuzzleElementType::Enum node)
|
||||||
{
|
{
|
||||||
assert(pos.X < Config::MaxPuzzleSizeCards && pos.Y < Config::MaxPuzzleSizeCards && pos.X >= 0 && pos.Y >= 0);
|
return PuzzleElementType::ShortName[node];
|
||||||
return PlacedNodes[pos.Y * Config::MaxPuzzleSizeCards + pos.X];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PuzzleElementType PuzzleData::GetElementAt(ElemPos pos) const
|
uint8_t GetRemainingCount(const PuzzleCardStack& stack)
|
||||||
{
|
{
|
||||||
assert(pos.ElemIdx < Config::MaxElementsPerTile);
|
assert(stack.MaxAvailableCount >= stack.UsedCount);
|
||||||
const PuzzleNode& node = GetNodeAt(pos.Position);
|
return stack.MaxAvailableCount - stack.UsedCount;
|
||||||
return node.PlacedTypes[pos.ElemIdx];
|
}
|
||||||
|
|
||||||
|
PuzzleElementType::Enum GetNodeAt(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.PlacedCards[cardIdxY * Puzzle::Config::MaxPuzzleSizeCards + cardIdxX];
|
||||||
|
int32_t offsetX = pos.X - (cardIdxX * Config::CardSize);
|
||||||
|
int32_t offsetY = pos.Y - (cardIdxY * Config::CardSize);
|
||||||
|
if (offsetX >= 0 && offsetX < Puzzle::Config::CardSize && offsetY >= 0 && offsetY < Puzzle::Config::CardSize &&
|
||||||
|
IsValid(card.RefCard))
|
||||||
|
{
|
||||||
|
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 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);
|
||||||
|
assert(y >= 0 && y < Puzzle::Config::CardSize);
|
||||||
|
|
||||||
|
uint8_t arrX = x;
|
||||||
|
uint8_t arrY = y;
|
||||||
|
if (rotation == 1)
|
||||||
|
{
|
||||||
|
arrX = y;
|
||||||
|
arrY = Config::CardSize - x - 1;
|
||||||
|
}
|
||||||
|
else if (rotation == 2)
|
||||||
|
{
|
||||||
|
arrX = Config::CardSize - x - 1;
|
||||||
|
arrY = Config::CardSize - y - 1;
|
||||||
|
}
|
||||||
|
else if (rotation == 3)
|
||||||
|
{
|
||||||
|
arrX = Config::CardSize - y - 1;
|
||||||
|
arrY = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return card.Elements[arrY * Puzzle::Config::CardSize + arrX];
|
||||||
|
}
|
||||||
|
|
||||||
|
PuzzleElementType::Enum& EditCardNodeAt(StaticPuzzleCard& card, uint8_t rotation, int8_t x, int8_t y)
|
||||||
|
{
|
||||||
|
assert(x >= 0 && x < Puzzle::Config::CardSize);
|
||||||
|
assert(y >= 0 && y < Puzzle::Config::CardSize);
|
||||||
|
|
||||||
|
uint8_t arrX = x;
|
||||||
|
uint8_t arrY = y;
|
||||||
|
if (rotation == 1)
|
||||||
|
{
|
||||||
|
arrX = y;
|
||||||
|
arrY = Config::CardSize - x - 1;
|
||||||
|
}
|
||||||
|
else if (rotation == 2)
|
||||||
|
{
|
||||||
|
arrX = Config::CardSize - x - 1;
|
||||||
|
arrY = Config::CardSize - y - 1;
|
||||||
|
}
|
||||||
|
else if (rotation == 3)
|
||||||
|
{
|
||||||
|
arrX = Config::CardSize - y - 1;
|
||||||
|
arrY = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return card.Elements[arrY * Puzzle::Config::CardSize + arrX];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PuzzleSolver::IsPuzzleSolved(const PuzzleData& puzzle)
|
bool PuzzleSolver::IsPuzzleSolved(const PuzzleData& puzzle)
|
||||||
@@ -93,38 +188,53 @@ namespace Puzzle
|
|||||||
return IsSolved;
|
return IsSolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PuzzleSolver::IsExitSatisfied(const PuzzleData& puzzle, ElemPos pos)
|
bool PuzzleSolver::IsExitSatisfied(const PuzzleData& puzzle, PuzPos pos)
|
||||||
{
|
{
|
||||||
const PuzzleNode& goalNode = puzzle.GetNodeAt(pos.Position);
|
PuzzleElementType::Enum goalType = GetNodeAt(puzzle, pos);
|
||||||
PuzzleElementType goalType = puzzle.GetElementAt(pos);
|
if (goalType == PuzzleElementType::None)
|
||||||
|
{
|
||||||
|
WARN_ONCE("TODO!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t currentPositionQueueIdx = 0;
|
uint32_t currentPositionQueueIdx = 0;
|
||||||
uint32_t positionQueueCount = 0;
|
uint32_t positionQueueCount = 0;
|
||||||
PuzPos positionQueue[Config::MaxTilesInPuzzle];
|
PuzPos positionQueue[Puzzle::Config::MaxTilesInPuzzle];
|
||||||
|
|
||||||
positionQueue[0] = pos.Position;
|
positionQueue[0] = pos;
|
||||||
positionQueueCount++;
|
positionQueueCount++;
|
||||||
while (positionQueueCount > 0)
|
while (currentPositionQueueIdx < positionQueueCount)
|
||||||
{
|
{
|
||||||
assert(currentPositionQueueIdx < Config::MaxTilesInPuzzle);
|
assert(currentPositionQueueIdx < Puzzle::Config::MaxTilesInPuzzle);
|
||||||
PuzPos currentPos = positionQueue[currentPositionQueueIdx];
|
PuzPos currentPos = positionQueue[currentPositionQueueIdx];
|
||||||
for (PuzPos dir : Dirs)
|
for (PuzPos dir : Dirs)
|
||||||
{
|
{
|
||||||
PuzPos nextPos = currentPos + dir;
|
PuzPos nextPos = currentPos + dir;
|
||||||
|
if (!(nextPos.X >= 0 && nextPos.Y >= 0 && nextPos.X < puzzle.WidthTiles &&
|
||||||
|
nextPos.Y < puzzle.HeightTiles))
|
||||||
|
continue;
|
||||||
if (IsValidGoalConnection(puzzle, nextPos, currentPos, goalType))
|
if (IsValidGoalConnection(puzzle, nextPos, currentPos, goalType))
|
||||||
{
|
{
|
||||||
const PuzzleNode& node = puzzle.GetNodeAt(nextPos);
|
if (IsValidSource(GetNodeAt(puzzle, nextPos), goalType))
|
||||||
for (PuzzleElementType e : node.PlacedTypes)
|
|
||||||
{
|
|
||||||
if (IsValidSource(e, goalType))
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
bool found = false;
|
||||||
|
for (int32_t i = 0; i < positionQueueCount; ++i)
|
||||||
|
{
|
||||||
|
if (positionQueue[i].X == nextPos.X && positionQueue[i].Y == nextPos.Y)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
positionQueue[positionQueueCount] = nextPos;
|
positionQueue[positionQueueCount] = nextPos;
|
||||||
positionQueueCount++;
|
positionQueueCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
currentPositionQueueIdx++;
|
currentPositionQueueIdx++;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -133,47 +243,229 @@ namespace Puzzle
|
|||||||
bool PuzzleSolver::IsValidGoalConnection(const PuzzleData& puzzle,
|
bool PuzzleSolver::IsValidGoalConnection(const PuzzleData& puzzle,
|
||||||
PuzPos flowFrom,
|
PuzPos flowFrom,
|
||||||
PuzPos flowTo,
|
PuzPos flowTo,
|
||||||
PuzzleElementType goalType)
|
PuzzleElementType::Enum goalType)
|
||||||
{
|
{
|
||||||
const PuzzleNode& from = puzzle.GetNodeAt(flowFrom);
|
auto from = GetNodeAt(puzzle, flowFrom);
|
||||||
const PuzzleNode& to = puzzle.GetNodeAt(flowTo);
|
auto to = GetNodeAt(puzzle, flowTo);
|
||||||
|
|
||||||
if (goalType == PuzzleElementType::WaterGoal)
|
if (goalType == PuzzleElementType::WaterGoal)
|
||||||
{
|
{
|
||||||
return from.HasElement(PuzzleElementType::WaterIn) || from.HasElement(PuzzleElementType::WaterChannel) ||
|
return from == PuzzleElementType::WaterIn || from == PuzzleElementType::WaterChannel ||
|
||||||
from.HasElement(PuzzleElementType::WaterGoal);
|
from == PuzzleElementType::WaterGoal || from == PuzzleElementType::Bridge;
|
||||||
}
|
}
|
||||||
else if (goalType == PuzzleElementType::ElectricGoal)
|
else if (goalType == PuzzleElementType::ElectricGoal)
|
||||||
{
|
{
|
||||||
return from.HasElement(PuzzleElementType::ElectricIn) || from.HasElement(PuzzleElementType::ElectricGoal) ||
|
return from == PuzzleElementType::ElectricIn || from == PuzzleElementType::ElectricGoal ||
|
||||||
from.IsEmpty();
|
from == PuzzleElementType::None;
|
||||||
}
|
}
|
||||||
assert(false);
|
// assert(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool PuzzleSolver::IsValidSource(PuzzleElementType sourceType, PuzzleElementType goalType)
|
bool PuzzleSolver::IsValidSource(PuzzleElementType::Enum sourceType, PuzzleElementType::Enum goalType)
|
||||||
{
|
{
|
||||||
return (sourceType == PuzzleElementType::WaterIn && goalType == PuzzleElementType::WaterGoal) ||
|
return (sourceType == PuzzleElementType::WaterIn && goalType == PuzzleElementType::WaterGoal) ||
|
||||||
(sourceType == PuzzleElementType::ElectricIn && goalType == PuzzleElementType::ElectricGoal);
|
(sourceType == PuzzleElementType::ElectricIn && goalType == PuzzleElementType::ElectricGoal);
|
||||||
}
|
}
|
||||||
|
void DrawCard(const StaticPuzzleCard& card, uint8_t rotation, ImVec2 pos)
|
||||||
bool PuzzleData::RenderDebugUI()
|
|
||||||
{
|
{
|
||||||
bool dataChanged = false;
|
auto& drawList = *ImGui::GetWindowDrawList();
|
||||||
|
for (int32_t y = 0; y < Puzzle::Config::CardSize; ++y)
|
||||||
|
{
|
||||||
|
for (int32_t x = 0; x < Puzzle::Config::CardSize; ++x)
|
||||||
|
{
|
||||||
|
ImGui::SetCursorScreenPos({pos.x + x * UIPuzBoxSize, pos.y + y * UIPuzBoxSize});
|
||||||
|
ImGui::Text("%s", GetShortNodeName(GetCardNodeAt(card, rotation, x, y)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int32_t y = 0; y <= Puzzle::Config::CardSize; ++y)
|
||||||
|
{
|
||||||
|
ImVec2 linePos = {pos.x, pos.y + y * UIPuzBoxSize};
|
||||||
|
drawList.AddLine(linePos,
|
||||||
|
{linePos.x + Puzzle::Config::CardSize * UIPuzBoxSize, linePos.y},
|
||||||
|
y % Puzzle::Config::CardSize == 0 ? 0xFFFFFFFF : 0x11FFFFFF);
|
||||||
|
}
|
||||||
|
for (int32_t x = 0; x <= Puzzle::Config::CardSize; ++x)
|
||||||
|
{
|
||||||
|
ImVec2 linePos = {pos.x + x * UIPuzBoxSize, pos.y};
|
||||||
|
drawList.AddLine(linePos,
|
||||||
|
{linePos.x, linePos.y + Puzzle::Config::CardSize * UIPuzBoxSize},
|
||||||
|
x % Puzzle::Config::CardSize == 0 ? 0xFFFFFFFF : 0x11FFFFFF);
|
||||||
|
}
|
||||||
|
ImGui::SetCursorScreenPos(pos);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
PlacedPuzzleCard& placedCard = GetCardAt(obj, targetPos);
|
||||||
|
if (IsValid(placedCard.RefCard))
|
||||||
|
{
|
||||||
|
if (GetFlag(placedCard.Flags, PlacedPuzzleCardFlags::Locked))
|
||||||
|
{
|
||||||
|
LOG_WARN("Card at %i %i is locked!", targetPos.X, targetPos.Y);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool found = false;
|
||||||
|
for (int32_t i = 0; i < obj.AvailableCardCount; ++i)
|
||||||
|
{
|
||||||
|
if (obj.AvailableCards[i].RefCard.Idx == placedCard.RefCard.Idx && obj.AvailableCards[i].UsedCount > 0)
|
||||||
|
{
|
||||||
|
obj.AvailableCards[i].UsedCount--;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Failed to find available card to return placed card of type %u to!", placedCard.RefCard.Idx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
placedCard.RefCard = {};
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DragAvailableCardTo(PuzzleData& obj, PuzPos targetPos, int32_t availIdx, uint8_t rotation)
|
||||||
|
{
|
||||||
|
if (availIdx >= obj.AvailableCardCount)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Invalid drag with avail idx %i!", availIdx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ReturnPlacedCard(obj, targetPos)) return false;
|
||||||
|
|
||||||
|
auto& draggedCard = obj.AvailableCards[availIdx];
|
||||||
|
draggedCard.UsedCount++;
|
||||||
|
|
||||||
|
PlacedPuzzleCard& placedCard = GetCardAt(obj, targetPos);
|
||||||
|
placedCard.RefCard = draggedCard.RefCard;
|
||||||
|
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 isVisible = true;
|
bool isVisible = true;
|
||||||
if (ImGui::Begin("Puzzle", &isVisible))
|
if (ImGui::Begin("Puzzle", &isVisible))
|
||||||
{
|
{
|
||||||
ImGui::Text("%s", PuzzleName);
|
if (ImGui::Button("Delete Puzzle"))
|
||||||
|
{
|
||||||
|
char filepath[128]{0};
|
||||||
|
WritePuzzleFilePath(filepath, sizeof(filepath), obj.ID);
|
||||||
|
bx::remove(filepath);
|
||||||
|
obj.ID = UINT16_MAX;
|
||||||
|
ImGui::End();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Reset"))
|
||||||
|
{
|
||||||
|
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 W = S.WidthTiles;
|
int32_t val = obj.ID;
|
||||||
int32_t H = S.HeightTiles;
|
if (ImGui::InputInt("ID", &val))
|
||||||
|
{
|
||||||
|
obj.ID = val;
|
||||||
|
}
|
||||||
|
ImGui::InputText("Name", obj.PuzzleName, sizeof(obj.PuzzleName));
|
||||||
|
|
||||||
|
int32_t W = obj.WidthTiles;
|
||||||
|
int32_t H = obj.HeightTiles;
|
||||||
ImGui::PushID("width");
|
ImGui::PushID("width");
|
||||||
ImGui::SetNextItemWidth(40);
|
ImGui::SetNextItemWidth(40);
|
||||||
if (ImGui::DragInt("", &W, 0.3f, 0, Config::MaxPuzzleSizeTiles))
|
if (ImGui::DragInt("", &W, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
|
||||||
{
|
{
|
||||||
S.WidthTiles = uint8_t(W);
|
obj.WidthTiles = uint8_t(W);
|
||||||
dataChanged = true;
|
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
@@ -181,22 +473,195 @@ namespace Puzzle
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(40);
|
ImGui::SetNextItemWidth(40);
|
||||||
ImGui::PushID("height");
|
ImGui::PushID("height");
|
||||||
if (ImGui::DragInt("", &H, 0.3f, 0, Config::MaxPuzzleSizeTiles))
|
if (ImGui::DragInt("", &H, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
|
||||||
{
|
{
|
||||||
S.HeightTiles = uint8_t(H);
|
obj.HeightTiles = uint8_t(H);
|
||||||
dataChanged = true;
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
ImVec2 puzCursorStart = ImGui::GetCursorScreenPos();
|
||||||
|
auto& drawList = *ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
|
obj.GoalPositionCount = 0;
|
||||||
|
for (int32_t y = 0; y < obj.HeightTiles; ++y)
|
||||||
|
{
|
||||||
|
ImGui::PushID(y);
|
||||||
|
for (int32_t x = 0; x < obj.WidthTiles; ++x)
|
||||||
|
{
|
||||||
|
ImGui::PushID(x);
|
||||||
|
PuzPos nodePos = {int8_t(x), int8_t(y)};
|
||||||
|
auto node = GetInitialNodeAt(obj, nodePos);
|
||||||
|
if (node == PuzzleElementType::WaterGoal)
|
||||||
|
{
|
||||||
|
obj.GoalPositions[obj.GoalPositionCount] = nodePos;
|
||||||
|
obj.GoalPositionCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 pos = ImVec2{puzCursorStart.x + x * UIPuzBoxSize + 5, puzCursorStart.y + y * UIPuzBoxSize};
|
||||||
|
ImGui::SetCursorScreenPos(pos);
|
||||||
|
ImGui::Text("%s", GetShortNodeName(node));
|
||||||
|
ImGui::SetCursorScreenPos(pos);
|
||||||
|
if (x % Puzzle::Config::CardSize == 0 && y % Puzzle::Config::CardSize == 0)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemClicked(ImGuiMouseButton_Middle))
|
||||||
|
{
|
||||||
|
if (ImGui::IsKeyDown(ImGuiKey_LeftShift))
|
||||||
|
{
|
||||||
|
placedCard = {};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
placedCard.Flags =
|
||||||
|
(PlacedPuzzleCardFlags::Enum)(placedCard.Flags ^ PlacedPuzzleCardFlags::Locked);
|
||||||
|
RecalculateInitialAvailable(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isLocked && IsValid(placedCard.RefCard))
|
||||||
|
{
|
||||||
|
ImVec2 s = {puzCursorStart.x + x * UIPuzBoxSize, puzCursorStart.y + y * UIPuzBoxSize};
|
||||||
|
drawList.AddRectFilled(s,
|
||||||
|
{s.x + UIPuzBoxSize * Puzzle::Config::CardSize,
|
||||||
|
s.y + UIPuzBoxSize * Puzzle::Config::CardSize},
|
||||||
|
0x33FFFFFF);
|
||||||
|
}
|
||||||
|
if (ImGui::BeginDragDropTarget())
|
||||||
|
{
|
||||||
|
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("cardtype", 0))
|
||||||
|
{
|
||||||
|
uint32_t CardIdx = *reinterpret_cast<uint32_t*>(payload->Data);
|
||||||
|
placedCard = {};
|
||||||
|
placedCard.RefCard = {(uint16_t)CardIdx};
|
||||||
|
placedCard.Rotation = 0;
|
||||||
|
placedCard.Position = cardPos;
|
||||||
|
placedCard.Flags = (PlacedPuzzleCardFlags::Enum)SetFlags(placedCard.Flags,
|
||||||
|
PlacedPuzzleCardFlags::Locked);
|
||||||
|
RecalculateInitialAvailable(obj);
|
||||||
|
}
|
||||||
|
ImGui::EndDragDropTarget();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::PopID();
|
||||||
|
|
||||||
if (dataChanged)
|
|
||||||
{
|
|
||||||
char path[128]{0};
|
|
||||||
bx::snprintf(path, sizeof(path), "game/data/%s.pzl", PuzzleName);
|
|
||||||
SerializeStruct(&S, sizeof(S), path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int32_t y = 0; y <= obj.HeightTiles; ++y)
|
||||||
|
{
|
||||||
|
ImVec2 linePos = {puzCursorStart.x, puzCursorStart.y + y * UIPuzBoxSize};
|
||||||
|
drawList.AddLine(linePos,
|
||||||
|
{linePos.x + obj.WidthTiles * UIPuzBoxSize, linePos.y},
|
||||||
|
y % Puzzle::Config::CardSize == 0 ? 0xFFFFFFFF : 0x11FFFFFF);
|
||||||
|
}
|
||||||
|
for (int32_t x = 0; x <= obj.WidthTiles; ++x)
|
||||||
|
{
|
||||||
|
ImVec2 linePos = {puzCursorStart.x + x * UIPuzBoxSize, puzCursorStart.y};
|
||||||
|
drawList.AddLine(linePos,
|
||||||
|
{linePos.x, linePos.y + obj.HeightTiles * UIPuzBoxSize},
|
||||||
|
x % Puzzle::Config::CardSize == 0 ? 0xFFFFFFFF : 0x11FFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 pos = ImVec2{puzCursorStart.x + obj.WidthTiles * UIPuzBoxSize + 5,
|
||||||
|
puzCursorStart.y + obj.HeightTiles * UIPuzBoxSize};
|
||||||
|
|
||||||
|
ImGui::SetCursorScreenPos(pos);
|
||||||
|
ImGui::NewLine();
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
PuzzleSolver solver;
|
||||||
|
ImGui::Text("Solved: %s", solver.IsPuzzleSolved(obj) ? "yes!" : "no.");
|
||||||
|
|
||||||
|
bool bAvailOpen =
|
||||||
|
ImGui::TreeNodeEx("Available Cards", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed);
|
||||||
|
if (ImGui::BeginDragDropTarget())
|
||||||
|
{
|
||||||
|
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("cardtype", 0))
|
||||||
|
{
|
||||||
|
uint32_t CardIdx = *reinterpret_cast<uint32_t*>(payload->Data);
|
||||||
|
bool found = false;
|
||||||
|
for (int32_t i = 0; i < obj.AvailableCardCount; ++i)
|
||||||
|
{
|
||||||
|
if (obj.AvailableCards[i].RefCard.Idx == CardIdx)
|
||||||
|
{
|
||||||
|
obj.AvailableCards[i].MaxAvailableCount++;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
if (obj.AvailableCardCount == BX_COUNTOF(obj.AvailableCards))
|
||||||
|
{
|
||||||
|
LOG_ERROR("Available card limit reached!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto& Card = obj.AvailableCards[obj.AvailableCardCount];
|
||||||
|
Card.RefCard.Idx = CardIdx;
|
||||||
|
Card.MaxAvailableCount = 1;
|
||||||
|
obj.AvailableCardCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndDragDropTarget();
|
||||||
|
}
|
||||||
|
if (bAvailOpen)
|
||||||
|
{
|
||||||
|
ImVec2 startPos = ImGui::GetCursorScreenPos();
|
||||||
|
for (uint32_t i = 0; i < obj.AvailableCardCount; ++i)
|
||||||
|
{
|
||||||
|
ImVec2 localPos = {startPos.x + i * 60.0f, startPos.y};
|
||||||
|
ImGui::SetCursorScreenPos(localPos);
|
||||||
|
ImGui::PushID(i);
|
||||||
|
auto& card = obj.AvailableCards[i];
|
||||||
|
DrawCard(GetCard(card.RefCard), 0, ImGui::GetCursorScreenPos());
|
||||||
|
int displayCount = card.MaxAvailableCount - card.UsedCount;
|
||||||
|
|
||||||
|
ImGui::SetCursorScreenPos({localPos.x, localPos.y + 55.0f});
|
||||||
|
ImGui::SetNextItemWidth(35);
|
||||||
|
ImGui::PushID("carc");
|
||||||
|
if (ImGui::DragInt("", &displayCount, 0.25f))
|
||||||
|
{
|
||||||
|
int diff = displayCount - (card.MaxAvailableCount - card.UsedCount);
|
||||||
|
card.MaxAvailableCount = bx::max(0, card.MaxAvailableCount + diff);
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
ImGui::SameLine(0, 3);
|
||||||
|
if (ImGui::Button("x"))
|
||||||
|
{
|
||||||
|
if (i < obj.AvailableCardCount - 1)
|
||||||
|
{
|
||||||
|
obj.AvailableCards[i] = obj.AvailableCards[obj.AvailableCardCount - 1];
|
||||||
|
}
|
||||||
|
obj.AvailableCardCount--;
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
return isVisible;
|
return isVisible;
|
||||||
}
|
}
|
||||||
|
void ResetPuzzle(PuzzleData& puz)
|
||||||
|
{
|
||||||
|
for (int32_t i = 0; i < puz.AvailableCardCount; ++i)
|
||||||
|
{
|
||||||
|
puz.AvailableCards[i].UsedCount = 0;
|
||||||
|
}
|
||||||
|
for (int32_t i = 0; i < BX_COUNTOF(puz.PlacedCards); ++i)
|
||||||
|
{
|
||||||
|
puz.PlacedCards[i] = puz.InitialPlacedCards[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace Puzzle
|
} // namespace Puzzle
|
||||||
|
|||||||
@@ -1,143 +1,66 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Serial.h"
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
#include "../../gen/Generated.h"
|
#include "../gen/Generated.h"
|
||||||
|
|
||||||
namespace Puzzle
|
namespace Puzzle
|
||||||
{
|
{
|
||||||
|
using namespace Gen;
|
||||||
|
|
||||||
|
constexpr const char* PuzzleFileDir = "game/data/puzzles/";
|
||||||
|
|
||||||
struct Config
|
struct Config
|
||||||
{
|
{
|
||||||
|
static constexpr uint32_t MaxVisiblePuzzles = 3;
|
||||||
static constexpr uint32_t CardSize = 2;
|
static constexpr uint32_t CardSize = 2;
|
||||||
static constexpr uint32_t NodesPerCard = CardSize * CardSize;
|
static constexpr uint32_t NodesPerCard = CardSize * CardSize;
|
||||||
static constexpr uint32_t MaxElementsPerTile = 4;
|
|
||||||
static constexpr uint32_t MaxPuzzleSizeCards = 16;
|
static constexpr uint32_t MaxPuzzleSizeCards = 16;
|
||||||
static constexpr uint32_t MaxCardsInPuzzle = MaxPuzzleSizeCards * MaxPuzzleSizeCards;
|
static constexpr uint32_t MaxCardsInPuzzle = MaxPuzzleSizeCards * MaxPuzzleSizeCards;
|
||||||
static constexpr uint32_t MaxPuzzleSizeTiles = 16 * CardSize;
|
static constexpr uint32_t MaxPuzzleSizeTiles = 16 * CardSize;
|
||||||
static constexpr uint32_t MaxTilesInPuzzle = MaxPuzzleSizeTiles * MaxPuzzleSizeTiles;
|
static constexpr uint32_t MaxTilesInPuzzle = MaxPuzzleSizeTiles * MaxPuzzleSizeTiles;
|
||||||
|
static constexpr uint32_t MaxTilesTotal =
|
||||||
|
MaxTilesInPuzzle * MaxVisiblePuzzles + MaxPuzzleSizeCards * MaxVisiblePuzzles + 64;
|
||||||
static constexpr uint32_t MaxAvailableStacks = 16;
|
static constexpr uint32_t MaxAvailableStacks = 16;
|
||||||
static constexpr uint32_t MaxGoalPositions = 16;
|
static constexpr uint32_t MaxGoalPositions = 16;
|
||||||
|
static constexpr float CardScaleWorld = 10.0f;
|
||||||
|
static constexpr uint32_t MaxCoversInTile = 8;
|
||||||
|
static constexpr uint32_t MaxCoversTotal = MaxCoversInTile * MaxTilesTotal;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PuzPos
|
|
||||||
{
|
|
||||||
int8_t X = 0;
|
|
||||||
int8_t Y = 0;
|
|
||||||
|
|
||||||
PuzPos& operator+=(const PuzPos& rhs)
|
|
||||||
{
|
|
||||||
X += rhs.X;
|
|
||||||
Y += rhs.Y;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend PuzPos operator+(PuzPos lhs, const PuzPos& rhs)
|
|
||||||
{
|
|
||||||
lhs += rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ElemPos
|
|
||||||
{
|
|
||||||
PuzPos Position;
|
|
||||||
uint8_t ElemIdx = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class PuzzleElementType : uint8_t
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
WaterIn,
|
|
||||||
WaterGoal,
|
|
||||||
WaterChannel,
|
|
||||||
ElectricIn,
|
|
||||||
ElectricGoal,
|
|
||||||
Blocked,
|
|
||||||
Bridge,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PuzzleNode
|
|
||||||
{
|
|
||||||
PuzzleElementType PlacedTypes[Config::MaxElementsPerTile]{PuzzleElementType::None};
|
|
||||||
|
|
||||||
bool HasElement(PuzzleElementType search) const;
|
|
||||||
bool IsEmpty() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StaticPuzzleCard
|
|
||||||
{
|
|
||||||
PuzzleNode Nodes[Config::NodesPerCard];
|
|
||||||
uint16_t ModelHandle = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StaticPuzzleCardHandle
|
|
||||||
{
|
|
||||||
uint16_t Idx = UINT16_MAX;
|
|
||||||
bool IsValid()
|
|
||||||
{
|
|
||||||
return Idx != UINT16_MAX;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StaticPuzzleData
|
|
||||||
{
|
|
||||||
StaticPuzzleCard Cards[64];
|
|
||||||
|
|
||||||
void Setup();
|
void Setup();
|
||||||
static StaticPuzzleData& Get();
|
StaticPuzzleData& GetStaticPuzzleData();
|
||||||
const StaticPuzzleCard& GetCard(StaticPuzzleCardHandle H) const;
|
void LoadStaticPuzzleData();
|
||||||
};
|
void SaveStaticPuzzleData();
|
||||||
|
const StaticPuzzleCard& GetCard(StaticPuzzleCardHandle H);
|
||||||
|
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);
|
||||||
|
|
||||||
struct PlacedPuzzleCard
|
PlacedPuzzleCard& GetCardAt(PuzzleData& obj, PuzPos pos);
|
||||||
{
|
PlacedPuzzleCard& GetInitialCardAt(PuzzleData& obj, PuzPos pos);
|
||||||
StaticPuzzleCardHandle RefCard;
|
// TODO: targetPos is of type CardPos
|
||||||
PuzPos Position;
|
bool ReturnPlacedCard(PuzzleData& obj, PuzPos targetPos);
|
||||||
uint8_t Rotation = 0;
|
// TODO: targetPos is of type CardPos
|
||||||
bool IsLocked = false;
|
bool DragAvailableCardTo(PuzzleData& obj, PuzPos targetPos, int32_t availIdx, uint8_t rotation);
|
||||||
};
|
void ResetPuzzle(PuzzleData& puz);
|
||||||
|
|
||||||
struct PuzzleCardStack
|
|
||||||
{
|
|
||||||
StaticPuzzleCardHandle RefCard;
|
|
||||||
uint8_t MaxAvailableCount = 0;
|
|
||||||
uint8_t UsedCount = 0;
|
|
||||||
|
|
||||||
uint8_t GetRemainingCount();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PuzzleData
|
|
||||||
{
|
|
||||||
SER_HEADER(1, "PZZL");
|
|
||||||
Generated::PuzzleData S;
|
|
||||||
|
|
||||||
uint32_t AvailableCardCount = 0;
|
|
||||||
PuzzleCardStack AvailableCards[Config::MaxAvailableStacks];
|
|
||||||
uint32_t PlacedCardCount = 0;
|
|
||||||
PlacedPuzzleCard PlacedCards[Config::MaxCardsInPuzzle];
|
|
||||||
|
|
||||||
// Indexed by board position
|
|
||||||
PuzzleNode PlacedNodes[Config::MaxTilesInPuzzle];
|
|
||||||
|
|
||||||
uint32_t GoalPositionCount = 0;
|
|
||||||
ElemPos GoalPositions[Config::MaxGoalPositions];
|
|
||||||
|
|
||||||
const PuzzleNode& GetNodeAt(PuzPos pos) const;
|
|
||||||
PuzzleElementType GetElementAt(ElemPos pos) const;
|
|
||||||
|
|
||||||
char PuzzleName[32]{"Unnamed"};
|
|
||||||
bool RenderDebugUI();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PuzzleSolver
|
struct PuzzleSolver
|
||||||
{
|
{
|
||||||
bool IsPuzzleSolved(const PuzzleData& puzzle);
|
bool IsPuzzleSolved(const PuzzleData& puzzle);
|
||||||
bool IsExitSatisfied(const PuzzleData& puzzle, ElemPos pos);
|
bool IsExitSatisfied(const PuzzleData& puzzle, PuzPos pos);
|
||||||
|
|
||||||
// This assumes flowFrom is already verified to be connected.
|
// This assumes flowFrom is already verified to be connected.
|
||||||
bool IsValidGoalConnection(const PuzzleData& puzzle,
|
bool IsValidGoalConnection(const PuzzleData& puzzle,
|
||||||
PuzPos flowFrom,
|
PuzPos flowFrom,
|
||||||
PuzPos flowTo,
|
PuzPos flowTo,
|
||||||
PuzzleElementType goalType);
|
PuzzleElementType::Enum goalType);
|
||||||
bool IsValidSource(PuzzleElementType sourceType, PuzzleElementType goalType);
|
bool IsValidSource(PuzzleElementType::Enum sourceType, PuzzleElementType::Enum goalType);
|
||||||
};
|
};
|
||||||
|
bool RenderDebugUI(PuzzleData& obj);
|
||||||
} // namespace Puzzle
|
} // namespace Puzzle
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
#include "Global.h"
|
|
||||||
#include "Log.h"
|
|
||||||
#include "Serial.h"
|
|
||||||
#include "bx/bx.h"
|
|
||||||
#include "bx/file.h"
|
|
||||||
#include "bx/filepath.h"
|
|
||||||
|
|
||||||
void SerializeStruct(void* data, uint64_t size, const char* path)
|
|
||||||
{
|
|
||||||
bx::Error err;
|
|
||||||
bx::FilePath filePath{path};
|
|
||||||
bx::FileWriter writer;
|
|
||||||
if (writer.open(filePath, false, &err))
|
|
||||||
{
|
|
||||||
if (!writer.write(data, size, &err))
|
|
||||||
{
|
|
||||||
LOG_ERROR("Failed to write to file %s: %s", path, err.getMessage().getCPtr());
|
|
||||||
writer.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR("Failed to open file %s: %s", path, err.getMessage().getCPtr());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LOG("Successful serialization");
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeserializeStruct(void* data, SerializationHeader& expectedHeader, const char* path)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#include <cstdint>
|
|
||||||
|
|
||||||
struct SerializationHeader
|
|
||||||
{
|
|
||||||
uint8_t _ID0 = 0;
|
|
||||||
uint8_t _ID1 = 0;
|
|
||||||
uint8_t _ID2 = 0;
|
|
||||||
uint8_t _ID3 = 0;
|
|
||||||
uint8_t HeaderVersion = 0;
|
|
||||||
uint8_t VersionNum = 0;
|
|
||||||
uint8_t Reserved0 = 0;
|
|
||||||
uint8_t Reserved1 = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SER_HEADER(Version, FCC) \
|
|
||||||
SerializationHeader __Header{ \
|
|
||||||
FCC[0], \
|
|
||||||
FCC[1], \
|
|
||||||
FCC[2], \
|
|
||||||
FCC[3], \
|
|
||||||
1, \
|
|
||||||
Version, \
|
|
||||||
0, \
|
|
||||||
0, \
|
|
||||||
}; \
|
|
||||||
bool VersionMatches(uint8_t headerVersion, uint8_t versionNum) \
|
|
||||||
{ \
|
|
||||||
return headerVersion == 1 && versionNum == Version; \
|
|
||||||
}
|
|
||||||
|
|
||||||
void SerializeStruct(void* data, uint64_t size, const char* path);
|
|
||||||
void DeserializeStruct(void* data, SerializationHeader& expectedHeader, const char* path);
|
|
||||||
@@ -1,11 +1,16 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
#include "Input.h"
|
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Setup.h"
|
#include "Setup.h"
|
||||||
|
#include "Tools.h"
|
||||||
|
#include "rendering/Rendering.h"
|
||||||
|
|
||||||
#include "bx/bx.h"
|
#include "bx/bx.h"
|
||||||
#include "bx/timer.h"
|
#include "bx/timer.h"
|
||||||
#include "rendering/Rendering.h"
|
#ifdef TRACY_ENABLE
|
||||||
|
#include <client/TracyProfiler.hpp>
|
||||||
|
#endif
|
||||||
|
#include <tracy/Tracy.hpp>
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
{
|
{
|
||||||
@@ -23,38 +28,45 @@ namespace Game
|
|||||||
void Setup(SharedData& shared)
|
void Setup(SharedData& shared)
|
||||||
{
|
{
|
||||||
LOG("Game Setup Start!");
|
LOG("Game Setup Start!");
|
||||||
|
#ifdef TRACY_ENABLE
|
||||||
|
LOG("Tracy is enabled");
|
||||||
|
tracy::StartupProfiler();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (shared.Game.PermanentStorage == nullptr)
|
if (shared.Game.PermanentArena.Base == nullptr)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Game memory not initialized!!");
|
LOG_ERROR("Game memory not initialized!!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (shared.Game.EntityStorage == nullptr)
|
if (shared.Game.EntityArena.Base == nullptr)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Entity memory not initialized!");
|
LOG_ERROR("Entity memory not initialized!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (shared.Game.PermanentStorageSize < sizeof(GameInstance))
|
if (shared.Game.PermanentArena.MaxSize < sizeof(GameInstance))
|
||||||
{
|
{
|
||||||
LOG_ERROR("Game memory too small! %u < %u", shared.Game.PermanentStorageSize, sizeof(GameInstance));
|
LOG_ERROR("Game memory too small! %u < %u", shared.Game.PermanentArena.MaxSize, sizeof(GameInstance));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GameInstance& instance = *reinterpret_cast<GameInstance*>(shared.Game.PermanentStorage);
|
GameInstance& instance = *reinterpret_cast<GameInstance*>(shared.Game.PermanentArena.Base);
|
||||||
if (sizeof(GameInstance) != instance.Size)
|
if (sizeof(GameInstance) != instance.Size)
|
||||||
{
|
{
|
||||||
LOG_WARN("Game instance size changed, resetting!");
|
LOG_WARN("Game instance size changed, resetting!");
|
||||||
instance = {};
|
instance = {};
|
||||||
}
|
}
|
||||||
instance.UsedScratchAmount = 0;
|
|
||||||
SetShared(shared);
|
SetShared(shared);
|
||||||
SetInstance(instance);
|
SetInstance(instance);
|
||||||
SetupInstance.Rendering.Setup();
|
ResetScratch();
|
||||||
|
Puzzle::LoadStaticPuzzleData();
|
||||||
|
SetupInstance.Rendering.Setup({});
|
||||||
instance.GameLevel.Setup(shared.Game);
|
instance.GameLevel.Setup(shared.Game);
|
||||||
instance.IsInitialized = true;
|
instance.IsInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
ZoneScopedN("TimeUpdate");
|
||||||
auto& inst = GetInstance();
|
auto& inst = GetInstance();
|
||||||
int64_t newNowHP = bx::getHPCounter() - inst.Time.StartTime;
|
int64_t newNowHP = bx::getHPCounter() - inst.Time.StartTime;
|
||||||
inst.Time.DeltaHP = newNowHP - inst.Time.NowHP;
|
inst.Time.DeltaHP = newNowHP - inst.Time.NowHP;
|
||||||
@@ -63,25 +75,28 @@ namespace Game
|
|||||||
inst.Time.Delta = (double)inst.Time.DeltaHP / bx::getHPFrequency();
|
inst.Time.Delta = (double)inst.Time.DeltaHP / bx::getHPFrequency();
|
||||||
GetShared().Window.PerfCounters[(int32_t)PerfCounterType::GameDelta].Write(inst.Time.DeltaHP,
|
GetShared().Window.PerfCounters[(int32_t)PerfCounterType::GameDelta].Write(inst.Time.DeltaHP,
|
||||||
GetShared().Window.FrameCounter);
|
GetShared().Window.FrameCounter);
|
||||||
|
|
||||||
if (GetKeyPressedNow(ScanCode::R))
|
|
||||||
{
|
|
||||||
GetInstance().Size = 0;
|
|
||||||
Shutdown();
|
|
||||||
Setup(GetShared());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupInstance.Rendering.Update();
|
SetupInstance.Rendering.Update();
|
||||||
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("MouseDeltaUpdate");
|
||||||
auto& win = GetShared().Window;
|
auto& win = GetShared().Window;
|
||||||
win.MouseDeltaX = 0.0f;
|
win.MouseDeltaX = 0.0f;
|
||||||
win.MouseDeltaY = 0.0f;
|
win.MouseDeltaY = 0.0f;
|
||||||
bx::memCopy(win.LastHeldScanCodes, win.HeldScanCodes, sizeof(win.HeldScanCodes));
|
bx::memCopy(win.LastHeldScanCodes, win.HeldScanCodes, sizeof(win.HeldScanCodes));
|
||||||
bx::memCopy(win.LastHeldMouseButtons, win.HeldMouseButtons, sizeof(win.HeldMouseButtons));
|
bx::memCopy(win.LastHeldMouseButtons, win.HeldMouseButtons, sizeof(win.HeldMouseButtons));
|
||||||
}
|
}
|
||||||
|
Tools::MeasureFrameEnd();
|
||||||
|
FrameMark;
|
||||||
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
LOG("Shutdown");
|
LOG("Shutdown");
|
||||||
SetupInstance.Rendering.Shutdown();
|
SetupInstance.Rendering.Shutdown();
|
||||||
|
#ifdef TRACY_ENABLE
|
||||||
|
tracy::ShutdownProfiler();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace Game
|
} // namespace Game
|
||||||
|
|||||||
760
src/game/Tools.cpp
Normal file
760
src/game/Tools.cpp
Normal file
@@ -0,0 +1,760 @@
|
|||||||
|
#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 "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>
|
||||||
|
|
||||||
|
using namespace Gen;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr int32_t FrameTimeBufSize = 512;
|
||||||
|
int64_t FrameTimes[FrameTimeBufSize]{0};
|
||||||
|
int32_t FrameTimeIdx = 0;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace Tools
|
||||||
|
{
|
||||||
|
const char* GetAssetPath(Gen::AssetHandle assetHandle)
|
||||||
|
{
|
||||||
|
const auto& inst = Game::GetInstance();
|
||||||
|
for (int32_t j = 0; j < inst.DebugData.AssetCount; ++j)
|
||||||
|
{
|
||||||
|
if (inst.DebugData.AssetHandles[j] == assetHandle)
|
||||||
|
{
|
||||||
|
return inst.DebugData.AssetHandlePaths[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "---";
|
||||||
|
}
|
||||||
|
|
||||||
|
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* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(title, name))
|
||||||
|
{
|
||||||
|
for (int32_t i = 0; i < R.MaxTextures; ++i)
|
||||||
|
{
|
||||||
|
if (!IsValid(R.Textures[i].TexHandle)) continue;
|
||||||
|
ImGui::PushID(i);
|
||||||
|
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||||
|
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});
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("%s", GetAssetPath(R.Textures[i].TexHandle.Asset));
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
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& debug = Game::GetInstance().DebugData;
|
||||||
|
|
||||||
|
if (ImGui::Begin("Log"))
|
||||||
|
{
|
||||||
|
ImGui::Checkbox("Shorten File Names", &debug.ShortenLogFileNames);
|
||||||
|
ImGui::BeginTable("tbl",
|
||||||
|
4,
|
||||||
|
ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_SizingFixedFit |
|
||||||
|
ImGuiTableFlags_RowBg);
|
||||||
|
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_NoResize);
|
||||||
|
ImGui::TableSetupColumn("Log");
|
||||||
|
ImGui::TableSetupColumn("Line", ImGuiTableColumnFlags_NoResize);
|
||||||
|
ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_NoResize);
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
auto& logs = GetLogHistory();
|
||||||
|
|
||||||
|
int32_t lineCount = bx::min(100, LogInternal::LogHistorySize);
|
||||||
|
for (int32_t i = 0; i < lineCount; ++i)
|
||||||
|
{
|
||||||
|
int32_t idx = logs.WriteIdx - i - 1;
|
||||||
|
if (idx < 0) idx += LogInternal::LogHistorySize;
|
||||||
|
const char* line = &logs.LogBuffer[idx * LogInternal::MaxLineSize];
|
||||||
|
if (line[0] != 0)
|
||||||
|
{
|
||||||
|
int64_t timeOffset = logs.WriteTime[idx] - time.StartTime;
|
||||||
|
double writeTime = (double)timeOffset / bx::getHPFrequency();
|
||||||
|
uint32_t fileLine = logs.LineBuffer[idx];
|
||||||
|
const char* filePath = &logs.FileBuffer[idx * LogInternal::MaxLineSize];
|
||||||
|
const char* filePathRes =
|
||||||
|
debug.ShortenLogFileNames ? bx::FilePath{filePath}.getFileName().getPtr() : filePath;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%.01f", writeTime);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%s", line);
|
||||||
|
ImGui::SetItemTooltip("%f\n%s%s:%u", writeTime, line, filePath, fileLine);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%u", fileLine);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%s", filePathRes);
|
||||||
|
|
||||||
|
if (i > 0) ImGui::PopStyleColor(2);
|
||||||
|
ImVec4 bgCol = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
if (logs.WriteType[idx] == ELogType::Warn)
|
||||||
|
bgCol = {0.2f, 0.2f, 0.0f, 1.0f};
|
||||||
|
else if (logs.WriteType[idx] == ELogType::Error)
|
||||||
|
bgCol = {0.2f, 0.0f, 0.0f, 1.0f};
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_TableRowBg, bgCol);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, bgCol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
|
||||||
|
if (lineCount > 0) ImGui::PopStyleColor(2);
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderRenderSettingsUI(Game::GameRendering& rendering)
|
||||||
|
{
|
||||||
|
auto& time = Game::GetInstance().Time;
|
||||||
|
auto& 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)
|
||||||
|
{
|
||||||
|
ImGui::TextColored({0.2f, 0.9f, 0.2f, 1.0f},
|
||||||
|
"Shader loaded %.0f seconds ago",
|
||||||
|
time.Now - rendering.LastShaderLoadTime);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::TextColored({0.9f, 0.2f, 0.2f, 1.0f}, "Shader load Failiure!");
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Reload Level"))
|
||||||
|
{
|
||||||
|
level = {};
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SliderInt("Recursion", &rendering.DitherRecursion, 1, 4);
|
||||||
|
ImGui::Text("%ux%ux%u",
|
||||||
|
rendering.DitherTextures.DitherTexWH,
|
||||||
|
rendering.DitherTextures.DitherTexWH,
|
||||||
|
rendering.DitherTextures.DitherTexDepth);
|
||||||
|
if (!isValid(rendering.DitherTextures.PreviewTex))
|
||||||
|
{
|
||||||
|
ImGui::Text("Invalid Texture");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::Image(
|
||||||
|
rendering.DitherTextures.PreviewTex.idx,
|
||||||
|
{(float)rendering.DitherTextures.DitherTexWH,
|
||||||
|
(float)rendering.DitherTextures.DitherTexWH * rendering.DitherTextures.DitherTexDepth});
|
||||||
|
}
|
||||||
|
if (isValid(rendering.DitherTextures.RampTex))
|
||||||
|
{
|
||||||
|
ImGui::Image(rendering.DitherTextures.RampTex.idx,
|
||||||
|
{BX_COUNTOF(rendering.DitherTextures.BrightnessRamp), 8});
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
{
|
||||||
|
rendering.LoadTextures();
|
||||||
|
}
|
||||||
|
for (int32_t i = 0; i < rendering.MaxTextures; ++i)
|
||||||
|
{
|
||||||
|
if (!isValid(rendering.Textures[i].RenderHandle)) continue;
|
||||||
|
ImGui::Text("%i", i);
|
||||||
|
float width = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.width);
|
||||||
|
float height = bx::min<float>(ImGui::GetContentRegionAvail().x, rendering.Textures[i].Info.height);
|
||||||
|
ImGui::Image(rendering.Textures[i].RenderHandle.idx, {width, height});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
{
|
||||||
|
char nameBuf[64]{0};
|
||||||
|
for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i)
|
||||||
|
{
|
||||||
|
ImGui::PushID(i);
|
||||||
|
auto& puzzleData = level.Puzzles[i].Data;
|
||||||
|
|
||||||
|
bool isSelected = debug.SelectedDebugLevel == i;
|
||||||
|
ImGui::PushID("selectable");
|
||||||
|
bx::snprintf(nameBuf, sizeof(nameBuf), "%u: %s", i, puzzleData.PuzzleName);
|
||||||
|
if (ImGui::Selectable(nameBuf, isSelected))
|
||||||
|
{
|
||||||
|
debug.SelectedDebugLevel = isSelected ? UINT16_MAX : i;
|
||||||
|
}
|
||||||
|
ImGui::DragFloat3("Pos", &level.Puzzles[i].WorldPosition.x);
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
if (debug.SelectedDebugLevel < BX_COUNTOF(level.Puzzles))
|
||||||
|
{
|
||||||
|
if (!Puzzle::RenderDebugUI(level.Puzzles[debug.SelectedDebugLevel].Data))
|
||||||
|
{
|
||||||
|
debug.SelectedDebugLevel = UINT16_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderCardsUI(Game::GameRendering& rendering)
|
||||||
|
{
|
||||||
|
auto& debug = Game::GetInstance().DebugData;
|
||||||
|
|
||||||
|
if (ImGui::Begin("Cards"))
|
||||||
|
{
|
||||||
|
Gen::StaticPuzzleData& staticData = Puzzle::GetStaticPuzzleData();
|
||||||
|
|
||||||
|
if (ImGui::Button("Save"))
|
||||||
|
{
|
||||||
|
Puzzle::SaveStaticPuzzleData();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Reload"))
|
||||||
|
{
|
||||||
|
Puzzle::LoadStaticPuzzleData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::ColorEdit3("Disabled Tint", &staticData.Visuals.DisabledCardTint.x);
|
||||||
|
ImGui::ColorEdit3("Tile Base Color", &staticData.Visuals.TileBaseColor.x);
|
||||||
|
ImGui::ColorEdit3("Tile Dot Color", &staticData.Visuals.TileDotColor.x);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < BX_COUNTOF(staticData.Cards); ++i)
|
||||||
|
{
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
Gen::StaticPuzzleCard& card = staticData.Cards[i];
|
||||||
|
ImGui::PushID(i);
|
||||||
|
char cardName[64]{0};
|
||||||
|
bx::snprintf(cardName, sizeof(cardName), "%i", i);
|
||||||
|
ImGui::Selectable(cardName);
|
||||||
|
if (ImGui::BeginDragDropSource())
|
||||||
|
{
|
||||||
|
Puzzle::DrawCard(card, debug.DebugCardRotation, ImGui::GetCursorScreenPos());
|
||||||
|
ImGui::SetDragDropPayload("cardtype", &i, sizeof(i));
|
||||||
|
ImGui::EndDragDropSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
for (int8_t x = 0; x < Puzzle::Config::CardSize; ++x)
|
||||||
|
{
|
||||||
|
if (x > 0) ImGui::SameLine();
|
||||||
|
ImGui::PushID(x);
|
||||||
|
auto& node = Puzzle::EditCardNodeAt(card, 0, x, y);
|
||||||
|
if (ImGui::Button(Gen::PuzzleElementType::ShortName[node], {26, 24}))
|
||||||
|
{
|
||||||
|
int32_t newVal = int32_t(node) + 1;
|
||||||
|
if (newVal >= Gen::PuzzleElementType::EntryCount)
|
||||||
|
{
|
||||||
|
newVal = 0;
|
||||||
|
}
|
||||||
|
node = Gen::PuzzleElementType::Enum(newVal);
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::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});
|
||||||
|
if (ImGui::Begin("Stats",
|
||||||
|
nullptr,
|
||||||
|
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoInputs |
|
||||||
|
ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
if (Game::GetInstance().Player.CameraM == Game::CameraMode::Freefly)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, {0.8f, 0.1f, 0.1f, 1.0f});
|
||||||
|
ImGui::Text("NOCLIP");
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
ImGui::Text("Delta: %.01fms", time.Delta * 1000);
|
||||||
|
ImGui::Text("FPS: %.0f", 1.0 / time.Delta);
|
||||||
|
|
||||||
|
constexpr ImVec2 FpsPlotSize{200, 60};
|
||||||
|
if (ImGui::BeginChild("FpsPlot", FpsPlotSize, 0, ImGuiWindowFlags_NoInputs))
|
||||||
|
{
|
||||||
|
auto& drawList = *ImGui::GetWindowDrawList();
|
||||||
|
ImVec2 pos = ImGui::GetWindowPos();
|
||||||
|
drawList.AddRectFilled(pos, {pos.x + FpsPlotSize.x, pos.y + FpsPlotSize.y}, 0x22222233);
|
||||||
|
|
||||||
|
float scale = 1000.0f;
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < FrameTimeBufSize; ++i)
|
||||||
|
{
|
||||||
|
int32_t idx = FrameTimeIdx - i - 1;
|
||||||
|
int32_t prevIdx = idx - 1;
|
||||||
|
if (idx < 0) idx += FrameTimeBufSize;
|
||||||
|
if (prevIdx < 0) prevIdx += FrameTimeBufSize;
|
||||||
|
|
||||||
|
if (FrameTimes[idx] == 0 || FrameTimes[prevIdx] == 0) continue;
|
||||||
|
|
||||||
|
int64_t frameTime = FrameTimes[idx] - FrameTimes[prevIdx];
|
||||||
|
double frameTimeSec = (double)frameTime / bx::getHPFrequency();
|
||||||
|
drawList.AddLine(
|
||||||
|
{pos.x + (FpsPlotSize.x - i - 1), pos.y + FpsPlotSize.y},
|
||||||
|
{pos.x + (FpsPlotSize.x - i - 1), pos.y + FpsPlotSize.y - (float)frameTimeSec * scale},
|
||||||
|
0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
++FrameTimeIdx;
|
||||||
|
if (FrameTimeIdx >= FrameTimeBufSize) FrameTimeIdx = 0;
|
||||||
|
}
|
||||||
|
} // namespace Tools
|
||||||
14
src/game/Tools.h
Normal file
14
src/game/Tools.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../gen/Generated.h"
|
||||||
|
#include "rendering/Rendering.h"
|
||||||
|
|
||||||
|
namespace Tools
|
||||||
|
{
|
||||||
|
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
|
||||||
BIN
src/game/compiled-shaders/dx11/dither/frag.bin
LFS
Normal file
BIN
src/game/compiled-shaders/dx11/dither/frag.bin
LFS
Normal file
Binary file not shown.
BIN
src/game/compiled-shaders/dx11/dither/vert.bin
LFS
Normal file
BIN
src/game/compiled-shaders/dx11/dither/vert.bin
LFS
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/game/compiled-shaders/dx11/normal/frag.bin
LFS
Normal file
BIN
src/game/compiled-shaders/dx11/normal/frag.bin
LFS
Normal file
Binary file not shown.
BIN
src/game/compiled-shaders/dx11/normal/vert.bin
LFS
Normal file
BIN
src/game/compiled-shaders/dx11/normal/vert.bin
LFS
Normal file
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.
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/game/data/puzzles/0.pzl
LFS
Normal file
BIN
src/game/data/puzzles/0.pzl
LFS
Normal file
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.
BIN
src/game/data/static/puzzle.dat
Normal file
BIN
src/game/data/static/puzzle.dat
Normal file
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.
@@ -1,41 +1,123 @@
|
|||||||
|
type Vec2
|
||||||
|
{
|
||||||
|
f32 x
|
||||||
|
f32 y
|
||||||
|
}
|
||||||
|
|
||||||
|
type Vec3
|
||||||
|
{
|
||||||
|
f32 x
|
||||||
|
f32 y
|
||||||
|
f32 z
|
||||||
|
}
|
||||||
|
|
||||||
|
type Vec4
|
||||||
|
{
|
||||||
|
f32 x
|
||||||
|
f32 y
|
||||||
|
f32 z
|
||||||
|
f32 w
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mat3
|
||||||
|
{
|
||||||
|
f32 M Arr(9) Default("{
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f
|
||||||
|
}")
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mat4
|
||||||
|
{
|
||||||
|
f32 M Arr(16) Default("{
|
||||||
|
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
|
||||||
|
}")
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModelHandle
|
||||||
|
{
|
||||||
|
u16 ModelIdx Default("UINT16_MAX")
|
||||||
|
AssetHandle Asset
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextureHandle
|
||||||
|
{
|
||||||
|
u16 TextureIdx Default("UINT16_MAX")
|
||||||
|
AssetHandle Asset
|
||||||
|
}
|
||||||
|
|
||||||
type PuzPos
|
type PuzPos
|
||||||
{
|
{
|
||||||
i8 X
|
i8 X
|
||||||
i8 Y
|
i8 Y
|
||||||
}
|
}
|
||||||
|
|
||||||
type ElemPos
|
|
||||||
{
|
|
||||||
PuzPos Position
|
|
||||||
u8 ElemIdx
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PuzzleElementType(u8)
|
enum PuzzleElementType(u8)
|
||||||
{
|
{
|
||||||
None GameName("Empty")
|
None GameName("Empty") ShortName(" ")
|
||||||
WaterIn GameName("Water Source")
|
WaterIn GameName("Water Source") ShortName("~+")
|
||||||
WaterGoal GameName("Water Goal")
|
WaterGoal GameName("Water Goal") ShortName("~!")
|
||||||
WaterChannel GameName("Water Channel")
|
WaterChannel GameName("Water Channel") ShortName("~")
|
||||||
ElectricIn GameName("Electricity Source")
|
ElectricIn GameName("Electricity Source") ShortName("e+")
|
||||||
ElectricGoal GameName("Electricity Goal")
|
ElectricGoal GameName("Electricity Goal") ShortName("e!")
|
||||||
Blocked GameName("Blocked")
|
Blocked GameName("Blocked") ShortName("B")
|
||||||
Bridge GameName("Bridge")
|
Bridge GameName("Bridge") ShortName("#")
|
||||||
}
|
}
|
||||||
|
|
||||||
type PuzzleNode
|
type CardSocket
|
||||||
{
|
{
|
||||||
PuzzleElementType PlacedTypes
|
ModelHandle Model
|
||||||
|
u8 ConnectionDirection
|
||||||
}
|
}
|
||||||
|
|
||||||
type StaticPuzzleCard
|
type StaticPuzzleCard
|
||||||
{
|
{
|
||||||
PuzzleNode Nodes Arr(8)
|
PuzzleElementType Elements Arr(4)
|
||||||
u16 ModelHandle
|
ModelHandle BaseModelHandle
|
||||||
|
ModelHandle NorthCoverHandle
|
||||||
|
ModelHandle EastCoverHandle
|
||||||
|
ModelHandle SouthCoverHandle
|
||||||
|
ModelHandle WestCoverHandle
|
||||||
|
CardSocket Sockets Arr(16)
|
||||||
|
TextureHandle ModelTextureHandle
|
||||||
|
TextureHandle BoardTextureHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
type StaticPuzzleCardHandle
|
type StaticPuzzleCardHandle
|
||||||
{
|
{
|
||||||
u16 Idx
|
u16 Idx Default("UINT16_MAX")
|
||||||
|
}
|
||||||
|
|
||||||
|
type PuzzleVisualSettings
|
||||||
|
{
|
||||||
|
Vec4 TileBaseColor
|
||||||
|
Vec4 TileDotColor
|
||||||
|
Vec3 Test
|
||||||
|
Vec4 DisabledCardTint
|
||||||
|
}
|
||||||
|
|
||||||
|
type StaticPuzzleData
|
||||||
|
{
|
||||||
|
StaticPuzzleCard Cards Arr(64)
|
||||||
|
PuzzleVisualSettings Visuals
|
||||||
}
|
}
|
||||||
|
|
||||||
type PuzzleCardStack
|
type PuzzleCardStack
|
||||||
@@ -45,23 +127,58 @@ type PuzzleCardStack
|
|||||||
u8 UsedCount
|
u8 UsedCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PlacedPuzzleCardFlags(u8) Flags
|
||||||
|
{
|
||||||
|
None
|
||||||
|
Locked
|
||||||
|
}
|
||||||
|
|
||||||
type PlacedPuzzleCard
|
type PlacedPuzzleCard
|
||||||
{
|
{
|
||||||
StaticPuzzleCardHandle RefCard
|
StaticPuzzleCardHandle RefCard
|
||||||
PuzPos Position
|
PuzPos Position
|
||||||
u8 Rotation
|
u8 Rotation
|
||||||
b IsLocked
|
PlacedPuzzleCardFlags Flags
|
||||||
}
|
}
|
||||||
|
|
||||||
type PuzzleData
|
type PuzzleData
|
||||||
{
|
{
|
||||||
|
u16 ID
|
||||||
|
str PuzzleName Arr(64)
|
||||||
u8 WidthTiles
|
u8 WidthTiles
|
||||||
u8 HeightTiles
|
u8 HeightTiles
|
||||||
u32 AvailableCardCount
|
u32 AvailableCardCount
|
||||||
PuzzleCardStack AvailableCards Arr(8)
|
PuzzleCardStack AvailableCards Arr(16)
|
||||||
u32 PlacedCardCount
|
PlacedPuzzleCard PlacedCards Arr(256)
|
||||||
PlacedPuzzleCard PlacedCards Arr(8)
|
PlacedPuzzleCard InitialPlacedCards Arr(256)
|
||||||
PuzzleNode PlacedNodes Arr(8)
|
PuzzleElementType BackgroundTiles Arr(1024)
|
||||||
u32 GoalPositionCount
|
u32 GoalPositionCount
|
||||||
ElemPos GoalPositions
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
134
src/game/rendering/Dither.cpp
Normal file
134
src/game/rendering/Dither.cpp
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
#include "../Gen.h"
|
||||||
|
#include "../Log.h"
|
||||||
|
#include "Dither.h"
|
||||||
|
|
||||||
|
#include "bx/math.h"
|
||||||
|
|
||||||
|
using namespace Gen;
|
||||||
|
|
||||||
|
void DitherGen(DitherData& data, int32_t recursion)
|
||||||
|
{
|
||||||
|
data.Points[0] = {0.0f, 0.0f};
|
||||||
|
data.Points[1] = {0.5f, 0.5f};
|
||||||
|
data.Points[2] = {0.5f, 0.0f};
|
||||||
|
data.Points[3] = {0.0f, 0.5f};
|
||||||
|
data.PointCount = 4;
|
||||||
|
for (int32_t i = 0; i < data.BrightnessBucketCount; ++i)
|
||||||
|
data.BrightnessBuckets[i] = 0;
|
||||||
|
|
||||||
|
// 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 = 1; i < 4; ++i)
|
||||||
|
{
|
||||||
|
for (int32_t j = 0; j < startCount; ++j)
|
||||||
|
{
|
||||||
|
data.Points[data.PointCount] = data.Points[j] + data.Points[i] * offset;
|
||||||
|
data.PointCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texture info setup
|
||||||
|
uint64_t dotsPerSide = bx::round(bx::pow(2, recursion));
|
||||||
|
data.DitherTexDepth = dotsPerSide * dotsPerSide;
|
||||||
|
data.DitherTexWH = 16 * dotsPerSide;
|
||||||
|
uint64_t texPixelCount = data.DitherTexWH * data.DitherTexWH * data.DitherTexDepth;
|
||||||
|
|
||||||
|
if (BX_COUNTOF(DitherData::DitherTex) < texPixelCount)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Too many pixels: %llu", texPixelCount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// What does this do?
|
||||||
|
float invRes = 1.0f / data.DitherTexWH;
|
||||||
|
for (int32_t z = 0; z < data.DitherTexDepth; ++z)
|
||||||
|
{
|
||||||
|
int32_t dotCount = z + 1;
|
||||||
|
float dotArea = 0.5f / dotCount;
|
||||||
|
float dotRadius = bx::sqrt(dotArea / bx::kPi);
|
||||||
|
|
||||||
|
int32_t zOffset = z * data.DitherTexWH * data.DitherTexWH;
|
||||||
|
for (int32_t y = 0; y < data.DitherTexWH; ++y)
|
||||||
|
{
|
||||||
|
int32_t yOffset = y * data.DitherTexWH;
|
||||||
|
for (int32_t x = 0; x < data.DitherTexWH; ++x)
|
||||||
|
{
|
||||||
|
Vec2 point{(x + 0.5f) * invRes, (y + 0.5f) * invRes};
|
||||||
|
float dist = bx::kFloatInfinity;
|
||||||
|
for (int32_t i = 0; i < dotCount; ++i)
|
||||||
|
{
|
||||||
|
Vec2 vec = point - data.Points[i];
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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};
|
||||||
|
int32_t bucket = bx::clamp(
|
||||||
|
uint32_t(val * DitherData::BrightnessBucketCount), 0, DitherData::BrightnessBucketCount - 1);
|
||||||
|
data.BrightnessBuckets[bucket] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Brightness ramp
|
||||||
|
int32_t sum = 0;
|
||||||
|
for (int32_t i = 0; i < data.BrightnessBucketCount; ++i)
|
||||||
|
{
|
||||||
|
sum += data.BrightnessBuckets[data.BrightnessBucketCount - 1 - i];
|
||||||
|
data.BrightnessRamp[i + 1] = sum / (float)texPixelCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload textures
|
||||||
|
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));
|
||||||
|
data.PreviewTex = bgfx::createTexture2D(data.DitherTexWH,
|
||||||
|
data.DitherTexWH * data.DitherTexDepth,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
bgfx::TextureFormat::RGBA32F,
|
||||||
|
0,
|
||||||
|
memPreview);
|
||||||
|
data.FinalTex = bgfx::createTexture3D(
|
||||||
|
data.DitherTexWH, data.DitherTexWH, data.DitherTexDepth, false, bgfx::TextureFormat::RGBA32F, 0, memFinal);
|
||||||
|
data.RampTex =
|
||||||
|
bgfx::createTexture2D(BX_COUNTOF(data.BrightnessRamp), 1, false, 1, bgfx::TextureFormat::R32F, 0, memRamp);
|
||||||
|
|
||||||
|
if (!isValid(data.DitherSampler))
|
||||||
|
{
|
||||||
|
data.DitherSampler = bgfx::createUniform("s_ditherSampler", bgfx::UniformType::Sampler);
|
||||||
|
}
|
||||||
|
if (!isValid(data.RampSampler))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/game/rendering/Dither.h
Normal file
27
src/game/rendering/Dither.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../../gen/Generated.h"
|
||||||
|
|
||||||
|
#include <bgfx/bgfx.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
struct DitherData
|
||||||
|
{
|
||||||
|
static constexpr uint32_t BrightnessBucketCount = 256;
|
||||||
|
Gen::Vec2 Points[4096];
|
||||||
|
uint32_t PointCount = 0;
|
||||||
|
Gen::Vec4 DitherTex[256 * 256 * 64];
|
||||||
|
uint32_t DitherTexWH = 0;
|
||||||
|
uint32_t DitherTexDepth = 0;
|
||||||
|
int32_t BrightnessBuckets[BrightnessBucketCount];
|
||||||
|
float BrightnessRamp[BrightnessBucketCount + 1];
|
||||||
|
bgfx::TextureHandle PreviewTex = BGFX_INVALID_HANDLE;
|
||||||
|
bgfx::TextureHandle FinalTex = BGFX_INVALID_HANDLE;
|
||||||
|
bgfx::TextureHandle RampTex = BGFX_INVALID_HANDLE;
|
||||||
|
|
||||||
|
bgfx::UniformHandle DitherSampler = BGFX_INVALID_HANDLE;
|
||||||
|
bgfx::UniformHandle RampSampler = BGFX_INVALID_HANDLE;
|
||||||
|
ImTextureID PreviewID = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void DitherGen(DitherData& data, int32_t recursion);
|
||||||
|
void CleanupDitherData(DitherData& data);
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user