diff --git a/Assets/compiled/Debug.vert.dxil b/Assets/compiled/Debug.vert.dxil index 865e6a3..9c8b91e 100644 Binary files a/Assets/compiled/Debug.vert.dxil and b/Assets/compiled/Debug.vert.dxil differ diff --git a/Assets/compiled/ImGui.frag.dxil b/Assets/compiled/ImGui.frag.dxil index 0529b79..f87c1e6 100644 Binary files a/Assets/compiled/ImGui.frag.dxil and b/Assets/compiled/ImGui.frag.dxil differ diff --git a/Assets/compiled/ImGui.vert.dxil b/Assets/compiled/ImGui.vert.dxil index 10a905d..14ac435 100644 Binary files a/Assets/compiled/ImGui.vert.dxil and b/Assets/compiled/ImGui.vert.dxil differ diff --git a/Assets/compiled/Skybox.vert.dxil b/Assets/compiled/Skybox.vert.dxil index 6cc5b90..f2a378b 100644 Binary files a/Assets/compiled/Skybox.vert.dxil and b/Assets/compiled/Skybox.vert.dxil differ diff --git a/Assets/compiled/SolidColor.frag.dxil b/Assets/compiled/SolidColor.frag.dxil index 910457d..522effa 100644 Binary files a/Assets/compiled/SolidColor.frag.dxil and b/Assets/compiled/SolidColor.frag.dxil differ diff --git a/Assets/compiled/Triangle.vert.dxil b/Assets/compiled/Triangle.vert.dxil index b674c48..efc42f6 100644 Binary files a/Assets/compiled/Triangle.vert.dxil and b/Assets/compiled/Triangle.vert.dxil differ diff --git a/Assets/source/RootConstants.hlsl b/Assets/source/RootConstants.hlsl index b2270a3..d23194d 100644 --- a/Assets/source/RootConstants.hlsl +++ b/Assets/source/RootConstants.hlsl @@ -27,10 +27,10 @@ cbuffer RootConstants : register(b0, space0) float2 Translate; // 2D translation float2 _Padding2; // Explicit padding to align LightDirection to 16 bytes - float3 LightDirection; // Normalized, world-space - float LightPad; - float3 LightColor; - float AmbientIntensity; + float3 GlobalLightDirection; // Normalized, world-space + float GlobalLightPad; + float3 GlobalLightColor; + float GlobalAmbientIntensity; uint LightBufferIndex; uint ActiveLightCount; diff --git a/Assets/source/SolidColor.frag.hlsl b/Assets/source/SolidColor.frag.hlsl index aad361b..e9ec3f6 100644 --- a/Assets/source/SolidColor.frag.hlsl +++ b/Assets/source/SolidColor.frag.hlsl @@ -12,11 +12,11 @@ float4 main(Input input) : SV_Target0 float3 normal = normalize(input.WorldNormal); // Initial ambient component - float3 result = input.Color.rgb * LightColor * AmbientIntensity; + float3 result = input.Color.rgb * GlobalLightColor * GlobalAmbientIntensity; // Directional light contribution - float ndotl = max(dot(normal, -LightDirection), 0.0); - result += input.Color.rgb * LightColor * ndotl; + float ndotl = max(dot(normal, -GlobalLightDirection), 0.0); + result += input.Color.rgb * GlobalLightColor * ndotl; // Point lights if (ActiveLightCount > 0) diff --git a/Juliet/include/Graphics/MeshRenderer.h b/Juliet/include/Graphics/MeshRenderer.h index 347482f..0dc8060 100644 --- a/Juliet/include/Graphics/MeshRenderer.h +++ b/Juliet/include/Graphics/MeshRenderer.h @@ -59,6 +59,8 @@ namespace Juliet [[nodiscard]] JULIET_API LightID AddPointLight(const PointLight& light); JULIET_API void SetPointLightPosition(LightID id, const Vector3& position); JULIET_API void SetPointLightColor(LightID id, const Vector3& color); + JULIET_API void SetPointLightRadius(LightID id, float radius); + JULIET_API void SetPointLightIntensity(LightID id, float intensity); JULIET_API void ClearPointLights(); // Utils diff --git a/Juliet/include/Graphics/PushConstants.h b/Juliet/include/Graphics/PushConstants.h index 740ad74..620c0e7 100644 --- a/Juliet/include/Graphics/PushConstants.h +++ b/Juliet/include/Graphics/PushConstants.h @@ -19,10 +19,10 @@ namespace Juliet float Translate[2]; float Padding2[2]; - Vector3 LightDirection; - float LightPad; - Vector3 LightColor; - float AmbientIntensity; + Vector3 GlobalLightDirection; + float GlobalLightPad; + Vector3 GlobalLightColor; + float GlobalAmbientIntensity; uint32 LightBufferIndex; uint32 ActiveLightCount; diff --git a/Juliet/src/Graphics/DebugDisplayRenderer.cpp b/Juliet/src/Graphics/DebugDisplayRenderer.cpp index bd56e5d..ed5fab3 100644 --- a/Juliet/src/Graphics/DebugDisplayRenderer.cpp +++ b/Juliet/src/Graphics/DebugDisplayRenderer.cpp @@ -313,10 +313,10 @@ namespace Juliet pushData.Translate[0] = 0.0f; pushData.Translate[1] = 0.0f; // Dummy light data as we don't light debug primitives - pushData.LightDirection = {0,0,-1}; - pushData.LightPad = 0; - pushData.LightColor = {1,1,1}; - pushData.AmbientIntensity = 1.0f; + pushData.GlobalLightDirection = {0,0,-1}; + pushData.GlobalLightPad = 0; + pushData.GlobalLightColor = {1,1,1}; + pushData.GlobalAmbientIntensity = 1.0f; SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData); @@ -341,10 +341,10 @@ namespace Juliet pushData.Translate[0] = 0.0f; pushData.Translate[1] = 0.0f; // Dummy light data as we don't light debug primitives - pushData.LightDirection = {0,0,-1}; - pushData.LightPad = 0; - pushData.LightColor = {1,1,1}; - pushData.AmbientIntensity = 1.0f; + pushData.GlobalLightDirection = {0,0,-1}; + pushData.GlobalLightPad = 0; + pushData.GlobalLightColor = {1,1,1}; + pushData.GlobalAmbientIntensity = 1.0f; SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData); diff --git a/Juliet/src/Graphics/MeshRenderer.cpp b/Juliet/src/Graphics/MeshRenderer.cpp index b56435a..23015cf 100644 --- a/Juliet/src/Graphics/MeshRenderer.cpp +++ b/Juliet/src/Graphics/MeshRenderer.cpp @@ -317,6 +317,26 @@ namespace Juliet } } + void SetPointLightRadius(LightID id, float radius) + { + Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); + g_MeshRenderer.PointLights.Data[id].Radius = radius; + if (g_MeshRenderer.MappedLights) + { + g_MeshRenderer.MappedLights[id].Radius = radius; + } + } + + void SetPointLightIntensity(LightID id, float intensity) + { + Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); + g_MeshRenderer.PointLights.Data[id].Intensity = intensity; + if (g_MeshRenderer.MappedLights) + { + g_MeshRenderer.MappedLights[id].Intensity = intensity; + } + } + void ClearPointLights() { g_MeshRenderer.PointLights.Clear(); diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp index 3fe9816..262620c 100644 --- a/JulietApp/main.cpp +++ b/JulietApp/main.cpp @@ -3,10 +3,18 @@ #ifdef global #undef global #endif +#include #include #include #define global static +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + #include #include #include @@ -42,15 +50,29 @@ static bool animateCubes = true; static bool animateLights = true; static bool animateCamera = true; -static bool freeCameraMode = false; -static float camYaw = 0.0f; -static float camPitch = 0.0f; -static Juliet::Vector3 camPos = { 25.0f, 0.0f, 12.5f }; +static bool freeCameraMode = false; +static float camYaw = 0.0f; +static float camPitch = 0.0f; +static Juliet::Vector3 camPos = { 25.0f, 0.0f, 12.5f }; static float animateCubesTime = 0.0f; static float animateLightsTime = 0.0f; static float animateCameraTime = 0.0f; +static float redLightRadius = 10.0f; +static float redLightIntensity = 5.0f; +static float redLightColor[3] = { 1.0f, 0.2f, 0.2f }; +static bool redLightFollowsCamera = false; + +static bool enableGlobalLight = true; +static float globalLightDir[3] = { 0.5f, -1.0f, -0.5f }; +static float globalLightColor[3] = { 1.0f, 0.95f, 0.8f }; +static float globalAmbientIntensity = 0.2f; + +static float blueLightRadius = 15.0f; +static float blueLightIntensity = 8.0f; +static float blueLightColor[3] = { 0.2f, 0.2f, 1.0f }; + // TODO : Replace with message box from framework + call main and not winmain + subsystem // TODO : Think how to do the draw pipeline. // Ex: Expose a Draw method ? @@ -139,16 +161,16 @@ void JulietApplication::Init(NonNullPtr) // Start with some default test lights PointLight redLight = {}; redLight.Position = { 5.0f, 5.0f, 2.0f }; - redLight.Radius = 10.0f; - redLight.Color = { 1.0f, 0.2f, 0.2f }; - redLight.Intensity = 5.0f; + redLight.Radius = redLightRadius; + redLight.Color = { redLightColor[0], redLightColor[1], redLightColor[2] }; + redLight.Intensity = redLightIntensity; RedLightID = AddPointLight(redLight); PointLight blueLight = {}; blueLight.Position = { -5.0f, 0.0f, 2.0f }; - blueLight.Radius = 15.0f; - blueLight.Color = { 0.2f, 0.2f, 1.0f }; - blueLight.Intensity = 8.0f; + blueLight.Radius = blueLightRadius; + blueLight.Color = { blueLightColor[0], blueLightColor[1], blueLightColor[2] }; + blueLight.Intensity = blueLightIntensity; BlueLightID = AddPointLight(blueLight); } @@ -262,24 +284,19 @@ void JulietApplication::Update() { reloadShadersDebounce = false; } - - if (evt.Type == EventType::Mouse_Move && freeCameraMode) - { - float sensitivity = 0.005f; - camYaw += evt.Data.MouseMovement.X_Displacement * sensitivity; - camPitch -= evt.Data.MouseMovement.Y_Displacement * sensitivity; - - // Limit pitch to avoid flipping - if (camPitch > 1.5f) camPitch = 1.5f; - if (camPitch < -1.5f) camPitch = -1.5f; - } } + static bool firstFreeFrame = false; + if (IsKeyDown(ScanCode::F1)) { if (!f1Debounce) { freeCameraMode = !freeCameraMode; + if (freeCameraMode) + { + firstFreeFrame = true; + } f1Debounce = true; } } @@ -288,6 +305,47 @@ void JulietApplication::Update() f1Debounce = false; } + // Confine and hide the mouse for Free Camera mode + if (freeCameraMode) + { +#ifdef JULIET_ENABLE_IMGUI + ImGui::SetMouseCursor(ImGuiMouseCursor_None); +#endif + +#ifdef _WIN32 + HWND hwnd = GetForegroundWindow(); + if (hwnd) + { + RECT rect; + GetClientRect(hwnd, &rect); + POINT ptCenterClient = { (rect.right - rect.left) / 2, (rect.bottom - rect.top) / 2 }; + + if (!firstFreeFrame) + { + POINT currentPos; + GetCursorPos(¤tPos); + ScreenToClient(hwnd, ¤tPos); + + float deltaX = static_cast(currentPos.x - ptCenterClient.x); + float deltaY = static_cast(currentPos.y - ptCenterClient.y); + + float sensitivity = 0.005f; + // Plus because the mouse is inverted inherently by windows to screen coordinate + camYaw += deltaX * sensitivity; + camPitch -= deltaY * sensitivity; + + camPitch = std::min(camPitch, 1.5f); + camPitch = std::max(camPitch, -1.5f); + } + firstFreeFrame = false; + + POINT ptCenterScreen = ptCenterClient; + ClientToScreen(hwnd, &ptCenterScreen); + SetCursorPos(ptCenterScreen.x, ptCenterScreen.y); + } +#endif + } + if (freeCameraMode) { float speed = 10.0f * deltaTime; @@ -300,39 +358,104 @@ void JulietApplication::Update() Vector3 right = { cosf(camYaw + 1.5708f), sinf(camYaw + 1.5708f), 0.0f }; Vector3 up = { 0.0f, 0.0f, 1.0f }; - if (IsKeyDown(ScanCode::W)) camPos = camPos + forward * speed; - if (IsKeyDown(ScanCode::S)) camPos = camPos - forward * speed; - if (IsKeyDown(ScanCode::D)) camPos = camPos + right * speed; - if (IsKeyDown(ScanCode::A)) camPos = camPos - right * speed; - if (IsKeyDown(ScanCode::E)) camPos = camPos + up * speed; - if (IsKeyDown(ScanCode::Q)) camPos = camPos - up * speed; + if (IsKeyDown(ScanCode::W)) + { + camPos = camPos + forward * speed; + } + if (IsKeyDown(ScanCode::S)) + { + camPos = camPos - forward * speed; + } + if (IsKeyDown(ScanCode::D)) + { + camPos = camPos + right * speed; + } + if (IsKeyDown(ScanCode::A)) + { + camPos = camPos - right * speed; + } + if (IsKeyDown(ScanCode::E)) + { + camPos = camPos + up * speed; + } + if (IsKeyDown(ScanCode::Q)) + { + camPos = camPos - up * speed; + } } - if (animateCubes) animateCubesTime += deltaTime; - if (animateLights) animateLightsTime += deltaTime; - if (animateCamera) animateCameraTime += deltaTime; + if (animateCubes) + { + animateCubesTime += deltaTime; + } + if (animateLights) + { + animateLightsTime += deltaTime; + } + if (animateCamera) + { + animateCameraTime += deltaTime; + } #ifdef JULIET_ENABLE_IMGUI ImGui::Begin("Debug Controls"); ImGui::Checkbox("Animate Cubes", &animateCubes); ImGui::Checkbox("Animate Lights", &animateLights); ImGui::Checkbox("Animate Camera", &animateCamera); + + ImGui::Separator(); + ImGui::Text("Global Light"); + ImGui::Checkbox("Enable Global Light", &enableGlobalLight); + if (enableGlobalLight) + { + ImGui::SliderFloat3("Direction", globalLightDir, -1.0f, 1.0f); + ImGui::ColorEdit3("Color", globalLightColor); + ImGui::SliderFloat("Ambient Intensity", &globalAmbientIntensity, 0.0f, 1.0f); + } + + ImGui::Separator(); + ImGui::Text("Red Point Light"); + ImGui::ColorEdit3("Red Color", redLightColor); + ImGui::SliderFloat("Red Radius", &redLightRadius, 1.0f, 50.0f); + ImGui::SliderFloat("Red Intensity", &redLightIntensity, 0.0f, 50.0f); + ImGui::Checkbox("Red Light Follows Camera", &redLightFollowsCamera); + + ImGui::Separator(); + ImGui::Text("Blue Point Light"); + ImGui::ColorEdit3("Blue Color", blueLightColor); + ImGui::SliderFloat("Blue Radius", &blueLightRadius, 1.0f, 50.0f); + ImGui::SliderFloat("Blue Intensity", &blueLightIntensity, 0.0f, 50.0f); + ImGui::End(); #endif ArenaClear(GameScratchArena); - Vector3 redLightPos = { 5.0f, 5.0f, 2.0f }; + Vector3 redLightPos = { 5.0f, 5.0f, 2.0f }; Vector3 blueLightPos = { -5.0f, 0.0f, 2.0f }; if (animateLights || animateLightsTime > 0.0f) { - redLightPos = { cosf(animateLightsTime * 2.0f) * 5.0f, sinf(animateLightsTime * 2.0f) * 5.0f, 2.0f }; + redLightPos = { cosf(animateLightsTime * 2.0f) * 5.0f, sinf(animateLightsTime * 2.0f) * 5.0f, 2.0f }; blueLightPos = { -5.0f, cosf(animateLightsTime) * 3.0f, 2.0f }; } + if (redLightFollowsCamera) + { + Camera cam = GetDebugCamera(); + redLightPos = cam.Position; + } + SetPointLightPosition(RedLightID, redLightPos); SetPointLightPosition(BlueLightID, blueLightPos); + + SetPointLightColor(RedLightID, { redLightColor[0], redLightColor[1], redLightColor[2] }); + SetPointLightRadius(RedLightID, redLightRadius); + SetPointLightIntensity(RedLightID, redLightIntensity); + + SetPointLightColor(BlueLightID, { blueLightColor[0], blueLightColor[1], blueLightColor[2] }); + SetPointLightRadius(BlueLightID, blueLightRadius); + SetPointLightIntensity(BlueLightID, blueLightIntensity); // Animate the 100 cubes (10x10 grid) constexpr int kGridSize = 10; @@ -351,24 +474,22 @@ void JulietApplication::Update() float timeZ = animateCubesTime * 2.0f + seed * 0.5f; float z = 0.0f; - float scaleF = 1.0f; + float scaleF = 1.0f; Matrix rotation = MatrixIdentity(); if (animateCubes || animateCubesTime > 0.0f) { - z = sinf(timeZ) * 1.5f; // Oscillate up and down + z = sinf(timeZ) * 1.5f; // Oscillate up and down scaleF = 1.0f + sinf(animateCubesTime * 1.5f + seed) * 0.3f; // Pulse scale rotation = MatrixRotation(animateCubesTime * 1.2f + seed * 0.73f, animateCubesTime * 0.8f + seed * 1.17f, - animateCubesTime * 0.5f + seed * 0.53f); + animateCubesTime * 0.5f + seed * 0.53f); } - Matrix scale = MatrixScale(scaleF, scaleF, scaleF); + Matrix scale = MatrixScale(scaleF, scaleF, scaleF); SetMeshTransform(cube, MatrixTranslation(x, y, z) * rotation * scale); } } - - DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f }, false); DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, true); DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true); @@ -435,9 +556,18 @@ void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd) PushData pushData = {}; pushData.ViewProjection = Camera_GetViewProjectionMatrix(GetDebugCamera()); - pushData.LightDirection = Normalize({ 0.5f, -1.0f, -0.5f }); - pushData.LightColor = { 1.0f, 0.95f, 0.8f }; - pushData.AmbientIntensity = 0.2f; + if (enableGlobalLight) + { + pushData.GlobalLightDirection = Normalize({ globalLightDir[0], globalLightDir[1], globalLightDir[2] }); + pushData.GlobalLightColor = { globalLightColor[0], globalLightColor[1], globalLightColor[2] }; + pushData.GlobalAmbientIntensity = globalAmbientIntensity; + } + else + { + 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); @@ -467,11 +597,11 @@ Camera JulietApplication::GetDebugCamera() { if (freeCameraMode) { - Camera cam = {}; - cam.Position = camPos; - cam.Target = camPos + Vector3{ cosf(camYaw) * cosf(camPitch), sinf(camYaw) * cosf(camPitch), sinf(camPitch) }; - cam.Up = { 0.0f, 0.0f, 1.0f }; - cam.FOV = 1.047f; + Camera cam = {}; + cam.Position = camPos; + cam.Target = camPos + Vector3{ cosf(camYaw) * cosf(camPitch), sinf(camYaw) * cosf(camPitch), sinf(camPitch) }; + cam.Up = { 0.0f, 0.0f, 1.0f }; + cam.FOV = 1.047f; cam.AspectRatio = 1200.0f / 800.0f; cam.NearPlane = 0.1f; cam.FarPlane = 1000.0f; @@ -482,16 +612,16 @@ Camera JulietApplication::GetDebugCamera() float baseRadius = 25.0f; // Increased to see 10x10 cube grid float radius = baseRadius; - + if (animateCamera || animateCameraTime > 0.0f) { - float orbitSpeed = 0.5f; + float orbitSpeed = 0.5f; float currentOrbitTime = animateCameraTime * orbitSpeed; - + float zoomAmplitude = 15.0f; float zoomSpeed = 0.5f; radius = baseRadius + (sinf(animateCameraTime * zoomSpeed) * zoomAmplitude); - + float zHeight = radius * 0.5f; // Keep a nice downward viewing angle Camera cam = {}; @@ -505,7 +635,7 @@ Camera JulietApplication::GetDebugCamera() return cam; } - + float zHeight = radius * 0.5f; // Keep a nice downward viewing angle Camera cam = {};