diff --git a/Juliet/include/Core/Application/IApplication.h b/Juliet/include/Core/Application/IApplication.h index 83acc0b..07b9214 100644 --- a/Juliet/include/Core/Application/IApplication.h +++ b/Juliet/include/Core/Application/IApplication.h @@ -26,9 +26,7 @@ namespace Juliet virtual struct GraphicsDevice* GetGraphicsDevice() = 0; // Render Lifecycle (Engine-Managed Render Loop) - virtual void OnPreRender(CommandList* cmd) = 0; - virtual void OnRender(RenderPass* pass, CommandList* cmd, const Camera& camera) = 0; - virtual ColorTargetInfo GetColorTargetInfo(Texture* swapchainTexture) = 0; - virtual DepthStencilTargetInfo* GetDepthTargetInfo() = 0; + virtual ColorTargetInfo GetColorTargetInfo(Texture* swapchainTexture) = 0; + virtual DepthStencilTargetInfo* GetDepthTargetInfo() = 0; }; } // namespace Juliet diff --git a/Juliet/include/Graphics/MeshRenderer.h b/Juliet/include/Graphics/MeshRenderer.h index 409c227..cff66f6 100644 --- a/Juliet/include/Graphics/MeshRenderer.h +++ b/Juliet/include/Graphics/MeshRenderer.h @@ -53,7 +53,7 @@ namespace Juliet JULIET_API void ShutdownMeshRendererGraphics(); JULIET_API void ShutdownMeshRenderer(); JULIET_API void LoadMeshesOnGPU(NonNullPtr cmdList); - JULIET_API void RenderMeshes(NonNullPtr pass, NonNullPtr cmdList, PushData& pushData); + JULIET_API void RenderMeshes(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection); // Lights [[nodiscard]] JULIET_API LightID AddPointLight(const PointLight& light); diff --git a/Juliet/include/Graphics/SkyboxRenderer.h b/Juliet/include/Graphics/SkyboxRenderer.h index cf3ad67..210a196 100644 --- a/Juliet/include/Graphics/SkyboxRenderer.h +++ b/Juliet/include/Graphics/SkyboxRenderer.h @@ -22,7 +22,7 @@ namespace Juliet [[nodiscard]] JULIET_API bool InitializeSkyboxRenderer(NonNullPtr device, NonNullPtr window); JULIET_API void ShutdownSkyboxRenderer(); - JULIET_API void RenderSkybox(NonNullPtr pass, NonNullPtr cmdList, const Matrix& viewProjection); + JULIET_API void RenderSkybox(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection); #if ALLOW_SHADER_HOT_RELOAD JULIET_API void ReloadSkyboxShaders(); diff --git a/Juliet/src/Engine/Engine.cpp b/Juliet/src/Engine/Engine.cpp index 6a42122..b5e11b8 100644 --- a/Juliet/src/Engine/Engine.cpp +++ b/Juliet/src/Engine/Engine.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #ifdef JULIET_ENABLE_IMGUI #include @@ -120,9 +119,6 @@ namespace Juliet if (swapChainTexture) { - // Pre-render phase (buffer uploads, etc.) - EngineInstance.Application->OnPreRender(cmdList); - // Prepare debug display data (before render pass) DebugDisplay_Prepare(cmdList); @@ -132,17 +128,15 @@ namespace Juliet RenderPass* pass = BeginRenderPass(cmdList, colorInfo, depthInfo); - Camera camera = *GetCurrentCamera(); + Camera camera = *GetCurrentCamera(); + Matrix viewProjectionMat = Camera_GetViewProjectionMatrix(camera); - // Application rendering - EngineInstance.Application->OnRender(pass, cmdList, camera); + RenderSkybox(cmdList, pass, viewProjectionMat); + RenderMeshes(cmdList, pass, viewProjectionMat); - // Debug display flush (inside render pass) + // Debug display flush must happen after game rendering DebugDisplay_Flush(cmdList, pass, camera); - // Note: The MeshRenderer and SkyboxRenderer draw calls are still inside Application->OnRender - // They shouldn't be moved here directly without an interface since they require PushData. - #ifdef JULIET_ENABLE_IMGUI // ImGui rendering (always last before EndRenderPass) ImGuiRenderer_Render(cmdList, pass); diff --git a/Juliet/src/Graphics/MeshRenderer.cpp b/Juliet/src/Graphics/MeshRenderer.cpp index 0180136..a4d2119 100644 --- a/Juliet/src/Graphics/MeshRenderer.cpp +++ b/Juliet/src/Graphics/MeshRenderer.cpp @@ -237,7 +237,7 @@ namespace Juliet TransitionBufferToReadable(cmdList, g_MeshRenderer.IndexBuffer); } - void RenderMeshes(NonNullPtr pass, NonNullPtr cmdList, PushData& pushData) + void RenderMeshes(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection) { // First destroy any buffer that needs to be if (g_MeshRenderer.LoadCopyBuffer) @@ -255,10 +255,15 @@ namespace Juliet uint32 transformsDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer); - pushData.BufferIndex = vertexDescriptorIndex; - pushData.LightBufferIndex = lightDescriptorIndex; - pushData.TransformsBufferIndex = transformsDescriptorIndex; - pushData.ActiveLightCount = static_cast(g_MeshRenderer.PointLights.Count); + PushData pushData = {}; + pushData.ViewProjection = viewProjection; + pushData.BufferIndex = vertexDescriptorIndex; + pushData.LightBufferIndex = lightDescriptorIndex; + pushData.TransformsBufferIndex = transformsDescriptorIndex; + pushData.ActiveLightCount = static_cast(g_MeshRenderer.PointLights.Count); + pushData.GlobalLightDirection = { 0.0f, -1.0f, 0.0f }; + pushData.GlobalLightColor = { 0.0f, 0.0f, 0.0f }; + pushData.GlobalAmbientIntensity = 0.0f; SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0); diff --git a/Juliet/src/Graphics/SkyboxRenderer.cpp b/Juliet/src/Graphics/SkyboxRenderer.cpp index 052ddb7..07601a2 100644 --- a/Juliet/src/Graphics/SkyboxRenderer.cpp +++ b/Juliet/src/Graphics/SkyboxRenderer.cpp @@ -19,35 +19,35 @@ namespace Juliet GraphicsDevice* graphicsDevice = g_SkyboxRenderer.Device = device.Get(); - String skyboxVSEntry = WrapString("main"); - ShaderCreateInfo skyboxVSCI = {}; - skyboxVSCI.EntryPoint = skyboxVSEntry; - skyboxVSCI.Stage = ShaderStage::Vertex; - String vsPath = GetAssetPath(WrapString("Skybox.vert.dxil")); - Shader* skyboxVS = CreateShader(graphicsDevice, vsPath, skyboxVSCI); + String skyboxVSEntry = WrapString("main"); + ShaderCreateInfo skyboxVSCI = {}; + skyboxVSCI.EntryPoint = skyboxVSEntry; + skyboxVSCI.Stage = ShaderStage::Vertex; + String vsPath = GetAssetPath(WrapString("Skybox.vert.dxil")); + Shader* skyboxVS = CreateShader(graphicsDevice, vsPath, skyboxVSCI); - String skyboxFSEntry = WrapString("main"); - ShaderCreateInfo skyboxFSCI = {}; - skyboxFSCI.EntryPoint = skyboxFSEntry; - skyboxFSCI.Stage = ShaderStage::Fragment; - String fsPath = GetAssetPath(WrapString("Skybox.frag.dxil")); - Shader* skyboxFS = CreateShader(graphicsDevice, fsPath, skyboxFSCI); + String skyboxFSEntry = WrapString("main"); + ShaderCreateInfo skyboxFSCI = {}; + skyboxFSCI.EntryPoint = skyboxFSEntry; + skyboxFSCI.Stage = ShaderStage::Fragment; + String fsPath = GetAssetPath(WrapString("Skybox.frag.dxil")); + Shader* skyboxFS = CreateShader(graphicsDevice, fsPath, skyboxFSCI); ColorTargetDescription colorTargetDesc = {}; - colorTargetDesc.Format = GetSwapChainTextureFormat(graphicsDevice, window); + colorTargetDesc.Format = GetSwapChainTextureFormat(graphicsDevice, window); - GraphicsPipelineCreateInfo skyboxPipelineCI = {}; - skyboxPipelineCI.VertexShader = skyboxVS; - skyboxPipelineCI.FragmentShader = skyboxFS; - skyboxPipelineCI.PrimitiveType = PrimitiveType::TriangleList; + GraphicsPipelineCreateInfo skyboxPipelineCI = {}; + skyboxPipelineCI.VertexShader = skyboxVS; + skyboxPipelineCI.FragmentShader = skyboxFS; + skyboxPipelineCI.PrimitiveType = PrimitiveType::TriangleList; skyboxPipelineCI.TargetInfo.ColorTargetDescriptions = &colorTargetDesc; - skyboxPipelineCI.TargetInfo.NumColorTargets = 1; - skyboxPipelineCI.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT; - skyboxPipelineCI.TargetInfo.HasDepthStencilTarget = true; - skyboxPipelineCI.RasterizerState.FillMode = FillMode::Solid; - skyboxPipelineCI.RasterizerState.CullMode = CullMode::None; - skyboxPipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise; - skyboxPipelineCI.DepthStencilState.EnableDepthTest = true; + skyboxPipelineCI.TargetInfo.NumColorTargets = 1; + skyboxPipelineCI.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT; + skyboxPipelineCI.TargetInfo.HasDepthStencilTarget = true; + skyboxPipelineCI.RasterizerState.FillMode = FillMode::Solid; + skyboxPipelineCI.RasterizerState.CullMode = CullMode::None; + skyboxPipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise; + skyboxPipelineCI.DepthStencilState.EnableDepthTest = true; skyboxPipelineCI.DepthStencilState.EnableDepthWrite = false; skyboxPipelineCI.DepthStencilState.CompareOperation = CompareOperation::LessOrEqual; @@ -75,7 +75,7 @@ namespace Juliet g_SkyboxRenderer = {}; } - void RenderSkybox(NonNullPtr pass, NonNullPtr cmdList, const Matrix& viewProjection) + void RenderSkybox(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection) { if (!g_SkyboxRenderer.Pipeline) { diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp index 80aa849..8df3728 100644 --- a/JulietApp/main.cpp +++ b/JulietApp/main.cpp @@ -537,32 +537,6 @@ void JulietApplication::Update(float deltaTime) } } -void JulietApplication::OnPreRender(CommandList* /*cmd*/) {} - -void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd, const Camera& camera) -{ - PushData pushData = {}; - pushData.ViewProjection = Camera_GetViewProjectionMatrix(camera); - -#if 0 - if (enableGlobalLight) - { - pushData.GlobalLightDirection = Normalize({ globalLightDir[0], globalLightDir[1], globalLightDir[2] }); - pushData.GlobalLightColor = { globalLightColor[0], globalLightColor[1], globalLightColor[2] }; - pushData.GlobalAmbientIntensity = globalAmbientIntensity; - } - else -#endif - { - pushData.GlobalLightDirection = { 0.0f, -1.0f, 0.0f }; - pushData.GlobalLightColor = { 0.0f, 0.0f, 0.0f }; - pushData.GlobalAmbientIntensity = 0.0f; - } - - RenderSkybox(pass, cmd, pushData.ViewProjection); - RenderMeshes(pass, cmd, pushData); -} - ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture) { ColorTargetInfo info = {}; diff --git a/JulietApp/main.h b/JulietApp/main.h index bc68eea..a9cd095 100644 --- a/JulietApp/main.h +++ b/JulietApp/main.h @@ -27,8 +27,6 @@ class JulietApplication : public Juliet::IApplication Juliet::GraphicsDevice* GetGraphicsDevice() override { return GraphicsDevice; } // Render Lifecycle - void OnPreRender(Juliet::CommandList* cmd) override; - void OnRender(Juliet::RenderPass* pass, Juliet::CommandList* cmd, const Juliet::Camera& camera) override; Juliet::ColorTargetInfo GetColorTargetInfo(Juliet::Texture* swapchainTexture) override; Juliet::DepthStencilTargetInfo* GetDepthTargetInfo() override; diff --git a/misc/build.bat b/misc/build.bat index 70b2b9a..0a61764 100644 --- a/misc/build.bat +++ b/misc/build.bat @@ -153,7 +153,7 @@ if !TARGET_SHADER! equ 1 echo UNITY JulietShaderCompiler Intermediate\JulietShad if !TARGET_JULIET! equ 1 echo UNITY_EXPLICIT Intermediate\External\imgui ImGui_Unity !UNITY_MAX_FILES! 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 COMMON_FLAGS=/nologo /std:c++20 /W4 /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 +set COMMON_FLAGS=/nologo /std:c++20 /W4 /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 /DIMGUI_DEFINE_MATH_OPERATORS /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4626 /wd5026 /wd5027 /wd4530 set COMPILE_ONLY_FLAGS=/Bt+ /EHa- echo !COMPILER! | findstr /i "clang-cl" >nul diff --git a/tools/build_system.c b/tools/build_system.c index a3e2494..d89e531 100644 --- a/tools/build_system.c +++ b/tools/build_system.c @@ -284,6 +284,11 @@ typedef struct int MaxFiles; } UnityConfig; +static int CompareFilePaths(const void* a, const void* b) +{ + return strcmp((const char*)a, (const char*)b); +} + static bool GenerateUnityFiles(const UnityConfig* ucfg) { FilePathList* srcFiles = CreateFilePathList(); @@ -299,6 +304,9 @@ static bool GenerateUnityFiles(const UnityConfig* ucfg) } } + // Sort files to ensure deterministic index + qsort(srcFiles->Paths, srcFiles->Count, MAX_PATH_LEN, CompareFilePaths); + EnsureDirectoryExists(ucfg->OutputDir); SYSTEMTIME st; @@ -311,91 +319,99 @@ static bool GenerateUnityFiles(const UnityConfig* ucfg) int64_t nowTime = liNow.QuadPart; int64_t oneHour = 3600LL * 10000000LL; - FilePathList* coldFiles = CreateFilePathList(); - FilePathList* hotFiles = CreateFilePathList(); - - for (int i = 0; i < srcFiles->Count; i++) - { - if (StringContains(srcFiles->Paths[i], "_Unity")) continue; - int64_t fileTime = GetFileModTimeInt64(srcFiles->Paths[i]); - if (nowTime - fileTime < oneHour) { - FilePathListAdd(hotFiles, srcFiles->Paths[i]); - } else { - FilePathListAdd(coldFiles, srcFiles->Paths[i]); - } - } - - int unityCount = 1; bool anyChanged = false; char currentUnityPath[MAX_PATH_LEN]; char* memBuf = (char*)ArenaPush(1024 * 1024); - // Process cold files (MaxFiles) - int fileIdx = 0; - int memOffset = 0; - int64_t maxIncludedTime = 0; - - for (int i = 0; i < coldFiles->Count; i++) + // Determine hot/cold for each file + bool* isHot = (bool*)ArenaPush(srcFiles->Count * sizeof(bool)); + for (int i = 0; i < srcFiles->Count; i++) { - char absPath[MAX_PATH_LEN]; - GetFullPathNameA(coldFiles->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++; - - int64_t fileTime = GetFileModTimeInt64(coldFiles->Paths[i]); - if (fileTime > maxIncludedTime) maxIncludedTime = fileTime; - - if (fileIdx >= ucfg->MaxFiles || i == coldFiles->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 && memcmp(exist.Data, memBuf, memOffset) == 0) write = false; - if (write) { WriteEntireFile(currentUnityPath, memBuf, memOffset); anyChanged = true; } - - // Touch Unity file if included files are newer - if (!write) { - int64_t unityTime = GetFileModTimeInt64(currentUnityPath); - if (maxIncludedTime > unityTime) { - HANDLE hFile = CreateFileA(currentUnityPath, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile != INVALID_HANDLE_VALUE) { - FILETIME ft; - ULARGE_INTEGER li; - li.QuadPart = nowTime; - ft.dwLowDateTime = li.LowPart; - ft.dwHighDateTime = li.HighPart; - SetFileTime(hFile, NULL, NULL, &ft); - CloseHandle(hFile); - } - } - } - - unityCount++; - fileIdx = 0; - memOffset = 0; - maxIncludedTime = 0; + isHot[i] = false; + if (StringContains(srcFiles->Paths[i], "_Unity")) continue; + int64_t fileTime = GetFileModTimeInt64(srcFiles->Paths[i]); + if (nowTime - fileTime < oneHour) { + isHot[i] = true; } } - // Process hot files (Standalone) - for (int i = 0; i < hotFiles->Count; i++) + int numBuckets = (srcFiles->Count + ucfg->MaxFiles - 1) / ucfg->MaxFiles; + if (numBuckets == 0) numBuckets = 1; // Always at least one bucket + + for (int b = 0; b < numBuckets; b++) { + int startIdx = b * ucfg->MaxFiles; + int endIdx = startIdx + ucfg->MaxFiles; + if (endIdx > srcFiles->Count) endIdx = srcFiles->Count; + + int memOffset = 0; + int64_t maxIncludedTime = 0; + int coldCount = 0; + + for (int i = startIdx; i < endIdx; i++) + { + if (isHot[i]) continue; + if (StringContains(srcFiles->Paths[i], "_Unity")) continue; + + 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); + coldCount++; + + int64_t fileTime = GetFileModTimeInt64(srcFiles->Paths[i]); + if (fileTime > maxIncludedTime) maxIncludedTime = fileTime; + } + + if (coldCount == 0) + { + memOffset += sprintf_s(memBuf + memOffset, (1024 * 1024) - memOffset, "// Empty bucket\n"); + } + + snprintf(currentUnityPath, sizeof(currentUnityPath), "%s\\%s%d.cpp", ucfg->OutputDir, ucfg->Prefix, b + 1); + FileContent exist = ReadEntireFile(currentUnityPath); + bool write = true; + if (exist.Data && exist.Size == memOffset && memcmp(exist.Data, memBuf, memOffset) == 0) write = false; + if (write) { WriteEntireFile(currentUnityPath, memBuf, memOffset); anyChanged = true; } + + // Touch Unity file if included files are newer + if (!write && coldCount > 0) { + int64_t unityTime = GetFileModTimeInt64(currentUnityPath); + if (maxIncludedTime > unityTime) { + HANDLE hFile = CreateFileA(currentUnityPath, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) { + FILETIME ft; + ULARGE_INTEGER li; + li.QuadPart = nowTime; + ft.dwLowDateTime = li.LowPart; + ft.dwHighDateTime = li.HighPart; + SetFileTime(hFile, NULL, NULL, &ft); + CloseHandle(hFile); + } + } + } + } + + // Process hot files + for (int i = 0; i < srcFiles->Count; i++) + { + if (!isHot[i]) continue; + char absPath[MAX_PATH_LEN]; - GetFullPathNameA(hotFiles->Paths[i], MAX_PATH_LEN, absPath, NULL); + 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, (1024 * 1024), "#include \"%s\"\n", absPath); + int memOffset = sprintf_s(memBuf, (1024 * 1024), "#include \"%s\"\n", absPath); - snprintf(currentUnityPath, sizeof(currentUnityPath), "%s\\%s%d.cpp", ucfg->OutputDir, ucfg->Prefix, unityCount); + snprintf(currentUnityPath, sizeof(currentUnityPath), "%s\\%s_Hot%d.cpp", ucfg->OutputDir, ucfg->Prefix, i); FileContent exist = ReadEntireFile(currentUnityPath); bool write = true; if (exist.Data && exist.Size == memOffset && memcmp(exist.Data, memBuf, memOffset) == 0) write = false; if (write) { WriteEntireFile(currentUnityPath, memBuf, memOffset); anyChanged = true; } if (!write) { - int64_t fileTime = GetFileModTimeInt64(hotFiles->Paths[i]); + int64_t fileTime = GetFileModTimeInt64(srcFiles->Paths[i]); int64_t unityTime = GetFileModTimeInt64(currentUnityPath); if (fileTime > unityTime) { HANDLE hFile = CreateFileA(currentUnityPath, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -410,21 +426,32 @@ static bool GenerateUnityFiles(const UnityConfig* ucfg) } } } - - unityCount++; } - // Delete remaining old unity files - while (true) + // Cleanup unused cold buckets + for (int b = numBuckets; b < numBuckets + 100; b++) { - snprintf(currentUnityPath, sizeof(currentUnityPath), "%s\\%s%d.cpp", ucfg->OutputDir, ucfg->Prefix, unityCount); - if (FileExists(currentUnityPath)) - { + snprintf(currentUnityPath, sizeof(currentUnityPath), "%s\\%s%d.cpp", ucfg->OutputDir, ucfg->Prefix, b + 1); + if (FileExists(currentUnityPath)) { DeleteFileA(currentUnityPath); anyChanged = true; - unityCount++; + } else { + break; + } + } + + // Cleanup unused hot files + for (int i = 0; i < srcFiles->Count + 1000; i++) + { + bool shouldExist = (i < srcFiles->Count && isHot[i]); + if (!shouldExist) + { + snprintf(currentUnityPath, sizeof(currentUnityPath), "%s\\%s_Hot%d.cpp", ucfg->OutputDir, ucfg->Prefix, i); + if (FileExists(currentUnityPath)) { + DeleteFileA(currentUnityPath); + anyChanged = true; + } } - else break; } return anyChanged; @@ -1135,10 +1162,6 @@ static void GenerateProject(const char* projectName, const char* projectDir, con int projectDirLen = (int)strlen(projectDir); for (int i = 0; i < srcFiles->Count; i++) { const char* path = srcFiles->Paths[i]; - const char* relPath = path; - if (strncmp(path, projectDir, projectDirLen) == 0 && (path[projectDirLen] == '\\' || path[projectDirLen] == '/')) { - relPath = path + projectDirLen + 1; - } if (EndsWithNoCase(path, ".cpp") || EndsWithNoCase(path, ".c")) { offset += sprintf_s(buf + offset, (4 * 1024 * 1024) - offset, " \n", path); @@ -1258,7 +1281,7 @@ static void GenerateProject(const char* projectName, const char* projectDir, con printf("Generated %s\n", filterOutPath); } -static void GenerateSolution(const char* slnName, const char** projectNames, const char** projectDirs, const char** projectGuids, int projCount) +static void GenerateSolution(const char* slnName, const char** projectNames, const char** projectGuids, int projCount) { char* buf = (char*)ArenaPush(4 * 1024 * 1024); int offset = 0; @@ -1501,19 +1524,17 @@ static int CommandGenVS(int argc, char* argv[]) for (int i = 0; i < slnCount; i++) { VSSolution* s = &solutions[i]; const char* pNames[16]; - const char* pDirs[16]; const char* pGuids[16]; for (int j = 0; j < s->ProjCount; j++) { pNames[j] = s->Projects[j]; for (int k = 0; k < projCount; k++) { if (strcmp(projects[k].Name, s->Projects[j]) == 0) { - pDirs[j] = projects[k].Dir; pGuids[j] = projects[k].Guid; break; } } } - GenerateSolution(s->Name, pNames, pDirs, pGuids, s->ProjCount); + GenerateSolution(s->Name, pNames, pGuids, s->ProjCount); } return 0;