diff --git a/Source/Game-Lib/Game-Lib/ECS/Systems/CharacterController.cpp b/Source/Game-Lib/Game-Lib/ECS/Systems/CharacterController.cpp index bfe93ec..64bcbc5 100644 --- a/Source/Game-Lib/Game-Lib/ECS/Systems/CharacterController.cpp +++ b/Source/Game-Lib/Game-Lib/ECS/Systems/CharacterController.cpp @@ -183,10 +183,18 @@ namespace ECS::Systems if (characterSingleton.moverEntity == entt::null || activeCamera.entity == entt::null) return false; + ModelLoader* modelLoader = ServiceLocator::GetGameRenderer()->GetModelLoader(); auto& unit = registry->get(characterSingleton.moverEntity); if ((modifier & KeybindModifier::Shift) != KeybindModifier::Invalid) { + // Unhighlight previous target + if (unit.targetEntity != entt::null && registry->all_of(unit.targetEntity)) + { + auto& model = registry->get(unit.targetEntity); + modelLoader->SetModelHighlight(model, 1.0f); + } + unit.targetEntity = entt::null; return true; } @@ -252,7 +260,21 @@ namespace ECS::Systems .targetGUID = targetNetworkID })) { + // Unhighlight previous target + if (registry->all_of(unit.targetEntity)) + { + auto& model = registry->get(unit.targetEntity); + modelLoader->SetModelHighlight(model, 1.0f); + } + unit.targetEntity = targetEntity; + + // Visually highlight the selected target for feedback + if (registry->all_of(targetEntity)) + { + auto& model = registry->get(targetEntity); + modelLoader->SetModelHighlight(model, 1.5f); + } } return true; diff --git a/Source/Game-Lib/Game-Lib/Rendering/Model/ModelLoader.cpp b/Source/Game-Lib/Game-Lib/Rendering/Model/ModelLoader.cpp index 07c164a..0fc0990 100644 --- a/Source/Game-Lib/Game-Lib/Rendering/Model/ModelLoader.cpp +++ b/Source/Game-Lib/Game-Lib/Rendering/Model/ModelLoader.cpp @@ -481,7 +481,7 @@ void ModelLoader::Update(f32 deltaTime) LoadRequestInternal& loadRequest = _internalLoadRequestsVector[i]; const DiscoveredModel& discoveredModel = _modelHashToDiscoveredModel[loadRequest.modelHash]; - bool isSupported = discoveredModel.model->modelHeader.numVertices > 0; + bool isSupported = (loadRequest.entity == entt::null || registry->valid(loadRequest.entity)) && discoveredModel.model->modelHeader.numVertices > 0; if (!isSupported) continue; @@ -842,6 +842,22 @@ void ModelLoader::SetModelTransparent(const ECS::Components::Model& model, bool _modelRenderer->RequestChangeTransparency(model.instanceID, transparent, opacity); } +void ModelLoader::SetEntityHighlight(entt::entity entity, f32 highlightIntensity) +{ + entt::registry* registry = ServiceLocator::GetEnttRegistries()->gameRegistry; + auto& modelComponent = registry->get(entity); + + SetModelHighlight(modelComponent, highlightIntensity); +} + +void ModelLoader::SetModelHighlight(const ECS::Components::Model& model, f32 highlightIntensity) +{ + if (model.instanceID == std::numeric_limits().max()) + return; + + _modelRenderer->RequestChangeHighlight(model.instanceID, highlightIntensity); +} + void ModelLoader::EnableGroupForEntity(entt::entity entity, u32 groupID) { entt::registry* registry = ServiceLocator::GetEnttRegistries()->gameRegistry; diff --git a/Source/Game-Lib/Game-Lib/Rendering/Model/ModelLoader.h b/Source/Game-Lib/Game-Lib/Rendering/Model/ModelLoader.h index 1db1483..35b3e7a 100644 --- a/Source/Game-Lib/Game-Lib/Rendering/Model/ModelLoader.h +++ b/Source/Game-Lib/Game-Lib/Rendering/Model/ModelLoader.h @@ -128,6 +128,9 @@ class ModelLoader void SetEntityTransparent(entt::entity entity, bool transparent, f32 opacity); void SetModelTransparent(const ECS::Components::Model& model, bool transparent, f32 opacity); + void SetEntityHighlight(entt::entity entity, f32 highlightIntensity); + void SetModelHighlight(const ECS::Components::Model& model, f32 highlightIntensity); + void EnableGroupForEntity(entt::entity entity, u32 groupID); void EnableGroupForModel(const ECS::Components::Model& model, u32 groupID); diff --git a/Source/Game-Lib/Game-Lib/Rendering/Model/ModelRenderer.cpp b/Source/Game-Lib/Game-Lib/Rendering/Model/ModelRenderer.cpp index f43d810..acbfbab 100644 --- a/Source/Game-Lib/Game-Lib/Rendering/Model/ModelRenderer.cpp +++ b/Source/Game-Lib/Game-Lib/Rendering/Model/ModelRenderer.cpp @@ -304,6 +304,21 @@ void ModelRenderer::Update(f32 deltaTime) _instancesDirty = true; } + u32 numChangeHighlightRequests = static_cast(_changeHighlightRequests.try_dequeue_bulk(_changeHighlightWork.begin(), 256)); + if (numChangeHighlightRequests > 0) + { + ZoneScopedN("Change Highlight Requests"); + for (u32 i = 0; i < numChangeHighlightRequests; i++) + { + ChangeHighlightRequest& changeHighlightRequest = _changeHighlightWork[i]; + + InstanceData& instanceData = _instanceDatas[changeHighlightRequest.instanceID]; + instanceData.highlightIntensity = changeHighlightRequest.highlightIntensity; + _instanceDatas.SetDirtyElement(changeHighlightRequest.instanceID); + } + _instancesDirty = true; + } + u32 numChangeSkyboxRequests = static_cast(_changeSkyboxRequests.try_dequeue_bulk(_changeSkyboxWork.begin(), 256)); if (numChangeSkyboxRequests > 0) { @@ -2125,6 +2140,17 @@ void ModelRenderer::RequestChangeTransparency(u32 instanceID, bool transparent, _changeTransparencyRequests.enqueue(changeTransparencyRequest); } +void ModelRenderer::RequestChangeHighlight(u32 instanceID, f32 highlightIntensity) +{ + ChangeHighlightRequest changeHighlightRequest = + { + .instanceID = instanceID, + .highlightIntensity = highlightIntensity + }; + + _changeHighlightRequests.enqueue(changeHighlightRequest); +} + void ModelRenderer::RequestChangeSkybox(u32 instanceID, bool skybox) { ChangeSkyboxRequest changeSkyboxRequest = @@ -2427,6 +2453,7 @@ void ModelRenderer::CreatePermanentResources() _changeHairTextureWork.resize(256); _changeVisibilityWork.resize(256); _changeTransparencyWork.resize(256); + _changeHighlightWork.resize(256); _changeSkyboxWork.resize(256); static constexpr u32 NumSamplers = 4; diff --git a/Source/Game-Lib/Game-Lib/Rendering/Model/ModelRenderer.h b/Source/Game-Lib/Game-Lib/Rendering/Model/ModelRenderer.h index 4973c00..0133233 100644 --- a/Source/Game-Lib/Game-Lib/Rendering/Model/ModelRenderer.h +++ b/Source/Game-Lib/Game-Lib/Rendering/Model/ModelRenderer.h @@ -164,8 +164,8 @@ class ModelRenderer : CulledRenderer u32 modelVertexOffset = InvalidID; u32 animatedVertexOffset = InvalidID; f32 opacity = 1.0f; + f32 highlightIntensity = 1.0f; u32 padding0; - u32 padding1; }; struct InstanceDataCPU @@ -241,6 +241,13 @@ class ModelRenderer : CulledRenderer f32 opacity = 1.0f; }; + struct ChangeHighlightRequest + { + public: + u32 instanceID = 0; + f32 highlightIntensity = 1.0f; + }; + struct ChangeTextureUnitColorRequest { public: @@ -320,6 +327,7 @@ class ModelRenderer : CulledRenderer void RequestChangeHairTexture(u32 instanceID, Renderer::TextureID textureID); void RequestChangeVisibility(u32 instanceID, bool visible); void RequestChangeTransparency(u32 instanceID, bool transparent, f32 opacity); + void RequestChangeHighlight(u32 instanceID, f32 highlightIntensity); void RequestChangeSkybox(u32 instanceID, bool skybox); bool AddUninstancedAnimationData(u32 modelID, u32& boneMatrixOffset, u32& textureTransformMatrixOffset); @@ -460,6 +468,9 @@ class ModelRenderer : CulledRenderer moodycamel::ConcurrentQueue _changeTransparencyRequests; std::vector _changeTransparencyWork; + moodycamel::ConcurrentQueue _changeHighlightRequests; + std::vector _changeHighlightWork; + moodycamel::ConcurrentQueue _changeSkyboxRequests; std::vector _changeSkyboxWork; diff --git a/Source/Shaders/Shaders/Include/VisibilityBuffers.inc.hlsl b/Source/Shaders/Shaders/Include/VisibilityBuffers.inc.hlsl index 63f87ef..cfd8652 100644 --- a/Source/Shaders/Shaders/Include/VisibilityBuffers.inc.hlsl +++ b/Source/Shaders/Shaders/Include/VisibilityBuffers.inc.hlsl @@ -374,6 +374,7 @@ struct PixelVertexData float3 worldPos; float4 viewPos; float2 pixelPos; + float highlightIntensity; }; PixelVertexData GetPixelVertexDataTerrain(const uint2 pixelPos, const VisibilityBuffer vBuffer, const uint cameraIndex, float2 renderSize) @@ -413,6 +414,9 @@ PixelVertexData GetPixelVertexDataTerrain(const uint2 pixelPos, const Visibility result.worldPos = InterpolateVertexAttribute(bary, vertices[0].position, vertices[1].position, vertices[2].position); result.viewPos = mul(float4(result.worldPos, 1.0f), _cameras[cameraIndex].worldToView); result.pixelPos = pixelPos; + + result.highlightIntensity = 1.0f; // No highlight for terrain... yet? + return result; } @@ -462,6 +466,9 @@ PixelVertexData GetPixelVertexDataModel(const uint2 pixelPos, const VisibilityBu result.worldPos = mul(float4(pixelVertexPos, 1.0f), instanceMatrix).xyz; result.viewPos = mul(float4(result.worldPos, 1.0f), _cameras[cameraIndex].worldToView); result.pixelPos = pixelPos; + + result.highlightIntensity = instanceData.highlightIntensity; + return result; } diff --git a/Source/Shaders/Shaders/MaterialPass.cs.hlsl b/Source/Shaders/Shaders/MaterialPass.cs.hlsl index bf0acbc..59b7bd8 100644 --- a/Source/Shaders/Shaders/MaterialPass.cs.hlsl +++ b/Source/Shaders/Shaders/MaterialPass.cs.hlsl @@ -244,6 +244,9 @@ float4 ShadeModel(const uint2 pixelPos, const float2 screenUV, const VisibilityB // Apply lighting color.rgb = ApplyLighting(screenUV, color.rgb, pixelVertexData, _constants.lightInfo, shadowSettings); + // Apply highlight + color.rgb *= pixelVertexData.highlightIntensity; + outPixelWorldPos = pixelVertexData.worldPos; return saturate(color); } diff --git a/Source/Shaders/Shaders/Model/ModelShared.inc.hlsl b/Source/Shaders/Shaders/Model/ModelShared.inc.hlsl index 572a9f6..94ed868 100644 --- a/Source/Shaders/Shaders/Model/ModelShared.inc.hlsl +++ b/Source/Shaders/Shaders/Model/ModelShared.inc.hlsl @@ -12,8 +12,8 @@ struct ModelInstanceData uint modelVertexOffset; uint animatedVertexOffset; float opacity; + float highlightIntensity; uint padding0; - uint padding1; }; struct ModelDrawCallData