diff --git a/Juliet/include/Core/Memory/MemoryArena.h b/Juliet/include/Core/Memory/MemoryArena.h index b789a23..6abb815 100644 --- a/Juliet/include/Core/Memory/MemoryArena.h +++ b/Juliet/include/Core/Memory/MemoryArena.h @@ -12,7 +12,13 @@ namespace Juliet constexpr global uint64 g_Arena_Default_Commit_Size = Kilobytes(64); constexpr global uint64 k_ArenaHeaderSize = 128; - struct ArenaFreeNode; + struct ArenaFreeNode + { + ArenaFreeNode* Next; + ArenaFreeNode* Previous; + index_t Position; + size_t Size; + }; #if JULIET_DEBUG struct ArenaDebugInfo; diff --git a/Juliet/include/Graphics/Graphics.h b/Juliet/include/Graphics/Graphics.h index 8be9a04..e3b66d0 100644 --- a/Juliet/include/Graphics/Graphics.h +++ b/Juliet/include/Graphics/Graphics.h @@ -11,11 +11,7 @@ #include #include -#if JULIET_DEBUG -#define ALLOW_SHADER_HOT_RELOAD 1 -#else -#define ALLOW_SHADER_HOT_RELOAD 0 -#endif + // Graphics Interface namespace Juliet diff --git a/Juliet/include/Graphics/GraphicsConfig.h b/Juliet/include/Graphics/GraphicsConfig.h index 8d2e1dd..3ef8691 100644 --- a/Juliet/include/Graphics/GraphicsConfig.h +++ b/Juliet/include/Graphics/GraphicsConfig.h @@ -1,5 +1,15 @@ #pragma once +#include + +#include + +#if JULIET_DEBUG +#define ALLOW_SHADER_HOT_RELOAD 1 +#else +#define ALLOW_SHADER_HOT_RELOAD 0 +#endif + namespace Juliet { enum class DriverType : uint8 @@ -11,6 +21,6 @@ namespace Juliet struct GraphicsConfig { DriverType PreferredDriver = DriverType::DX12; - bool EnableDebug; + bool EnableDebug; }; } // namespace Juliet diff --git a/Juliet/include/Graphics/MeshRenderer.h b/Juliet/include/Graphics/MeshRenderer.h index 38f1897..f778410 100644 --- a/Juliet/include/Graphics/MeshRenderer.h +++ b/Juliet/include/Graphics/MeshRenderer.h @@ -2,11 +2,13 @@ #include #include +#include #include #include #include #include + namespace Juliet { struct GraphicsTransferBuffer; @@ -40,8 +42,8 @@ namespace Juliet GraphicsTransferBuffer* StreamCopyBuffer; GraphicsTransferBuffer* LoadCopyBuffer; - GraphicsBuffer* LightsBuffer; - PointLight* MappedLights; + GraphicsBuffer* LightsBuffer; + PointLight* MappedLights; GraphicsDevice* Device; GraphicsPipeline* Pipeline; diff --git a/Juliet/include/Graphics/SkyboxRenderer.h b/Juliet/include/Graphics/SkyboxRenderer.h index f1a5eb6..cf3ad67 100644 --- a/Juliet/include/Graphics/SkyboxRenderer.h +++ b/Juliet/include/Graphics/SkyboxRenderer.h @@ -1,8 +1,11 @@ #pragma once -#include #include +#include +#include +#include + namespace Juliet { struct RenderPass; @@ -17,10 +20,9 @@ namespace Juliet GraphicsPipeline* Pipeline; }; - [[nodiscard]] JULIET_API bool InitializeSkyboxRenderer(NonNullPtr device, - NonNullPtr window); - JULIET_API void ShutdownSkyboxRenderer(); - JULIET_API void RenderSkybox(NonNullPtr pass, NonNullPtr cmdList, const Matrix& viewProjection); + [[nodiscard]] JULIET_API bool InitializeSkyboxRenderer(NonNullPtr device, NonNullPtr window); + JULIET_API void ShutdownSkyboxRenderer(); + JULIET_API void RenderSkybox(NonNullPtr pass, NonNullPtr cmdList, const Matrix& viewProjection); #if ALLOW_SHADER_HOT_RELOAD JULIET_API void ReloadSkyboxShaders(); diff --git a/Juliet/src/Core/Logging/LogManager.cpp b/Juliet/src/Core/Logging/LogManager.cpp index 4964492..7baf3d7 100644 --- a/Juliet/src/Core/Logging/LogManager.cpp +++ b/Juliet/src/Core/Logging/LogManager.cpp @@ -1,8 +1,18 @@ #include #include +#ifdef global +#undef global +#define RESTORE_GLOBAL +#endif + #include +#ifdef RESTORE_GLOBAL +#define global static +#undef RESTORE_GLOBAL +#endif + // Begin Todo JULIET debug output #include #include diff --git a/Juliet/src/Core/Memory/MemoryArena.cpp b/Juliet/src/Core/Memory/MemoryArena.cpp index ebc59e8..477dca3 100644 --- a/Juliet/src/Core/Memory/MemoryArena.cpp +++ b/Juliet/src/Core/Memory/MemoryArena.cpp @@ -18,14 +18,6 @@ namespace Juliet constexpr uint64 k_PageSize = Kilobytes(4); } // namespace - struct ArenaFreeNode - { - ArenaFreeNode* Next; - ArenaFreeNode* Previous; - index_t Position; - size_t Size; - }; - namespace { static_assert(sizeof(ArenaFreeNode) == 32, "ArenaFreeNode should be 32 bytes and not more"); diff --git a/Juliet/src/Core/Networking/SocketPlatformImpl.h b/Juliet/src/Core/Networking/SocketPlatformImpl.h index b86dff5..559c041 100644 --- a/Juliet/src/Core/Networking/SocketPlatformImpl.h +++ b/Juliet/src/Core/Networking/SocketPlatformImpl.h @@ -5,11 +5,11 @@ // Windows uses a non standard header to define its socket types. // Because of that we need to include those in this header. // TODO : implement for other platforms -// #if JULIET_WIN32 -// #include -// #else -// // UNIMPLEMENT_SOCKETS -// #endif +#if JULIET_WIN32 +#include +#else +// UNIMPLEMENT_SOCKETS +#endif namespace Juliet::SocketImpl { diff --git a/Juliet/src/Engine/Debug/MemoryDebugger.cpp b/Juliet/src/Engine/Debug/MemoryDebugger.cpp index 8b5799d..6bb30c7 100644 --- a/Juliet/src/Engine/Debug/MemoryDebugger.cpp +++ b/Juliet/src/Engine/Debug/MemoryDebugger.cpp @@ -1,9 +1,10 @@ -#include -#include -#include // Added for Arena definition -#include #include +#include +#include +#include +#include +#include #include #if JULIET_DEBUG diff --git a/Juliet/src/Graphics/D3D12/D3D12Buffer.h b/Juliet/src/Graphics/D3D12/D3D12Buffer.h index 7480b63..af99f0b 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Buffer.h +++ b/Juliet/src/Graphics/D3D12/D3D12Buffer.h @@ -1,9 +1,9 @@ #pragma once #include -#include -#include #include +#include + namespace Juliet { @@ -20,14 +20,18 @@ namespace Juliet::D3D12 size_t Size; }; - extern GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic); + extern GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr driver, size_t size, size_t stride, + BufferUsage usage, bool isDynamic); extern void DestroyGraphicsBuffer(NonNullPtr buffer); extern GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr driver, size_t size, TransferBufferUsage usage); extern void DestroyGraphicsTransferBuffer(NonNullPtr buffer); - extern void* MapBuffer(NonNullPtr driver, NonNullPtr buffer); - extern void UnmapBuffer(NonNullPtr driver, NonNullPtr buffer); + extern void* MapBuffer(NonNullPtr driver, NonNullPtr buffer); + extern void UnmapBuffer(NonNullPtr driver, NonNullPtr buffer); + extern void* MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer); + extern void UnmapBuffer(NonNullPtr driver, NonNullPtr buffer); + extern uint32 GetDescriptorIndex(NonNullPtr driver, NonNullPtr buffer); extern void CopyBuffer(NonNullPtr commandList, NonNullPtr dst, NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset); diff --git a/Juliet/src/Graphics/ImGuiRenderer.cpp b/Juliet/src/Graphics/ImGuiRenderer.cpp index 17a6559..80f365e 100644 --- a/Juliet/src/Graphics/ImGuiRenderer.cpp +++ b/Juliet/src/Graphics/ImGuiRenderer.cpp @@ -1,15 +1,17 @@ #include + #ifdef JULIET_ENABLE_IMGUI #include +#include +#include +#include #include #include -#include #include #include - -#include +#include #include namespace Juliet diff --git a/misc/build.bat b/misc/build.bat index dee8a64..8ef3429 100644 --- a/misc/build.bat +++ b/misc/build.bat @@ -132,14 +132,19 @@ if not exist "Intermediate\x64-!CFG!" mkdir "Intermediate\x64-!CFG!" echo CONFIG !CFG!>>"!PLAN_FILE!" -set FASTBUILD_TARGETS=Juliet-Unity -if /i not "!CFG!"=="Release" set FASTBUILD_TARGETS=!FASTBUILD_TARGETS! ImGui-Unity -if !TARGET_JULIET! equ 1 set FASTBUILD_TARGETS=!FASTBUILD_TARGETS! JulietApp-Unity Game-Unity -if !TARGET_GAME! equ 1 set FASTBUILD_TARGETS=!FASTBUILD_TARGETS! Game-Unity -if !TARGET_ROMEO! equ 1 set FASTBUILD_TARGETS=!FASTBUILD_TARGETS! Romeo-Unity -if !TARGET_SHADER! equ 1 set FASTBUILD_TARGETS=!FASTBUILD_TARGETS! JulietShaderCompiler-Unity +set UNITY_MAX_FILES=50 -echo FASTBUILD !FASTBUILD_TARGETS!>>"!PLAN_FILE!" +echo UNITY Juliet Intermediate\Juliet Juliet_Unity !UNITY_MAX_FILES!>>"!PLAN_FILE!" +if /i not "!CFG!"=="Release" echo UNITY_EXPLICIT Intermediate\External\imgui ImGui_Unity 1 External\imgui\imgui.cpp^|External\imgui\imgui_demo.cpp^|External\imgui\imgui_draw.cpp^|External\imgui\imgui_tables.cpp^|External\imgui\imgui_widgets.cpp^|External\imgui\backends\imgui_impl_win32.cpp^|External\imgui\backends\imgui_impl_dx12.cpp>>"!PLAN_FILE!" + +set ADD_GAME_UNITY=0 +if !TARGET_JULIET! equ 1 set ADD_GAME_UNITY=1 +if !TARGET_GAME! equ 1 set ADD_GAME_UNITY=1 + +if !TARGET_JULIET! equ 1 echo UNITY JulietApp Intermediate\JulietApp JulietApp_Unity !UNITY_MAX_FILES!>>"!PLAN_FILE!" +if !ADD_GAME_UNITY! equ 1 echo UNITY Game Intermediate\Game Game_Unity !UNITY_MAX_FILES!>>"!PLAN_FILE!" +if !TARGET_ROMEO! equ 1 echo UNITY Romeo Intermediate\Romeo Romeo_Unity !UNITY_MAX_FILES!>>"!PLAN_FILE!" +if !TARGET_SHADER! equ 1 echo UNITY JulietShaderCompiler Intermediate\JulietShaderCompiler JulietShaderCompiler_Unity !UNITY_MAX_FILES!>>"!PLAN_FILE!" set COMMON_FLAGS=/nologo /std:c++20 /W4 /EHa- /utf-8 /DUNICODE /D_UNICODE /DWIN32_LEAN_AND_MEAN /D_CRT_SECURE_NO_WARNINGS /I"Juliet/include" /I"Juliet/src" /I"Game" /I"External/imgui" /I"External/imgui/backends" /DJULIET_WIN32 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4626 /wd5026 /wd5027 /wd4530 @@ -160,7 +165,7 @@ if defined IMGUI_UNITY_SRCS ( echo STEP Compiling ImGui Shared Objs [!CFG!]>>"!PLAN_FILE!" echo OUTPUT Intermediate\x64-!CFG!\ImGui_Unity1.obj>>"!PLAN_FILE!" echo DEPENDS External\imgui>>"!PLAN_FILE!" - echo COMMAND %COMPILER% %COMPILER_FLAGS% /c !IMGUI_UNITY_SRCS! /Fo"Intermediate\x64-!CFG!\\">>"!PLAN_FILE!" + echo COMMAND %COMPILER% %COMPILER_FLAGS% /DIMGUI_API=__declspec^(dllexport^) /c !IMGUI_UNITY_SRCS! /Fo"Intermediate\x64-!CFG!\\">>"!PLAN_FILE!" ) set IMGUI_OBJS= diff --git a/tools/build_system.c b/tools/build_system.c index d93bf80..6e27555 100644 --- a/tools/build_system.c +++ b/tools/build_system.c @@ -126,7 +126,19 @@ static bool DirectoryExists(const char* path) static void EnsureDirectoryExists(const char* path) { - CreateDirectoryA(path, NULL); + char tmp[MAX_PATH_LEN]; + strncpy_s(tmp, MAX_PATH_LEN, path, _TRUNCATE); + for (int i = 0; tmp[i]; i++) + { + if (tmp[i] == '\\' || tmp[i] == '/') + { + char c = tmp[i]; + tmp[i] = '\0'; + CreateDirectoryA(tmp, NULL); + tmp[i] = c; + } + } + CreateDirectoryA(tmp, NULL); } static int64_t GetFileModTimeInt64(const char* path) @@ -142,187 +154,6 @@ static int64_t GetFileModTimeInt64(const char* path) return 0; } -// ============================================================================ -// FNV-1a hash -// ============================================================================ - -static uint64_t ComputeFnv1aHash(const char* data, long size) -{ - uint64_t hash = 14695981039346656037ULL; - for (long i = 0; i < size; i++) - { - hash ^= (uint64_t)(unsigned char)data[i]; - hash *= 1099511628211ULL; - } - return hash; -} - -// ============================================================================ -// Hash cache -// ============================================================================ - -typedef struct -{ - char Path[MAX_PATH_LEN]; - char HashStr[32]; -} HashEntry; - -typedef struct -{ - HashEntry* Entries; - int Count; -} HashCache; - -static HashCache* CreateHashCache() -{ - HashCache* cache = (HashCache*)ArenaPush(sizeof(HashCache)); - cache->Entries = (HashEntry*)ArenaPush(sizeof(HashEntry) * MAX_HASH_ENTRIES); - cache->Count = 0; - return cache; -} - -static const char* HashCacheFind(const HashCache* cache, const char* path) -{ - for (int i = 0; i < cache->Count; i++) - { - if (strcmp(cache->Entries[i].Path, path) == 0) - { - return cache->Entries[i].HashStr; - } - } - return NULL; -} - -static void HashCacheAdd(HashCache* cache, const char* path, const char* hash) -{ - if (cache->Count < MAX_HASH_ENTRIES) - { - strncpy_s(cache->Entries[cache->Count].Path, MAX_PATH_LEN, path, _TRUNCATE); - strncpy_s(cache->Entries[cache->Count].HashStr, 32, hash, _TRUNCATE); - cache->Count++; - } -} - -static void LoadHashCache(const char* cachePath, HashCache* cache) -{ - FileContent content = ReadEntireFile(cachePath); - if (!content.Data) return; - - const char* pos = content.Data; - while (*pos != '\0') - { - const char* lineStart = pos; - while (*pos != '\0' && *pos != '\n' && *pos != '\r') - pos++; - int lineLen = (int)(pos - lineStart); - - if (lineLen > 0) - { - const char* sep = NULL; - for (const char* c = lineStart; c < lineStart + lineLen; c++) - { - if (*c == '=') - { - sep = c; - break; - } - } - if (sep) - { - char key[MAX_PATH_LEN] = { 0 }; - int keyLen = (int)(sep - lineStart); - if (keyLen >= MAX_PATH_LEN) keyLen = MAX_PATH_LEN - 1; - memcpy(key, lineStart, keyLen); - - int valLen = (int)((lineStart + lineLen) - (sep + 1)); - char val[32] = { 0 }; - if (valLen > 0 && valLen < 32) - { - memcpy(val, sep + 1, valLen); - } - HashCacheAdd(cache, key, val); - } - } - while (*pos == '\n' || *pos == '\r') - pos++; - } -} - -static void SaveHashCache(const char* cachePath, const HashCache* cache) -{ - long bufSize = MAX_HASH_ENTRIES * (MAX_PATH_LEN + 32 + 2); - char* buffer = (char*)ArenaPush(bufSize); - int offset = 0; - - for (int i = 0; i < cache->Count; i++) - { - int written = sprintf_s(buffer + offset, bufSize - offset, "%s=%s\n", cache->Entries[i].Path, cache->Entries[i].HashStr); - if (written > 0) offset += written; - } - WriteEntireFile(cachePath, buffer, offset); -} - -// ============================================================================ -// Clean #pragma message lines and compute hash for a unity file -// ============================================================================ - -typedef struct -{ - char HashStr[32]; - bool WasCleaned; -} CleanResult; - -static CleanResult CleanAndHashUnityFile(const char* filePath) -{ - CleanResult result = { { 0 }, false }; - FileContent content = ReadEntireFile(filePath); - if (!content.Data) return result; - - if (StringContains(content.Data, "#pragma message")) - { - char* filtered = (char*)ArenaPush(content.Size + 1); - long filteredSize = 0; - - const char* pos = content.Data; - while (*pos != '\0') - { - const char* lineStart = pos; - while (*pos != '\0' && *pos != '\n') - pos++; - - bool skipLine = false; - for (const char* c = lineStart; c < pos; c++) - { - if (c + 15 <= content.Data + content.Size && memcmp(c, "#pragma message", 15) == 0) - { - skipLine = true; - break; - } - } - - if (!skipLine) - { - long lineLen = (long)(pos - lineStart); - memcpy(filtered + filteredSize, lineStart, lineLen); - filteredSize += lineLen; - if (*pos == '\n') filtered[filteredSize++] = '\n'; - } - if (*pos == '\n') pos++; - } - filtered[filteredSize] = '\0'; - - WriteEntireFile(filePath, filtered, filteredSize); - uint64_t hashVal = ComputeFnv1aHash(filtered, filteredSize); - sprintf_s(result.HashStr, sizeof(result.HashStr), "%llu", hashVal); - result.WasCleaned = true; - } - else - { - uint64_t hashVal = ComputeFnv1aHash(content.Data, content.Size); - sprintf_s(result.HashStr, sizeof(result.HashStr), "%llu", hashVal); - } - return result; -} // ============================================================================ // Recursive directory scan @@ -403,7 +234,7 @@ static void FilePathListAdd(FilePathList* list, const char* path) } } -static void CollectUnityFiles(const char* dirPath, FilePathList* list) +static void CollectFiles(const char* dirPath, const char* containsStr, const char* endsWithStr, FilePathList* list) { char searchPath[MAX_PATH_LEN]; snprintf(searchPath, sizeof(searchPath), "%s\\*", dirPath); @@ -425,11 +256,14 @@ static void CollectUnityFiles(const char* dirPath, FilePathList* list) if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - CollectUnityFiles(fullPath, list); + CollectFiles(fullPath, containsStr, endsWithStr, list); } else { - if (StringContains(findData.cFileName, "_Unity") && EndsWithNoCase(findData.cFileName, ".cpp")) + bool match = true; + if (containsStr && !StringContains(findData.cFileName, containsStr)) match = false; + if (endsWithStr && !EndsWithNoCase(findData.cFileName, endsWithStr)) match = false; + if (match) { FilePathListAdd(list, fullPath); } @@ -440,6 +274,101 @@ static void CollectUnityFiles(const char* dirPath, FilePathList* list) FindClose(hFind); } +typedef struct +{ + char SourceDir[MAX_PATH_LEN]; + char OutputDir[MAX_PATH_LEN]; + char Prefix[256]; + char* ExplicitFiles[64]; + int ExplicitFileCount; + int MaxFiles; +} UnityConfig; + +static bool GenerateUnityFiles(const UnityConfig* ucfg) +{ + FilePathList* srcFiles = CreateFilePathList(); + if (ucfg->SourceDir[0] != '\0') + { + CollectFiles(ucfg->SourceDir, NULL, ".cpp", srcFiles); + } + else + { + for (int i = 0; i < ucfg->ExplicitFileCount; i++) + { + FilePathListAdd(srcFiles, ucfg->ExplicitFiles[i]); + } + } + + EnsureDirectoryExists(ucfg->OutputDir); + + int fileIdx = 0; + int unityCount = 1; + char currentUnityPath[MAX_PATH_LEN]; + bool anyChanged = false; + + char* memBuf = (char*)ArenaPush(1024 * 1024); + int memOffset = 0; + + for (int i = 0; i < srcFiles->Count; i++) + { + if (StringContains(srcFiles->Paths[i], "_Unity")) continue; + + if (fileIdx == 0) + { + memOffset = 0; + } + + char absPath[MAX_PATH_LEN]; + GetFullPathNameA(srcFiles->Paths[i], MAX_PATH_LEN, absPath, NULL); + for (int k = 0; absPath[k]; k++) { + if (absPath[k] == '\\') absPath[k] = '/'; + } + + memOffset += sprintf_s(memBuf + memOffset, (1024 * 1024) - memOffset, "#include \"%s\"\n", absPath); + fileIdx++; + + if (fileIdx >= ucfg->MaxFiles || i == srcFiles->Count - 1) + { + snprintf(currentUnityPath, sizeof(currentUnityPath), "%s\\%s%d.cpp", ucfg->OutputDir, ucfg->Prefix, unityCount); + + FileContent exist = ReadEntireFile(currentUnityPath); + bool write = true; + if (exist.Data && exist.Size == memOffset) + { + if (memcmp(exist.Data, memBuf, memOffset) == 0) + { + write = false; + } + } + if (write) + { + WriteEntireFile(currentUnityPath, memBuf, memOffset); + anyChanged = true; + } + + unityCount++; + fileIdx = 0; + } + } + + while (true) + { + snprintf(currentUnityPath, sizeof(currentUnityPath), "%s\\%s%d.cpp", ucfg->OutputDir, ucfg->Prefix, unityCount); + if (FileExists(currentUnityPath)) + { + DeleteFileA(currentUnityPath); + anyChanged = true; + unityCount++; + } + else + { + break; + } + } + + return anyChanged; +} + // ============================================================================ // Commands // ============================================================================ @@ -454,10 +383,11 @@ typedef struct typedef struct { - char Name[64]; - char FastBuildTargets[512]; - BuildStep Steps[32]; - int StepCount; + char Name[64]; + UnityConfig UnitySteps[16]; + int UnityStepCount; + BuildStep Steps[32]; + int StepCount; } BuildConfig; static int ExecuteCmd(const char* cmdLine) @@ -544,8 +474,7 @@ static int CommandRunPlan(int argc, char* argv[]) QueryPerformanceFrequency(&perfFreq); // Parse plan file - BuildConfig configs[4]; - memset(configs, 0, sizeof(configs)); + BuildConfig* configs = (BuildConfig*)ArenaPush(4 * sizeof(BuildConfig)); int configCount = 0; const char* pos = planContent.Data; @@ -572,12 +501,65 @@ static int CommandRunPlan(int argc, char* argv[]) else if (configCount > 0) { BuildConfig* curCfg = &configs[configCount - 1]; - if (lineLen > 10 && memcmp(lineStart, "FASTBUILD ", 10) == 0) + if (lineLen > 6 && memcmp(lineStart, "UNITY ", 6) == 0) { - int nLen = lineLen - 10; - if (nLen >= (int)sizeof(curCfg->FastBuildTargets)) nLen = (int)sizeof(curCfg->FastBuildTargets) - 1; - memcpy(curCfg->FastBuildTargets, lineStart + 10, nLen); - curCfg->FastBuildTargets[nLen] = '\0'; + if (curCfg->UnityStepCount < 16) + { + char lineBuf[1024]; + int nLen = lineLen - 6; + if (nLen >= (int)sizeof(lineBuf)) nLen = (int)sizeof(lineBuf) - 1; + memcpy(lineBuf, lineStart + 6, nLen); + lineBuf[nLen] = '\0'; + + UnityConfig* ucfg = &curCfg->UnitySteps[curCfg->UnityStepCount]; + ucfg->ExplicitFileCount = 0; + if (sscanf_s(lineBuf, "%s %s %s %d", + ucfg->SourceDir, (unsigned)_countof(ucfg->SourceDir), + ucfg->OutputDir, (unsigned)_countof(ucfg->OutputDir), + ucfg->Prefix, (unsigned)_countof(ucfg->Prefix), + &ucfg->MaxFiles) == 4) + { + curCfg->UnityStepCount++; + } + } + } + else if (lineLen > 15 && memcmp(lineStart, "UNITY_EXPLICIT ", 15) == 0) + { + if (curCfg->UnityStepCount < 16) + { + char lineBuf[2048]; + int nLen = lineLen - 15; + if (nLen >= (int)sizeof(lineBuf)) nLen = (int)sizeof(lineBuf) - 1; + memcpy(lineBuf, lineStart + 15, nLen); + lineBuf[nLen] = '\0'; + + UnityConfig* ucfg = &curCfg->UnitySteps[curCfg->UnityStepCount]; + ucfg->SourceDir[0] = '\0'; + ucfg->ExplicitFileCount = 0; + + char fileList[1024]; + if (sscanf_s(lineBuf, "%s %s %d %s", + ucfg->OutputDir, (unsigned)_countof(ucfg->OutputDir), + ucfg->Prefix, (unsigned)_countof(ucfg->Prefix), + &ucfg->MaxFiles, + fileList, (unsigned)_countof(fileList)) == 4) + { + char* ctx = NULL; + char* token = strtok_s(fileList, "|", &ctx); + while(token) + { + if (ucfg->ExplicitFileCount < 64) + { + size_t tLen = strlen(token); + char* storedStr = (char*)ArenaPush(tLen + 1); + strcpy_s(storedStr, tLen + 1, token); + ucfg->ExplicitFiles[ucfg->ExplicitFileCount++] = storedStr; + } + token = strtok_s(NULL, "|", &ctx); + } + curCfg->UnityStepCount++; + } + } } else if (lineLen > 5 && memcmp(lineStart, "STEP ", 5) == 0) { @@ -627,66 +609,37 @@ static int CommandRunPlan(int argc, char* argv[]) { BuildConfig* cfg = &configs[i]; printf("\n==============================================================================\n"); - printf("Generating Unity Files into Intermediate/ via FASTBuild [%s]...\n", cfg->Name); + printf("Generating Unity Files [%s]...\n", cfg->Name); printf("==============================================================================\n"); - if (cfg->FastBuildTargets[0] != '\0') - { - char fbuildCmd[MAX_PATH_LEN]; - sprintf_s(fbuildCmd, sizeof(fbuildCmd), "misc\\fbuild.exe %s", cfg->FastBuildTargets); + bool unityChanged = false; + if (cfg->UnityStepCount > 0) + { LARGE_INTEGER tStart, tEnd; QueryPerformanceCounter(&tStart); - int res = ExecuteCmd(fbuildCmd); - QueryPerformanceCounter(&tEnd); - - char stepName[MAX_PATH_LEN]; - sprintf_s(stepName, sizeof(stepName), "FASTBuild Unity Gen [%s]", cfg->Name); - AppendTiming(stepName, (double)(tEnd.QuadPart - tStart.QuadPart) / (double)perfFreq.QuadPart); - - if (res != 0) + + for (int u = 0; u < cfg->UnityStepCount; u++) { - printf("[BUILD FAILED] FASTBuild failed for %s.\n", cfg->Name); - return res; - } - } - - HashCache* oldCache = CreateHashCache(); - LoadHashCache("Intermediate\\.unity_hashes_cache", oldCache); - - HashCache* newCache = CreateHashCache(); - bool unityChanged = false; - - FilePathList* unityFiles = CreateFilePathList(); - CollectUnityFiles("Intermediate", unityFiles); - - if (unityFiles->Count == 0) - { - unityChanged = true; - } - else - { - for (int k = 0; k < unityFiles->Count; k++) - { - CleanResult cr = CleanAndHashUnityFile(unityFiles->Paths[k]); - HashCacheAdd(newCache, unityFiles->Paths[k], cr.HashStr); - - const char* oldHash = HashCacheFind(oldCache, unityFiles->Paths[k]); - if (oldHash == NULL || strcmp(oldHash, cr.HashStr) != 0) + if (GenerateUnityFiles(&cfg->UnitySteps[u])) { unityChanged = true; } } + + QueryPerformanceCounter(&tEnd); + char stepName[MAX_PATH_LEN]; + sprintf_s(stepName, sizeof(stepName), "Unity Gen [%s]", cfg->Name); + AppendTiming(stepName, (double)(tEnd.QuadPart - tStart.QuadPart) / (double)perfFreq.QuadPart); } - SaveHashCache("Intermediate\\.unity_hashes_cache", newCache); if (unityChanged) { - printf("[FASTBuild] Unity structure or source file list changed.\n"); + printf("[Unity] Source file list or include mapping changed.\n"); } else { - printf("[FASTBuild] No Unity file structure changes detected [up-to-date].\n"); + printf("[Unity] No changes detected [up-to-date].\n"); } printf("\n==============================================================================\n");