Fixing adaptive incremental build.
Moved more functions into engine.cpp
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Juliet
|
||||
JULIET_API void ShutdownMeshRendererGraphics();
|
||||
JULIET_API void ShutdownMeshRenderer();
|
||||
JULIET_API void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList);
|
||||
JULIET_API void RenderMeshes(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, PushData& pushData);
|
||||
JULIET_API void RenderMeshes(NonNullPtr<CommandList> cmdList, NonNullPtr<RenderPass> pass, const Matrix& viewProjection);
|
||||
|
||||
// Lights
|
||||
[[nodiscard]] JULIET_API LightID AddPointLight(const PointLight& light);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Juliet
|
||||
|
||||
[[nodiscard]] JULIET_API bool InitializeSkyboxRenderer(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window);
|
||||
JULIET_API void ShutdownSkyboxRenderer();
|
||||
JULIET_API void RenderSkybox(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, const Matrix& viewProjection);
|
||||
JULIET_API void RenderSkybox(NonNullPtr<CommandList> cmdList, NonNullPtr<RenderPass> pass, const Matrix& viewProjection);
|
||||
|
||||
#if ALLOW_SHADER_HOT_RELOAD
|
||||
JULIET_API void ReloadSkyboxShaders();
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <Graphics/MeshRenderer.h>
|
||||
#include <Graphics/RenderPass.h>
|
||||
#include <Graphics/SkyboxRenderer.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef JULIET_ENABLE_IMGUI
|
||||
#include <Core/ImGui/ImGuiService.h>
|
||||
@@ -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);
|
||||
|
||||
@@ -237,7 +237,7 @@ namespace Juliet
|
||||
TransitionBufferToReadable(cmdList, g_MeshRenderer.IndexBuffer);
|
||||
}
|
||||
|
||||
void RenderMeshes(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, PushData& pushData)
|
||||
void RenderMeshes(NonNullPtr<CommandList> cmdList, NonNullPtr<RenderPass> 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<uint32>(g_MeshRenderer.PointLights.Count);
|
||||
PushData pushData = {};
|
||||
pushData.ViewProjection = viewProjection;
|
||||
pushData.BufferIndex = vertexDescriptorIndex;
|
||||
pushData.LightBufferIndex = lightDescriptorIndex;
|
||||
pushData.TransformsBufferIndex = transformsDescriptorIndex;
|
||||
pushData.ActiveLightCount = static_cast<uint32>(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);
|
||||
|
||||
|
||||
@@ -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<RenderPass> pass, NonNullPtr<CommandList> cmdList, const Matrix& viewProjection)
|
||||
void RenderSkybox(NonNullPtr<CommandList> cmdList, NonNullPtr<RenderPass> pass, const Matrix& viewProjection)
|
||||
{
|
||||
if (!g_SkyboxRenderer.Pipeline)
|
||||
{
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+104
-83
@@ -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, " <ClCompile Include=\"..\\%s\" />\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;
|
||||
|
||||
Reference in New Issue
Block a user