diff --git a/CMakeLists.txt b/CMakeLists.txt index c9cdbc7b..e81faae2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,8 +85,8 @@ add_executable( src/context/editor/dock-spaces/metrics/MetricsPanel.h src/service/log/LogService.cpp src/service/log/LogService.h - src/context/editor/dock-spaces/hierarchy/HierarchyPanel.cpp - src/context/editor/dock-spaces/hierarchy/HierarchyPanel.h + src/context/editor/dock-spaces/world/WorldPanel.cpp + src/context/editor/dock-spaces/world/WorldPanel.h src/repository/abstract/RuntimeResource.h src/util/ShaderUtil.cpp src/util/ShaderUtil.h @@ -151,19 +151,20 @@ add_executable( src/service/camera/Camera.cpp src/repository/world/WorldRepository.cpp src/repository/world/WorldRepository.h - src/repository/world/impl/EntityComponent.h + src/repository/world/impl/MetadataComponent.h + src/enum/ComponentType.cpp src/enum/ComponentType.h src/repository/world/impl/AbstractComponent.h - src/repository/world/components/MeshComponent.h + src/repository/world/components/PrimitiveComponent.h src/repository/world/components/TransformComponent.h src/enum/ShadingMode.h - src/context/editor/dock-spaces/hierarchy/HierarchyHeaderPanel.cpp - src/context/editor/dock-spaces/hierarchy/HierarchyHeaderPanel.h + src/context/editor/dock-spaces/world/WorldHeaderPanel.cpp + src/context/editor/dock-spaces/world/WorldHeaderPanel.h src/service/selection/SelectionService.cpp src/service/selection/SelectionService.h - src/repository/world/impl/EntityComponent.cpp + src/repository/world/impl/MetadataComponent.cpp src/repository/world/components/TransformComponent.cpp - src/repository/world/components/MeshComponent.cpp + src/repository/world/components/PrimitiveComponent.cpp src/context/editor/abstract/form/types/ResourceField.cpp src/context/editor/abstract/form/types/ResourceField.h src/context/editor/abstract/form/types/ColorField.cpp @@ -191,9 +192,6 @@ add_executable( src/context/editor/abstract/form/types/QuatField.h src/service/transform/TransformService.cpp src/service/transform/TransformService.h - src/repository/world/impl/WorldGridRepository.cpp - src/repository/world/impl/WorldGridRepository.h - src/repository/world/impl/WorldTile.h src/repository/world/impl/BoundingBox.h src/service/voxel/impl/SparseVoxelOctreeBuilder.cpp src/service/voxel/impl/SparseVoxelOctreeBuilder.h @@ -201,8 +199,6 @@ add_executable( src/service/voxel/impl/OctreeNode.h src/service/voxel/impl/VoxelData.h src/service/mesh/SceneData.h - src/service/mesh/EntityAssetData.h - src/service/material/MaterialFileData.h src/context/engine/render-pass/impl/PostProcessingPass.cpp src/context/engine/render-pass/impl/PostProcessingPass.h src/context/engine/compute-pass/impl/HWRayTracingPass.cpp @@ -221,22 +217,17 @@ add_executable( src/dto/Notification.h src/enum/NotificationSeverity.h src/service/voxel/impl/SparseVoxelOctreeData.h - src/context/engine/render-pass/impl/tools/SelectedDotPass.cpp - src/context/engine/render-pass/impl/tools/SelectedDotPass.h + src/context/engine/render-pass/impl/tools/SelectionOutlinePass.cpp + src/context/engine/render-pass/impl/tools/SelectionOutlinePass.h src/service/picking/PickingService.cpp src/service/picking/PickingService.h src/service/voxel/SVOInstance.h - src/service/world/WorldGridService.cpp - src/service/world/WorldGridService.h src/dto/buffers/TileInfoUBO.h src/dto/buffers/LightData.h - src/repository/world/components/LightComponent.cpp - src/repository/world/components/LightComponent.h - src/repository/world/components/SphereLightComponent.cpp - src/repository/world/components/SphereLightComponent.h - src/repository/world/components/PlaneLightComponent.h src/context/engine/render-pass/impl/tools/IconsPass.cpp src/context/engine/render-pass/impl/tools/IconsPass.h + src/context/engine/render-pass/impl/tools/SelectionIDPass.cpp + src/context/engine/render-pass/impl/tools/SelectionIDPass.h src/repository/editor/EditorRepository.cpp src/dto/push-constant/GridPushConstant.h src/context/engine/compute-pass/AbstractComputePass.cpp @@ -244,17 +235,9 @@ add_executable( src/context/engine/passes/AbstractPass.cpp src/context/engine/passes/AbstractPass.h src/util/ImageUtils.h - src/service/material/MaterialInstance.h src/service/material/MaterialService.cpp src/service/material/MaterialService.h - src/service/material/MaterialFileData.cpp - src/repository/inspection/FilesRepository.cpp - src/repository/inspection/FilesRepository.h - src/context/editor/dock-spaces/inspector/MaterialEditPanel.cpp - src/context/editor/dock-spaces/inspector/MaterialEditPanel.h src/enum/LightType.h - src/context/engine/compute-pass/impl/AccumulationPass.cpp - src/context/engine/compute-pass/impl/AccumulationPass.h src/service/lights/LightService.cpp src/service/lights/LightService.h src/repository/world/components/VolumeComponent.cpp @@ -263,10 +246,7 @@ add_executable( src/service/notification/AsyncTask.h src/service/voxel/VoxelImporterService.cpp src/service/voxel/VoxelImporterService.h - src/dto/buffers/MaterialData.h src/dto/buffers/VolumeData.h - src/service/volumes/VolumeService.cpp - src/service/volumes/VolumeService.h src/service/voxel/VoxelService.cpp src/service/voxel/VoxelService.h src/util/Serializable.cpp @@ -297,6 +277,13 @@ add_executable( src/context/engine/compute-pass/impl/TemporalAccumulationPass.h src/context/engine/compute-pass/impl/SpatialFilterPass.cpp src/context/engine/compute-pass/impl/SpatialFilterPass.h + src/enum/ComponentType.cpp + src/service/mesh/SceneEntityData.h + src/context/editor/dock-spaces/repositories/RepositoriesPanel.cpp + src/context/editor/dock-spaces/repositories/RepositoriesPanel.h + src/service/volumes/VolumeService.cpp + src/service/volumes/VolumeService.h + src/repository/dock/DockRepository.cpp ) diff --git a/resources/shaders/GlobalDataBuffer.glsl b/resources/shaders/GlobalDataBuffer.glsl index 62bdd11d..47cad588 100644 --- a/resources/shaders/GlobalDataBuffer.glsl +++ b/resources/shaders/GlobalDataBuffer.glsl @@ -10,7 +10,6 @@ layout (set = 0, binding = 0) uniform GlobalDataBlock { vec3 cameraWorldPosition; vec3 sunColor; vec3 sunPosition; - vec2 outputRes; uint volumeCount; uint lightsCount; diff --git a/resources/shaders/MaterialBuffer.glsl b/resources/shaders/MaterialBuffer.glsl deleted file mode 100644 index 9798ac08..00000000 --- a/resources/shaders/MaterialBuffer.glsl +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef MATERIAL_V -#define MATERIAL_V -struct MaterialData { - vec3 albedo; - float roughness; - float metallic; - float transmission; - float thickness; - float ior; - uint isEmissive; - - uint useAlbedoTexture; - uint useNormalTexture; - uint useRoughnessTexture; - uint useMetallicTexture; - - uint albedoTexture; - uint normalTexture; - uint roughnessTexture; - uint metallicTexture; -}; - -layout (set = 0, binding = MATERIAL_SET) readonly buffer Materials { - MaterialData items[]; -} materialBuffer; -#endif diff --git a/resources/shaders/MeshMetadata.glsl b/resources/shaders/MeshMetadata.glsl index 5022112d..1867b4af 100644 --- a/resources/shaders/MeshMetadata.glsl +++ b/resources/shaders/MeshMetadata.glsl @@ -5,9 +5,20 @@ struct MeshMetadata { uint renderIndex; - uint materialIndex; uint64_t vertexBufferAddress; uint64_t indexBufferAddress; + + vec3 albedo; + float roughness; + float metallic; + float transmission; + float thickness; + float ior; + uint isEmissive; + + uint albedoTexture; + uint roughnessTexture; + uint metallicTexture; }; layout (set = 0, binding = MESH_METADATA_SET) readonly buffer MeshMetadatas { diff --git a/resources/shaders/TemporalAccumulation.comp b/resources/shaders/TemporalAccumulation.comp index faaaf7e6..1eaeb052 100644 --- a/resources/shaders/TemporalAccumulation.comp +++ b/resources/shaders/TemporalAccumulation.comp @@ -49,7 +49,7 @@ void main() { prevNormal = imageLoad(previousNormalImage, prevCoord).rgb; vec4 prevDenoised = imageLoad(previousDenoisedImage, prevCoord); prevDenoisedColor = prevDenoised.rgb; - historyLen = prevDenoised.a; + historyLen = globalData.pathTracerAccumulationCount - 1; // Validation checks if (currentIdx != prevPositionIndex.a) valid = false; diff --git a/resources/shaders/rt/HWRayTracing.rchit b/resources/shaders/rt/HWRayTracing.rchit index 6f96d602..4a4be645 100644 --- a/resources/shaders/rt/HWRayTracing.rchit +++ b/resources/shaders/rt/HWRayTracing.rchit @@ -1,15 +1,13 @@ #extension GL_EXT_ray_tracing: require #extension GL_EXT_nonuniform_qualifier: enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require +#extension GL_EXT_shader_explicit_arithmetic_types_int64: require +#extension GL_EXT_buffer_reference2: require #include "../util/HWRayTracingUtil.glsl" -#define MATERIAL_SET 7 -#include "../MaterialBuffer.glsl" -#define MESH_METADATA_SET 8 +#define MESH_METADATA_SET 7 #include "../MeshMetadata.glsl" -layout (set = 0, binding = 9) uniform sampler2D textureArray[]; +layout (set = 0, binding = 8) uniform sampler2D textureArray[]; layout (location = 0) rayPayloadInEXT RayPayload payload; hitAttributeEXT vec2 attribs; // Barycentric coordinates for the hit @@ -20,11 +18,11 @@ struct VertexData { float u, v; }; -layout(buffer_reference, std430) readonly buffer Vertices { +layout (buffer_reference, std430) readonly buffer Vertices { VertexData vertices[]; }; -layout(buffer_reference, std430) readonly buffer Indices { +layout (buffer_reference, std430) readonly buffer Indices { uint indices[]; }; @@ -44,11 +42,11 @@ void main() { VertexData v2 = vBuffer.vertices[i2]; const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - + vec3 n0 = vec3(v0.nx, v0.ny, v0.nz); vec3 n1 = vec3(v1.nx, v1.ny, v1.nz); vec3 n2 = vec3(v2.nx, v2.ny, v2.nz); - + vec2 uv0 = vec2(v0.u, v0.v); vec2 uv1 = vec2(v1.u, v1.v); vec2 uv2 = vec2(v2.u, v2.v); @@ -62,7 +60,6 @@ void main() { payload.hitNormal = normalize(vec3(gl_ObjectToWorldEXT * vec4(normal, 0.0))); payload.uv = uv; - uint matIndex = metadata.materialIndex; payload.renderIndex = metadata.renderIndex; vec3 baseColor = vec3(1.0); @@ -73,28 +70,28 @@ void main() { float ior = 1.45; bool isEmissive = false; - if (matIndex != 0u) { - MaterialData mat = materialBuffer.items[matIndex]; - if (mat.useAlbedoTexture == 1u) { - baseColor = texture(textureArray[nonuniformEXT(mat.albedoTexture)], uv).rgb; - } else { - baseColor = mat.albedo; - } - if (mat.useRoughnessTexture == 1u) { - roughness = texture(textureArray[nonuniformEXT(mat.roughnessTexture)], uv).r; - } else { - roughness = mat.roughness; - } - if (mat.useMetallicTexture == 1u) { - metallic = texture(textureArray[nonuniformEXT(mat.metallicTexture)], uv).r; - } else { - metallic = mat.metallic; - } - transmission = mat.transmission; - thickness = mat.thickness; - ior = mat.ior; - isEmissive = mat.isEmissive == 1u; + payload.alpha = 1.0; + if (metadata.albedoTexture != 0u) { + vec4 alb = texture(textureArray[nonuniformEXT(metadata.albedoTexture)], uv); + payload.alpha = alb.a; + baseColor = alb.rgb; + } else { + baseColor = metadata.albedo; + } + if (metadata.roughnessTexture != 0u) { + roughness = texture(textureArray[nonuniformEXT(metadata.roughnessTexture)], uv).r; + } else { + roughness = metadata.roughness; + } + if (metadata.metallicTexture != 0u) { + metallic = texture(textureArray[nonuniformEXT(metadata.metallicTexture)], uv).r; + } else { + metallic = metadata.metallic; } + transmission = metadata.transmission; + thickness = metadata.thickness; + ior = metadata.ior; + isEmissive = metadata.isEmissive == 1u; payload.material.baseColor = baseColor; payload.material.roughness = max(roughness, 0.015); diff --git a/resources/shaders/rt/HWRayTracing.rgen b/resources/shaders/rt/HWRayTracing.rgen index 5b29db03..c09ac1bd 100644 --- a/resources/shaders/rt/HWRayTracing.rgen +++ b/resources/shaders/rt/HWRayTracing.rgen @@ -15,18 +15,17 @@ layout (location = 0) rayPayloadEXT RayPayload payload; #define LIGHT_SET 5 #include "../LightBuffer.glsl" + #define VOLUME_SET 6 #include "../VolumeBuffer.glsl" -#define MATERIAL_SET 7 -#include "../MaterialBuffer.glsl" -#define MESH_METADATA_SET 8 + +#define MESH_METADATA_SET 7 #include "../MeshMetadata.glsl" #include "../util/DisneyBSDF.glsl" #include "../util/PixelShading.glsl" #include "../util/VolumeRayTracer.glsl" - #include "../GBufferUtil.glsl" #ifdef DEBUG @@ -66,9 +65,19 @@ void main() { payload.hit = false; payload.renderIndex = 0; - - if(pushConstants.shouldTrace == 1){ - traceRayEXT(topLevelAS, gl_RayFlagsOpaqueEXT, 0xFF, 0, 0, 0, rayOrigin, 0.001, rayDirection, 10000.0, 0); + payload.alpha = 1.0; + + if (pushConstants.shouldTrace == 1) { + float tMin = 0.001; + vec3 origin = rayOrigin; + for (int i = 0; i < 8; i++) { + traceRayEXT(topLevelAS, gl_RayFlagsOpaqueEXT, 0xFF, 0, 0, 0, origin, tMin, rayDirection, 10000.0, 0); + if (!payload.hit || payload.alpha > 0.0) { + break; + } + origin = payload.hitPosition; + tMin = 0.001; + } } if (!payload.hit) { @@ -88,7 +97,7 @@ void main() { interaction.anyHit = true; #ifdef DEBUG - if (globalData.debugFlag != LIT) { + if (globalData.debugFlag != LIT) { bool shouldReturn = true; if (globalData.debugFlag == NORMAL) { finalColor = interaction.normal; @@ -134,6 +143,11 @@ void main() { finalColor = volumetricColor.rgb * volumetricColor.a + finalColor * (1.0 - volumetricColor.a); } - finalColor = max(vec3(0), finalColor); - imageStore(outputImage, ivec2(gl_LaunchIDEXT.xy), vec4(finalColor, 1)); + vec4 prev = imageLoad(outputImage, ivec2(gl_LaunchIDEXT.xy)); + float count = min(float(globalData.pathTracerMaxSamples), max(globalData.pathTracerAccumulationCount, 1.0)); + vec3 color = prev.rgb * (1.0 - 1.0 / count) + finalColor.rgb * (1.0 / count); + + imageStore(outputImage, ivec2(gl_LaunchIDEXT.xy), vec4(color, 1)); + + } diff --git a/resources/shaders/tools/SelectedDot.frag b/resources/shaders/tools/SelectedDot.frag index 2a176237..0eea4f3f 100644 --- a/resources/shaders/tools/SelectedDot.frag +++ b/resources/shaders/tools/SelectedDot.frag @@ -1,6 +1,6 @@ #include "../GlobalDataBuffer.glsl" -layout (set = 0, binding = 1, rgba32f) uniform readonly image2D gBufferPositionIndex; +layout (set = 0, binding = 1) uniform sampler2D selectionIdSampler; layout (location = 0) out vec4 outColor; @@ -11,12 +11,15 @@ layout (push_constant) uniform Push { } push; void main() { - uint currentIndex = uint(abs(imageLoad(gBufferPositionIndex, ivec2(gl_FragCoord.xy)).a)); - + uint currentIndex = uint(abs(texelFetch(selectionIdSampler, ivec2(gl_FragCoord.xy), 0).r)); + if (currentIndex == 0) { + discard; + } int thickness = int(push.selectionColor.a); bool isBoundary = false; ivec2 pixel = ivec2(gl_FragCoord.xy); + ivec2 texSize = textureSize(selectionIdSampler, 0); for (int y = -thickness; y <= thickness; ++y) { for (int x = -thickness; x <= thickness; ++x) { @@ -26,15 +29,15 @@ void main() { ivec2 neighborPixel = pixel + ivec2(x, y); - if (neighborPixel.x < 0 || neighborPixel.x >= int(globalData.outputRes.x) || - neighborPixel.y < 0 || neighborPixel.y >= int(globalData.outputRes.y)) { + if (neighborPixel.x < 0 || neighborPixel.x >= int(texSize.x) || + neighborPixel.y < 0 || neighborPixel.y >= int(texSize.y)) { isBoundary = true; break; } - uint neighborIndex = uint(abs(imageLoad(gBufferPositionIndex, neighborPixel).a)); + uint neighborIndex = uint(abs(texelFetch(selectionIdSampler, neighborPixel, 0).r)); - if (neighborIndex != push.renderIndex + 1) { + if (neighborIndex != currentIndex) { isBoundary = true; break; } @@ -42,25 +45,10 @@ void main() { if (isBoundary) break; } - bool isDiff = currentIndex != (push.renderIndex + 1); - if (isBoundary && !isDiff) { - outColor = vec4(push.selectionColor.rgb, 1.0); - } else { - int dotSpacing = 10; - int dotRadius = 2; - - vec2 gridIndex = floor(gl_FragCoord.xy / float(dotSpacing)); - vec2 gridCenter = (gridIndex + 0.5) * float(dotSpacing); - - float dist = distance(gl_FragCoord.xy, gridCenter); - if (dist >= dotRadius) { - discard; - } + if (isBoundary) { outColor = vec4(push.selectionColor.rgb, 1.0); - - if (isDiff) { - outColor.a = .5; - } + return; } + discard; } \ No newline at end of file diff --git a/resources/shaders/tools/SelectionID.frag b/resources/shaders/tools/SelectionID.frag new file mode 100644 index 00000000..a2b45ccf --- /dev/null +++ b/resources/shaders/tools/SelectionID.frag @@ -0,0 +1,11 @@ +layout (location = 0) out float outID; + +layout (push_constant) uniform Push { + mat4 model; + vec4 selectionColor; + uint renderIndex; +} push; + +void main() { + outID = float(push.renderIndex + 1); +} diff --git a/resources/shaders/tools/SelectedDot.vert b/resources/shaders/tools/SelectionID.vert similarity index 100% rename from resources/shaders/tools/SelectedDot.vert rename to resources/shaders/tools/SelectionID.vert diff --git a/resources/shaders/util/HWRayTracingUtil.glsl b/resources/shaders/util/HWRayTracingUtil.glsl index c446a09f..05226bb4 100644 --- a/resources/shaders/util/HWRayTracingUtil.glsl +++ b/resources/shaders/util/HWRayTracingUtil.glsl @@ -33,6 +33,7 @@ struct RayPayload { vec3 hitNormal; vec2 uv; uint renderIndex; + float alpha; bool hit; float t; }; diff --git a/resources/shaders/util/PixelShading.glsl b/resources/shaders/util/PixelShading.glsl index 789e6d47..0fbea52a 100644 --- a/resources/shaders/util/PixelShading.glsl +++ b/resources/shaders/util/PixelShading.glsl @@ -3,26 +3,18 @@ #include "../CreateRay.glsl" -struct BounceInfo { +struct PathInfo { MaterialInfo material; SurfaceInteraction interaction; vec3 throughput; - vec3 indirectLight; + vec3 radiance; }; -void computeRadiance(inout BounceInfo bounceInfo) -{ - if (bounceInfo.material.isEmissive) - { - vec3 emission = bounceInfo.material.baseColor * pushConstants.pathTracingEmissiveFactor; - bounceInfo.indirectLight += bounceInfo.throughput * emission; - return; - } - - vec3 directRadiance = vec3(0); +void addDirectLighting(inout PathInfo pathInfo) { + vec3 wo = -pathInfo.interaction.incomingRayDir; + vec3 Ld = vec3(0); - for (int i = 0; i < int(globalData.lightsCount); ++i) - { + for (int i = 0; i < int(globalData.lightsCount); ++i) { Light l = lightBuffer.items[i]; l.color.rgb *= l.color.a; @@ -30,68 +22,80 @@ void computeRadiance(inout BounceInfo bounceInfo) vec3 f; float scatteringPdf; - directRadiance += calculateDirectLight(l, bounceInfo.interaction, bounceInfo.material, wi, f, scatteringPdf); + Ld += calculateDirectLight(l, pathInfo.interaction, pathInfo.material, wi, f, scatteringPdf); } - bounceInfo.indirectLight += bounceInfo.throughput * directRadiance; + pathInfo.radiance += pathInfo.throughput * Ld; } -vec3 calculateIndirectLighting(MaterialInfo material, SurfaceInteraction interaction) { - if (pushConstants.pathTracerBounces == 0) return vec3(0); - - BounceInfo bounceInfo; - bounceInfo.indirectLight = vec3(0); - bounceInfo.throughput = vec3(1); - bounceInfo.material = material; - bounceInfo.interaction = interaction; +vec3 tracePath(vec3 rayDirection, MaterialInfo material, SurfaceInteraction interaction) { + PathInfo pathInfo; + pathInfo.radiance = vec3(0); + pathInfo.throughput = vec3(1); + pathInfo.material = material; + pathInfo.interaction = interaction; + pathInfo.interaction.incomingRayDir = rayDirection; + + // First hit might be emissive + if (pathInfo.material.isEmissive) { + return pathInfo.material.baseColor * pushConstants.pathTracingEmissiveFactor; + } for (uint j = 0; j < pushConstants.pathTracerBounces; j++) { + // Direct Lighting + addDirectLighting(pathInfo); + + // Sample next direction vec3 wi; float pdf; vec3 X = vec3(0.), Y = vec3(0.); - directionOfAnisotropicity(bounceInfo.interaction.normal, X, Y); - bounceInfo.interaction.tangent = X; - bounceInfo.interaction.binormal = Y; + directionOfAnisotropicity(pathInfo.interaction.normal, X, Y); + pathInfo.interaction.tangent = X; + pathInfo.interaction.binormal = Y; - vec3 f = bsdfSample(wi, -bounceInfo.interaction.incomingRayDir, X, Y, pdf, bounceInfo.interaction, bounceInfo.material); - f *= abs(dot(wi, bounceInfo.interaction.normal)); + vec3 f = bsdfSample(wi, -pathInfo.interaction.incomingRayDir, X, Y, pdf, pathInfo.interaction, pathInfo.material); + f *= abs(dot(wi, pathInfo.interaction.normal)); if (pdf < EPSILON || dot(f, f) < EPSILON) break; - bounceInfo.throughput *= f / pdf; + pathInfo.throughput *= f / pdf; + + // Russian Roulette + if (j >= 3) { + float q = max(0.05, 1.0 - max(pathInfo.throughput.r, max(pathInfo.throughput.g, pathInfo.throughput.b))); + if (random() < q) break; + pathInfo.throughput /= (1.0 - q); + } float bias = 0.001; - vec3 rayOrigin = bounceInfo.interaction.point + (dot(wi, bounceInfo.interaction.normal) > 0.0 ? 1.0 : -1.0) * bounceInfo.interaction.normal * bias; + vec3 rayOrigin = pathInfo.interaction.point + (dot(wi, pathInfo.interaction.normal) > 0.0 ? 1.0 : -1.0) * pathInfo.interaction.normal * bias; - payload.hit = true; - traceRayEXT(topLevelAS, gl_RayFlagsOpaqueEXT, 0xFF, 0, 0, 0, rayOrigin, 0.001, wi, 1000.0, 0); + payload.hit = false; + traceRayEXT(topLevelAS, gl_RayFlagsOpaqueEXT, 0xFF, 0, 0, 0, rayOrigin, 0.001, wi, 10000.0, 0); if (!payload.hit) { if (pushConstants.isAtmosphereEnabled != 0) { - bounceInfo.material.baseColor = calculate_sky_luminance_rgb(normalize(globalData.sunPosition), wi, 2.0f) * 0.05f; - bounceInfo.material.isEmissive = true; - bounceInfo.interaction.point = rayOrigin + wi * 1000.0; // Placeholder point for atmosphere - computeRadiance(bounceInfo); + vec3 skyLuminance = calculate_sky_luminance_rgb(normalize(globalData.sunPosition), wi, 2.0f) * 0.05f; + pathInfo.radiance += pathInfo.throughput * skyLuminance; } break; } - bounceInfo.material = payload.material; - bounceInfo.interaction.normal = payload.hitNormal; - bounceInfo.interaction.point = payload.hitPosition; - bounceInfo.interaction.incomingRayDir = wi; + pathInfo.material = payload.material; + pathInfo.interaction.normal = payload.hitNormal; + pathInfo.interaction.point = payload.hitPosition; + pathInfo.interaction.incomingRayDir = wi; - computeRadiance(bounceInfo); + if (pathInfo.material.isEmissive) { + pathInfo.radiance += pathInfo.throughput * pathInfo.material.baseColor * pushConstants.pathTracingEmissiveFactor; + break; // Stop at emissive for now, or continue if you want multiple emissive hits + } } - return bounceInfo.indirectLight; + return pathInfo.radiance; } vec3 calculatePixelColor(vec3 rayDirection, in vec2 texCoords, MaterialInfo material, SurfaceInteraction interaction) { vec3 L = vec3(0.); - vec3 beta = vec3(1.); - - vec3 wi; - interaction.incomingRayDir = rayDirection; material.subsurface = 0.; material.specular = 0.; @@ -102,33 +106,8 @@ vec3 calculatePixelColor(vec3 rayDirection, in vec2 texCoords, MaterialInfo mate material.sheen = 0.; material.sheenTint = 0.; - vec3 X = vec3(0.), Y = vec3(0.); - directionOfAnisotropicity(interaction.normal, X, Y); - interaction.tangent = X; - interaction.binormal = Y; - for (uint i = 0; i < pushConstants.pathTracerSamples; i++) { - vec3 f = vec3(0.); - float scatteringPdf = 0.; - vec3 Ld = vec3(0); - for (uint i = 0; i < globalData.lightsCount; i++) { - Light l = lightBuffer.items[i]; - l.color.rgb *= l.color.a; - Ld += beta * calculateDirectLight(l, interaction, material, wi, f, scatteringPdf) ; - } - - L += Ld; - - if (pushConstants.pathTracerBounces > 0 && pushConstants.pathTracerMultiplier > 0) { - L += beta * calculateIndirectLighting(material, interaction) * pushConstants.pathTracerMultiplier; - } - - if (scatteringPdf > EPSILON && dot(f, f) > EPSILON) { - beta *= f / scatteringPdf; - - float bias = 0.001; - interaction.point += (dot(wi, interaction.normal) > 0.0 ? 1.0 : -1.0) * interaction.normal * bias; - } + L += tracePath(rayDirection, material, interaction); } return L / pushConstants.pathTracerSamples; diff --git a/src/context/ApplicationContext.cpp b/src/context/ApplicationContext.cpp index 1827b4f0..f489b20b 100644 --- a/src/context/ApplicationContext.cpp +++ b/src/context/ApplicationContext.cpp @@ -13,7 +13,7 @@ namespace Metal { std::unique_ptr ApplicationContext::CONTEXT = nullptr; - ApplicationContext &CTX { + ApplicationContext &ApplicationContext::Get() { if (CONTEXT == nullptr) { throw std::runtime_error("Context not initialized"); } @@ -42,7 +42,6 @@ namespace Metal { } PARSE_TEMPLATE(editorRepository, rootDirectory + "/" + HASH_OF_CLASS_NAME(EditorRepository) + ".json") PARSE_TEMPLATE(engineRepository, rootDirectory + "/" + HASH_OF_CLASS_NAME(EngineRepository) + ".json") - PARSE_TEMPLATE(worldGridRepository, rootDirectory + "/" + HASH_OF_CLASS_NAME(WorldGridRepository) + ".json") PARSE_TEMPLATE(worldRepository, rootDirectory + "/" + HASH_OF_CLASS_NAME(WorldRepository) + ".json") @@ -127,7 +126,6 @@ namespace Metal { try { DUMP_TEMPLATE(rootDirectory + "/" + HASH_OF_CLASS_NAME(EditorRepository) + ".json", editorRepository) DUMP_TEMPLATE(rootDirectory + "/" + HASH_OF_CLASS_NAME(EngineRepository) + ".json", engineRepository) - DUMP_TEMPLATE(rootDirectory + "/" + HASH_OF_CLASS_NAME(WorldGridRepository) + ".json", worldGridRepository) DUMP_TEMPLATE(rootDirectory + "/" + HASH_OF_CLASS_NAME(WorldRepository) + ".json", worldRepository) notificationService.pushMessage("Project saved", NotificationSeverities::SUCCESS); } catch (const std::exception &e) { diff --git a/src/context/ApplicationContext.h b/src/context/ApplicationContext.h index ea94bd01..aad857a1 100644 --- a/src/context/ApplicationContext.h +++ b/src/context/ApplicationContext.h @@ -8,7 +8,6 @@ #include "vulkan/VulkanContext.h" #include "../service/mesh/MeshService.h" -#include "../service/world/WorldGridService.h" #include "../service/texture/TextureService.h" #include "../service/framebuffer/FrameBufferService.h" #include "../service/pipeline/PipelineService.h" @@ -25,8 +24,6 @@ #include "../service/files/FileImporterService.h" #include "../service/camera/CameraService.h" -#include "../repository/world/impl/WorldGridRepository.h" -#include "../repository/inspection/FilesRepository.h" #include "../repository/world/WorldRepository.h" #include "../repository/runtime/RuntimeRepository.h" #include "../repository/streaming/StreamingService.h" @@ -67,9 +64,6 @@ namespace Metal { GuiContext guiContext{}; GLFWContext glfwContext{}; - // // ----------- CORE REPOSITORIES - // ----------- CORE REPOSITORIES - // ----------- Services NotificationService notificationService; AsyncTaskService asyncTaskService; @@ -92,7 +86,6 @@ namespace Metal { FileImporterService fileImporterService{}; CameraService cameraService{}; PickingService pickingService{}; - WorldGridService worldGridService{}; TransformService transformService{}; LightService lightService{}; VolumeService volumeService{}; @@ -103,8 +96,6 @@ namespace Metal { // ----------- Services // ----------- Repository - FilesRepository fileInspection{}; - WorldGridRepository worldGridRepository{}; WorldRepository worldRepository{}; RuntimeRepository runtimeRepository{}; StreamingService streamingService{}; diff --git a/src/context/editor/abstract/form/FormPanel.cpp b/src/context/editor/abstract/form/FormPanel.cpp index afa405a9..3a48ef77 100644 --- a/src/context/editor/abstract/form/FormPanel.cpp +++ b/src/context/editor/abstract/form/FormPanel.cpp @@ -17,19 +17,19 @@ namespace Metal { void FormPanel::processFields(Inspectable *inspection) { - std::unordered_map groups{}; - const auto rootPanel = new AccordionPanel(); + std::unordered_map groups{}; + const auto rootPanel = new ChildPanel(); rootPanel->setFilter(&searchFilter); appendChild(rootPanel); rootPanel->setTitle(std::string(inspection->getIcon()) + " " + inspection->getTitle()); for (const auto &field: inspection->getFields()) { if (!groups.contains(field->group)) { - const auto panel = new ChildPanel(); + const auto panel = new AccordionPanel(); panel->setFilter(&searchFilter); groups[field->group] = panel; rootPanel->appendChild(panel); } - ChildPanel *group = groups[field->group]; + AccordionPanel *group = groups[field->group]; group->setTitle(field->group); AbstractFormFieldPanel *fieldPanel = nullptr; switch (field->type) { diff --git a/src/context/editor/abstract/form/types/QuatField.cpp b/src/context/editor/abstract/form/types/QuatField.cpp index 2b09407c..24134b71 100644 --- a/src/context/editor/abstract/form/types/QuatField.cpp +++ b/src/context/editor/abstract/form/types/QuatField.cpp @@ -3,6 +3,7 @@ #include #include #include "../../../../../common/inspection/Inspectable.h" +#include "../../../../../util/UIUtil.h" namespace Metal { QuatField::QuatField(InspectedField &field) : field(field) { @@ -14,8 +15,7 @@ namespace Metal { values[1] = field.field->y; values[2] = field.field->z; values[3] = field.field->w; - ImGui::Text(field.name.c_str()); - if (ImGui::DragFloat4(field.id.c_str(), values, field.incrementF.value())) { + if (UIUtil::DrawQuatControl(field.name, field.id, values, field.incrementF.value())) { field.field->x = values[0]; field.field->y = values[1]; field.field->z = values[2]; diff --git a/src/context/editor/abstract/form/types/Vec2Field.cpp b/src/context/editor/abstract/form/types/Vec2Field.cpp index 8bc3cc7f..d45d650d 100644 --- a/src/context/editor/abstract/form/types/Vec2Field.cpp +++ b/src/context/editor/abstract/form/types/Vec2Field.cpp @@ -2,6 +2,7 @@ #include #include #include "../../../../../common/inspection/Inspectable.h" +#include "../../../../../util/UIUtil.h" namespace Metal { Vec2Field::Vec2Field(InspectedField &field) : field(field) { @@ -11,8 +12,7 @@ namespace Metal { if (!field.disabled) { values[0] = field.field->x; values[1] = field.field->y; - ImGui::Text(field.name.c_str()); - if (ImGui::DragFloat2(field.id.c_str(), values, field.incrementF.value())) { + if (UIUtil::DrawVec2Control(field.name, field.id, values, field.incrementF.value())) { field.field->x = values[0]; field.field->y = values[1]; field.instance->registerChange(); diff --git a/src/context/editor/abstract/form/types/Vec3Field.cpp b/src/context/editor/abstract/form/types/Vec3Field.cpp index 27de3d77..e518b42e 100644 --- a/src/context/editor/abstract/form/types/Vec3Field.cpp +++ b/src/context/editor/abstract/form/types/Vec3Field.cpp @@ -2,6 +2,7 @@ #include #include #include "../../../../../common/inspection/Inspectable.h" +#include "../../../../../util/UIUtil.h" namespace Metal { Vec3Field::Vec3Field(InspectedField &field) : field(field) { @@ -12,8 +13,7 @@ namespace Metal { values[0] = field.field->x; values[1] = field.field->y; values[2] = field.field->z; - ImGui::Text(field.name.c_str()); - if (ImGui::DragFloat3(field.id.c_str(), values, field.incrementF.value())) { + if (UIUtil::DrawVec3Control(field.name, field.id, values, field.incrementF.value())) { field.field->x = values[0]; field.field->y = values[1]; field.field->z = values[2]; diff --git a/src/context/editor/abstract/form/types/Vec4Field.cpp b/src/context/editor/abstract/form/types/Vec4Field.cpp index d760d068..07cc3dde 100644 --- a/src/context/editor/abstract/form/types/Vec4Field.cpp +++ b/src/context/editor/abstract/form/types/Vec4Field.cpp @@ -2,6 +2,7 @@ #include #include #include "../../../../../common/inspection/Inspectable.h" +#include "../../../../../util/UIUtil.h" namespace Metal { Vec4Field::Vec4Field(InspectedField &field) : field(field) { @@ -13,8 +14,7 @@ namespace Metal { values[1] = field.field->y; values[2] = field.field->z; values[3] = field.field->w; - ImGui::Text(field.name.c_str()); - if (ImGui::DragFloat4(field.id.c_str(), values, field.incrementF.value())) { + if (UIUtil::DrawVec4Control(field.name, field.id, values, field.incrementF.value())) { field.field->x = values[0]; field.field->y = values[1]; field.field->z = values[2]; diff --git a/src/context/editor/dock-spaces/docks/DockSpacePanel.cpp b/src/context/editor/dock-spaces/docks/DockSpacePanel.cpp index ba1b2ca4..e07fe1ac 100644 --- a/src/context/editor/dock-spaces/docks/DockSpacePanel.cpp +++ b/src/context/editor/dock-spaces/docks/DockSpacePanel.cpp @@ -50,7 +50,7 @@ namespace Metal { void DockSpacePanel::handleShortcut() const { if (view != nullptr) { - const bool isHovered = ImGui::IsWindowFocused(ImGuiHoveredFlags_RootAndChildWindows); + const bool isHovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); if (isHovered) { CTX.editorRepository.focusedShortcuts = view->getShortcuts(); CTX.editorRepository.focusedWindowName = view->dock->name; diff --git a/src/context/editor/dock-spaces/files/FilePreviewPanel.cpp b/src/context/editor/dock-spaces/files/FilePreviewPanel.cpp index 5003b87e..7c7c050b 100644 --- a/src/context/editor/dock-spaces/files/FilePreviewPanel.cpp +++ b/src/context/editor/dock-spaces/files/FilePreviewPanel.cpp @@ -3,19 +3,12 @@ #include "../../../../util/UIUtil.h" #include "../../../../dto/file/FSEntry.h" #include "../../../../context/ApplicationContext.h" -#include "../../../../common/interface/Icons.h" #include "../../../../service/texture/TextureInstance.h" -#include "../inspector/MaterialEditPanel.h" namespace Metal { FilePreviewPanel::FilePreviewPanel(FilesContext &filesContext) : filesContext(filesContext) { } - void FilePreviewPanel::onInitialize() { - materialInspection = new MaterialEditPanel(); - appendChild(materialInspection); - } - void FilePreviewPanel::onSync() { if (filesContext.selected.empty()) { ImGui::Text("Select a file to preview"); @@ -28,7 +21,7 @@ namespace Metal { ImGui::Separator(); if (selected->type == EntryType::TEXTURE) { - auto *texture = CTX.streamingService.streamTexture(selected->getId()); + auto *texture = CTX.textureService.stream(selected->getId()); if (texture != nullptr) { float availWidth = ImGui::GetContentRegionAvail().x; float availHeight = ImGui::GetContentRegionAvail().y * 0.6f; // reserve space for table @@ -51,12 +44,7 @@ namespace Metal { CTX.guiContext.renderImage(texture, renderWidth, renderHeight); ImGui::Separator(); } - } else if (selected->type == EntryType::MATERIAL) { - CTX.fileInspection.materialId = selected->getId(); - materialInspection->onSync(); - ImGui::Separator(); } - if (ImGui::BeginTable((id + "metadata").c_str(), 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { ImGui::TableSetupColumn("Property"); ImGui::TableSetupColumn("Value"); @@ -76,7 +64,6 @@ namespace Metal { case EntryType::MESH: typeLabel = "Mesh"; break; case EntryType::TEXTURE: typeLabel = "Texture"; break; case EntryType::VOLUME: typeLabel = "Volume"; break; - case EntryType::MATERIAL: typeLabel = "Material"; break; case EntryType::DIRECTORY: typeLabel = "Directory"; break; default: typeLabel = "Unknown"; break; } diff --git a/src/context/editor/dock-spaces/files/FilePreviewPanel.h b/src/context/editor/dock-spaces/files/FilePreviewPanel.h index 5e381cc4..689ac058 100644 --- a/src/context/editor/dock-spaces/files/FilePreviewPanel.h +++ b/src/context/editor/dock-spaces/files/FilePreviewPanel.h @@ -5,17 +5,12 @@ #include "FilesContext.h" namespace Metal { - class MaterialEditPanel; - class FilePreviewPanel final : public AbstractPanel { FilesContext &filesContext; - MaterialEditPanel *materialInspection = nullptr; public: explicit FilePreviewPanel(FilesContext &filesContext); - void onInitialize() override; - void onSync() override; }; } diff --git a/src/context/editor/dock-spaces/files/FilesHeaderPanel.cpp b/src/context/editor/dock-spaces/files/FilesHeaderPanel.cpp index 8767846f..3924fb73 100644 --- a/src/context/editor/dock-spaces/files/FilesHeaderPanel.cpp +++ b/src/context/editor/dock-spaces/files/FilesHeaderPanel.cpp @@ -35,15 +35,7 @@ namespace Metal { ImGui::SameLine(); ImGui::Text(filesContext.pathToCurrentDirectory.c_str()); - UIUtil::DynamicSpacing(264); - - if (UIUtil::ButtonSimple(Icons::format_paint + id, UIUtil::ONLY_ICON_BUTTON_SIZE, - UIUtil::ONLY_ICON_BUTTON_SIZE)) { - CTX.filesService.createMaterial(filesContext.currentDirectory->absolutePath, filesContext.currentDirectory); - FilesService::GetEntries(filesContext.currentDirectory); - } - UIUtil::RenderTooltip("Create material"); - ImGui::SameLine(); + UIUtil::DynamicSpacing(200); ImGui::SetNextItemWidth(100); editorMode = IndexOfValue(filesContext.filterType); diff --git a/src/context/editor/dock-spaces/files/FilesListPanel.cpp b/src/context/editor/dock-spaces/files/FilesListPanel.cpp index 10d0f27b..54f75cd0 100644 --- a/src/context/editor/dock-spaces/files/FilesListPanel.cpp +++ b/src/context/editor/dock-spaces/files/FilesListPanel.cpp @@ -196,8 +196,6 @@ namespace Metal { break; case EntryType::VOLUME: typeLabel = "Volume"; break; - case EntryType::MATERIAL: typeLabel = "Material"; - break; default: typeLabel = ""; break; } diff --git a/src/context/editor/dock-spaces/files/FilesPanel.cpp b/src/context/editor/dock-spaces/files/FilesPanel.cpp index bfb9a569..32f0e537 100644 --- a/src/context/editor/dock-spaces/files/FilesPanel.cpp +++ b/src/context/editor/dock-spaces/files/FilesPanel.cpp @@ -32,17 +32,17 @@ namespace Metal { } }); if (!files.empty()) { - CTX.fileInspection.pendingImports = files; - CTX.fileInspection.importSettingsMap.clear(); - for (const auto& file : CTX.fileInspection.pendingImports) { + CTX.editorRepository.pendingImports = files; + CTX.editorRepository.importSettingsMap.clear(); + for (const auto& file : CTX.editorRepository.pendingImports) { if (CTX.sceneImporterService.isCompatible(file)) { - CTX.fileInspection.importSettingsMap.emplace(file, std::make_shared()); + CTX.editorRepository.importSettingsMap.emplace(file, std::make_shared()); } else { - CTX.fileInspection.importSettingsMap.emplace(file, std::make_shared()); + CTX.editorRepository.importSettingsMap.emplace(file, std::make_shared()); } } - CTX.fileInspection.selectedFileForSettings = CTX.fileInspection.pendingImports[0]; - CTX.fileInspection.targetImportDirectory = filesContext.currentDirectory; + CTX.editorRepository.selectedFileForSettings = CTX.editorRepository.pendingImports[0]; + CTX.editorRepository.targetImportDirectory = filesContext.currentDirectory; } }; } @@ -123,15 +123,13 @@ namespace Metal { void FilesPanel::openResource(FSEntry *root) { switch (root->type) { - case EntryType::MESH: { - CTX.meshService.createMeshEntity(root->name, root->getId(), ""); - break; - } case EntryType::SCENE: { - CTX.meshService.createSceneEntities(root->getId()); + CTX.notificationService.pushMessage("Loading scene", NotificationSeverities::SUCCESS); + CTX.worldRepository.loadScene(root->getId()); break; } case EntryType::VOLUME: { + CTX.notificationService.pushMessage("Loading volume", NotificationSeverities::SUCCESS); CTX.voxelService.create(root->getId()); break; } @@ -142,6 +140,7 @@ namespace Metal { break; } default: + CTX.notificationService.pushMessage("Unsupported resource type", NotificationSeverities::ERROR); break; } } diff --git a/src/context/editor/dock-spaces/hierarchy/HierarchyHeaderPanel.cpp b/src/context/editor/dock-spaces/hierarchy/HierarchyHeaderPanel.cpp deleted file mode 100644 index 24a7eebe..00000000 --- a/src/context/editor/dock-spaces/hierarchy/HierarchyHeaderPanel.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "HierarchyHeaderPanel.h" - -#include "../../../../context/ApplicationContext.h" -#include "../../../../util/UIUtil.h" - -namespace Metal { - void HierarchyHeaderPanel::onSync() { - ImGui::InputText(("##hierarchySearch" + id).c_str(), search, sizeof(search)); - ImGui::SameLine(); - if (UIUtil::ButtonSimple(Icons::inventory_2 + "##hierarchyAdd" + id, UIUtil::ONLY_ICON_BUTTON_SIZE, - UIUtil::ONLY_ICON_BUTTON_SIZE)) { - CTX.worldRepository.createEntity(); - } - UIUtil::RenderTooltip("Create folder"); - } -} // Metal diff --git a/src/context/editor/dock-spaces/hierarchy/HierarchyPanel.cpp b/src/context/editor/dock-spaces/hierarchy/HierarchyPanel.cpp deleted file mode 100644 index 6db2000b..00000000 --- a/src/context/editor/dock-spaces/hierarchy/HierarchyPanel.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include "HierarchyPanel.h" - -#include "HierarchyHeaderPanel.h" -#include "../../../../common/interface/Icons.h" -#include "../../../../util/UIUtil.h" -#include "../../../../context/ApplicationContext.h" -#include "../../../../repository/world/impl/EntityComponent.h" -#include "../../../../enum/ComponentType.h" - -namespace Metal { - void HierarchyPanel::onInitialize() { - appendChild(headerPanel = new HierarchyHeaderPanel()); - world = &CTX.worldRepository; - editorRepository = &CTX.editorRepository; - - shortcuts = { - ShortcutDTO("Delete", ImGuiKey_Delete, [this]() { - std::vector entities; - for (auto &entry: CTX.editorRepository.selected) { - entities.push_back(entry.first); - } - CTX.worldRepository.deleteEntities(entities); - CTX.selectionService.clearSelection(); - }), - ShortcutDTO("Select All", ImGuiMod_Ctrl | ImGuiKey_A, [this]() { - std::vector entities; - auto &storage = world->registry.storage(); - for (auto it = storage.begin(); it != storage.end(); ++it) { - auto entity = *it; - if (static_cast(entity) != WorldRepository::ROOT_ID && world->registry.all_of< - EntityComponent>(entity)) { - entities.push_back(static_cast(entity)); - } - } - CTX.selectionService.addAllSelected(entities); - }), - ShortcutDTO("Save", ImGuiMod_Ctrl | ImGuiKey_S, [] { - CTX.save(); - }), - }; - } - - void HierarchyPanel::contextMenu() const { - if (ImGui::BeginPopupContextItem((id + "contextMenu").c_str())) { - if (ImGui::MenuItem("Delete")) { - std::vector entities; - for (auto &entry: CTX.editorRepository.selected) { - entities.push_back(entry.first); - } - CTX.worldRepository.deleteEntities(entities); - CTX.selectionService.clearSelection(); - } - ImGui::EndPopup(); - } - - if (isSomethingHovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { - ImGui::OpenPopup((id + "contextMenu").c_str()); - } - } - - void HierarchyPanel::onSync() { - isOnSearch = strlen(headerPanel->search) > 0; - - isSomethingHovered = ImGui::IsItemHovered(); - - // hotKeys(); - onSyncChildren(); - ImGui::Separator(); - if (ImGui::BeginTable((id + "hierarchyTable").c_str(), 2, TABLE_FLAGS)) { - isSomethingHovered = isSomethingHovered || ImGui::IsItemHovered(); - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); - ImGui::TableSetupColumn(Icons::visibility.c_str(), ImGuiTableColumnFlags_WidthFixed, 20.f); - ImGui::TableHeadersRow(); - renderNode(WorldRepository::ROOT_ID); - ImGui::EndTable(); - } - if (!CTX.editorRepository.selected.empty()) { - contextMenu(); - } - } - - bool HierarchyPanel::renderNode(const EntityID entityId) { - EntityComponent *node = world->getEntity(entityId); - if (node == nullptr || (isOnSearch && - searchMatch.contains(entityId) && - searchMatchWith.contains(entityId) && - strcmp(searchMatchWith[entityId].c_str(), headerPanel->search) == 0)) { - return false; - } - - const bool isSearchMatch = matchSearch(entityId); - ImGui::TableNextRow(); - if (editorRepository->selected.contains(entityId)) { - ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, editorRepository->accentU32); - ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, editorRepository->accentU32); - } - ImGui::TableNextColumn(); - const int flags = getFlags(entityId); - bool open; - - if (world->culled.contains(entityId) || world->hiddenEntities.contains(entityId)) { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(node->color.x, node->color.y, node->color.z, .5)); - open = isOpen(entityId, flags); - ImGui::PopStyleColor(); - } else { - rowColor.x = node->color.x; - rowColor.y = node->color.y; - rowColor.z = node->color.z; - ImGui::PushStyleColor(ImGuiCol_Text, rowColor); - open = isOpen(entityId, flags); - ImGui::PopStyleColor(); - } - - handleDragDrop(entityId); - renderEntityColumns(entityId, false); - - if (open) { - opened.insert({entityId, ImGuiTreeNodeFlags_DefaultOpen}); - renderEntityChildren(entityId); - } else { - opened.insert({entityId, ImGuiTreeNodeFlags_None}); - } - - return isSearchMatch; - } - - bool HierarchyPanel::isOpen(const EntityID entityId, const int flags) const { - return ImGui::TreeNodeEx(getNodeLabel(entityId, true).c_str(), flags); - } - - const char *HierarchyPanel::GetIcon(const EntityID entityId) const { - const auto entity = static_cast(entityId); - if (world->registry.all_of(entity)) { - return ComponentTypes::IconOf(ComponentTypes::MESH); - } - if (world->registry.all_of >(entity)) { - return ComponentTypes::IconOf(ComponentTypes::SPHERE_LIGHT); - } - if (world->registry.all_of(entity)) { - return ComponentTypes::IconOf(ComponentTypes::VOLUME); - } - return Icons::inventory_2.c_str(); - } - - std::string HierarchyPanel::getNodeLabel(const EntityID entityId, const bool addId) const { - const auto node = world->getEntity(entityId); - return std::format("{}{}##{}{}", - GetIcon(entityId), - node->name, - entityId, - addId ? id : ""); - } - - bool HierarchyPanel::matchSearch(const EntityID entityId) { - bool isSearchMatch = false; - const auto node = world->getEntity(entityId); - if (isOnSearch) { - isSearchMatch = node->name.find(headerPanel->search) != std::string::npos; - if (isSearchMatch) { - searchMatch.insert({entityId, true}); - } else { - searchMatch.erase(entityId); - } - searchMatchWith.insert({entityId, headerPanel->search}); - } else { - searchMatch.erase(entityId); - searchMatchWith.erase(entityId); - } - return isSearchMatch; - } - - void HierarchyPanel::renderEntityChildren(const EntityID entityId) { - const auto entity = static_cast(entityId); - if (!world->registry.all_of(entity)) { - ImGui::TreePop(); - return; - } - - const auto &hierarchy = world->registry.get(entity); - if (isOnSearch) { - for (const auto child: hierarchy.children) { - if (searchMatch.contains(entityId) || renderNode(child)) { - searchMatch.insert({entityId, true}); - } else { - searchMatch.erase(entityId); - } - } - } else { - for (const auto child: hierarchy.children) { - renderNode(child); - } - } - - ImGui::TreePop(); - } - - int HierarchyPanel::getFlags(const EntityID entityId) { - int flags = ImGuiTreeNodeFlags_SpanFullWidth; - if (isOnSearch) { - flags |= ImGuiTreeNodeFlags_DefaultOpen; - } - - if (opened.contains(entityId)) { - flags |= opened[entityId]; - } - return flags; - } - - void HierarchyPanel::renderEntityColumns(const EntityID entityId, const bool isPinned) const { - const auto idString = std::to_string(entityId); - handleClick(entityId); - ImGui::TableNextColumn(); - - ImGui::PushStyleColor(ImGuiCol_Button, TRANSPARENT); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, PADDING); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0); - - bool isVisible = !world->hiddenEntities.contains(entityId); - if (UIUtil::ButtonSimple( - (isVisible ? Icons::visibility : Icons::visibility_off) + (isPinned ? "##vpinned" : "##v") + idString + - id, 20, 15)) { - CTX.worldRepository.changeVisibility(entityId, !isVisible); - } - ImGui::PopStyleColor(); - ImGui::PopStyleVar(2); - } - - void HierarchyPanel::handleClick(const EntityID entityId) const { - if (ImGui::IsItemClicked()) { - if (const bool isMultiSelect = ImGui::IsKeyDown(ImGuiKey_LeftCtrl); !isMultiSelect) { - CTX.selectionService.clearSelection(); - } - CTX.selectionService.addSelected(entityId); - } - } - - void HierarchyPanel::handleDragDrop(const EntityID entityId) { - const auto node = world->getEntity(entityId); - if (ImGui::BeginDragDropSource()) { - ImGui::SetDragDropPayload(id.c_str(), id.c_str(), sizeof(id.c_str())); - onDrag = entityId; - ImGui::Text("Dragging Node %s", node->getTitle()); - ImGui::EndDragDropSource(); - } - - if (ImGui::BeginDragDropTarget()) { - if (strcmp(static_cast(ImGui::AcceptDragDropPayload(id.c_str())->Data), id.c_str())) { - world->linkEntities(entityId, onDrag); - } - ImGui::EndDragDropTarget(); - } - } -} // Metal diff --git a/src/context/editor/dock-spaces/hierarchy/HierarchyPanel.h b/src/context/editor/dock-spaces/hierarchy/HierarchyPanel.h deleted file mode 100644 index 4a1a9c67..00000000 --- a/src/context/editor/dock-spaces/hierarchy/HierarchyPanel.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef HIERARCHYPANEL_H -#define HIERARCHYPANEL_H -#include -#include - -#include "../../../../enum/engine-definitions.h" -#include "../../../../enum/ComponentType.h" -#include "../docks/AbstractDockPanel.h" - -namespace Metal { - struct EditorRepository; - struct WorldRepository; - struct AbstractComponent; - struct EntityComponent; - struct HierarchyComponent; - class HierarchyHeaderPanel; - - class HierarchyPanel final : public AbstractDockPanel { - static constexpr auto TRANSPARENT = ImVec4(0, 0, 0, 0); - static constexpr auto PADDING = ImVec2(0, 0); - static constexpr auto TABLE_FLAGS = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg - | ImGuiTableFlags_NoBordersInBody; - HierarchyHeaderPanel *headerPanel = nullptr; - ImVec4 rowColor = ImVec4(0, 0, 0, 1); - EntityID onDrag = EMPTY_ENTITY; - bool isOnSearch = false; - std::unordered_map searchMatchWith{}; - std::unordered_map searchMatch{}; - std::unordered_map opened{}; - WorldRepository *world = nullptr; - EditorRepository *editorRepository = nullptr; - bool isSomethingHovered = false; - - public: - void onInitialize() override; - - void contextMenu() const; - - void onSync() override; - - bool renderNode(EntityID entityId); - - bool isOpen(EntityID entityId, int flags) const; - - const char *GetIcon(EntityID entityId) const; - - std::string getNodeLabel(EntityID entityId, bool addId) const; - - bool matchSearch(EntityID entityId); - - void renderEntityChildren(EntityID entityId); - - int getFlags(EntityID entityId); - - void renderEntityColumns(EntityID entityId, bool isPinned) const; - - void handleClick(EntityID entityId) const; - - void handleDragDrop(EntityID entityId); - }; -} // Metal - -#endif //HIERARCHYPANEL_H diff --git a/src/context/editor/dock-spaces/inspector/InspectorPanel.cpp b/src/context/editor/dock-spaces/inspector/InspectorPanel.cpp index 6b438f70..9a09e624 100644 --- a/src/context/editor/dock-spaces/inspector/InspectorPanel.cpp +++ b/src/context/editor/dock-spaces/inspector/InspectorPanel.cpp @@ -4,34 +4,41 @@ #include "../../../../util/UIUtil.h" #include "../../../../common/inspection/Inspectable.h" #include "../../../../context/ApplicationContext.h" -#include "../../../../repository/world/impl/EntityComponent.h" -#include "../../../../repository/world/components/VolumeComponent.h" -#include "../../../../repository/world/components/LightComponent.h" -#include "../../../../service/camera/Camera.h" +#include "../../../../repository/world/impl/MetadataComponent.h" +#include +#include namespace Metal { void InspectorPanel::onInitialize() { formPanel = new FormPanel(); appendChild(formPanel); - Inspectable *editorRepo = &CTX.editorRepository; - Inspectable *engineRepo = &CTX.engineRepository; - Inspectable *cameraRepo = &CTX.worldRepository.camera; - repositories.push_back(editorRepo); - repositories.push_back(engineRepo); - repositories.push_back(cameraRepo); } void InspectorPanel::onSync() { tick(); - { - for (auto *repo: repositories) { - formPanel->setInspection(repo); + formPanel->onSync(); + + if (selectedId != EMPTY_ENTITY) { + ImGui::Separator(); + if (ImGui::Button((Icons::add + " Add Component" + id + "addComp").c_str(), ImVec2(-1, 0))) { + ImGui::OpenPopup((id + "AddComponentPopup").c_str()); } - for (auto *component: additionalInspection) { - formPanel->setInspection(component); + + if (ImGui::BeginPopup((id + "AddComponentPopup").c_str())) { + for (const auto &compDef: ComponentTypes::getComponents()) { + bool hasComponent = compDef.getInspectable(CTX.worldRepository, selectedId) != nullptr; + if (!hasComponent) { + if (ImGui::MenuItem( + (compDef.icon + " " + compDef.name + id + "adCOmp" + compDef.name).c_str())) { + CTX.worldRepository.createComponent(selectedId, compDef.type); + selectedId = EMPTY_ENTITY; + tick(); + } + } + } + ImGui::EndPopup(); } } - formPanel->onSync(); } void InspectorPanel::tick() { @@ -42,29 +49,24 @@ namespace Metal { formPanel->resetForm(); if (selectedId != EMPTY_ENTITY) { auto &repo = CTX.worldRepository; - const auto entity = static_cast(selectedId); selectedEntity = repo.getEntity(selectedId); if (selectedEntity != nullptr) { additionalInspection.push_back(selectedEntity); - if (repo.registry.all_of(entity)) { - additionalInspection.push_back((Inspectable *) &repo.registry.get(entity)); - } - if (repo.registry.all_of(entity)) { - additionalInspection.push_back((Inspectable *) &repo.registry.get(entity)); - } - if (repo.registry.all_of >(entity)) { - additionalInspection.push_back( - (Inspectable *) repo.registry.get >(entity).get()); - } - if (repo.registry.all_of(entity)) { - additionalInspection.push_back((Inspectable *) &repo.registry.get(entity)); + for (const auto &compDef: ComponentTypes::getComponents()) { + if (Inspectable *inspectable = compDef.getInspectable(repo, selectedId)) { + additionalInspection.push_back(inspectable); + } } } } else { selectedEntity = nullptr; } } + + for (auto *component: additionalInspection) { + formPanel->setInspection(component); + } } } diff --git a/src/context/editor/dock-spaces/inspector/InspectorPanel.h b/src/context/editor/dock-spaces/inspector/InspectorPanel.h index e871d53e..5d024e96 100644 --- a/src/context/editor/dock-spaces/inspector/InspectorPanel.h +++ b/src/context/editor/dock-spaces/inspector/InspectorPanel.h @@ -9,12 +9,11 @@ namespace Metal { class Inspectable; class InspectorPanel final : public AbstractDockPanel { - std::vector repositories{}; std::vector additionalInspection{}; Inspectable *selectedEntity = nullptr; FormPanel *formPanel = nullptr; - EntityID selectedId = EMPTY_ENTITY; + entt::entity selectedId = EMPTY_ENTITY; public: void onInitialize() override; diff --git a/src/context/editor/dock-spaces/inspector/MaterialEditPanel.cpp b/src/context/editor/dock-spaces/inspector/MaterialEditPanel.cpp deleted file mode 100644 index 2a127070..00000000 --- a/src/context/editor/dock-spaces/inspector/MaterialEditPanel.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "MaterialEditPanel.h" - -#include "../../../ApplicationContext.h" -#include "../../../../util/UIUtil.h" -#include "../../../../util/serialization-definitions.h" -#include "../../../../service/material/MaterialFileData.h" -#include "../../../../enum/engine-definitions.h" - -namespace Metal { - void MaterialEditPanel::onInitialize() { - formPanel = new FormPanel(); - appendChild(formPanel); - } - - void MaterialEditPanel::saveChanges() { - CTX.engineContext.setGISettingsUpdated(true); - data->freezeVersion(); - DUMP_TEMPLATE(CTX.getAssetDirectory() + FORMAT_FILE_MATERIAL(prevSelection), *data) - CTX.notificationService.pushMessage("Material was saved", NotificationSeverities::SUCCESS); - - CTX.materialService.dispose(prevSelection); - } - - void MaterialEditPanel::onSync() { - if (prevSelection != CTX.fileInspection.materialId) { - delete data; - data = CTX.materialService.stream(CTX.fileInspection.materialId); - prevSelection = CTX.fileInspection.materialId; - formPanel->resetForm(); - } - if (prevSelection.empty()) { - return; - } - ImGui::Spacing(); - bool changed = data->isNotFrozen(); - if (changed) { - ImGui::PushStyleColor(ImGuiCol_Button, CTX.editorRepository.accent); // Orange-ish - } - if (ImGui::Button(("Save" + id + "save1").c_str())) { - saveChanges(); - } - if (changed) { - ImGui::PopStyleColor(); - } - ImGui::Spacing(); - - formPanel->setInspection(data); - formPanel->onSync(); - - ImGui::Spacing(); - changed = data->isNotFrozen(); - if (changed) { - ImGui::PushStyleColor(ImGuiCol_Button, CTX.editorRepository.accent); // Orange-ish - } - if (ImGui::Button(("Save" + id + "save").c_str())) { - saveChanges(); - } - if (changed) { - ImGui::PopStyleColor(); - } - } -} // Metal diff --git a/src/context/editor/dock-spaces/inspector/MaterialEditPanel.h b/src/context/editor/dock-spaces/inspector/MaterialEditPanel.h deleted file mode 100644 index 1f02daee..00000000 --- a/src/context/editor/dock-spaces/inspector/MaterialEditPanel.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MATERIALINSPECTION_H -#define MATERIALINSPECTION_H -#include "../../abstract/AbstractPanel.h" -#include "../../abstract/form/FormPanel.h" - -namespace Metal { - struct MaterialFileData; - - class MaterialEditPanel final : public AbstractPanel { - std::string prevSelection; - MaterialFileData *data = nullptr; - FormPanel *formPanel = nullptr; - public: - void onInitialize() override; - - void saveChanges(); - - void onSync() override; - }; -} // Metal - -#endif //MATERIALINSPECTION_H diff --git a/src/context/editor/dock-spaces/metrics/MetricsPanel.cpp b/src/context/editor/dock-spaces/metrics/MetricsPanel.cpp index 1ff17f73..fc27f0e2 100644 --- a/src/context/editor/dock-spaces/metrics/MetricsPanel.cpp +++ b/src/context/editor/dock-spaces/metrics/MetricsPanel.cpp @@ -23,7 +23,6 @@ namespace Metal { void MetricsPanel::onSync() { drawResourceList("Meshes", CTX.meshService, id); - drawResourceList("Materials", CTX.materialService, id); drawResourceList("Voxels", CTX.voxelService, id); drawResourceList("Framebuffers", CTX.framebufferService, id); drawResourceList("Textures", CTX.textureService, id); diff --git a/src/context/editor/dock-spaces/repositories/RepositoriesPanel.cpp b/src/context/editor/dock-spaces/repositories/RepositoriesPanel.cpp new file mode 100644 index 00000000..19af1c73 --- /dev/null +++ b/src/context/editor/dock-spaces/repositories/RepositoriesPanel.cpp @@ -0,0 +1,22 @@ +#include "RepositoriesPanel.h" +#include "../../abstract/form/FormPanel.h" +#include "../../../../context/ApplicationContext.h" +#include "../../../../common/inspection/Inspectable.h" + +namespace Metal { + void RepositoriesPanel::onInitialize() { + formPanel = new FormPanel(); + appendChild(formPanel); + + repositories.push_back(&CTX.editorRepository); + repositories.push_back(&CTX.engineRepository); + repositories.push_back(&CTX.worldRepository.camera); + } + + void RepositoriesPanel::onSync() { + for (auto *repo : repositories) { + formPanel->setInspection(repo); + } + formPanel->onSync(); + } +} diff --git a/src/context/editor/dock-spaces/repositories/RepositoriesPanel.h b/src/context/editor/dock-spaces/repositories/RepositoriesPanel.h new file mode 100644 index 00000000..b566b984 --- /dev/null +++ b/src/context/editor/dock-spaces/repositories/RepositoriesPanel.h @@ -0,0 +1,20 @@ +#ifndef REPOSITORIESPANEL_H +#define REPOSITORIESPANEL_H + +#include "../docks/AbstractDockPanel.h" + +namespace Metal { + class FormPanel; + class Inspectable; + + class RepositoriesPanel final : public AbstractDockPanel { + std::vector repositories{}; + FormPanel *formPanel = nullptr; + + public: + void onInitialize() override; + void onSync() override; + }; +} + +#endif diff --git a/src/context/editor/dock-spaces/viewport/CameraPositionPanel.cpp b/src/context/editor/dock-spaces/viewport/CameraPositionPanel.cpp index 38857420..e84ed0b5 100644 --- a/src/context/editor/dock-spaces/viewport/CameraPositionPanel.cpp +++ b/src/context/editor/dock-spaces/viewport/CameraPositionPanel.cpp @@ -19,11 +19,6 @@ namespace Metal { if (ImGui::Begin(id.c_str(), &UIUtil::OPEN, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse)) { const auto &positionCamera = CTX.worldRepository.camera.position; - ImGui::Text("Current tile: %i %i | N of tiles: %i", - CTX.worldGridRepository.getCurrentTile()->x, - CTX.worldGridRepository.getCurrentTile()->z, - CTX.worldGridRepository.getTiles().size()); - ImGui::SameLine(); ImGui::TextColored(RED, "X: %i", static_cast(positionCamera.x)); ImGui::SameLine(); ImGui::TextColored(GREEN, "Y: %i", static_cast(positionCamera.y)); diff --git a/src/context/editor/dock-spaces/viewport/EngineFramePanel.cpp b/src/context/editor/dock-spaces/viewport/EngineFramePanel.cpp index 1b151545..d1bdc025 100644 --- a/src/context/editor/dock-spaces/viewport/EngineFramePanel.cpp +++ b/src/context/editor/dock-spaces/viewport/EngineFramePanel.cpp @@ -1,19 +1,15 @@ #include "EngineFramePanel.h" #include "../../../../context/ApplicationContext.h" -#include "ViewportPanel.h" #include "../../../../context/engine/frame-builder/EngineFrameBuilder.h" #include "../../../../context/engine/frame-builder/EngineFrame.h" -#include "../../../../service/framebuffer/FrameBufferService.h" #include "../../../../service/descriptor/DescriptorInstance.h" #include "../../../../service/framebuffer/FrameBufferInstance.h" #include "../../../../service/picking/PickingService.h" #include "../../../../enum/engine-definitions.h" #include "../../../../enum/EngineResourceIDs.h" #include "../../../../dto/buffers/GlobalDataUBO.h" -#include "../../../../dto/buffers/TileInfoUBO.h" #include "../../../../dto/buffers/LightData.h" #include "../../../../dto/buffers/VolumeData.h" -#include "../../../../dto/buffers/MaterialData.h" #include "../../../../dto/buffers/MeshMetadata.h" #include "ViewportHeaderPanel.h" #include "ImGuizmo.h" @@ -27,36 +23,34 @@ namespace Metal { engineFrame = EngineFrameBuilder() .addBuffer(RID_GLOBAL_DATA, sizeof(GlobalDataUBO), VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, UNIFORM_BUFFER) - .addBuffer(RID_TILE_INFO, sizeof(TileInfoUBO), - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, UNIFORM_BUFFER) .addBuffer(RID_LIGHT_BUFFER, MAX_LIGHTS * sizeof(LightData), VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, STORAGE_BUFFER) - .addBuffer(RID_VOLUMES_BUFFER, MAX_VOLUMES * sizeof(VolumeData), - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, STORAGE_BUFFER) - .addBuffer(RID_MATERIAL_BUFFER, MAX_MATERIALS * sizeof(MaterialData), - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, STORAGE_BUFFER) + .addBuffer(RID_VOLUMES_BUFFER, MAX_VOLUMES * sizeof(VolumeData), + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, STORAGE_BUFFER) .addBuffer(RID_MESH_METADATA_BUFFER, MAX_MESH_INSTANCES * sizeof(MeshMetadata), VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, STORAGE_BUFFER) - .addTexture(RID_RAW_RENDERED_FRAME, gBufferW, gBufferH) .addTexture(RID_ACCUMULATED_FRAME, gBufferW, gBufferH) .addTexture(RID_GBUFFER_POSITION_INDEX, gBufferW, gBufferH, VK_FORMAT_R32G32B32A32_SFLOAT) .addTexture(RID_GBUFFER_NORMAL, gBufferW, gBufferH, VK_FORMAT_R16G16B16A16_SFLOAT) - .addTexture(RID_PREVIOUS_COLOR, gBufferW, gBufferH, VK_FORMAT_R16G16B16A16_SFLOAT) .addTexture(RID_PREVIOUS_POSITION_INDEX, gBufferW, gBufferH, VK_FORMAT_R32G32B32_SFLOAT) // I noticed current position is rgba32f, but let's check. .addTexture(RID_PREVIOUS_NORMAL, gBufferW, gBufferH, VK_FORMAT_R16G16B16A16_SFLOAT) .addTexture(RID_DENOISED_FRAME, gBufferW, gBufferH, VK_FORMAT_R16G16B16A16_SFLOAT) .addTexture(RID_TEMPORAL_OUTPUT, gBufferW, gBufferH, VK_FORMAT_R16G16B16A16_SFLOAT) .addTexture(RID_PREVIOUS_DENOISED_FRAME, gBufferW, gBufferH, VK_FORMAT_R16G16B16A16_SFLOAT) + .addFramebuffer(RID_SELECTION_FBO, gBufferW, gBufferH, glm::vec4(0, 0, 0, 0)) + .addColor(VK_FORMAT_R16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) .addFramebuffer(RID_POST_PROCESSING_FBO, gBufferW, gBufferH, glm::vec4(0, 0, 0, 0)) - .addColor("Color", VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) + .addColor(VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) .addComputeCommandBuffer(RID_COMPUTE_CB) .addPass(RAY_TRACING, RID_COMPUTE_CB) .addPass(ACCUMULATION, RID_COMPUTE_CB) .addPass(TEMPORAL_ACCUMULATION, RID_COMPUTE_CB) .addPass(SPATIAL_FILTER, RID_COMPUTE_CB) + .addCommandBuffer(RID_SELECTION_CB, RID_SELECTION_FBO) + .addPass(SELECTION_ID, RID_SELECTION_CB) .addCommandBuffer(RID_POST_PROCESSING_CB, RID_POST_PROCESSING_FBO) .addPass(POST_PROCESSING, RID_POST_PROCESSING_CB) - .addPass(SELECTED_DOT, RID_POST_PROCESSING_CB) + .addPass(SELECTION_OUTLINE, RID_POST_PROCESSING_CB) .addPass(GRID, RID_POST_PROCESSING_CB) .addPass(ICONS, RID_POST_PROCESSING_CB) .build(); @@ -66,11 +60,6 @@ namespace Metal { void EngineFramePanel::onSync() { engineFrame->setShouldRender(true); - - const float tabHeight = ImGui::GetFrameHeightWithSpacing(); - // Assuming this panel is inside ViewportPanel, we need to get its size. - // But for now, let's use ImGui::GetContentRegionAvail() or similar if we can't access parent size easily. - // Actually, ViewportPanel sets its size in updateInputs. const ImVec2 viewportSize = ImGui::GetContentRegionAvail(); auto *framebuffer = engineFrame->getResourceAs(RID_POST_PROCESSING_FBO); @@ -106,21 +95,16 @@ namespace Metal { return; } - auto *rawRenderedFrame = engineFrame->getResourceAs(RID_RAW_RENDERED_FRAME); - if (!rawRenderedFrame) { + auto *gBufferPositionIndex = engineFrame->getResourceAs(RID_GBUFFER_POSITION_INDEX); + if (!gBufferPositionIndex) { return; } - const auto width = rawRenderedFrame->width; - const auto height = rawRenderedFrame->height; + const auto width = gBufferPositionIndex->width; + const auto height = gBufferPositionIndex->height; const uint32_t pixelX = std::min(static_cast(u * static_cast(width)), width - 1); const uint32_t pixelY = std::min(static_cast(v * static_cast(height)), height - 1); - auto *gBufferPositionIndex = engineFrame->getResourceAs(RID_GBUFFER_POSITION_INDEX); - if (!gBufferPositionIndex) { - return; - } - const auto picked = CTX.pickingService.pickEntityFromGBuffer(gBufferPositionIndex, pixelX, pixelY); CTX.selectionService.clearSelection(); CTX.selectionService.addSelected(picked.value_or(EMPTY_ENTITY)); diff --git a/src/context/editor/dock-spaces/viewport/GizmoSettingsPanel.cpp b/src/context/editor/dock-spaces/viewport/GizmoSettingsPanel.cpp index 0d209f37..3d2638d9 100644 --- a/src/context/editor/dock-spaces/viewport/GizmoSettingsPanel.cpp +++ b/src/context/editor/dock-spaces/viewport/GizmoSettingsPanel.cpp @@ -16,7 +16,7 @@ namespace Metal { gizmoGrid(); UIUtil::Spacing(); if (selectedEntityId != editorRepository->mainSelection && CTX.worldRepository.registry.all_of( - static_cast::entity_type>(editorRepository->mainSelection))) { + editorRepository->mainSelection)) { selectedEntity = CTX.worldRepository.getEntity(editorRepository->mainSelection); selectedEntityId = editorRepository->mainSelection; } diff --git a/src/context/editor/dock-spaces/viewport/GizmoSettingsPanel.h b/src/context/editor/dock-spaces/viewport/GizmoSettingsPanel.h index c9f89abd..aec3a185 100644 --- a/src/context/editor/dock-spaces/viewport/GizmoSettingsPanel.h +++ b/src/context/editor/dock-spaces/viewport/GizmoSettingsPanel.h @@ -7,7 +7,7 @@ #include "../../abstract/AbstractPanel.h" namespace Metal { - struct EntityComponent; + struct MetadataComponent; struct EditorRepository; class GizmoSettingsPanel final : public AbstractPanel { @@ -19,8 +19,8 @@ namespace Metal { static constexpr const char *SNAP_SCALE_OPTIONS = "0.5\0 1\0 2\0 5\0 10\0"; static constexpr std::array SNAP_SCALE_OPTIONS_A = {0.5, 1, 2, 5, 10}; EditorRepository *editorRepository = nullptr; - EntityComponent *selectedEntity = nullptr; - EntityID selectedEntityId = 0; + MetadataComponent *selectedEntity = nullptr; + entt::entity selectedEntityId = EMPTY_ENTITY; public: void onInitialize() override; diff --git a/src/context/editor/dock-spaces/viewport/ViewportHeaderPanel.cpp b/src/context/editor/dock-spaces/viewport/ViewportHeaderPanel.cpp index abc4a532..945b926e 100644 --- a/src/context/editor/dock-spaces/viewport/ViewportHeaderPanel.cpp +++ b/src/context/editor/dock-spaces/viewport/ViewportHeaderPanel.cpp @@ -16,15 +16,7 @@ namespace Metal { ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX() + 2, ImGui::GetCursorPosY() + 4)); gizmo->onSync(); ImGui::SameLine(); - int option = 0; - UIUtil::DynamicSpacing(365); - ImGui::SetNextItemWidth(100); - if (ImGui::Combo((id + "##entities").c_str(), &option, ComponentTypes::NAMES)) { - auto id = CTX.worldRepository.createEntity(); - CTX.worldRepository.createComponent(id, ComponentTypes::ValueOfIndex(option)); - CTX.selectionService.clearSelection(); - CTX.selectionService.addSelected(id); - } + UIUtil::DynamicSpacing(270); ImGui::SameLine(); cameraMode(); diff --git a/src/context/editor/dock-spaces/viewport/ViewportPanel.cpp b/src/context/editor/dock-spaces/viewport/ViewportPanel.cpp index 41b09ad7..4d283a47 100644 --- a/src/context/editor/dock-spaces/viewport/ViewportPanel.cpp +++ b/src/context/editor/dock-spaces/viewport/ViewportPanel.cpp @@ -6,18 +6,9 @@ #include "ViewportHeaderPanel.h" #include "EngineFramePanel.h" #include "../../../../context/ApplicationContext.h" -#include "../../../../service/descriptor/DescriptorInstance.h" -#include "../../../../service/framebuffer/FrameBufferInstance.h" #include "../../../../service/camera/Camera.h" #include "../../../../context/engine/frame-builder/EngineFrameBuilder.h" -#include "../../../../service/framebuffer/FrameBufferService.h" #include "../../../../enum/engine-definitions.h" -#include "../../../../dto/buffers/GlobalDataUBO.h" -#include "../../../../dto/buffers/TileInfoUBO.h" -#include "../../../../dto/buffers/LightData.h" -#include "../../../../dto/buffers/VolumeData.h" -#include "../../../../dto/buffers/MaterialData.h" - #include namespace Metal { @@ -42,7 +33,7 @@ namespace Metal { CTX.editorRepository.gizmoType = ImGuizmo::OPERATION::ROTATE; }), ShortcutDTO("Delete", ImGuiKey_Delete, [this]() { - std::vector entities; + std::vector entities; for (auto &entry: CTX.editorRepository.selected) { entities.push_back(entry.first); } @@ -50,13 +41,12 @@ namespace Metal { CTX.selectionService.clearSelection(); }), ShortcutDTO("Select All", ImGuiMod_Ctrl | ImGuiKey_A, [this]() { - std::vector entities; + std::vector entities; auto &storage = CTX.worldRepository.registry.storage(); for (auto it = storage.begin(); it != storage.end(); ++it) { auto entity = *it; - if (static_cast(entity) != WorldRepository::ROOT_ID && CTX.worldRepository.registry.all_of - (entity)) { - entities.push_back(static_cast(entity)); + if (CTX.worldRepository.registry.all_of(entity)) { + entities.push_back(entity); } } CTX.selectionService.addAllSelected(entities); @@ -68,10 +58,8 @@ namespace Metal { } void ViewportPanel::onSync() { - if (!CTX.engineRepository.isBaking) { - updateCamera(); - updateInputs(); - } + updateCamera(); + updateInputs(); headerPanel->onSync(); engineFramePanel->onSync(); diff --git a/src/context/editor/dock-spaces/world/WorldHeaderPanel.cpp b/src/context/editor/dock-spaces/world/WorldHeaderPanel.cpp new file mode 100644 index 00000000..98b04ce1 --- /dev/null +++ b/src/context/editor/dock-spaces/world/WorldHeaderPanel.cpp @@ -0,0 +1,35 @@ +#include "WorldHeaderPanel.h" + +#include "../../../../context/ApplicationContext.h" +#include "../../../../util/UIUtil.h" +#include "../../../../enum/ComponentType.h" + +namespace Metal { + void WorldHeaderPanel::onSync() { + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 120.f - UIUtil::ONLY_ICON_BUTTON_SIZE - 20.f); + ImGui::InputTextWithHint(("##hierarchySearch" + id).c_str(), "Search...", search, sizeof(search)); + ImGui::SameLine(); + ImGui::SetNextItemWidth(120.f); + if (ImGui::BeginCombo(("##hierarchyFilter" + id).c_str(), + selectedComponentType == -1 + ? "All" + : ComponentTypes::NameOf(static_cast(selectedComponentType)))) { + if (ImGui::Selectable("All", selectedComponentType == -1)) { + selectedComponentType = -1; + } + for (const auto &compDef: ComponentTypes::getComponents()) { + if (ImGui::Selectable((compDef.icon + compDef.name).c_str(), + selectedComponentType == static_cast(compDef.type))) { + selectedComponentType = static_cast(compDef.type); + } + } + ImGui::EndCombo(); + } + ImGui::SameLine(); + if (UIUtil::ButtonSimple(Icons::add + "##hierarchyAdd" + id, UIUtil::ONLY_ICON_BUTTON_SIZE, + UIUtil::ONLY_ICON_BUTTON_SIZE)) { + CTX.worldRepository.createEntity(); + } + UIUtil::RenderTooltip("Create entity"); + } +} // Metal diff --git a/src/context/editor/dock-spaces/hierarchy/HierarchyHeaderPanel.h b/src/context/editor/dock-spaces/world/WorldHeaderPanel.h similarity index 71% rename from src/context/editor/dock-spaces/hierarchy/HierarchyHeaderPanel.h rename to src/context/editor/dock-spaces/world/WorldHeaderPanel.h index e2078659..1e9f025a 100644 --- a/src/context/editor/dock-spaces/hierarchy/HierarchyHeaderPanel.h +++ b/src/context/editor/dock-spaces/world/WorldHeaderPanel.h @@ -3,11 +3,12 @@ #include "../../abstract/AbstractPanel.h" namespace Metal { - class HierarchyHeaderPanel final : public AbstractPanel { + class WorldHeaderPanel final : public AbstractPanel { public: void onSync() override; char search[512]; + int selectedComponentType = -1; }; } // Metal diff --git a/src/context/editor/dock-spaces/world/WorldPanel.cpp b/src/context/editor/dock-spaces/world/WorldPanel.cpp new file mode 100644 index 00000000..ac2265da --- /dev/null +++ b/src/context/editor/dock-spaces/world/WorldPanel.cpp @@ -0,0 +1,200 @@ +#include "WorldPanel.h" + +#include "WorldHeaderPanel.h" +#include "../../../../common/interface/Icons.h" +#include "../../../../util/UIUtil.h" +#include "../../../../context/ApplicationContext.h" +#include "../../../../repository/world/impl/MetadataComponent.h" +#include "../../../../enum/ComponentType.h" + +namespace Metal { + void WorldPanel::onInitialize() { + appendChild(headerPanel = new WorldHeaderPanel()); + world = &CTX.worldRepository; + editorRepository = &CTX.editorRepository; + + shortcuts = { + ShortcutDTO("Delete", ImGuiKey_Delete, [this]() { + std::vector entities; + for (auto &entry: CTX.editorRepository.selected) { + entities.push_back(entry.first); + } + CTX.worldRepository.deleteEntities(entities); + CTX.selectionService.clearSelection(); + }), + ShortcutDTO("Select All", ImGuiMod_Ctrl | ImGuiKey_A, [this]() { + std::vector entities; + for (auto entity : world->registry.view()) { + if (isMatched(entity)) { + entities.push_back(entity); + } + } + CTX.selectionService.addAllSelected(entities); + }), + ShortcutDTO("Save", ImGuiMod_Ctrl | ImGuiKey_S, [] { + CTX.save(); + }), + }; + } + + void WorldPanel::contextMenu() const { + if (ImGui::BeginPopupContextItem((id + "contextMenu").c_str())) { + if (ImGui::MenuItem("Delete")) { + std::vector entities; + for (auto &entry: CTX.editorRepository.selected) { + entities.push_back(entry.first); + } + CTX.worldRepository.deleteEntities(entities); + CTX.selectionService.clearSelection(); + } + ImGui::EndPopup(); + } + + if (isSomethingHovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { + ImGui::OpenPopup((id + "contextMenu").c_str()); + } + } + + void WorldPanel::onSync() { + isOnSearch = strlen(headerPanel->search) > 0 || headerPanel->selectedComponentType != -1; + isSomethingHovered = ImGui::IsItemHovered(); + onSyncChildren(); + ImGui::Separator(); + if (ImGui::BeginTable((id + "hierarchyTable").c_str(), 2, TABLE_FLAGS)) { + isSomethingHovered = isSomethingHovered || ImGui::IsItemHovered(); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); + ImGui::TableSetupColumn(Icons::visibility.c_str(), ImGuiTableColumnFlags_WidthFixed, 20.f); + ImGui::TableHeadersRow(); + + auto view = world->registry.view(); + for (const auto entity: view) { + renderNode(entity); + } + + ImGui::EndTable(); + } + if (!CTX.editorRepository.selected.empty()) { + contextMenu(); + } + } + + void WorldPanel::renderNode(const entt::entity entityId) { + MetadataComponent *node = world->getEntity(entityId); + if (node == nullptr || (isOnSearch && !isMatched(entityId))) { + return; + } + + applyRowStyle(entityId, node); + + if (processEntityNode(entityId, node)) { + renderEntityChildren(entityId); + ImGui::TreePop(); + } + } + + bool WorldPanel::processEntityNode(const entt::entity entityId, MetadataComponent *node) { + ImGui::TableNextRow(); + if (editorRepository->selected.contains(entityId)) { + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, editorRepository->accentU32); + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, editorRepository->accentU32); + } + + ImGui::TableNextColumn(); + const bool open = ImGui::TreeNodeEx(getNodeLabel(entityId).c_str(), getFlags(entityId)); + + handleDragDrop(entityId); + renderEntityColumns(entityId); + return open; + } + + void WorldPanel::applyRowStyle(const entt::entity entityId, MetadataComponent *node) const { + ImVec4 color = ImVec4(node->color.x, node->color.y, node->color.z, 1.0f); + if (world->culled.contains(entityId) || world->hiddenEntities.contains(entityId)) { + color.w = 0.5f; + } + ImGui::PushStyleColor(ImGuiCol_Text, color); + } + + std::string WorldPanel::getNodeLabel(const entt::entity entityId) const { + const auto node = world->getEntity(entityId); + return std::format("{} {}##{}{}", Icons::category, node->name, entt::to_integral(entityId), id); + } + + bool WorldPanel::isMatched(const entt::entity entityId) const { + const auto node = world->getEntity(entityId); + if (node == nullptr) return false; + bool matches = node->name.find(headerPanel->search) != std::string::npos; + if (headerPanel->selectedComponentType != -1) { + bool hasComponent = false; + for (const auto &compDef : ComponentTypes::getComponents()) { + if (static_cast(compDef.type) == headerPanel->selectedComponentType) { + hasComponent = compDef.getInspectable(*world, entityId) != nullptr; + break; + } + } + matches &= hasComponent; + } + return matches; + } + + void WorldPanel::renderEntityChildren(const entt::entity entityId) { + for (const auto &compDef: ComponentTypes::getComponents()) { + if (compDef.getInspectable(*world, entityId)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + constexpr ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | + ImGuiTreeNodeFlags_SpanFullWidth; + ImGui::TreeNodeEx((compDef.icon + " " + compDef.name + "##comp" + std::to_string(static_cast(entt::to_integral(entityId)))).c_str(), + flags); + + ImGui::TableNextColumn(); // Visibility column + } + } + } + + int WorldPanel::getFlags(const entt::entity entityId) const { + int flags = ImGuiTreeNodeFlags_SpanFullWidth; + if (isOnSearch) { + flags |= ImGuiTreeNodeFlags_DefaultOpen; + } + return flags; + } + + void WorldPanel::renderEntityColumns(const entt::entity entityId) const { + handleClick(entityId); + ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_Button, TRANSPARENT); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, PADDING); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0); + + const bool isVisible = !world->hiddenEntities.contains(entityId); + if (UIUtil::ButtonSimple((isVisible ? Icons::visibility : Icons::visibility_off) + ("##v") + + std::to_string(static_cast(entt::to_integral(entityId))) + id, 20, 15)) { + CTX.worldRepository.changeVisibility(entityId, !isVisible); + } + ImGui::PopStyleColor(); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(); // Pop Row Style (from applyRowStyle) + } + + void WorldPanel::handleClick(const entt::entity entityId) const { + if (ImGui::IsItemClicked()) { + if (const bool isMultiSelect = ImGui::IsKeyDown(ImGuiKey_LeftCtrl); !isMultiSelect) { + CTX.selectionService.clearSelection(); + } + CTX.selectionService.addSelected(entityId); + } + } + + void WorldPanel::handleDragDrop(const entt::entity entityId) { + const auto node = world->getEntity(entityId); + if (ImGui::BeginDragDropSource()) { + ImGui::SetDragDropPayload(id.c_str(), id.c_str(), sizeof(id.c_str())); + onDrag = entityId; + ImGui::Text("Dragging Node %s", node->getTitle()); + ImGui::EndDragDropSource(); + } + } +} // Metal diff --git a/src/context/editor/dock-spaces/world/WorldPanel.h b/src/context/editor/dock-spaces/world/WorldPanel.h new file mode 100644 index 00000000..a6e87e81 --- /dev/null +++ b/src/context/editor/dock-spaces/world/WorldPanel.h @@ -0,0 +1,58 @@ +#ifndef HIERARCHYPANEL_H +#define HIERARCHYPANEL_H +#include +#include + +#include "../../../../enum/engine-definitions.h" +#include "../../../../enum/ComponentType.h" +#include "../docks/AbstractDockPanel.h" + +namespace Metal { + struct EditorRepository; + struct WorldRepository; + struct AbstractComponent; + struct MetadataComponent; + class WorldHeaderPanel; + + class WorldPanel final : public AbstractDockPanel { + static constexpr auto TRANSPARENT = ImVec4(0, 0, 0, 0); + static constexpr auto PADDING = ImVec2(0, 0); + static constexpr auto TABLE_FLAGS = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg + | ImGuiTableFlags_NoBordersInBody; + WorldHeaderPanel *headerPanel = nullptr; + entt::entity onDrag = EMPTY_ENTITY; + bool isOnSearch = false; + WorldRepository *world = nullptr; + EditorRepository *editorRepository = nullptr; + bool isSomethingHovered = false; + + public: + void onInitialize() override; + + void contextMenu() const; + + void onSync() override; + + void renderNode(entt::entity entityId); + + bool processEntityNode(entt::entity entityId, MetadataComponent *node); + + void applyRowStyle(entt::entity entityId, MetadataComponent *node) const; + + std::string getNodeLabel(entt::entity entityId) const; + + bool isMatched(entt::entity entityId) const; + + void renderEntityChildren(entt::entity entityId); + + int getFlags(entt::entity entityId) const; + + void renderEntityColumns(entt::entity entityId) const; + + void handleClick(entt::entity entityId) const; + + void handleDragDrop(entt::entity entityId); + }; +} // Metal + +#endif //HIERARCHYPANEL_H diff --git a/src/context/editor/panel/FileImportModalPanel.cpp b/src/context/editor/panel/FileImportModalPanel.cpp index 170704ce..2e22bab1 100644 --- a/src/context/editor/panel/FileImportModalPanel.cpp +++ b/src/context/editor/panel/FileImportModalPanel.cpp @@ -13,14 +13,15 @@ namespace Metal { } void FileImportModalPanel::onSync() { - if (CTX.fileInspection.pendingImports.empty()) { + auto &editorRepository = CTX.editorRepository; + if (editorRepository.pendingImports.empty()) { isFirst = true; return; } if (isFirst) { formPanel->setInspection( - CTX.fileInspection.importSettingsMap.at(CTX.fileInspection.selectedFileForSettings).get()); + editorRepository.importSettingsMap.at(editorRepository.selectedFileForSettings).get()); isFirst = false; } @@ -32,7 +33,7 @@ namespace Metal { ImGui::SetNextWindowSizeConstraints(ImVec2(width, 400), ImVec2(width, maxHeight)); if (ImGui::Begin(("Import files?" + id + "importModal").c_str(), nullptr, - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove)) { + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove)) { if (ImGui::BeginTable((id + "ImportLayoutTable").c_str(), 2, ImGuiTableFlags_Resizable)) { ImGui::TableSetupColumn("FileList", ImGuiTableColumnFlags_WidthStretch, 0.4f); ImGui::TableSetupColumn("Settings", ImGuiTableColumnFlags_WidthStretch, 0.6f); @@ -49,16 +50,16 @@ namespace Metal { ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, 80.0f); ImGui::TableHeadersRow(); - for (const auto &filePath: CTX.fileInspection.pendingImports) { + for (const auto &filePath: editorRepository.pendingImports) { std::filesystem::path p(filePath); ImGui::TableNextRow(); ImGui::TableNextColumn(); - bool isSelected = (CTX.fileInspection.selectedFileForSettings == filePath); + bool isSelected = (editorRepository.selectedFileForSettings == filePath); if (ImGui::Selectable(p.filename().string().c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns)) { - CTX.fileInspection.selectedFileForSettings = filePath; + editorRepository.selectedFileForSettings = filePath; formPanel->setInspection( - CTX.fileInspection.importSettingsMap.at(CTX.fileInspection.selectedFileForSettings). + editorRepository.importSettingsMap.at(editorRepository.selectedFileForSettings). get()); } ImGui::TableNextColumn(); @@ -75,7 +76,7 @@ namespace Metal { ImGui::TableNextColumn(); ImGui::Text("Settings: %s", - std::filesystem::path(CTX.fileInspection.selectedFileForSettings).filename().string(). + std::filesystem::path(editorRepository.selectedFileForSettings).filename().string(). c_str()); ImGui::BeginChild((id + "SettingsFormChild").c_str(), ImVec2(0, maxHeight - 180.0f), true); formPanel->onSync(); @@ -89,20 +90,20 @@ namespace Metal { ImGui::Spacing(); if (ImGui::Button(("Approve" + id + "approveImport").c_str(), ImVec2(120, 0))) { - for (const std::string &file: CTX.fileInspection.pendingImports) { - CTX.fileImporterService.importFile(CTX.fileInspection.targetImportDirectory->absolutePath, file, - CTX.fileInspection.importSettingsMap.at(file)); + for (const std::string &file: editorRepository.pendingImports) { + CTX.fileImporterService.importFile(editorRepository.targetImportDirectory->absolutePath, file, + editorRepository.importSettingsMap.at(file)); } CTX.notificationService.pushMessage("Importing files...", NotificationSeverities::WARNING); - FilesService::GetEntries(CTX.fileInspection.targetImportDirectory); - CTX.fileInspection.pendingImports.clear(); - CTX.fileInspection.importSettingsMap.clear(); + FilesService::GetEntries(editorRepository.targetImportDirectory); + editorRepository.pendingImports.clear(); + editorRepository.importSettingsMap.clear(); formPanel->resetForm(); } ImGui::SameLine(); if (ImGui::Button(("Cancel" + id + "cancel").c_str(), ImVec2(120, 0))) { - CTX.fileInspection.pendingImports.clear(); - CTX.fileInspection.importSettingsMap.clear(); + editorRepository.pendingImports.clear(); + editorRepository.importSettingsMap.clear(); formPanel->resetForm(); } } diff --git a/src/context/engine/EngineContext.cpp b/src/context/engine/EngineContext.cpp index 1f011c76..4b8d6c85 100644 --- a/src/context/engine/EngineContext.cpp +++ b/src/context/engine/EngineContext.cpp @@ -3,11 +3,8 @@ #include "../../enum/EngineResourceIDs.h" #include "../../context/ApplicationContext.h" #include "../../service/buffer/BufferInstance.h" -#include "../../service/descriptor/DescriptorBinding.h" -#include "../../service/voxel/SVOInstance.h" #include "../../service/camera/Camera.h" -#include "../../service/framebuffer/FrameBufferInstance.h" -#include "../../service/texture/TextureInstance.h" +#include "../../repository/world/components/TransformComponent.h" namespace Metal { void EngineContext::resetPathTracerAccumulationCount() const { @@ -15,34 +12,6 @@ namespace Metal { } void EngineContext::onInitialize() { - CTX.worldGridService.onSync(); - } - - void EngineContext::updateTileData() { - if (CTX.worldGridRepository.hasMainTileChanged) { - unsigned int i = 0; - std::vector bindings{}; - for (auto *tile: CTX.worldGridRepository.getLoadedTiles()) { - if (tile != nullptr) { - const auto *svo = CTX.streamingService.streamSVO(tile->id); - if (svo != nullptr) { - tileInfoUBO.tileCenterValid[i] = glm::vec4(tile->x, 0, - tile->z, 1); - tileInfoUBO.voxelBufferOffset[i] = svo->voxelBufferOffset; - i++; - } - } - } - - for (unsigned int j = i; j < 9; j++) { - tileInfoUBO.tileCenterValid[i].w = 0; - } - - if (i > 0) { - currentFrame->getResourceAs(RID_TILE_INFO)->update(tileInfoUBO.tileCenterValid.data()); - } - CTX.worldGridRepository.hasMainTileChanged = false; - } } void EngineContext::updateCurrentTime() { @@ -69,25 +38,15 @@ namespace Metal { updateCurrentTime(); CTX.transformService.onSync(); - CTX.worldGridService.onSync(); CTX.streamingService.onSync(); + CTX.rayTracingService.onSync(); CTX.cameraService.onSync(); + CTX.lightService.onSync(); + CTX.volumeService.onSync(); for (auto *frame: registeredFrames) { if (frame->getShouldRender()) { currentFrame = frame; - - updateTileData(); - if (updateLights || isFirstFrame) { - CTX.lightService.onSync(); - } - - if (updateVolumes || isFirstFrame) { - CTX.volumeService.onSync(); - } - - isFirstFrame = false; - updateGlobalData(); currentFrame->onSync(); @@ -95,16 +54,12 @@ namespace Metal { } } - CTX.rayTracingService.onSync(); - - setUpdateLights(false); setCameraUpdated(false); setGISettingsUpdated(false); } void EngineContext::updateGlobalData() { auto &camera = CTX.worldRepository.camera; - auto *fbo = currentFrame->getResourceAs( RID_POST_PROCESSING_FBO); globalDataUBO.previousProjView = globalDataUBO.projView; globalDataUBO.viewMatrix = camera.viewMatrix; globalDataUBO.projectionMatrix = camera.projectionMatrix; @@ -118,15 +73,12 @@ namespace Metal { CTX.engineRepository.pathTracerAccumulationCount++; globalDataUBO.pathTracerAccumulationCount = CTX.engineRepository.pathTracerAccumulationCount; globalDataUBO.globalFrameCount++; - globalDataUBO.outputRes = {fbo->bufferWidth, fbo->bufferHeight}; globalDataUBO.pathTracerMaxSamples = CTX.engineRepository.pathTracerMaxSamples; - globalDataUBO.denoiserEnabled = CTX.engineRepository.denoiserEnabled && (globalDataUBO.debugFlag == LIT || globalDataUBO.debugFlag == LIGHTING_ONLY)? 1 : 0; + globalDataUBO.denoiserEnabled = CTX.engineRepository.denoiserEnabled && ( + globalDataUBO.debugFlag == LIT || globalDataUBO.debugFlag == LIGHTING_ONLY) + ? 1 + : 0; - if (CTX.engineRepository.incrementTime) { - CTX.engineRepository.elapsedTime += .0005f * CTX.engineRepository.elapsedTimeSpeed; - setGISettingsUpdated(true); - updateLights = true; - } CTX.lightService.computeSunInfo(); globalDataUBO.sunPosition = CTX.lightService.getSunPosition(); globalDataUBO.sunColor = CTX.lightService.getSunColor(); diff --git a/src/context/engine/EngineContext.h b/src/context/engine/EngineContext.h index f9e63bcb..79e99f4b 100644 --- a/src/context/engine/EngineContext.h +++ b/src/context/engine/EngineContext.h @@ -15,33 +15,13 @@ using TimePoint = std::chrono::time_point; namespace Metal { class EngineContext final : public AbstractRuntimeComponent { GlobalDataUBO globalDataUBO{}; - TileInfoUBO tileInfoUBO{}; long long start = -1; bool cameraUpdated = true; - bool updateLights = true; - bool updateVolumes = true; bool giSettingsUpdated = true; - bool isFirstFrame = true; public: GlobalDataUBO &getGlobalDataUBO() { return globalDataUBO; } - void setUpdateLights(const bool val) { - updateLights = val; - } - - [[nodiscard]] bool isUpdateLights() const { - return updateLights; - } - - void setUpdateVolumes(const bool val) { - updateVolumes = val; - } - - [[nodiscard]] bool isUpdateVolumes() const { - return updateVolumes; - } - void setCameraUpdated(const bool val) { cameraUpdated = val; } @@ -62,13 +42,8 @@ namespace Metal { void onInitialize() override; - void updateTileData(); - void updateCurrentTime(); - explicit EngineContext() : AbstractRuntimeComponent() { - } - long long currentTimeMs = 0; TimePoint currentTime; TimePoint previousTime = Clock::now(); diff --git a/src/context/engine/compute-pass/impl/AccumulationPass.cpp b/src/context/engine/compute-pass/impl/AccumulationPass.cpp deleted file mode 100644 index 9effbae3..00000000 --- a/src/context/engine/compute-pass/impl/AccumulationPass.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "AccumulationPass.h" -#include "../../../ApplicationContext.h" -#include "../../../../service/pipeline/PipelineBuilder.h" -#include "../../../../service/texture/TextureInstance.h" -#include "../../../../enum/EngineResourceIDs.h" - -namespace Metal { - void AccumulationPass::onInitialize() { - PipelineBuilder builder = PipelineBuilder::Of("PathTracerAccumulation.comp") - .addBufferBinding(getScopedResourceId(RID_GLOBAL_DATA)) - .addStorageImageBinding(getScopedResourceId(RID_RAW_RENDERED_FRAME)) - .addStorageImageBinding(getScopedResourceId(RID_ACCUMULATED_FRAME)); - pipelineInstance = CTX.pipelineService.createPipeline(builder); - } - - void AccumulationPass::onSync() { - auto *accumulatedFrame = frame->getResourceAs(RID_ACCUMULATED_FRAME); - auto *rawRenderedFrame = frame->getResourceAs(RID_RAW_RENDERED_FRAME); - syncWriting(accumulatedFrame->vkImage); - recordImageDispatch(accumulatedFrame, 8, 8); - endWriting(rawRenderedFrame->vkImage); - } -} // Metal diff --git a/src/context/engine/compute-pass/impl/AccumulationPass.h b/src/context/engine/compute-pass/impl/AccumulationPass.h deleted file mode 100644 index e319ee7b..00000000 --- a/src/context/engine/compute-pass/impl/AccumulationPass.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ACCUMULATIONPASS_H -#define ACCUMULATIONPASS_H -#include "../AbstractComputePass.h" - -namespace Metal { - class AccumulationPass final : public AbstractComputePass { - public: - explicit AccumulationPass(const std::string &id) : AbstractComputePass(id) {} - - void onSync() override; - - void onInitialize() override; - - }; -} // Metal - -#endif //ACCUMULATIONPASS_H diff --git a/src/context/engine/compute-pass/impl/HWRayTracingPass.cpp b/src/context/engine/compute-pass/impl/HWRayTracingPass.cpp index 25055e11..dcba2bfa 100644 --- a/src/context/engine/compute-pass/impl/HWRayTracingPass.cpp +++ b/src/context/engine/compute-pass/impl/HWRayTracingPass.cpp @@ -16,12 +16,11 @@ namespace Metal { .setPushConstantsSize(sizeof(HWRayTracingPushConstant)) .addBufferBinding(getScopedResourceId(RID_GLOBAL_DATA)) .addAccelerationStructureBinding(CTX.rayTracingService.getTLAS()) - .addStorageImageBinding(getScopedResourceId(RID_RAW_RENDERED_FRAME)) + .addStorageImageBinding(getScopedResourceId(RID_ACCUMULATED_FRAME)) .addStorageImageBinding(getScopedResourceId(RID_GBUFFER_POSITION_INDEX)) .addStorageImageBinding(getScopedResourceId(RID_GBUFFER_NORMAL)) .addBufferBinding(getScopedResourceId(RID_LIGHT_BUFFER)) .addBufferBinding(getScopedResourceId(RID_VOLUMES_BUFFER)) - .addBufferBinding(getScopedResourceId(RID_MATERIAL_BUFFER)) .addBufferBinding(getScopedResourceId(RID_MESH_METADATA_BUFFER)) .addCombinedImageSamplerBinding(CTX.vulkanContext.vkImageSampler, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1000); @@ -29,37 +28,21 @@ namespace Metal { } void HWRayTracingPass::onSync() { - bool anyMeshes = false; - auto view = CTX.worldRepository.registry.view(); - for (auto entity: view) { - CTX.streamingService.streamMesh(view.get(entity).meshId); - anyMeshes = true; - } - - rawRenderedFrame = frame->getResourceAs(RID_RAW_RENDERED_FRAME); - accumulatedFrame = frame->getResourceAs(RID_ACCUMULATED_FRAME); - gBufferPositionIndex = frame->getResourceAs(RID_GBUFFER_POSITION_INDEX); - gBufferNormal = frame->getResourceAs(RID_GBUFFER_NORMAL); - previousColor = frame->getResourceAs(RID_PREVIOUS_COLOR); - previousPositionIndex = frame->getResourceAs(RID_PREVIOUS_POSITION_INDEX); - previousNormal = frame->getResourceAs(RID_PREVIOUS_NORMAL); + auto *accumulatedFrame = frame->getResourceAs(RID_ACCUMULATED_FRAME); + auto *gBufferPositionIndex = frame->getResourceAs(RID_GBUFFER_POSITION_INDEX); + auto *gBufferNormal = frame->getResourceAs(RID_GBUFFER_NORMAL); + auto *previousPositionIndex = frame->getResourceAs(RID_PREVIOUS_POSITION_INDEX); + auto *previousNormal = frame->getResourceAs(RID_PREVIOUS_NORMAL); - bool worldChanged = CTX.engineContext.isUpdateLights() || CTX.worldGridService.isNotFrozen(); - if (isFirstRun || CTX.engineContext.isCameraUpdated() || CTX.engineContext.isGISettingsUpdated() || - worldChanged) { - CTX.worldGridService.freezeVersion(); - clearTexture(rawRenderedFrame->vkImage); + if (isFirstRun || CTX.engineContext.isCameraUpdated() || CTX.engineContext.isGISettingsUpdated()) { clearTexture(accumulatedFrame->vkImage); CTX.engineContext.resetPathTracerAccumulationCount(); isFirstRun = false; } - // Copy current to previous before writing new values - copyTexture(rawRenderedFrame, previousColor); copyTexture(gBufferPositionIndex, previousPositionIndex); copyTexture(gBufferNormal, previousNormal); - startWriting(rawRenderedFrame->vkImage); startWriting(gBufferPositionIndex->vkImage); startWriting(gBufferNormal->vkImage); @@ -72,7 +55,7 @@ namespace Metal { pushConstant.pathTracerSamples = CTX.engineRepository.pathTracerSamples; pushConstant.pathTracerBounces = CTX.engineRepository.pathTracerBounces; pushConstant.pathTracingEmissiveFactor = CTX.engineRepository.pathTracingEmissiveFactor; - pushConstant.shouldTrace = CTX.rayTracingService.isReady() && anyMeshes ? 1 : 0; + pushConstant.shouldTrace = CTX.rayTracingService.isReady(); pushConstant.dofEnabled = CTX.engineRepository.dofEnabled; pushConstant.dofFocusDistance = CTX.engineRepository.dofFocusDistance; @@ -87,11 +70,11 @@ namespace Metal { &pipelineInstance->missRegion, &pipelineInstance->hitRegion, &pipelineInstance->callableRegion, - rawRenderedFrame->width, - rawRenderedFrame->height, + accumulatedFrame->width, + accumulatedFrame->height, 1); - endWriting(rawRenderedFrame->vkImage); + endWriting(accumulatedFrame->vkImage); endWriting(gBufferPositionIndex->vkImage); endWriting(gBufferNormal->vkImage); } diff --git a/src/context/engine/compute-pass/impl/HWRayTracingPass.h b/src/context/engine/compute-pass/impl/HWRayTracingPass.h index 55e50e7a..bdd574e5 100644 --- a/src/context/engine/compute-pass/impl/HWRayTracingPass.h +++ b/src/context/engine/compute-pass/impl/HWRayTracingPass.h @@ -7,13 +7,6 @@ namespace Metal { class HWRayTracingPass final : public AbstractComputePass { bool isFirstRun = true; HWRayTracingPushConstant pushConstant{}; - TextureInstance *rawRenderedFrame = nullptr; - TextureInstance *accumulatedFrame = nullptr; - TextureInstance *gBufferPositionIndex = nullptr; - TextureInstance *gBufferNormal = nullptr; - TextureInstance *previousColor = nullptr; - TextureInstance *previousPositionIndex = nullptr; - TextureInstance *previousNormal = nullptr; public: explicit HWRayTracingPass(const std::string &id) : AbstractComputePass(id) { diff --git a/src/context/engine/frame-builder/EngineFrame.cpp b/src/context/engine/frame-builder/EngineFrame.cpp index 1953f907..6f714a1b 100644 --- a/src/context/engine/frame-builder/EngineFrame.cpp +++ b/src/context/engine/frame-builder/EngineFrame.cpp @@ -3,7 +3,8 @@ #include "../passes/AbstractPass.h" namespace Metal { - EngineFrame::EngineFrame(std::string id) : id(std::move(id)) {} + EngineFrame::EngineFrame(std::string id) : id(std::move(id)) { + } void EngineFrame::addResource(RuntimeResource *resource) { if (resource) { @@ -33,4 +34,8 @@ namespace Metal { } passes.clear(); } + + std::string EngineFrame::getScopedResourceId(const std::string &resourceId) const { + return id + "_" + resourceId; + } } diff --git a/src/context/engine/frame-builder/EngineFrame.h b/src/context/engine/frame-builder/EngineFrame.h index 4cf326e7..b86e3edc 100644 --- a/src/context/engine/frame-builder/EngineFrame.h +++ b/src/context/engine/frame-builder/EngineFrame.h @@ -11,6 +11,7 @@ namespace Metal { class CommandBufferRecorder; class AbstractPass; + class EngineFrame { std::string id; bool shouldRender = false; @@ -30,7 +31,7 @@ namespace Metal { template T *getResourceAs(const std::string &resourceId) { - auto it = resources.find(id + "_" +resourceId); + auto it = resources.find(getScopedResourceId(resourceId)); if (it != resources.end()) { return dynamic_cast(it->second); } @@ -39,7 +40,8 @@ namespace Metal { void addPass(CommandBufferRecorder *recorder, const std::vector &p); - [[nodiscard]] const std::vector > > &getPasses() const { + [[nodiscard]] const std::vector > > & + getPasses() const { return passes; } @@ -47,7 +49,10 @@ namespace Metal { void dispose(); - void destroy() {} + void destroy() { + } + + [[nodiscard]] std::string getScopedResourceId(const std::string &resourceId) const; }; } diff --git a/src/context/engine/frame-builder/EngineFrameBuilder.cpp b/src/context/engine/frame-builder/EngineFrameBuilder.cpp index 51a69988..9b870737 100644 --- a/src/context/engine/frame-builder/EngineFrameBuilder.cpp +++ b/src/context/engine/frame-builder/EngineFrameBuilder.cpp @@ -8,7 +8,7 @@ #include "EngineFrame.h" #include "../../ApplicationContext.h" #include "../passes/CommandBufferRecorder.h" -#include "../render-pass/impl/tools/SelectedDotPass.h" +#include "../render-pass/impl/tools/SelectionOutlinePass.h" namespace Metal { EngineFrameBuilder::EngineFrameBuilder(std::string frameId) : frameId(std::move(frameId)) { @@ -28,8 +28,8 @@ namespace Metal { return *this; } - EngineFrameBuilder &EngineFrameBuilder::addColor(std::string id, VkFormat format, VkImageUsageFlagBits usage) { - dynamic_cast(currentBuilder.get())->addColor(frameId + "_" + id, format, usage, nullptr); + EngineFrameBuilder &EngineFrameBuilder::addColor(VkFormat format, VkImageUsageFlagBits usage) { + dynamic_cast(currentBuilder.get())->addColor(format, usage, nullptr); return *this; } @@ -54,7 +54,9 @@ namespace Metal { EngineFrameBuilder &EngineFrameBuilder::addBuffer(const std::string &id, VkDeviceSize size, VkMemoryPropertyFlags properties, BufferType type) { currentBuilder = std::make_shared( - frameId + "_" + id, size, type == UNIFORM_BUFFER ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + frameId + "_" + id, size, type == UNIFORM_BUFFER + ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, properties, type); builders.push_back(currentBuilder); return *this; @@ -68,8 +70,9 @@ namespace Metal { } EngineFrameBuilder &EngineFrameBuilder::addCommandBuffer(const std::string &id, const std::string &framebufferId, - const bool clearBuffer) { - currentBuilder = std::make_shared(frameId + "_" + id, frameId + "_" + framebufferId, clearBuffer); + const bool clearBuffer) { + currentBuilder = std::make_shared( + frameId + "_" + id, frameId + "_" + framebufferId, clearBuffer); builders.push_back(currentBuilder); return *this; } diff --git a/src/context/engine/frame-builder/EngineFrameBuilder.h b/src/context/engine/frame-builder/EngineFrameBuilder.h index 58584b87..fd42fc69 100644 --- a/src/context/engine/frame-builder/EngineFrameBuilder.h +++ b/src/context/engine/frame-builder/EngineFrameBuilder.h @@ -29,7 +29,7 @@ namespace Metal { EngineFrameBuilder &addFramebuffer(const std::string &id); - EngineFrameBuilder &addColor(std::string id, VkFormat format, VkImageUsageFlagBits usage); + EngineFrameBuilder &addColor(VkFormat format, VkImageUsageFlagBits usage); EngineFrameBuilder &addDepth(); diff --git a/src/context/engine/frame-builder/structures/FramebufferBuilder.cpp b/src/context/engine/frame-builder/structures/FramebufferBuilder.cpp index 6073ff99..02d973f0 100644 --- a/src/context/engine/frame-builder/structures/FramebufferBuilder.cpp +++ b/src/context/engine/frame-builder/structures/FramebufferBuilder.cpp @@ -18,7 +18,7 @@ namespace Metal { fbo = framebufferService.createFrameBuffer(id, w, h, clearColor); for (const auto& attachment : attachments) { - framebufferService.createAttachment(attachment.id.c_str(), attachment.format, attachment.usage, fbo); + framebufferService.createAttachment(attachment.format, attachment.usage, fbo); } if (hasDepth) { diff --git a/src/context/engine/frame-builder/structures/FramebufferBuilder.h b/src/context/engine/frame-builder/structures/FramebufferBuilder.h index 80f7d3b0..f5ebead5 100644 --- a/src/context/engine/frame-builder/structures/FramebufferBuilder.h +++ b/src/context/engine/frame-builder/structures/FramebufferBuilder.h @@ -9,7 +9,6 @@ namespace Metal { struct FrameBufferInstance; struct FramebufferAttachmentBuilder { - std::string id; VkFormat format; VkImageUsageFlagBits usage; FrameBufferInstance *framebuffer; @@ -29,9 +28,9 @@ namespace Metal { ResourceType getType() override; - void addColor(std::string id, VkFormat format, VkImageUsageFlagBits usage, + void addColor( VkFormat format, VkImageUsageFlagBits usage, FrameBufferInstance *framebuffer) { - attachments.push_back({std::move(id), format, usage, framebuffer}); + attachments.push_back({ format, usage, framebuffer}); } void addDepth() { diff --git a/src/context/engine/frame-builder/structures/PassBuilder.cpp b/src/context/engine/frame-builder/structures/PassBuilder.cpp index e0db905b..56ce5f6a 100644 --- a/src/context/engine/frame-builder/structures/PassBuilder.cpp +++ b/src/context/engine/frame-builder/structures/PassBuilder.cpp @@ -1,12 +1,12 @@ #include "PassBuilder.h" #include "../../render-pass/impl/PostProcessingPass.h" #include "../../compute-pass/impl/HWRayTracingPass.h" -#include "../../compute-pass/impl/AccumulationPass.h" #include "../../compute-pass/impl/TemporalAccumulationPass.h" #include "../../compute-pass/impl/SpatialFilterPass.h" -#include "../../render-pass/impl/tools/SelectedDotPass.h" +#include "../../render-pass/impl/tools/SelectionOutlinePass.h" #include "../../render-pass/impl/tools/GridPass.h" #include "../../render-pass/impl/tools/IconsPass.h" +#include "../../render-pass/impl/tools/SelectionIDPass.h" namespace Metal { RuntimeResource* PassBuilder::build() { @@ -15,18 +15,18 @@ namespace Metal { return new PostProcessingPass(id); case RAY_TRACING: return new HWRayTracingPass(id); - case ACCUMULATION: - return new AccumulationPass(id); case TEMPORAL_ACCUMULATION: return new TemporalAccumulationPass(id); case SPATIAL_FILTER: return new SpatialFilterPass(id); - case SELECTED_DOT: - return new SelectedDotPass(id); + case SELECTION_OUTLINE: + return new SelectionOutlinePass(id); case GRID: return new GridPass(id); case ICONS: return new IconsPass(id); + case SELECTION_ID: + return new SelectionIDPass(id); default: return nullptr; } diff --git a/src/context/engine/passes/AbstractPass.cpp b/src/context/engine/passes/AbstractPass.cpp index 14d18725..31c60932 100644 --- a/src/context/engine/passes/AbstractPass.cpp +++ b/src/context/engine/passes/AbstractPass.cpp @@ -79,9 +79,6 @@ namespace Metal { } std::string AbstractPass::getScopedResourceId(const std::string &id) const { - if (frame != nullptr) { - return frame->getId() + "_" + id; - } - return id; + return frame->getScopedResourceId(id); } } diff --git a/src/context/engine/render-pass/impl/tools/SelectedDotPass.cpp b/src/context/engine/render-pass/impl/tools/SelectionIDPass.cpp similarity index 50% rename from src/context/engine/render-pass/impl/tools/SelectedDotPass.cpp rename to src/context/engine/render-pass/impl/tools/SelectionIDPass.cpp index 267efdab..f34d9bee 100644 --- a/src/context/engine/render-pass/impl/tools/SelectedDotPass.cpp +++ b/src/context/engine/render-pass/impl/tools/SelectionIDPass.cpp @@ -1,4 +1,4 @@ -#include "SelectedDotPass.h" +#include "SelectionIDPass.h" #include "../../../../../context/ApplicationContext.h" #include "../../../../../repository/world/components/TransformComponent.h" @@ -7,38 +7,34 @@ #include "../../../../../enum/EngineResourceIDs.h" namespace Metal { - void SelectedDotPass::onInitialize() { + void SelectionIDPass::onInitialize() { PipelineBuilder builder = PipelineBuilder::Of( - getScopedResourceId(RID_POST_PROCESSING_FBO), - "tools/SelectedDot.vert", - "tools/SelectedDot.frag" + getScopedResourceId(RID_SELECTION_FBO), + "tools/SelectionID.vert", + "tools/SelectionID.frag" ) - .setBlendEnabled() .setPrepareForMesh() - .setCullMode(VK_CULL_MODE_BACK_BIT) + .setCullMode(VK_CULL_MODE_NONE) .setPushConstantsSize(sizeof(SelectedDotPushConstant)) - .addBufferBinding(getScopedResourceId(RID_GLOBAL_DATA)) - .addStorageImageBinding(getScopedResourceId(RID_GBUFFER_POSITION_INDEX)); + .addBufferBinding(getScopedResourceId(RID_GLOBAL_DATA)); pipelineInstance = CTX.pipelineService.createPipeline(builder); } - bool SelectedDotPass::shouldRun() { + bool SelectionIDPass::shouldRun() { return !CTX.editorRepository.selected.empty(); } - void SelectedDotPass::onSync() { + void SelectionIDPass::onSync() { auto &worldRepository = CTX.worldRepository; - for (const auto &pair: CTX.editorRepository.selected) { - if (!pair.second) { + for (auto const& [entityId, selected] : CTX.editorRepository.selected) { + if (!selected) { continue; } - const EntityID entityId = pair.first; - const auto entity = static_cast(entityId); - if (!worldRepository.registry.all_of(entity) || !worldRepository.registry.all_of(entity)) { + if (!worldRepository.registry.all_of(entityId) || !worldRepository.registry.all_of(entityId)) { continue; } - const auto &mesh = worldRepository.registry.get(entity); + const auto &mesh = worldRepository.registry.get(entityId); if (mesh.meshId.empty()) { continue; } @@ -46,16 +42,13 @@ namespace Metal { continue; } - const auto *meshInstance = CTX.streamingService.streamMesh(mesh.meshId); + const auto *meshInstance = CTX.meshService.stream(mesh.meshId); if (!meshInstance) { continue; } - pushConstant.model = worldRepository.registry.get(entity).model; - pushConstant.selectionColor.x = CTX.editorRepository.selectionColor.x; - pushConstant.selectionColor.y = CTX.editorRepository.selectionColor.y; - pushConstant.selectionColor.z = CTX.editorRepository.selectionColor.z; - pushConstant.selectionColor.w = CTX.editorRepository.selectionOutlineThickness; + pushConstant.model = worldRepository.registry.get(entityId).model; + pushConstant.selectionColor = glm::vec4(CTX.editorRepository.selectionColor, CTX.editorRepository.selectionOutlineThickness); pushConstant.renderIndex = mesh.renderIndex; recordPushConstant(&pushConstant); diff --git a/src/context/engine/render-pass/impl/tools/SelectionIDPass.h b/src/context/engine/render-pass/impl/tools/SelectionIDPass.h new file mode 100644 index 00000000..31957bac --- /dev/null +++ b/src/context/engine/render-pass/impl/tools/SelectionIDPass.h @@ -0,0 +1,22 @@ +#ifndef SELECTIONIDPASS_H +#define SELECTIONIDPASS_H + +#include "../../AbstractRenderPass.h" +#include "../../../../../dto/push-constant/SelectedDotPushConstant.h" + +namespace Metal { + class SelectionIDPass final : public AbstractRenderPass { + SelectedDotPushConstant pushConstant{}; + + public: + explicit SelectionIDPass(const std::string &id) : AbstractRenderPass(id) {} + + void onInitialize() override; + + bool shouldRun() override; + + void onSync() override; + }; +} // Metal + +#endif // SELECTIONIDPASS_H diff --git a/src/context/engine/render-pass/impl/tools/SelectionOutlinePass.cpp b/src/context/engine/render-pass/impl/tools/SelectionOutlinePass.cpp new file mode 100644 index 00000000..6e1ca4a4 --- /dev/null +++ b/src/context/engine/render-pass/impl/tools/SelectionOutlinePass.cpp @@ -0,0 +1,37 @@ +#include "SelectionOutlinePass.h" + +#include "../../../../../context/ApplicationContext.h" +#include "../../../../../repository/world/components/TransformComponent.h" +#include "../../../../../dto/push-constant/SelectedDotPushConstant.h" +#include "../../../../../service/pipeline/PipelineBuilder.h" +#include "../../../../../enum/EngineResourceIDs.h" + +namespace Metal { + void SelectionOutlinePass::onInitialize() { + PipelineBuilder builder = PipelineBuilder::Of( + getScopedResourceId(RID_POST_PROCESSING_FBO), + "QUAD.vert", + "tools/SelectedDot.frag" + ) + .setBlendEnabled() + .setPushConstantsSize(sizeof(SelectedDotPushConstant)) + .addBufferBinding(getScopedResourceId(RID_GLOBAL_DATA)) + .addFboBinding(getScopedResourceId(RID_SELECTION_FBO), 0); + pipelineInstance = CTX.pipelineService.createPipeline(builder); + } + + bool SelectionOutlinePass::shouldRun() { + return !CTX.editorRepository.selected.empty(); + } + + void SelectionOutlinePass::onSync() { + + pushConstant.selectionColor.x = CTX.editorRepository.selectionColor.x; + pushConstant.selectionColor.y = CTX.editorRepository.selectionColor.y; + pushConstant.selectionColor.z = CTX.editorRepository.selectionColor.z; + pushConstant.selectionColor.w = CTX.editorRepository.selectionOutlineThickness; + + recordPushConstant(&pushConstant); + recordDrawSimpleInstanced(3, 1); + } +} // Metal diff --git a/src/context/engine/render-pass/impl/tools/SelectedDotPass.h b/src/context/engine/render-pass/impl/tools/SelectionOutlinePass.h similarity index 71% rename from src/context/engine/render-pass/impl/tools/SelectedDotPass.h rename to src/context/engine/render-pass/impl/tools/SelectionOutlinePass.h index f9a8ad0e..2e620341 100644 --- a/src/context/engine/render-pass/impl/tools/SelectedDotPass.h +++ b/src/context/engine/render-pass/impl/tools/SelectionOutlinePass.h @@ -5,11 +5,11 @@ #include "../../../../../dto/push-constant/SelectedDotPushConstant.h" namespace Metal { - class SelectedDotPass final : public AbstractRenderPass { + class SelectionOutlinePass final : public AbstractRenderPass { SelectedDotPushConstant pushConstant{}; public: - explicit SelectedDotPass(const std::string &id) : AbstractRenderPass(id) {} + explicit SelectionOutlinePass(const std::string &id) : AbstractRenderPass(id) {} void onInitialize() override; diff --git a/src/context/vulkan/VulkanContext.cpp b/src/context/vulkan/VulkanContext.cpp index e5cb97b8..c2ef2593 100644 --- a/src/context/vulkan/VulkanContext.cpp +++ b/src/context/vulkan/VulkanContext.cpp @@ -281,11 +281,9 @@ namespace Metal { createMemoryAllocator(); createCommandPool(); createDescriptorPool(); - CTX.framebufferService.createSampler(false, vkImageSampler); + CTX.textureService.createSampler(false, vkImageSampler, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + CTX.textureService.createSampler(true, vkTextureSampler, VK_SAMPLER_ADDRESS_MODE_REPEAT); // ------- CORE INITIALIZATION - - // ------- REPOSITORY INITIALIZATION - // ------- REPOSITORY INITIALIZATION } void VulkanContext::dispose() const { @@ -296,6 +294,7 @@ namespace Metal { CTX.rayTracingService.destroyAccelerationStructures(); vkDestroySampler(device.device, vkImageSampler, nullptr); + vkDestroySampler(device.device, vkTextureSampler, nullptr); vkDestroyDescriptorPool(CTX.vulkanContext.device.device, descriptorPool, nullptr); diff --git a/src/context/vulkan/VulkanContext.h b/src/context/vulkan/VulkanContext.h index 5084fcfd..2f74c8e4 100644 --- a/src/context/vulkan/VulkanContext.h +++ b/src/context/vulkan/VulkanContext.h @@ -69,6 +69,7 @@ namespace Metal { VkCommandPool commandPool = VK_NULL_HANDLE; VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingPipelineProperties{}; VkSampler vkImageSampler = VK_NULL_HANDLE; + VkSampler vkTextureSampler = VK_NULL_HANDLE; PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR = nullptr; PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR = nullptr; diff --git a/src/dto/buffers/GlobalDataUBO.h b/src/dto/buffers/GlobalDataUBO.h index f56e6ca9..32440007 100644 --- a/src/dto/buffers/GlobalDataUBO.h +++ b/src/dto/buffers/GlobalDataUBO.h @@ -9,19 +9,13 @@ namespace Metal { alignas(16) glm::mat4x4 projView{}; alignas(16) glm::mat4x4 invView{}; alignas(16) glm::mat4x4 invProj{}; - alignas(16) glm::mat4x4 previousProjView{}; - alignas(16) glm::vec3 cameraWorldPosition{}; alignas(16) glm::vec3 sunColor{}; alignas(16) glm::vec3 sunPosition{}; - alignas(8) glm::vec2 outputRes{}; - alignas(4) unsigned int volumeCount{}; alignas(4) unsigned int lightsCount{}; - alignas(4) unsigned int debugFlag; - alignas(4) unsigned int pathTracerAccumulationCount = 0; alignas(4) unsigned int globalFrameCount = 0; alignas(4) unsigned int pathTracerMaxSamples{}; diff --git a/src/dto/buffers/MaterialData.h b/src/dto/buffers/MaterialData.h deleted file mode 100644 index dc1c4769..00000000 --- a/src/dto/buffers/MaterialData.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MATERIAL_DATA_H -#define MATERIAL_DATA_H -#include -#include -#include - -namespace Metal { - struct MaterialData final { - alignas(16) glm::vec3 albedo{}; - alignas(4) float roughness{}; - alignas(4) float metallic{}; - alignas(4) float transmission{}; - alignas(4) float thickness{}; - alignas(4) float ior{1.45f}; - alignas(4) unsigned int isEmissive{}; - - alignas(4) unsigned int useAlbedoTexture; - alignas(4) unsigned int useNormalTexture; - alignas(4) unsigned int useRoughnessTexture; - alignas(4) unsigned int useMetallicTexture; - - alignas(4) unsigned int albedoTextureId{}; - alignas(4) unsigned int normalTextureId{}; - alignas(4) unsigned int roughnessTextureId{}; - alignas(4) unsigned int metallicTextureId{}; - }; -} - -#endif //LIGHTDATA_H diff --git a/src/dto/buffers/MeshMetadata.h b/src/dto/buffers/MeshMetadata.h index dcbf9ddd..bfe11d8e 100644 --- a/src/dto/buffers/MeshMetadata.h +++ b/src/dto/buffers/MeshMetadata.h @@ -2,13 +2,25 @@ #define MESHMETADATA_H #include +#include namespace Metal { struct MeshMetadata { unsigned int renderIndex; - unsigned int materialIndex; uint64_t vertexBufferAddress; uint64_t indexBufferAddress; + + alignas(16) glm::vec3 albedo{}; + alignas(4) float roughness{}; + alignas(4) float metallic{}; + alignas(4) float transmission{}; + alignas(4) float thickness{}; + alignas(4) float ior{1.45f}; + alignas(4) unsigned int isEmissive{}; + + alignas(4) unsigned int albedoTextureId = 0; + alignas(4) unsigned int roughnessTextureId = 0; + alignas(4) unsigned int metallicTextureId = 0; }; } diff --git a/src/enum/ComponentType.cpp b/src/enum/ComponentType.cpp new file mode 100644 index 00000000..7dfbe93e --- /dev/null +++ b/src/enum/ComponentType.cpp @@ -0,0 +1,78 @@ +#include "ComponentType.h" +#include "../repository/world/WorldRepository.h" +#include "../context/ApplicationContext.h" + +#define DEFINE_COMPONENT(TYPE, NAME, JSON_KEY, ICON, DEPS, CLASS, CREATOR) \ +{ \ +TYPE, NAME, JSON_KEY, ICON, DEPS, \ +CREATOR, \ +[](WorldRepository &repo, entt::entity entityId) { \ +if (auto *comp = repo.registry.try_get(entityId)) { \ +return comp->toJson(); \ +} \ +return nlohmann::json(); \ +}, \ +[](WorldRepository &repo, entt::entity entityId, const nlohmann::json &j) { \ +repo.registry.get(entityId).fromJson(j); \ +}, \ +[](WorldRepository &repo, entt::entity entityId) -> Inspectable* { \ +if (auto *comp = repo.registry.try_get(entityId)) { \ +return static_cast(comp); \ +} \ +return nullptr; \ +} \ +} + +namespace Metal::ComponentTypes { + const std::vector &getComponents() { + static const std::vector COMPONENTS = { + DEFINE_COMPONENT( + PRIMITIVE, "Primitive", "mesh", Icons::view_in_ar, {TRANSFORM}, PrimitiveComponent, + [](WorldRepository &repo, entt::entity entityId) { + auto &mesh = repo.registry.emplace_or_replace(entityId); + mesh.setEntityId(entityId); + CTX.rayTracingService.markDirty(); + } + ), + DEFINE_COMPONENT( + TRANSFORM, "Transformation", "transform", Icons::transform, {}, TransformComponent, + [](WorldRepository &repo, entt::entity entityId) { + if (!repo.registry.all_of(entityId)) { + auto &trans = repo.registry.emplace(entityId); + trans.setEntityId(entityId); + } + } + ), + DEFINE_COMPONENT( + VOLUME, "Volume Component", "volume", Icons::blur_on, {TRANSFORM}, VolumeComponent, + [](WorldRepository &repo, entt::entity entityId) { + auto &vol = repo.registry.emplace_or_replace(entityId); + vol.setEntityId(entityId); + } + ), + DEFINE_COMPONENT( + METADATA, "Metadata", "metadata", Icons::data_array, {}, MetadataComponent, + [](WorldRepository &repo, entt::entity entityId) { + auto &atmo = repo.registry.emplace_or_replace(entityId); + atmo.setEntityId(entityId); + CTX.engineContext.setGISettingsUpdated(true); + } + ) + }; + return COMPONENTS; + } + + const char *NameOf(ComponentType mode) { + for (const auto &comp: getComponents()) { + if (comp.type == mode) return comp.name.c_str(); + } + return nullptr; + } + + const char *IconOf(ComponentType mode) { + for (const auto &comp: getComponents()) { + if (comp.type == mode) return comp.icon.c_str(); + } + return nullptr; + } +} diff --git a/src/enum/ComponentType.h b/src/enum/ComponentType.h index d5b9850a..6a5433d3 100644 --- a/src/enum/ComponentType.h +++ b/src/enum/ComponentType.h @@ -1,55 +1,44 @@ #ifndef COMPONENTTYPE_H #define COMPONENTTYPE_H +#include +#include +#include +#include +#include #include "../common/interface/Icons.h" -namespace Metal::ComponentTypes { +namespace Metal { + class Inspectable; + struct WorldRepository; + enum ComponentType { - MESH, + PRIMITIVE, TRANSFORM, SPHERE_LIGHT, PLANE_LIGHT, - VOLUME + VOLUME, + ATMOSPHERE, + METADATA }; +} - static constexpr const char *NAMES = "Add Entity\0Mesh\0Sphere Light\0Plane Light\0Volume\0"; +namespace Metal::ComponentTypes { + struct ComponentDefinition { + ComponentType type; + std::string name; + std::string jsonKey; + std::string icon; + std::vector dependencies; + std::function creator; + std::function toJson; + std::function fromJson; + std::function getInspectable; + }; - static ComponentType ValueOfIndex(const int option) { - if (option == 1) { - return MESH; - } - if (option == 2) { - return SPHERE_LIGHT; - } - if (option == 3) { - return PLANE_LIGHT; - } - return VOLUME; - } + const std::vector &getComponents(); - static const char *NameOf(const ComponentType mode) { - if (mode == MESH) - return "Mesh Component"; - if (mode == TRANSFORM) - return "Transformation Component"; - if (mode == SPHERE_LIGHT) - return "Sphere Light Component"; - if (mode == PLANE_LIGHT) - return "Plane Light Component"; - if (mode == VOLUME) - return "Volume Component"; - return nullptr; - } + const char *NameOf(ComponentType mode); - static const char *IconOf(const ComponentType mode) { - if (mode == MESH) - return Icons::view_in_ar.c_str(); - if (mode == TRANSFORM) - return Icons::transform.c_str(); - if (mode == SPHERE_LIGHT || mode == PLANE_LIGHT) - return Icons::lightbulb.c_str(); - if (mode == VOLUME) - return Icons::blur_on.c_str(); - return nullptr; - } + const char *IconOf(ComponentType mode); } #endif //COMPONENTTYPE_H diff --git a/src/enum/EngineResourceIDs.h b/src/enum/EngineResourceIDs.h index ddfbacaa..8913ec70 100644 --- a/src/enum/EngineResourceIDs.h +++ b/src/enum/EngineResourceIDs.h @@ -3,17 +3,12 @@ namespace Metal { inline constexpr const char* RID_GLOBAL_DATA = "globalData"; - inline constexpr const char* RID_TILE_INFO = "tileInfo"; inline constexpr const char* RID_LIGHT_BUFFER = "lightBuffer"; - inline constexpr const char* RID_VOLUMES_BUFFER = "volumesBuffer"; - inline constexpr const char* RID_MATERIAL_BUFFER = "materialBuffer"; inline constexpr const char* RID_MESH_METADATA_BUFFER = "meshMetadataBuffer"; inline constexpr const char* RID_GBUFFER_POSITION_INDEX = "gBufferPositionIndex"; inline constexpr const char* RID_GBUFFER_NORMAL = "gBufferNormal"; - inline constexpr const char* RID_PREVIOUS_COLOR = "previousColor"; inline constexpr const char* RID_PREVIOUS_POSITION_INDEX = "previousPositionIndex"; inline constexpr const char* RID_PREVIOUS_NORMAL = "previousNormal"; - inline constexpr const char* RID_RAW_RENDERED_FRAME = "rawRenderedFrame"; inline constexpr const char* RID_ACCUMULATED_FRAME = "accumulatedFrame"; inline constexpr const char* RID_DENOISED_FRAME = "denoisedFrame"; inline constexpr const char* RID_TEMPORAL_OUTPUT = "temporalOutput"; @@ -21,6 +16,9 @@ namespace Metal { inline constexpr const char* RID_POST_PROCESSING_FBO = "postProcessingFBO"; inline constexpr const char* RID_COMPUTE_CB = "ComputeCB"; inline constexpr const char* RID_POST_PROCESSING_CB = "PostProcessingCB"; + inline constexpr const char* RID_VOLUMES_BUFFER = "volumesBuffer"; + inline constexpr const char* RID_SELECTION_FBO = "selectionFBO"; + inline constexpr const char* RID_SELECTION_CB = "selectionCB"; } #endif //ENGINE_RESOURCE_IDS_H diff --git a/src/enum/EntryType.h b/src/enum/EntryType.h index b1c63117..ea1790a7 100644 --- a/src/enum/EntryType.h +++ b/src/enum/EntryType.h @@ -8,11 +8,10 @@ namespace Metal::EntryType { TEXTURE, VOLUME, DIRECTORY, - MATERIAL, NONE }; - static const char *Names = "Scene\0Mesh\0Texture\0Volume\0Directory\0Material\0None\0"; + static const char *Names = "Scene\0Mesh\0Texture\0Volume\0Directory\0None\0"; static EntryType ValueOfIndex(const int option) { if (option == 0) { @@ -30,9 +29,6 @@ namespace Metal::EntryType { if (option == 4) { return EntryType::DIRECTORY; } - if (option == 5) { - return EntryType::MATERIAL; - } return EntryType::NONE; } @@ -52,9 +48,6 @@ namespace Metal::EntryType { if (mode == DIRECTORY) { return 4; } - if (mode == MATERIAL) { - return 5; - } if (mode == NONE) { return 6; } diff --git a/src/enum/PassType.h b/src/enum/PassType.h index 38d3cbb2..d0c67489 100644 --- a/src/enum/PassType.h +++ b/src/enum/PassType.h @@ -8,9 +8,10 @@ namespace Metal { TEMPORAL_ACCUMULATION, SPATIAL_FILTER, POST_PROCESSING, - SELECTED_DOT, + SELECTION_OUTLINE, GRID, - ICONS + ICONS, + SELECTION_ID }; } diff --git a/src/enum/ShadingMode.h b/src/enum/ShadingMode.h index 236bb631..4a296079 100644 --- a/src/enum/ShadingMode.h +++ b/src/enum/ShadingMode.h @@ -13,7 +13,6 @@ namespace Metal { NORMAL, ROUGHNESS, METALLIC, - AO, RANDOM, DEPTH, UV, @@ -37,7 +36,6 @@ namespace Metal { {"NORMAL", "Normal", Icons::gradient, NORMAL}, {"ROUGHNESS", "Roughness", Icons::texture, ROUGHNESS}, {"METALLIC", "Metallic", Icons::blur_on, METALLIC}, - {"AO", "Occlusion", Icons::contrast, AO}, {"RANDOM", "Random", Icons::casino, RANDOM}, {"DEPTH", "Depth", Icons::layers, DEPTH}, {"UV", "UV", Icons::grid_on, UV}, diff --git a/src/enum/engine-definitions.h b/src/enum/engine-definitions.h index 4b026676..cb8984f8 100644 --- a/src/enum/engine-definitions.h +++ b/src/enum/engine-definitions.h @@ -1,12 +1,12 @@ #ifndef ENGINEID_H #define ENGINEID_H -typedef unsigned long long EntityID; +#include #define MAX_VOLUMES 300 #define MAX_LIGHTS 300 #define MAX_MATERIALS 100 #define MAX_MESH_INSTANCES 1000 -#define EMPTY_ENTITY 0 +#define EMPTY_ENTITY entt::null #define FILE_METADATA ".mjson" #define FILE_SCENE "-scene" #define FILE_MESH "-mesh" diff --git a/src/repository/dock/DockDTO.h b/src/repository/dock/DockDTO.h index 4b539b1e..60a8109f 100644 --- a/src/repository/dock/DockDTO.h +++ b/src/repository/dock/DockDTO.h @@ -2,6 +2,7 @@ #define METAL_ENGINE_DOCKDTO_H #include +#include #include #include "DockSpace.h" #include "DockPosition.h" @@ -19,7 +20,6 @@ namespace Metal { float sizeRatioForNodeAtDir{}; DockDTO *outAtOppositeDir = nullptr; DockDTO *origin = nullptr; - DockPosition direction = RIGHT_TOP; std::vector dockSpaces{}; diff --git a/src/repository/dock/DockPosition.h b/src/repository/dock/DockPosition.h index a6e01522..b0b3ae35 100644 --- a/src/repository/dock/DockPosition.h +++ b/src/repository/dock/DockPosition.h @@ -6,6 +6,8 @@ namespace Metal { TOP, RIGHT_BOTTOM, RIGHT_TOP, + LEFT_TOP, + LEFT_BOTTOM, BOTTOM }; } diff --git a/src/repository/dock/DockRepository.cpp b/src/repository/dock/DockRepository.cpp new file mode 100644 index 00000000..560f31d7 --- /dev/null +++ b/src/repository/dock/DockRepository.cpp @@ -0,0 +1,25 @@ +#include "DockRepository.h" + +namespace Metal { + DockRepository::DockRepository() : AbstractRuntimeComponent() { + auto *rightT = new DockDTO{&DockSpace::WORLD}; + auto *leftTop = new DockDTO{&DockSpace::REPOSITORIES}; + auto *leftDown = new DockDTO{&DockSpace::INSPECTOR}; + auto *downLeft = new DockDTO{&DockSpace::CONSOLE}; + auto *downRight = new DockDTO{&DockSpace::FILES}; + + center.sizeRatioForNodeAtDir = 0.5f; + rightT->sizeRatioForNodeAtDir = 0.25f; + leftTop->sizeRatioForNodeAtDir = 0.2f; + leftDown->sizeRatioForNodeAtDir = 0.5f; + downLeft->sizeRatioForNodeAtDir = 0.25f; + downRight->sizeRatioForNodeAtDir = 0.5f; + + right.push_back(rightT); + left.push_back(leftTop); + left.push_back(leftDown); + + bottom.push_back(downLeft); + bottom.push_back(downRight); + } +} // Metal diff --git a/src/repository/dock/DockRepository.h b/src/repository/dock/DockRepository.h index 79d181fa..dfbd6d79 100644 --- a/src/repository/dock/DockRepository.h +++ b/src/repository/dock/DockRepository.h @@ -1,16 +1,20 @@ #ifndef METAL_ENGINE_DOCKREPOSITORY_H #define METAL_ENGINE_DOCKREPOSITORY_H +#include #include "DockDTO.h" #include "../../common/AbstractRuntimeComponent.h" namespace Metal { struct DockRepository final : AbstractRuntimeComponent { - DockDTO top{&DockSpace::VIEWPORT, 0.17f}; - DockDTO bottom{&DockSpace::FILES, .25f}; - DockDTO rightTop{&DockSpace::HIERARCHY, 0.6f}; - DockDTO rightBottom{&DockSpace::INSPECTOR, 0.4f}; + DockDTO center{&DockSpace::VIEWPORT}; + std::vector bottom; + std::vector left; + std::vector right; + bool isInitialized = false; + + explicit DockRepository(); }; } // Metal diff --git a/src/repository/dock/DockSpace.cpp b/src/repository/dock/DockSpace.cpp index 1f3e379b..ce757cbc 100644 --- a/src/repository/dock/DockSpace.cpp +++ b/src/repository/dock/DockSpace.cpp @@ -3,20 +3,22 @@ #include "../../context/editor/dock-spaces/console/ConsolePanel.h" #include "../../context/editor/dock-spaces/files/FilesPanel.h" #include "../../context/editor/dock-spaces/metrics/MetricsPanel.h" +#include "../../context/editor/dock-spaces/repositories/RepositoriesPanel.h" #include "../../context/editor/dock-spaces/inspector/InspectorPanel.h" #include "../../context/editor/dock-spaces/viewport/ViewportPanel.h" -#include "../../context/editor/dock-spaces/hierarchy/HierarchyPanel.h" +#include "../../context/editor/dock-spaces/world/WorldPanel.h" #define CB(clazz) []() { return new clazz; } namespace Metal { DockSpace DockSpace::VIEWPORT{-1, "Viewport", Icons::ipublic, 0, 0,CB(ViewportPanel)}; DockSpace DockSpace::INSPECTOR{0, "Inspector", Icons::search, 4, 4,CB(InspectorPanel)}; - DockSpace DockSpace::HIERARCHY{1, "Hierarchy", Icons::account_tree, 4, 4, CB(HierarchyPanel)}; + DockSpace DockSpace::WORLD{1, "World", Icons::account_tree, 4, 4, CB(WorldPanel)}; DockSpace DockSpace::CONSOLE{2, "Console", Icons::terminal, 4, 4, CB(ConsolePanel)}; DockSpace DockSpace::FILES{3, "Files", Icons::folder_open, 4, 4, CB(FilesPanel)}; DockSpace DockSpace::METRICS{4, "Metrics", Icons::analytics, 4, 4, CB(MetricsPanel)}; - const char *DockSpace::OPTIONS = "Inspector\0Hierarchy\0Console\0Files\0Metrics"; + DockSpace DockSpace::REPOSITORIES{5, "Repositories", Icons::search, 4, 4, CB(RepositoriesPanel)}; + const char *DockSpace::OPTIONS = "Inspector\0World\0Console\0Files\0Metrics\0Repositories\0"; DockSpace *DockSpace::GetOption(const int selected) { @@ -24,13 +26,15 @@ namespace Metal { case 0: return &INSPECTOR; case 1: - return &HIERARCHY; + return &WORLD; case 2: return &CONSOLE; case 3: return &FILES; case 4: return &METRICS; + case 5: + return &REPOSITORIES; default: return nullptr; } diff --git a/src/repository/dock/DockSpace.h b/src/repository/dock/DockSpace.h index 46eb694b..25b2dcd8 100644 --- a/src/repository/dock/DockSpace.h +++ b/src/repository/dock/DockSpace.h @@ -10,10 +10,11 @@ namespace Metal { struct DockSpace { static DockSpace VIEWPORT; static DockSpace INSPECTOR; - static DockSpace HIERARCHY; + static DockSpace WORLD; static DockSpace CONSOLE; static DockSpace FILES; static DockSpace METRICS; + static DockSpace REPOSITORIES; static const char *OPTIONS; const int index; diff --git a/src/repository/editor/EditorRepository.cpp b/src/repository/editor/EditorRepository.cpp index 21c19f90..84c7cea2 100644 --- a/src/repository/editor/EditorRepository.cpp +++ b/src/repository/editor/EditorRepository.cpp @@ -35,9 +35,15 @@ namespace Metal { j["gizmoUseSnapRotate"] = gizmoUseSnapRotate; j["gizmoUseSnapScale"] = gizmoUseSnapScale; j["showOnlyEntitiesHierarchy"] = showOnlyEntitiesHierarchy; - j["mainSelection"] = mainSelection; - j["selected"] = selected; - j["copied"] = copied; + j["mainSelection"] = static_cast(entt::to_integral(mainSelection)); + j["selected"] = nlohmann::json::array(); + for (auto const& [key, val] : selected) { + j["selected"].push_back(static_cast(entt::to_integral(key))); + } + j["copied"] = nlohmann::json::array(); + for (auto const& entity : copied) { + j["copied"].push_back(static_cast(entt::to_integral(entity))); + } j["shadingMode"] = shadingMode; return j; } @@ -66,9 +72,19 @@ namespace Metal { gizmoUseSnapRotate = j.at("gizmoUseSnapRotate").get(); gizmoUseSnapScale = j.at("gizmoUseSnapScale").get(); showOnlyEntitiesHierarchy = j.at("showOnlyEntitiesHierarchy").get(); - mainSelection = j.at("mainSelection").get(); - selected = j.at("selected").get >(); - copied = j.at("copied").get >(); + mainSelection = static_cast(j.at("mainSelection").get()); + selected.clear(); + if (j.contains("selected") && j.at("selected").is_array()) { + for (auto const& item : j.at("selected")) { + selected[static_cast(item.get())] = true; + } + } + copied.clear(); + if (j.contains("copied") && j.at("copied").is_array()) { + for (auto const& item : j.at("copied")) { + copied.push_back(static_cast(item.get())); + } + } shadingMode = static_cast(j.at("shadingMode").get()); } diff --git a/src/repository/editor/EditorRepository.h b/src/repository/editor/EditorRepository.h index 27c3a4bc..95ae4ac5 100644 --- a/src/repository/editor/EditorRepository.h +++ b/src/repository/editor/EditorRepository.h @@ -14,6 +14,8 @@ namespace Metal { struct TransformComponent; + struct FSEntry; + struct ImportSettingsDTO; struct EditorRepository final : Inspectable, Serializable { ImVec4 accent{}; @@ -43,13 +45,19 @@ namespace Metal { bool gizmoUseSnapScale = false; bool showOnlyEntitiesHierarchy = false; TransformComponent *primitiveSelected = nullptr; - EntityID mainSelection = EMPTY_ENTITY; - std::unordered_map selected{}; - std::vector copied{}; + entt::entity mainSelection = EMPTY_ENTITY; + std::unordered_map selected{}; + std::vector copied{}; std::string focusedWindowName{}; std::vector focusedShortcuts{}; ShadingMode shadingMode = LIT; + + std::vector pendingImports; + std::unordered_map > importSettingsMap; + std::string selectedFileForSettings; + FSEntry *targetImportDirectory = nullptr; + void registerFields() override; const char *getTitle() override; diff --git a/src/repository/engine/EngineRepository.cpp b/src/repository/engine/EngineRepository.cpp index c634beff..1add07b1 100644 --- a/src/repository/engine/EngineRepository.cpp +++ b/src/repository/engine/EngineRepository.cpp @@ -15,8 +15,6 @@ namespace Metal { registerInt(shadingResInvScale, "Display settings (Restart required)", "Shading inverted resolution scale", 1, 16); registerBool(vsync, "Display settings (Restart required)", "VSync?"); - registerInt(numberOfTiles, "World", "Number of tiles", 2, 100); - // registerInt(maxVideoFrames, "", "Max video frames", 1); registerInt(volumeShadowSteps, VOLUMES, "Shadow steps", 1); @@ -35,8 +33,6 @@ namespace Metal { registerBool(atmosphereEnabled, ATMOSPHERE, "Enable atmosphere?"); registerFloat(elapsedTime, ATMOSPHERE, "Elapsed time"); - registerBool(incrementTime, ATMOSPHERE, "Increment time"); - registerFloat(elapsedTimeSpeed, ATMOSPHERE, "Time of day speed"); registerFloat(sunDistance, ATMOSPHERE, "Sun distance"); registerFloat(sunRadius, ATMOSPHERE, "Sun radius"); registerFloat(sunLightIntensity, ATMOSPHERE, "Sun light intensity"); @@ -46,13 +42,9 @@ namespace Metal { } void EngineRepository::onUpdate(InspectableMember *member) { - if (member != nullptr && member->name == LEVEL_OF_DETAIL) { - CTX.worldGridRepository.hasMainTileChanged = true; - } if (member != nullptr && (member->group == PATH_TRACER || member->group == ATMOSPHERE || member->group == SUN || member->group == DEPTH_OF_FIELD)) { CTX.engineContext.setGISettingsUpdated(true); - CTX.engineContext.setUpdateLights(true); } } @@ -64,8 +56,6 @@ namespace Metal { j["pathTracerBounces"] = pathTracerBounces; j["atmosphereEnabled"] = atmosphereEnabled; j["elapsedTime"] = elapsedTime; - j["incrementTime"] = incrementTime; - j["elapsedTimeSpeed"] = elapsedTimeSpeed; j["sunRadius"] = sunRadius; j["sunDistance"] = sunDistance; j["sunLightIntensity"] = sunLightIntensity; @@ -93,8 +83,6 @@ namespace Metal { pathTracerBounces = j.at("pathTracerBounces").get(); atmosphereEnabled = j.at("atmosphereEnabled").get(); elapsedTime = j.at("elapsedTime").get(); - incrementTime = j.at("incrementTime").get(); - elapsedTimeSpeed = j.at("elapsedTimeSpeed").get(); sunRadius = j.at("sunRadius").get(); sunDistance = j.at("sunDistance").get(); sunLightIntensity = j.at("sunLightIntensity").get(); diff --git a/src/repository/engine/EngineRepository.h b/src/repository/engine/EngineRepository.h index e671bd1f..de4db803 100644 --- a/src/repository/engine/EngineRepository.h +++ b/src/repository/engine/EngineRepository.h @@ -8,7 +8,6 @@ namespace Metal { struct EngineRepository final : Inspectable, Serializable { bool vsync = true; - bool isBaking = false; bool denoiserEnabled = false; bool dofEnabled = false; float dofFocusDistance = 10; @@ -16,7 +15,6 @@ namespace Metal { float dofFocalLength = 5; bool multipleImportanceSampling = false; - int maxVideoFrames = 100; int volumeShadowSteps = 8; int shadingResInvScale = 2; int pathTracerMaxSamples = 200; @@ -25,11 +23,8 @@ namespace Metal { int pathTracerBounces = 1; int pathTracerAccumulationCount = 0; float pathTracerMultiplier = 1; - int numberOfTiles = 10; float elapsedTime = .5f; bool atmosphereEnabled = false; - bool incrementTime = false; - float elapsedTimeSpeed = 1; float sunDistance = 10000; float sunRadius = 3000; float sunLightIntensity = 2; diff --git a/src/repository/inspection/FilesRepository.cpp b/src/repository/inspection/FilesRepository.cpp deleted file mode 100644 index 8667cf4e..00000000 --- a/src/repository/inspection/FilesRepository.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "FilesRepository.h" - -#include "../../common/interface/Icons.h" - -namespace Metal { - void FilesRepository::registerFields() { - registerResourceSelection(materialId, "", "Material", EntryType::MATERIAL, false); - } - - const char * FilesRepository::getIcon() { - return Icons::file_open.c_str(); - } - - const char * FilesRepository::getTitle() { - return "File Inspection"; - } -} // Metal diff --git a/src/repository/inspection/FilesRepository.h b/src/repository/inspection/FilesRepository.h deleted file mode 100644 index 49aa5e05..00000000 --- a/src/repository/inspection/FilesRepository.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef FILEINSPECTIONREPOSITORY_H -#define FILEINSPECTIONREPOSITORY_H -#include - -#include "../../common/inspection/Inspectable.h" - -namespace Metal { - struct FSEntry; - struct ImportSettingsDTO; - - struct FilesRepository final : Inspectable { - std::string materialId; - - std::vector pendingImports; - std::unordered_map > importSettingsMap; - std::string selectedFileForSettings; - FSEntry *targetImportDirectory = nullptr; - - void registerFields() override; - - const char *getIcon() override; - - const char *getTitle() override; - }; -} // Metal - -#endif //FILEINSPECTIONREPOSITORY_H diff --git a/src/repository/streaming/StreamingService.cpp b/src/repository/streaming/StreamingService.cpp index 4bab32e5..a3c3667d 100644 --- a/src/repository/streaming/StreamingService.cpp +++ b/src/repository/streaming/StreamingService.cpp @@ -4,58 +4,11 @@ #include "../../service/voxel/SVOInstance.h" #include "../../service/mesh/MeshInstance.h" #include "../../service/texture/TextureInstance.h" -#include -#include "../../repository/abstract/RuntimeResource.h" -#include "../../service/material/MaterialInstance.h" + +#include "../../repository/world/components/PrimitiveComponent.h" namespace Metal { static constexpr int MAX_TIMEOUT = 10000; - static constexpr int MAX_TRIES = 5; - - template - T *stream(IStreamable &service, const std::string &id, - std::unordered_map &lastUse, - std::unordered_map &tries) { - if (!id.empty() && service.getResources().contains(id)) { - auto *e = service.getResource(id); - lastUse[e->getId()] = CTX.engineContext.currentTimeMs; - return e; - } - if (!tries.contains(id)) { - tries[id] = 0; - } - tries[id]++; - if (tries[id] < MAX_TRIES) { - LOG_DEBUG("Streaming " + id); - auto *instance = service.create(id); - if (instance != nullptr) { - tries[id] = 0; - for (auto &dep: instance->getDependencies()) { - if (lastUse.contains(dep)) { - lastUse[dep] = CTX.engineContext.currentTimeMs; - } - } - } - return instance; - } - return nullptr; - } - - MaterialInstance *StreamingService::streamMaterial(const std::string &id) { - return stream(CTX.materialService, id, lastUse, tries); - } - - SVOInstance *StreamingService::streamSVO(const std::string &id) { - return stream(CTX.voxelService, id, lastUse, tries); - } - - MeshInstance *StreamingService::streamMesh(const std::string &id) { - return stream(CTX.meshService, id, lastUse, tries); - } - - TextureInstance *StreamingService::streamTexture(const std::string &id) { - return stream(CTX.textureService, id, lastUse, tries); - } template void disposeResources(AbstractResourceService &service, std::unordered_map &lastUse) { @@ -76,12 +29,28 @@ namespace Metal { } void StreamingService::onSync() { + auto view = CTX.worldRepository.registry.view(); + for (auto entity: view) { + auto &meshComp = view.get(entity); + if (!meshComp.meshId.empty()) { + lastUse[meshComp.meshId] = CTX.engineContext.currentTimeMs; + } + if (!meshComp.albedo.empty()) { + lastUse[meshComp.albedo] = CTX.engineContext.currentTimeMs; + } + if (!meshComp.roughness.empty()) { + lastUse[meshComp.roughness] = CTX.engineContext.currentTimeMs; + } + if (!meshComp.metallic.empty()) { + lastUse[meshComp.metallic] = CTX.engineContext.currentTimeMs; + } + } + if ((CTX.engineContext.currentTime - sinceLastCleanup).count() >= MAX_TIMEOUT) { sinceLastCleanup = CTX.engineContext.currentTime; disposeResources(CTX.meshService, lastUse); disposeResources(CTX.textureService, lastUse); disposeResources(CTX.voxelService, lastUse); - disposeResources(CTX.materialService, lastUse); } } } diff --git a/src/repository/streaming/StreamingService.h b/src/repository/streaming/StreamingService.h index f6636d64..2fcba091 100644 --- a/src/repository/streaming/StreamingService.h +++ b/src/repository/streaming/StreamingService.h @@ -6,36 +6,21 @@ #include "../../service/abstract/AbstractResourceService.h" #include "../abstract/AbstractCoreRepository.h" -#include "../../service/abstract/IStreamable.h" #include "../abstract/RuntimeResource.h" - -namespace Metal { - struct SVOInstance; -} - using Clock = std::chrono::high_resolution_clock; using TimePoint = std::chrono::time_point; namespace Metal { struct MeshInstance; struct TextureInstance; - struct MaterialInstance; + struct SVOInstance; class StreamingService final : public AbstractRuntimeComponent { - std::unordered_map tries{}; std::unordered_map lastUse{}; TimePoint sinceLastCleanup; public: - MeshInstance *streamMesh(const std::string &id); - - MaterialInstance *streamMaterial(const std::string &id); - - SVOInstance *streamSVO(const std::string &id); - - TextureInstance *streamTexture(const std::string &id); - void onSync() override; }; } // Metal diff --git a/src/repository/world/WorldRepository.cpp b/src/repository/world/WorldRepository.cpp index 4f915675..fd9a1cc9 100644 --- a/src/repository/world/WorldRepository.cpp +++ b/src/repository/world/WorldRepository.cpp @@ -2,87 +2,29 @@ #include "../../context/ApplicationContext.h" #include "../../enum/ComponentType.h" +#include "../../service/mesh/SceneData.h" +#include "../../util/serialization-definitions.h" namespace Metal { - WorldRepository::WorldRepository(): AbstractRuntimeComponent() { - const auto root = registry.create(static_cast(ROOT_ID)); - auto &entity = registry.emplace(root); - entity.initialize(true); - entity.name = "Scene"; - registry.emplace(root); - } - - EntityID WorldRepository::createEntity(std::string name, const bool container) { + entt::entity WorldRepository::createEntity() { registerChange(); const auto entity = registry.create(); - auto &entityComp = registry.emplace(entity); - entityComp.initialize(container); - entityComp.name = std::move(name); - - registry.emplace(entity); - linkEntities(ROOT_ID, static_cast(entity)); - - return static_cast(entity); - } - - void WorldRepository::linkEntities(EntityID parentId, EntityID childId) { - registerChange(); - - const auto child = static_cast(childId); - auto &childHierarchy = registry.get(child); - - if (childHierarchy.parent != EMPTY_ENTITY) { - const auto oldParent = static_cast(childHierarchy.parent); - if (registry.valid(oldParent)) { - auto &oldParentHierarchy = registry.get(oldParent); - oldParentHierarchy.children.erase( - std::ranges::remove(oldParentHierarchy.children, childId).begin(), - oldParentHierarchy.children.end()); - } - } - - const auto newParent = static_cast(parentId); - if (registry.valid(newParent)) { - auto &newParentHierarchy = registry.get(newParent); - newParentHierarchy.children.push_back(childId); - childHierarchy.parent = parentId; - } + createComponent(entity, METADATA); + return entity; } - EntityComponent *WorldRepository::getEntity(const EntityID node) { - const auto entity = static_cast(node); - if (registry.valid(entity)) { - return ®istry.get(entity); + MetadataComponent *WorldRepository::getEntity(const entt::entity node) { + if (registry.valid(node)) { + return ®istry.get(node); } return nullptr; } - Inspectable *WorldRepository::getComponent(ComponentTypes::ComponentType comp, EntityID entityId) { - const auto entity = static_cast(entityId); - if (!registry.valid(entity)) return nullptr; - - switch (comp) { - case ComponentTypes::MESH: - return registry.all_of(entity) ? ®istry.get(entity) : nullptr; - case ComponentTypes::TRANSFORM: - return registry.all_of(entity) ? ®istry.get(entity) : nullptr; - case ComponentTypes::SPHERE_LIGHT: - case ComponentTypes::PLANE_LIGHT: - return registry.all_of>(entity) - ? registry.get>(entity).get() - : nullptr; - case ComponentTypes::VOLUME: - return registry.all_of(entity) ? ®istry.get(entity) : nullptr; - default: - return nullptr; - } - } - - void WorldRepository::deleteRecursively(const std::vector &entities) { - for (EntityID entityId: entities) { - const auto entity = static_cast(entityId); - if (!registry.valid(entity)) continue; + void WorldRepository::deleteEntities(const std::vector &entities) { + registerChange(); + for (entt::entity entityId: entities) { + if (!registry.valid(entityId)) continue; if (hiddenEntities.contains(entityId)) { hiddenEntities.erase(entityId); @@ -91,104 +33,77 @@ namespace Metal { culled.erase(entityId); } - if (registry.all_of(entity)) { - auto &hierarchy = registry.get(entity); - if (!hierarchy.children.empty()) { - std::vector childrenToDelete = hierarchy.children; - deleteRecursively(childrenToDelete); - } - - auto parentId = hierarchy.parent; - const auto parent = static_cast(parentId); - if (registry.valid(parent) && registry.all_of(parent)) { - auto &parentHierarchy = registry.get(parent); - parentHierarchy.children.erase( - std::ranges::remove(parentHierarchy.children, entityId).begin(), - parentHierarchy.children.end()); - } - } - registry.destroy(entity); + registry.destroy(entityId); } - } - - void WorldRepository::deleteEntities(const std::vector &entities) { - registerChange(); - deleteRecursively(entities); - CTX.engineContext.setUpdateLights(true); - CTX.engineContext.setUpdateVolumes(true); CTX.rayTracingService.markDirty(); } - void WorldRepository::changeVisibility(EntityID entity, bool isVisible) { + void WorldRepository::changeVisibility(entt::entity entity, bool isVisible) { registerChange(); - changeVisibilityRecursively(entity, isVisible); - CTX.engineContext.setUpdateLights(true); - CTX.engineContext.setUpdateVolumes(true); - CTX.rayTracingService.markDirty(); - } - - void WorldRepository::changeVisibilityRecursively(EntityID entity, const bool isVisible) { if (isVisible) { hiddenEntities.erase(entity); } else { hiddenEntities.insert({entity, true}); } + CTX.rayTracingService.markDirty(); + } - const auto e = static_cast(entity); - if (registry.valid(e) && registry.all_of(e)) { - for (const auto child: registry.get(e).children) { - changeVisibilityRecursively(child, isVisible); + void WorldRepository::loadScene(const std::string &sceneId) { + SceneData sceneData; + const auto pathToFile = CTX.getAssetDirectory() + FORMAT_FILE_SCENE(sceneId); + PARSE_TEMPLATE(sceneData, pathToFile) + + for (auto &entityData: sceneData.entities) { + const auto entityId = createEntity(); + + auto &entityComp = registry.get(entityId); + entityComp.name = entityData.entity.name; + + createComponent(entityId, TRANSFORM); + auto &transform = registry.get(entityId); + transform.translation = entityData.transform.translation; + transform.rotation = entityData.transform.rotation; + transform.rotationEuler = entityData.transform.rotationEuler; + transform.scale = entityData.transform.scale; + transform.gizmoCenter = entityData.transform.gizmoCenter; + transform.isStatic = entityData.transform.isStatic; + + if (entityData.primitive) { + + createComponent(entityId, PRIMITIVE); + auto &primitive = registry.get(entityId); + primitive.meshId = entityData.primitive->meshId; + primitive.albedo = entityData.primitive->albedo; + primitive.roughness = entityData.primitive->roughness; + primitive.metallic = entityData.primitive->metallic; + primitive.albedoColor = entityData.primitive->albedoColor; + primitive.roughnessFactor = entityData.primitive->roughnessFactor; + primitive.metallicFactor = entityData.primitive->metallicFactor; + primitive.transmissionFactor = entityData.primitive->transmissionFactor; + primitive.thicknessFactor = entityData.primitive->thicknessFactor; + primitive.ior = entityData.primitive->ior; + primitive.isEmissive = entityData.primitive->isEmissive; } } + + CTX.rayTracingService.markDirty(); } - void WorldRepository::createComponent(const EntityID entityId, ComponentTypes::ComponentType type) { - const auto entity = static_cast(entityId); - if (!registry.valid(entity)) { + void WorldRepository::createComponent(const entt::entity entityId, ComponentType type) { + if (!registry.valid(entityId)) { return; } - switch (type) { - case ComponentTypes::MESH: { - auto &mesh = registry.emplace_or_replace(entity); - mesh.setEntityId(entityId); - createComponent(entityId, ComponentTypes::TRANSFORM); - CTX.rayTracingService.markDirty(); - break; - } - case ComponentTypes::SPHERE_LIGHT: { - auto light = std::make_unique(); - light->setEntityId(entityId); - registry.emplace_or_replace>(entity, std::move(light)); - createComponent(entityId, ComponentTypes::TRANSFORM); - CTX.engineContext.setUpdateLights(true); - break; - } - case ComponentTypes::PLANE_LIGHT: { - auto light = std::make_unique(); - light->setEntityId(entityId); - registry.emplace_or_replace>(entity, std::move(light)); - createComponent(entityId, ComponentTypes::TRANSFORM); - CTX.engineContext.setUpdateLights(true); - break; - } - case ComponentTypes::VOLUME: { - auto &vol = registry.emplace_or_replace(entity); - vol.setEntityId(entityId); - createComponent(entityId, ComponentTypes::TRANSFORM); - CTX.engineContext.setUpdateVolumes(true); - break; - } - case ComponentTypes::TRANSFORM: { - if (!registry.all_of(entity)) { - auto &trans = registry.emplace(entity); - trans.setEntityId(entityId); - CTX.worldGridRepository.getCurrentTile()->entities.push_back(entityId); - registry.get(entity).onTile = CTX.worldGridRepository.getCurrentTile()->id; + + for (const auto &compDef: ComponentTypes::getComponents()) { + if (compDef.type == type) { + for (const auto &dep: compDef.dependencies) { + createComponent(entityId, dep); + } + if (compDef.creator) { + compDef.creator(*this, entityId); } break; } - default: - break; } } @@ -197,30 +112,20 @@ namespace Metal { j["camera"] = camera.toJson(); nlohmann::json entitiesJson; - for (auto entity : registry.view()) { - const auto id = static_cast(entity); + for (auto entity: registry.view()) { nlohmann::json ej; - if (registry.all_of(entity)) { - ej["entity"] = registry.get(entity).toJson(); - } - if (registry.all_of(entity)) { - auto &h = registry.get(entity); - ej["hierarchy"] = {{"parent", h.parent}, {"children", h.children}}; - } - if (registry.all_of(entity)) { - ej["mesh"] = registry.get(entity).toJson(); + if (registry.all_of(entity)) { + ej["entity"] = registry.get(entity).toJson(); } - if (registry.all_of(entity)) { - ej["transform"] = registry.get(entity).toJson(); - } - if (registry.all_of>(entity)) { - ej["light"] = registry.get>(entity)->toJson(); - } - if (registry.all_of(entity)) { - ej["volume"] = registry.get(entity).toJson(); + + for (const auto &compDef: ComponentTypes::getComponents()) { + auto cj = compDef.toJson(const_cast(*this), entity); + if (!cj.is_null()) { + ej[compDef.jsonKey] = std::move(cj); + } } - entitiesJson[std::to_string(id)] = ej; + entitiesJson[std::to_string(entt::to_integral(entity))] = ej; } j["registry"] = entitiesJson; j["hiddenEntities"] = hiddenEntities; @@ -233,44 +138,24 @@ namespace Metal { registry.clear(); if (j.contains("registry")) { for (auto const &[key, val]: j.at("registry").items()) { - const auto id = static_cast(std::stoull(key)); - const auto entity = registry.create(static_cast(id)); + const auto id = static_cast(static_cast(std::stoul(key))); + const auto entity = registry.create(id); if (val.contains("entity")) { - registry.emplace(entity).fromJson(val.at("entity")); - } - if (val.contains("hierarchy")) { - auto &h = registry.emplace(entity); - h.parent = val.at("hierarchy").at("parent").get(); - h.children = val.at("hierarchy").at("children").get>(); - } - if (val.contains("mesh")) { - registry.emplace(entity).fromJson(val.at("mesh")); + registry.emplace(entity).fromJson(val.at("entity")); } - if (val.contains("transform")) { - registry.emplace(entity).fromJson(val.at("transform")); - } - if (val.contains("light")) { - auto &lj = val.at("light"); - std::string type = lj.at("lightType").get(); - if (type == "SPHERE") { - auto light = std::make_unique(); - light->fromJson(lj); - registry.emplace>(entity, std::move(light)); - } else if (type == "PLANE") { - auto light = std::make_unique(); - light->fromJson(lj); - registry.emplace>(entity, std::move(light)); + + for (const auto &compDef: ComponentTypes::getComponents()) { + if (val.contains(compDef.jsonKey)) { + compDef.creator(*this, id); + compDef.fromJson(*this, id, val.at(compDef.jsonKey)); } } - if (val.contains("volume")) { - registry.emplace(entity).fromJson(val.at("volume")); - } } } if (j.contains("hiddenEntities")) { - hiddenEntities = j.at("hiddenEntities").get>(); + hiddenEntities = j.at("hiddenEntities").get >(); } } } // Metal diff --git a/src/repository/world/WorldRepository.h b/src/repository/world/WorldRepository.h index 06ab9599..2088eff3 100644 --- a/src/repository/world/WorldRepository.h +++ b/src/repository/world/WorldRepository.h @@ -10,51 +10,37 @@ #include "../../util/Serializable.h" #include "../../enum/engine-definitions.h" #include "../../service/camera/Camera.h" -#include "impl/EntityComponent.h" +#include "impl/MetadataComponent.h" #include "../../enum/ComponentType.h" -#include "components/LightComponent.h" -#include "components/MeshComponent.h" -#include "components/SphereLightComponent.h" -#include "components/PlaneLightComponent.h" #include "components/TransformComponent.h" +#include "components/PrimitiveComponent.h" #include "components/VolumeComponent.h" namespace Metal { class Inspectable; struct WorldRepository final : AbstractRuntimeComponent, Serializable { - static constexpr EntityID ROOT_ID = 1; - - explicit WorldRepository(); - Camera camera{-(glm::pi() / 4), glm::pi() / 4, {10, 10, 10}}; entt::registry registry{}; - std::unordered_map culled{}; - std::unordered_map hiddenEntities{}; - - void createComponent(EntityID entity, ComponentTypes::ComponentType type); + std::unordered_map culled{}; + std::unordered_map hiddenEntities{}; - EntityID createEntity(std::string name = "New Entity", bool container = false); + void createComponent(entt::entity entity, ComponentType type); - void linkEntities(EntityID parentId, EntityID childId); + entt::entity createEntity(); - [[nodiscard]] EntityComponent *getEntity(EntityID node); + [[nodiscard]] MetadataComponent *getEntity(entt::entity node); - Inspectable *getComponent(ComponentTypes::ComponentType comp, EntityID entity); + void deleteEntities(const std::vector &entities); + void changeVisibility(entt::entity entity, bool isVisible); - void deleteEntities(const std::vector &entities); - - void changeVisibility(EntityID entity, bool isVisible); + void loadScene(const std::string &sceneId); nlohmann::json toJson() const override; void fromJson(const nlohmann::json &j) override; - private: - void deleteRecursively(const std::vector &entities); - - void changeVisibilityRecursively(EntityID entity, bool isVisible); }; } // Metal diff --git a/src/repository/world/components/LightComponent.cpp b/src/repository/world/components/LightComponent.cpp deleted file mode 100644 index 3acc9ddb..00000000 --- a/src/repository/world/components/LightComponent.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "LightComponent.h" - -#include "../../../context/ApplicationContext.h" - -namespace Metal { - void LightComponent::registerFields() { - registerColor(color, "", "Color"); - registerFloat(intensity, "", "Intensity", .1, 100); - } - - void LightComponent::onUpdate(InspectableMember *member) { - CTX.engineContext.setUpdateLights(true); - } -} // Metal diff --git a/src/repository/world/components/LightComponent.h b/src/repository/world/components/LightComponent.h deleted file mode 100644 index 59970491..00000000 --- a/src/repository/world/components/LightComponent.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef LIGHTCOMPONENT_H -#define LIGHTCOMPONENT_H - -#include "../impl/AbstractComponent.h" -#include "../../../util/Serializable.h" -#include - -#include "../../../enum/LightType.h" - -namespace Metal { - struct LightComponent : AbstractComponent, Serializable { - glm::vec3 color = glm::vec3(1.0f); - float intensity = 1.0f; - - virtual LightTypes::LightType getLightType() = 0; - - void registerFields() override; - - void onUpdate(InspectableMember *member) override; - - nlohmann::json toJson() const override { - nlohmann::json j; - j["entityId"] = entityId; - j["color"] = {color.x, color.y, color.z}; - j["intensity"] = intensity; - return j; - } - - void fromJson(const nlohmann::json& j) override { - entityId = j.at("entityId").get(); - color.x = j.at("color")[0].get(); - color.y = j.at("color")[1].get(); - color.z = j.at("color")[2].get(); - intensity = j.at("intensity").get(); - } - }; -} // Metal - -#endif //LIGHTCOMPONENT_H diff --git a/src/repository/world/components/MeshComponent.cpp b/src/repository/world/components/MeshComponent.cpp deleted file mode 100644 index ca6935e6..00000000 --- a/src/repository/world/components/MeshComponent.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "MeshComponent.h" -#include "../../../context/ApplicationContext.h" -#include "../../../enum/EntryType.h" -#include "../../../service/mesh/MeshData.h" - -namespace Metal { - void MeshComponent::registerFields() { - registerResourceSelection(meshId, "", "Mesh", EntryType::MESH); - registerResourceSelection(materialId, "", "Material", EntryType::MATERIAL); - } - - void MeshComponent::onUpdate(InspectableMember *member) { - if (member != nullptr && member->name == "meshId") { - MeshData *data = CTX.meshService.stream(meshId); - if (data != nullptr) { - const auto e = static_cast(entityId); - if (CTX.worldRepository.registry.all_of(e)) { - CTX.worldRepository.registry.get(e).gizmoCenter = data->gizmoCenter; - } - delete data; - } - } - CTX.engineContext.setGISettingsUpdated(true); - } - - ComponentTypes::ComponentType MeshComponent::getType() { - return ComponentTypes::MESH; - } - - nlohmann::json MeshComponent::toJson() const { - nlohmann::json j; - j["entityId"] = entityId; - j["meshId"] = meshId; - j["materialId"] = materialId; - return j; - } - - void MeshComponent::fromJson(const nlohmann::json &j) { - entityId = j.at("entityId").get(); - meshId = j.at("meshId").get(); - materialId = j.at("materialId").get(); - } -} diff --git a/src/repository/world/components/MeshComponent.h b/src/repository/world/components/MeshComponent.h deleted file mode 100644 index 7e81347f..00000000 --- a/src/repository/world/components/MeshComponent.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef MESHCOMPONENT_H -#define MESHCOMPONENT_H - -#include "../impl/AbstractComponent.h" -#include "../../../util/Serializable.h" -#include - -namespace Metal { - struct MeshComponent final : AbstractComponent, Serializable { - std::string meshId; - std::string materialId; - - unsigned int renderIndex = 0; - - void registerFields() override; - - void onUpdate(InspectableMember *member) override; - - ComponentTypes::ComponentType getType() override; - - nlohmann::json toJson() const override; - - void fromJson(const nlohmann::json& j) override; - }; -} -#endif //MESHCOMPONENT_H diff --git a/src/repository/world/components/PlaneLightComponent.h b/src/repository/world/components/PlaneLightComponent.h deleted file mode 100644 index 8838a44e..00000000 --- a/src/repository/world/components/PlaneLightComponent.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PLANELIGHTCOMPONENT_H -#define PLANELIGHTCOMPONENT_H - -#include "LightComponent.h" -#include "../../../util/Serializable.h" - -namespace Metal { - struct PlaneLightComponent final : LightComponent { - LightTypes::LightType getLightType() override { return LightTypes::PLANE; } - - ComponentTypes::ComponentType getType() override { - return ComponentTypes::PLANE_LIGHT; - } - - nlohmann::json toJson() const override { - nlohmann::json j = LightComponent::toJson(); - j["lightType"] = "PLANE"; - return j; - } - - void fromJson(const nlohmann::json &j) override { - LightComponent::fromJson(j); - } - }; -} // Metal -#endif //PLANELIGHTCOMPONENT_H diff --git a/src/repository/world/components/PrimitiveComponent.cpp b/src/repository/world/components/PrimitiveComponent.cpp new file mode 100644 index 00000000..26bf57c4 --- /dev/null +++ b/src/repository/world/components/PrimitiveComponent.cpp @@ -0,0 +1,72 @@ +#include "PrimitiveComponent.h" +#include "../../../context/ApplicationContext.h" +#include "../../../enum/EntryType.h" +#include "../../../service/mesh/MeshData.h" + +namespace Metal { + void PrimitiveComponent::registerFields() { + registerResourceSelection(meshId, "", "Mesh", EntryType::MESH); + registerColor(albedoColor, "Material", "Albedo color"); + registerBool(isEmissive, "Material", "Is Emissive?"); + registerFloat(roughnessFactor, "Material", "Roughness factor", 0, 1); + registerFloat(metallicFactor, "Material", "Metallic factor", 0, 1); + registerFloat(transmissionFactor, "Material", "Transmission factor", 0, 1); + registerFloat(thicknessFactor, "Material", "Thickness factor", 0, 10); + registerFloat(ior, "Material", "IOR", 1, 3); + registerResourceSelection(albedo, "Material", "Albedo", EntryType::TEXTURE); + registerResourceSelection(roughness, "Material", "Roughness texture", EntryType::TEXTURE); + registerResourceSelection(metallic, "Material", "Metallic Texture", EntryType::TEXTURE); + } + + void PrimitiveComponent::onUpdate(InspectableMember *member) { + if (member != nullptr && member->name == "meshId") { + MeshData *data = CTX.meshService.loadMeshData(meshId); + if (data != nullptr) { + if (CTX.worldRepository.registry.all_of(entityId)) { + CTX.worldRepository.registry.get(entityId).gizmoCenter = data->gizmoCenter; + } + delete data; + } + } + CTX.engineContext.setGISettingsUpdated(true); + CTX.rayTracingService.setNeedsMaterialUpdate(true); + } + + ComponentType PrimitiveComponent::getType() { + return ComponentType::PRIMITIVE; + } + + nlohmann::json PrimitiveComponent::toJson() const { + nlohmann::json j; + j["entityId"] = entityId; + j["meshId"] = meshId; + j["albedo"] = albedo; + j["roughness"] = roughness; + j["metallic"] = metallic; + j["albedoColor"] = {albedoColor.x, albedoColor.y, albedoColor.z}; + j["roughnessFactor"] = roughnessFactor; + j["metallicFactor"] = metallicFactor; + j["transmissionFactor"] = transmissionFactor; + j["thicknessFactor"] = thicknessFactor; + j["ior"] = ior; + j["isEmissive"] = isEmissive; + return j; + } + + void PrimitiveComponent::fromJson(const nlohmann::json &j) { + entityId = j.at("entityId").get(); + meshId = j.at("meshId").get(); + + albedo = j.at("albedo").get(); + roughness = j.at("roughness").get(); + metallic = j.at("metallic").get(); + roughnessFactor = j.at("roughnessFactor").get(); + metallicFactor = j.at("metallicFactor").get(); + transmissionFactor = j.value("transmissionFactor", 0.0f); + thicknessFactor = j.value("thicknessFactor", 0.0f); + ior = j.value("ior", 1.45f); + isEmissive = j.at("isEmissive").get(); + + albedoColor = {j.at("albedoColor")[0], j.at("albedoColor")[1], j.at("albedoColor")[2]}; + } +} diff --git a/src/service/material/MaterialFileData.h b/src/repository/world/components/PrimitiveComponent.h similarity index 50% rename from src/service/material/MaterialFileData.h rename to src/repository/world/components/PrimitiveComponent.h index 9635b75c..d5229ac4 100644 --- a/src/service/material/MaterialFileData.h +++ b/src/repository/world/components/PrimitiveComponent.h @@ -1,15 +1,15 @@ -#ifndef MATERIAL_FILE_DATA_H -#define MATERIAL_FILE_DATA_H -#include +#ifndef PRIMITIVE_COMPONENT_H +#define PRIMITIVE_COMPONENT_H -#include "../../common/inspection/Inspectable.h" -#include "../../util/Serializable.h" +#include "../impl/AbstractComponent.h" +#include "../../../util/Serializable.h" #include namespace Metal { - struct MaterialFileData final : Inspectable, Serializable { + struct PrimitiveComponent final : AbstractComponent, Serializable { + std::string meshId; + std::string albedo; - std::string normal; std::string roughness; std::string metallic; glm::vec3 albedoColor{1, 1, 1}; @@ -20,16 +20,17 @@ namespace Metal { float ior = 1.45; bool isEmissive = false; + unsigned int renderIndex = 0; + void registerFields() override; - const char *getIcon() override; + void onUpdate(InspectableMember *member) override; - const char *getTitle() override; + ComponentType getType() override; nlohmann::json toJson() const override; - void fromJson(const nlohmann::json &j) override; + void fromJson(const nlohmann::json& j) override; }; } - -#endif //MATERIALDATA_H +#endif //MESHCOMPONENT_H diff --git a/src/repository/world/components/SphereLightComponent.cpp b/src/repository/world/components/SphereLightComponent.cpp deleted file mode 100644 index a1f10ba9..00000000 --- a/src/repository/world/components/SphereLightComponent.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "SphereLightComponent.h" -#include "../../../context/ApplicationContext.h" - -namespace Metal { - void SphereLightComponent::registerFields() { - LightComponent::registerFields(); - registerFloat(radiusSize, "", "Radius", .1, 10); - } -} // Metal diff --git a/src/repository/world/components/SphereLightComponent.h b/src/repository/world/components/SphereLightComponent.h deleted file mode 100644 index 45513378..00000000 --- a/src/repository/world/components/SphereLightComponent.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef SPHERELIGHTCOMPONENT_H -#define SPHERELIGHTCOMPONENT_H - -#include "LightComponent.h" - -namespace Metal { - struct SphereLightComponent final : LightComponent { - float radiusSize = 1; - - LightTypes::LightType getLightType() override { return LightTypes::SPHERE; } - - void registerFields() override; - - ComponentTypes::ComponentType getType() override { - return ComponentTypes::SPHERE_LIGHT; - } - - nlohmann::json toJson() const override { - nlohmann::json j = LightComponent::toJson(); - j["radiusSize"] = radiusSize; - j["lightType"] = "SPHERE"; - return j; - } - - void fromJson(const nlohmann::json& j) override { - LightComponent::fromJson(j); - radiusSize = j.at("radiusSize").get(); - } - }; -} // Metal - -#endif //SPHERELIGHTCOMPONENT_H diff --git a/src/repository/world/components/TransformComponent.cpp b/src/repository/world/components/TransformComponent.cpp index 119b5709..73104008 100644 --- a/src/repository/world/components/TransformComponent.cpp +++ b/src/repository/world/components/TransformComponent.cpp @@ -1,7 +1,5 @@ #include "TransformComponent.h" #include "VolumeComponent.h" -#include "LightComponent.h" -#include "../../../common/interface/Icons.h" #include "../../../context/ApplicationContext.h" #define ROTATION "Rotation" @@ -14,20 +12,11 @@ namespace Metal { registerBool(isStatic, "", "Static?"); } - ComponentTypes::ComponentType TransformComponent::getType() { - return ComponentTypes::TRANSFORM; + ComponentType TransformComponent::getType() { + return TRANSFORM; } void TransformComponent::onUpdate(InspectableMember *member) { - const auto e = static_cast(entityId); - bool isVolume = CTX.worldRepository.registry.all_of(e); - bool isLight = CTX.worldRepository.registry.all_of >(e); - if (isLight) { - CTX.engineContext.setUpdateLights(true); - } - if (isVolume) { - CTX.engineContext.setUpdateVolumes(true); - } if (member != nullptr && member->name == ROTATION) { rotation = normalize(glm::quat(rotationEuler * (glm::pi() / 180.f))); } @@ -52,7 +41,7 @@ namespace Metal { } void TransformComponent::fromJson(const nlohmann::json &j) { - entityId = j.at("entityId").get(); + entityId = j.at("entityId").get(); translation = {j.at("translation")[0], j.at("translation")[1], j.at("translation")[2]}; rotation = {j.at("rotation")[3], j.at("rotation")[0], j.at("rotation")[1], j.at("rotation")[2]}; rotationEuler = {j.at("rotationEuler")[0], j.at("rotationEuler")[1], j.at("rotationEuler")[2]}; diff --git a/src/repository/world/components/TransformComponent.h b/src/repository/world/components/TransformComponent.h index 6e627233..3315bcfd 100644 --- a/src/repository/world/components/TransformComponent.h +++ b/src/repository/world/components/TransformComponent.h @@ -22,7 +22,7 @@ namespace Metal { void registerFields() override; - ComponentTypes::ComponentType getType() override; + ComponentType getType() override; void onUpdate(InspectableMember *member) override; diff --git a/src/repository/world/components/VolumeComponent.cpp b/src/repository/world/components/VolumeComponent.cpp index ded620c7..e0f7b99d 100644 --- a/src/repository/world/components/VolumeComponent.cpp +++ b/src/repository/world/components/VolumeComponent.cpp @@ -10,11 +10,7 @@ namespace Metal { registerInt(samples, "", "Samples", 1); } - ComponentTypes::ComponentType VolumeComponent::getType() { - return ComponentTypes::VOLUME; - } - - void VolumeComponent::onUpdate(InspectableMember *member) { - CTX.engineContext.setUpdateVolumes(true); + ComponentType VolumeComponent::getType() { + return VOLUME; } } // Metal diff --git a/src/repository/world/components/VolumeComponent.h b/src/repository/world/components/VolumeComponent.h index 88696b55..4ea910c8 100644 --- a/src/repository/world/components/VolumeComponent.h +++ b/src/repository/world/components/VolumeComponent.h @@ -15,9 +15,7 @@ namespace Metal { void registerFields() override; - ComponentTypes::ComponentType getType() override; - - void onUpdate(InspectableMember *member) override; + ComponentType getType() override; nlohmann::json toJson() const override { nlohmann::json j; @@ -31,7 +29,7 @@ namespace Metal { } void fromJson(const nlohmann::json& j) override { - entityId = j.at("entityId").get(); + entityId = j.at("entityId").get(); albedo = {j.at("albedo")[0], j.at("albedo")[1], j.at("albedo")[2]}; density = j.at("density").get(); g = j.at("g").get(); diff --git a/src/repository/world/impl/AbstractComponent.h b/src/repository/world/impl/AbstractComponent.h index 14bf540f..b9ab3ebb 100644 --- a/src/repository/world/impl/AbstractComponent.h +++ b/src/repository/world/impl/AbstractComponent.h @@ -1,35 +1,34 @@ #ifndef ABSTRACTCOMPONENT_H #define ABSTRACTCOMPONENT_H #include "../../../common/inspection/Inspectable.h" -#include "../../../enum/engine-definitions.h" #include "../../../enum/ComponentType.h" namespace Metal { struct AbstractComponent : Inspectable { AbstractComponent() = default; - [[nodiscard]] EntityID getEntityId() const { + [[nodiscard]] entt::entity getEntityId() const { return entityId; } - void setEntityId(const EntityID entityId) { + void setEntityId(const entt::entity entityId) { this->entityId = entityId; } const char *getIcon() override { - return ComponentTypes::IconOf(getType()); + return Metal::ComponentTypes::IconOf(getType()); } const char *getTitle() override { - return ComponentTypes::NameOf(getType()); + return Metal::ComponentTypes::NameOf(getType()); } - virtual ComponentTypes::ComponentType getType() { + virtual ComponentType getType() { throw std::runtime_error("Not implemented"); } protected: - EntityID entityId{}; + entt::entity entityId{}; }; } // Metal diff --git a/src/repository/world/impl/EntityComponent.cpp b/src/repository/world/impl/EntityComponent.cpp deleted file mode 100644 index 9a65f908..00000000 --- a/src/repository/world/impl/EntityComponent.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "EntityComponent.h" -#include "../../../common/interface/Icons.h" -#include "../../../util/UIUtil.h" - -namespace Metal { - void EntityComponent::initialize(bool container) { - this->isContainer = container; - if (container) { - color = glm::vec3(UIUtil::DIRECTORY_COLOR.x, UIUtil::DIRECTORY_COLOR.y, UIUtil::DIRECTORY_COLOR.z); - } else { - color = glm::vec3(1, 1, 1); - } - } - - void EntityComponent::registerFields() { - registerText(name, "", "Name"); - registerColor(color, "", "Hierarchy Color"); - } - - const char *EntityComponent::getIcon() { - return isContainer ? Icons::inventory_2.c_str() : Icons::category.c_str(); - } -} diff --git a/src/repository/world/impl/MetadataComponent.cpp b/src/repository/world/impl/MetadataComponent.cpp new file mode 100644 index 00000000..bd5dc915 --- /dev/null +++ b/src/repository/world/impl/MetadataComponent.cpp @@ -0,0 +1,14 @@ +#include "MetadataComponent.h" +#include "../../../common/interface/Icons.h" +#include "../../../util/UIUtil.h" + +namespace Metal { + void MetadataComponent::registerFields() { + registerText(name, "", "Name"); + registerColor(color, "", "Hierarchy Color"); + } + + ComponentType MetadataComponent::getType() { + return METADATA; + } +} diff --git a/src/repository/world/impl/EntityComponent.h b/src/repository/world/impl/MetadataComponent.h similarity index 56% rename from src/repository/world/impl/EntityComponent.h rename to src/repository/world/impl/MetadataComponent.h index ee998e69..4923e86e 100644 --- a/src/repository/world/impl/EntityComponent.h +++ b/src/repository/world/impl/MetadataComponent.h @@ -3,52 +3,34 @@ #include #include +#include "AbstractComponent.h" #include "../../../enum/engine-definitions.h" #include "../../../enum/ComponentType.h" #include "../../../common/inspection/Inspectable.h" #include "../../../util/Serializable.h" namespace Metal { - struct EntityComponent final : Inspectable, Serializable { - std::string onTile; + struct MetadataComponent final : AbstractComponent, Serializable { std::string name = "New entity"; - glm::vec3 color{}; - bool isContainer = false; + glm::vec3 color{1,1,1}; nlohmann::json toJson() const override { nlohmann::json j; - j["onTile"] = onTile; j["name"] = name; j["color"] = {color.x, color.y, color.z}; - j["isContainer"] = isContainer; return j; } void fromJson(const nlohmann::json &j) override { - onTile = j.at("onTile").get(); name = j.at("name").get(); color.x = j.at("color")[0].get(); color.y = j.at("color")[1].get(); color.z = j.at("color")[2].get(); - isContainer = j.at("isContainer").get(); } - EntityComponent() = default; - - void initialize(bool container); - void registerFields() override; - const char *getIcon() override; - - const char *getTitle() override { - return name.c_str(); - } - }; - - struct HierarchyComponent { - EntityID parent = EMPTY_ENTITY; - std::vector children{}; + ComponentType getType() override; }; } // Metal diff --git a/src/repository/world/impl/WorldGridRepository.cpp b/src/repository/world/impl/WorldGridRepository.cpp deleted file mode 100644 index 694d61cf..00000000 --- a/src/repository/world/impl/WorldGridRepository.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "WorldGridRepository.h" - -#include "../../../context/ApplicationContext.h" - -namespace Metal { - bool WorldGridRepository::updateLoadedTiles() { - if (auto *center = getOrCreateTile(CTX.worldRepository.camera.position); - currentTile != center || prevSize != tiles.size()) { - hasMainTileChanged = true; - currentTile = center; - prevSize = tiles.size(); - loadedWorldTiles[0] = center; - for (int i = 0; i < 8; i++) { - if (!center->adjacentTiles[i].empty() && tiles.contains(center->adjacentTiles[i])) { - loadedWorldTiles[i + 1] = &tiles.at(center->adjacentTiles[i]); - } - } - return true; - } - return false; - } - - std::array &WorldGridRepository::getLoadedTiles() { - return loadedWorldTiles; - } - - WorldTile *WorldGridRepository::getOrCreateTile(const glm::vec3 &point) { - const int tileX = getTileLocation(point.x); - const int tileZ = getTileLocation(point.z); - const std::string id = TILE_ID(tileX, tileZ); - if (!tiles.contains(id)) { - addTile(point); - } - return &tiles.at(id); - } - - WorldTile *WorldGridRepository::getTile(const glm::vec3 &point) { - const int tileX = getTileLocation(point.x); - const int tileZ = getTileLocation(point.z); - const std::string id = TILE_ID(tileX, tileZ); - if (!tiles.contains(id)) { - return nullptr; - } - return &tiles.at(id); - } - - WorldTile *WorldGridRepository::getCurrentTile() const { - return currentTile; - } - - void WorldGridRepository::createIfAbsent(const int x, const int z) { - if (std::string id = TILE_ID(x, z); !tiles.contains(id)) { - LOG_INFO("Creating tile " + std::to_string(x) + " " + std::to_string(z) + " " + id); - tiles.insert({id, WorldTile(x, z, id)}); - } - } - - void WorldGridRepository::addTile(const glm::vec3 &point) { - const int x = getTileLocation(point.x); - const int z = getTileLocation(point.z); - std::string id = TILE_ID(x, z); - if (tiles.contains(id)) { - return; - } - tiles.insert({id, WorldTile(x, z, id)}); - - updateAdjacentTiles(&tiles.at(id)); - } - - void WorldGridRepository::updateAdjacentTiles(WorldTile *newTile) { - const int x = newTile->x; - const int z = newTile->z; - const std::array westTile{x, z - 1}; - const std::array eastTile{x, z + 1}; - const std::array northTile{x + 1, z}; - const std::array southTile{x - 1, z}; - const std::array northEastTile{x + 1, z + 1}; - const std::array northWestTile{x + 1, z - 1}; - const std::array southEastTile{x - 1, z + 1}; - const std::array southWestTile{x - 1, z - 1}; - - putAdjacentTile(westTile, newTile); - putAdjacentTile(eastTile, newTile); - putAdjacentTile(northTile, newTile); - putAdjacentTile(southTile, newTile); - putAdjacentTile(northEastTile, newTile); - putAdjacentTile(northWestTile, newTile); - putAdjacentTile(southEastTile, newTile); - putAdjacentTile(southWestTile, newTile); - } - - void WorldGridRepository::putAdjacentTile(const std::array &tileLocation, WorldTile *newTile) { - if (const std::string tileId = TILE_ID(tileLocation[0], tileLocation[1]); tiles.contains(tileId)) { - auto &tile = tiles.at(tileId); - tile.putAdjacentTile(newTile); - newTile->putAdjacentTile(&tile); - } - } - - void WorldGridRepository::removeTile(const std::string &id) { - const auto &tileToRemove = tiles.at(id); - tiles.erase(id); - for (auto &tile: tiles) { - tile.second.removeAdjacentTile(&tileToRemove); - } - } - - void WorldGridRepository::moveBetweenTiles(const EntityID entityId, WorldTile *previousWorldTile, - WorldTile *newWorldTile) const { - auto *entity = CTX.worldRepository.getEntity(entityId); - entity->registerChange(); - entity->freezeVersion(); - if (!entity->onTile.empty()) { - previousWorldTile->entities.erase( - std::ranges::remove(previousWorldTile->entities, entityId).begin(), - previousWorldTile->entities.end()); - newWorldTile->entities.push_back(entityId); - } else { - newWorldTile->entities.push_back(entityId); - } - entity->onTile = newWorldTile->id; - } -} // Metal diff --git a/src/repository/world/impl/WorldGridRepository.h b/src/repository/world/impl/WorldGridRepository.h deleted file mode 100644 index 96aabd4e..00000000 --- a/src/repository/world/impl/WorldGridRepository.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef WORLDGRID_H -#define WORLDGRID_H -#include - -#include "WorldTile.h" -#include "../../../common/AbstractRuntimeComponent.h" -#include "../../../common/inspection/Inspectable.h" -#include "../../../enum/engine-definitions.h" -#include "../../../util/Serializable.h" - -namespace Metal { - class WorldGridRepository final : public AbstractRuntimeComponent, public Serializable { - std::unordered_map tiles{}; - std::array loadedWorldTiles{}; - WorldTile *currentTile = nullptr; - unsigned int prevSize = 0; - - public: - bool hasMainTileChanged = false; - - bool updateLoadedTiles(); - - explicit WorldGridRepository() - : AbstractRuntimeComponent() { - } - - static int getTileLocation(const float v) { - return static_cast(std::floor(v / TILE_SIZE) + 0.5); - } - - /** - * Returns current tile and its adjacent ones - * @return May contain null elements - */ - std::array &getLoadedTiles(); - - WorldTile *getOrCreateTile(const glm::vec3 &point); - - WorldTile *getCurrentTile() const; - - WorldTile *getTile(const glm::vec3 &point); - - void createIfAbsent(int x, int z); - - void addTile(const glm::vec3 &point); - - void updateAdjacentTiles(WorldTile *newTile); - - void putAdjacentTile(const std::array &tileLocation, WorldTile *newTile); - - void removeTile(const std::string &id); - - void moveBetweenTiles(EntityID entityId, WorldTile *previousWorldTile, WorldTile *newWorldTile) const; - - std::unordered_map &getTiles() { - return tiles; - } - - nlohmann::json toJson() const override { - nlohmann::json j; - nlohmann::json t; - for (auto const& [key, val] : tiles) { - t[key] = val.toJson(); - } - j["tiles"] = t; - return j; - } - - void fromJson(const nlohmann::json& j) override { - tiles.clear(); - if (j.contains("tiles")) { - for (auto const& [key, val] : j.at("tiles").items()) { - WorldTile tile; - tile.fromJson(val); - tiles.emplace(key, tile); - } - } - } - }; -} // Metal - -#endif //WORLDGRID_H diff --git a/src/repository/world/impl/WorldTile.h b/src/repository/world/impl/WorldTile.h deleted file mode 100644 index b8452ec4..00000000 --- a/src/repository/world/impl/WorldTile.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef WORLDTILE_H -#define WORLDTILE_H -#include -#include -#include -#include - -#include "BoundingBox.h" -#include "../../../enum/engine-definitions.h" -#include "../../../service/voxel/impl/SparseVoxelOctreeBuilder.h" -#include "../../../util/Serializable.h" -#define TILE_SIZE 64 - -#define TILE_ID(x, z) (std::to_string(x) + "_" + std::to_string(z)) - -namespace Metal { - struct WorldTile final : Serializable { - std::array adjacentTiles{}; - int x; - int z; - std::string id; - bool loaded = false; - std::vector entities{}; - BoundingBox boundingBox{}; - int normalizedDistance = 0; - - void updateTiles(const WorldTile *adjacentWorldTile, const std::string &key) { - bool isWest = adjacentWorldTile->z < z && adjacentWorldTile->x == x; - bool isEast = adjacentWorldTile->z > z && adjacentWorldTile->x == x; - bool isNorth = adjacentWorldTile->x > x && adjacentWorldTile->z == z; - bool isSouth = adjacentWorldTile->x < x && adjacentWorldTile->z == z; - - bool isSouthEast = adjacentWorldTile->x < x && adjacentWorldTile->z > z; - bool isSouthWest = adjacentWorldTile->x < x && adjacentWorldTile->z < z; - bool isNorthEast = adjacentWorldTile->x > x && adjacentWorldTile->z > z; - bool isNorthWest = adjacentWorldTile->x > x && adjacentWorldTile->z < z; - - if (isWest) adjacentTiles[0] = key; - if (isNorth) adjacentTiles[1] = key; - if (isEast) adjacentTiles[2] = key; - if (isSouth) adjacentTiles[3] = key; - if (isSouthWest) adjacentTiles[4] = key; - if (isSouthEast) adjacentTiles[5] = key; - if (isNorthWest) adjacentTiles[6] = key; - if (isNorthEast) adjacentTiles[7] = key; - } - - explicit WorldTile(int x, int z, std::string id) - : x(x), z(z), id(std::move(id)) { - boundingBox.center.x = x * TILE_SIZE; - boundingBox.center.z = z * TILE_SIZE; - boundingBox.max = boundingBox.center + glm::vec3(TILE_SIZE / 2.0f, TILE_SIZE / 2.0f, TILE_SIZE / 2.0f); - boundingBox.min = boundingBox.center - glm::vec3(TILE_SIZE / 2.0f, TILE_SIZE / 2.0f, TILE_SIZE / 2.0f); - } - - explicit WorldTile(): x(0), z(0) { - } - - void putAdjacentTile(const WorldTile *adjacentWorldTile) { - updateTiles(adjacentWorldTile, adjacentWorldTile->id); - } - - void removeAdjacentTile(const WorldTile *adjacentWorldTile) { - updateTiles(adjacentWorldTile, ""); - } - - nlohmann::json toJson() const override { - nlohmann::json j; - j["adjacentTiles"] = adjacentTiles; - j["x"] = x; - j["z"] = z; - j["id"] = id; - j["loaded"] = loaded; - j["entities"] = entities; - j["boundingBox"] = boundingBox.toJson(); - j["normalizedDistance"] = normalizedDistance; - return j; - } - - void fromJson(const nlohmann::json& j) override { - adjacentTiles = j.at("adjacentTiles").get>(); - x = j.at("x").get(); - z = j.at("z").get(); - id = j.at("id").get(); - loaded = j.at("loaded").get(); - entities = j.at("entities").get>(); - boundingBox.fromJson(j.at("boundingBox")); - normalizedDistance = j.at("normalizedDistance").get(); - } - }; -} // Metal - -#endif //WORLDTILE_H diff --git a/src/service/abstract/IStreamable.h b/src/service/abstract/IStreamable.h deleted file mode 100644 index 26727f23..00000000 --- a/src/service/abstract/IStreamable.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef ISTREAMABLE_H -#define ISTREAMABLE_H - -#include -#include "AbstractResourceService.h" - -namespace Metal { - class RuntimeResource; - - template - class IStreamable : public AbstractResourceService { - public: - virtual ~IStreamable() = default; - - virtual T *create(const std::string &id) = 0; - }; -} - -#endif //ISTREAMABLE_H diff --git a/src/service/camera/CameraService.cpp b/src/service/camera/CameraService.cpp index 2783a948..723c06d6 100644 --- a/src/service/camera/CameraService.cpp +++ b/src/service/camera/CameraService.cpp @@ -4,6 +4,8 @@ #include "../../context/ApplicationContext.h" namespace Metal { + // Per frame + // TODO - EVENT SYSTEM void CameraService::onSync() { camera = &CTX.worldRepository.camera; if (camera != nullptr) { diff --git a/src/service/descriptor/DescriptorSetService.cpp b/src/service/descriptor/DescriptorSetService.cpp index cde1e917..81f7093a 100644 --- a/src/service/descriptor/DescriptorSetService.cpp +++ b/src/service/descriptor/DescriptorSetService.cpp @@ -11,7 +11,7 @@ namespace Metal { DescriptorInstance *DescriptorSetService::createDescriptor(const PipelineBuilder &pipelineBuilder, const std::string &id, VkShaderStageFlags stageFlags) { auto *descriptorInstance = createResourceInstance(id); - + for (auto &builder : pipelineBuilder.resourceBindings) { DescriptorBinding binding{}; binding.bindingPoint = builder.bindingPoint; @@ -70,7 +70,7 @@ namespace Metal { binding.stageFlags = static_cast(stageFlags); descriptorInstance->bindings.push_back(binding); } - + updateDescriptor(descriptorInstance); return descriptorInstance; } @@ -93,7 +93,7 @@ namespace Metal { unsigned int attachmentIndex) { auto attachment = framebuffer->attachments[attachmentIndex]; if (attachment->imageDescriptor == nullptr) { - attachment->imageDescriptor = createResourceInstance(std::string(attachment->name)); + attachment->imageDescriptor = createResourceInstance(framebuffer->getId() + std::to_string(attachmentIndex)); attachment->imageDescriptor->bindings.push_back(DescriptorBinding::Of(VK_SHADER_STAGE_FRAGMENT_BIT, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, CTX.vulkanContext.vkImageSampler, diff --git a/src/service/dock/DockService.cpp b/src/service/dock/DockService.cpp index c2a992b1..ee1ab8e4 100644 --- a/src/service/dock/DockService.cpp +++ b/src/service/dock/DockService.cpp @@ -8,9 +8,6 @@ #include "../../context/ApplicationContext.h" namespace Metal { - DockService::DockService() : AbstractRuntimeComponent() { - } - void DockService::buildViews(ImGuiID windowId, AbstractPanel *panel) const { if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable) { DockRepository &dockRepository = CTX.dockRepository; @@ -39,45 +36,62 @@ namespace Metal { ImGui::DockBuilderRemoveNode(windowId); ImGui::DockBuilderAddNode(windowId, ImGuiDockNodeFlags_NoTabBar); ImGui::DockBuilderSetNodeSize(windowId, ImGui::GetMainViewport()->Size); - { - dockRepository.top.direction = TOP; - dockRepository.top.origin = nullptr; - dockRepository.top.outAtOppositeDir = nullptr; - dockRepository.top.splitDir = ImGuiDir_Right; - createDockSpace(&dockRepository.top, &windowId); - addWindow(&dockRepository.top, panel); + const auto &left = dockRepository.left; + for (size_t i = 0; i < left.size(); i++) { + DockDTO *dockSpace = left[i]; + if (i == 0) { + dockSpace->origin = nullptr; + dockSpace->outAtOppositeDir = nullptr; + dockSpace->splitDir = ImGuiDir_Left; + } else { + DockDTO *previous = left[i - 1]; + dockSpace->origin = previous; + dockSpace->outAtOppositeDir = previous; + dockSpace->splitDir = ImGuiDir_Down; + } + createDockSpace(dockSpace, &windowId); + addWindow(dockSpace, panel); } - { - dockRepository.rightTop.origin = &dockRepository.top; - dockRepository.rightTop.outAtOppositeDir = &dockRepository.top; - dockRepository.rightTop.splitDir = ImGuiDir_Down; - dockRepository.rightTop.direction = RIGHT_TOP; - createDockSpace(&dockRepository.rightTop, &windowId); - addWindow(&dockRepository.rightTop, panel); + const auto &right = dockRepository.right; + for (size_t i = 0; i < right.size(); i++) { + DockDTO *dockSpace = right[i]; + if (i == 0) { + dockSpace->origin = nullptr; + dockSpace->outAtOppositeDir = nullptr; + dockSpace->splitDir = ImGuiDir_Right; + } else { + DockDTO *previous = right[i - 1]; + dockSpace->origin = previous; + dockSpace->outAtOppositeDir = previous; + dockSpace->splitDir = ImGuiDir_Down; + } + createDockSpace(dockSpace, &windowId); + addWindow(dockSpace, panel); } - { - dockRepository.rightBottom.origin = &dockRepository.rightTop; - dockRepository.rightBottom.outAtOppositeDir = &dockRepository.rightTop; - - dockRepository.rightBottom.splitDir = ImGuiDir_Down; - dockRepository.rightBottom.direction = RIGHT_BOTTOM; - createDockSpace(&dockRepository.rightBottom, &windowId); - addWindow(&dockRepository.rightBottom, panel); + const auto &bottom = dockRepository.bottom; + for (size_t i = 0, bottomSize = bottom.size(); i < bottomSize; i++) { + DockDTO *dockSpace = bottom[i]; + if (i == 0) { + dockSpace->origin = nullptr; + dockSpace->outAtOppositeDir = nullptr; + dockSpace->splitDir = ImGuiDir_Down; + } else { + DockDTO *previous = bottom[i - 1]; + dockSpace->origin = previous; + dockSpace->outAtOppositeDir = previous; + dockSpace->splitDir = ImGuiDir_Right; + } + createDockSpace(dockSpace, &windowId); + addWindow(dockSpace, panel); } - { - dockRepository.bottom.origin = nullptr; - dockRepository.bottom.outAtOppositeDir = nullptr; - dockRepository.bottom.splitDir = ImGuiDir_Down; + dockRepository.center.nodeId = windowId; + addWindow(&dockRepository.center, panel); - dockRepository.bottom.direction = BOTTOM; - createDockSpace(&dockRepository.bottom, &windowId); - addWindow(&dockRepository.bottom, panel); - } - ImGui::DockBuilderDockWindow(dockRepository.top.internalId.c_str(), windowId); + ImGui::DockBuilderDockWindow(dockRepository.center.internalId.c_str(), windowId); ImGui::DockBuilderFinish(windowId); } } diff --git a/src/service/dock/DockService.h b/src/service/dock/DockService.h index 7b97a22f..fe3c9cfd 100644 --- a/src/service/dock/DockService.h +++ b/src/service/dock/DockService.h @@ -16,8 +16,6 @@ namespace Metal { static void createDockSpace(DockDTO *dockSpace, ImGuiID *dockMainId); static void addWindow(DockDTO *d, AbstractPanel *panel); - - explicit DockService(); }; } // Metal diff --git a/src/service/files/FilesService.cpp b/src/service/files/FilesService.cpp index 7cd0b086..9d6af371 100644 --- a/src/service/files/FilesService.cpp +++ b/src/service/files/FilesService.cpp @@ -81,10 +81,6 @@ namespace Metal { DELETE_S(FORMAT_FILE_SCENE) break; } - case EntryType::MATERIAL: { - DELETE_S(FORMAT_FILE_MATERIAL) - break; - } case EntryType::VOLUME: { DELETE_S(FORMAT_FILE_VOLUME) break; @@ -94,22 +90,6 @@ namespace Metal { } } - void FilesService::createMaterial(const std::string &targetDir, FSEntry *currentDirectory) const { - EntryMetadata materialMetadata{}; - materialMetadata.type = EntryType::MATERIAL; - int count = 0; - for (FSEntry *child: currentDirectory->children) { - if (child->type == EntryType::MATERIAL && child->name == "New Material (" + std::to_string(count) + ")") { - count++; - } - } - materialMetadata.name = "New Material (" + std::to_string(count+1) + ")"; - - DUMP_TEMPLATE(targetDir + '/' + FORMAT_FILE_METADATA(materialMetadata.getId()), materialMetadata) - MaterialFileData data{}; - DUMP_TEMPLATE(CTX.getAssetDirectory() + FORMAT_FILE_MATERIAL(materialMetadata.getId()), data) - } - void FilesService::CreateDirectory(FSEntry *currentDirectory) { int count = 0; for (FSEntry *child: currentDirectory->children) { diff --git a/src/service/files/FilesService.h b/src/service/files/FilesService.h index 06eb19e3..c2906941 100644 --- a/src/service/files/FilesService.h +++ b/src/service/files/FilesService.h @@ -27,8 +27,6 @@ namespace Metal { void deleteFiles(const std::unordered_map &files_context); - void createMaterial(const std::string &targetDir, FSEntry *currentDirectory) const; - void Move(FSEntry *toMove, FSEntry *targetDir); static void CreateDirectory(FSEntry *currentDirectory); diff --git a/src/service/framebuffer/FrameBufferAttachment.h b/src/service/framebuffer/FrameBufferAttachment.h index 78784105..1c865e8f 100644 --- a/src/service/framebuffer/FrameBufferAttachment.h +++ b/src/service/framebuffer/FrameBufferAttachment.h @@ -10,7 +10,6 @@ namespace Metal { VkFormat format = VK_FORMAT_MAX_ENUM; DescriptorInstance *imageDescriptor = nullptr; bool depth = false; - const char *name = nullptr; void dispose() const; }; diff --git a/src/service/framebuffer/FrameBufferService.cpp b/src/service/framebuffer/FrameBufferService.cpp index 387394c1..3cb4a0ff 100644 --- a/src/service/framebuffer/FrameBufferService.cpp +++ b/src/service/framebuffer/FrameBufferService.cpp @@ -10,27 +10,9 @@ #include "../../context/ApplicationContext.h" namespace Metal { - void FrameBufferService::createSampler(bool linear, VkSampler &vkImageSampler) { - VkSamplerCreateInfo samplerCreateInfo{}; - samplerCreateInfo.magFilter = linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; - samplerCreateInfo.minFilter = linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; - samplerCreateInfo.mipmapMode = linear ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; - samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - samplerCreateInfo.mipLodBias = 0.0f; - samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER; - samplerCreateInfo.minLod = 0.0f; - samplerCreateInfo.maxLod = 1; - // TODO - ENABLE/DISABLE ANISOTROPY - samplerCreateInfo.maxAnisotropy = 8; - samplerCreateInfo.anisotropyEnable = VK_TRUE; - samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - VulkanUtils::CheckVKResult(vkCreateSampler(CTX.vulkanContext.device.device, &samplerCreateInfo, nullptr, - &vkImageSampler)); - } - FrameBufferInstance *FrameBufferService::createFrameBuffer(const std::string &id, const unsigned w, const unsigned h, glm::vec4 clearColor) { + FrameBufferInstance *FrameBufferService::createFrameBuffer(const std::string &id, const unsigned w, + const unsigned h, glm::vec4 clearColor) { auto *framebuffer = createResourceInstance(id); framebuffer->bufferWidth = w; framebuffer->bufferHeight = h; @@ -41,25 +23,24 @@ namespace Metal { void FrameBufferService::createDepthAttachment(FrameBufferInstance *framebuffer) const { VkFormat depthFormat = VulkanUtils::GetValidDepthFormat(CTX.vulkanContext.physDevice.physical_device); - const auto att = createAttachmentInternal("Depth attachment", depthFormat, + const auto att = createAttachmentInternal(depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, framebuffer); att->depth = true; } - void FrameBufferService::createAttachment(const char *name, VkFormat format, VkImageUsageFlagBits usage, + void FrameBufferService::createAttachment(VkFormat format, VkImageUsageFlagBits usage, FrameBufferInstance *framebuffer) const { - const auto att = createAttachmentInternal(name, format, + const auto att = createAttachmentInternal(format, usage, framebuffer); att->depth = false; } std::shared_ptr FrameBufferService::createAttachmentInternal( - const char *name, VkFormat format, + VkFormat format, VkImageUsageFlagBits usage, FrameBufferInstance *framebuffer) const { std::shared_ptr attachment = std::make_shared(); - attachment->name = name; framebuffer->attachments.push_back(attachment); attachment->format = format; @@ -90,7 +71,8 @@ namespace Metal { image.initialLayout = layout; image.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VulkanUtils::CheckVKResult(vkCreateImage(CTX.vulkanContext.device.device, &image, nullptr, &attachment->vkImage)); + VulkanUtils::CheckVKResult( + vkCreateImage(CTX.vulkanContext.device.device, &image, nullptr, &attachment->vkImage)); VkMemoryAllocateInfo memAlloc{}; VkMemoryRequirements memReqs; diff --git a/src/service/framebuffer/FrameBufferService.h b/src/service/framebuffer/FrameBufferService.h index 2e18e6cf..15fab167 100644 --- a/src/service/framebuffer/FrameBufferService.h +++ b/src/service/framebuffer/FrameBufferService.h @@ -12,35 +12,22 @@ namespace Metal { struct FrameBufferAttachment; struct FrameBufferInstance; - /** - * Responsible for creating: - * - Framebuffer attachments - * - Command buffers - * - Render passes - * - Framebuffers - */ class FrameBufferService final : public AbstractResourceService { - std::shared_ptr createAttachmentInternal(const char *name, VkFormat format, + std::shared_ptr createAttachmentInternal(VkFormat format, VkImageUsageFlagBits usage, FrameBufferInstance *framebuffer) const; void createVKFrameBuffer(FrameBufferInstance *framebuffer) const; public: - explicit FrameBufferService() - : AbstractResourceService() { - } - - void createSampler(bool linear, VkSampler &vkImageSampler); - - FrameBufferInstance *createFrameBuffer(const std::string &id, unsigned int w, unsigned int h, glm::vec4 clearColor = glm::vec4(0.0f)); + FrameBufferInstance *createFrameBuffer(const std::string &id, unsigned int w, unsigned int h, + glm::vec4 clearColor = glm::vec4(0.0f)); void createDepthAttachment(FrameBufferInstance *framebuffer) const; - void createAttachment(const char *name, VkFormat format, VkImageUsageFlagBits usage, + void createAttachment(VkFormat format, VkImageUsageFlagBits usage, FrameBufferInstance *framebuffer) const; - void createRenderPass(FrameBufferInstance *framebuffer) const; void disposeResource(FrameBufferInstance *resource) override; diff --git a/src/service/lights/LightService.cpp b/src/service/lights/LightService.cpp index 56f6449b..2ce80c93 100644 --- a/src/service/lights/LightService.cpp +++ b/src/service/lights/LightService.cpp @@ -1,56 +1,17 @@ #include "LightService.h" -#include #include "../../context/ApplicationContext.h" -#include "../../repository/world/components/SphereLightComponent.h" #include "../buffer/BufferInstance.h" #include "../../enum/EngineResourceIDs.h" namespace Metal { void LightService::registerLights() { - auto view = CTX.worldRepository.registry.view, TransformComponent>(); - for (auto [entity, l_ptr, t]: view.each()) { - const auto entityId = static_cast(entity); - if (CTX.worldRepository.hiddenEntities.contains(entityId)) { - continue; - } - auto &translation = t.translation; - auto &l = *l_ptr; - const auto lightType = l.getLightType(); - glm::vec3 normal(0.0f, 1.0f, 0.0f); - glm::vec3 rotatedNormal = t.rotation * normal; - - float radiusOrScale = 0; - if (lightType == LightTypes::SPHERE) { - radiusOrScale = static_cast(l).radiusSize; - } - - items.push_back(LightData( - glm::vec4(l.color, l.intensity), - translation, - glm::normalize(rotatedNormal), - lightType == LightTypes::SPHERE ? glm::vec3(radiusOrScale) : glm::vec3(t.scale), - lightType - )); - } - } - - void LightService::registerSun() { - if (CTX.engineRepository.atmosphereEnabled) { - items.push_back(LightData( - glm::vec4(sunColor, CTX.engineRepository.sunLightIntensity), - sunPosition, - glm::vec3(0), - glm::vec3(CTX.engineRepository.sunRadius), - LightTypes::SPHERE - )); - } } + // TODO - ADD EVENT SYSTEM THAT TRIGGERS THIS UPDATE void LightService::onSync() { items.clear(); - registerSun(); registerLights(); if (!items.empty()) { @@ -58,7 +19,6 @@ namespace Metal { } } - void LightService::computeSunInfo() { sunPosition = glm::vec3(0, std::cos(CTX.engineRepository.elapsedTime), diff --git a/src/service/lights/LightService.h b/src/service/lights/LightService.h index 2b806bd4..35a71ace 100644 --- a/src/service/lights/LightService.h +++ b/src/service/lights/LightService.h @@ -13,18 +13,12 @@ namespace Metal { void registerLights(); - void registerSun(); - static glm::vec3 CalculateSunColor(float elevation, glm::vec3 &nightColor, glm::vec3 &dawnColor, glm::vec3 &middayColor); static glm::vec3 BlendColors(glm::vec3 &c1, glm::vec3 &c2, float t); public: - explicit LightService() - : AbstractRuntimeComponent() { - } - void onSync() override; void computeSunInfo(); diff --git a/src/service/material/MaterialFileData.cpp b/src/service/material/MaterialFileData.cpp deleted file mode 100644 index 720e86d4..00000000 --- a/src/service/material/MaterialFileData.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "MaterialFileData.h" - -#include "../../common/interface/Icons.h" - -namespace Metal { - void MaterialFileData::registerFields() { - registerColor(albedoColor, "", "Albedo color"); - registerBool(isEmissive, "", "Is Emissive"); - registerFloat(roughnessFactor, "", "Roughness factor", 0, 1); - registerFloat(metallicFactor, "", "Metallic factor", 0, 1); - registerFloat(transmissionFactor, "", "Transmission factor", 0, 1); - registerFloat(thicknessFactor, "", "Thickness factor", 0, 10); - registerFloat(ior, "", "IOR", 1, 3); - - registerResourceSelection(albedo, "", "Albedo", EntryType::TEXTURE); - registerResourceSelection(normal, "", "Normal", EntryType::TEXTURE); - registerResourceSelection(roughness, "", "Roughness texture", EntryType::TEXTURE); - registerResourceSelection(metallic, "", "Metallic Texture", EntryType::TEXTURE); - } - - const char *MaterialFileData::getIcon() { - return Icons::format_paint.c_str(); - } - - const char *MaterialFileData::getTitle() { - return "Material"; - } - - nlohmann::json MaterialFileData::toJson() const { - nlohmann::json j; - j["albedo"] = albedo; - j["normal"] = normal; - j["roughness"] = roughness; - j["metallic"] = metallic; - j["albedoColor"] = {albedoColor.x, albedoColor.y, albedoColor.z}; - j["roughnessFactor"] = roughnessFactor; - j["metallicFactor"] = metallicFactor; - j["transmissionFactor"] = transmissionFactor; - j["thicknessFactor"] = thicknessFactor; - j["ior"] = ior; - j["isEmissive"] = isEmissive; - return j; - } - - void MaterialFileData::fromJson(const nlohmann::json &j) { - albedo = j.at("albedo").get(); - normal = j.at("normal").get(); - roughness = j.at("roughness").get(); - metallic = j.at("metallic").get(); - roughnessFactor = j.at("roughnessFactor").get(); - metallicFactor = j.at("metallicFactor").get(); - transmissionFactor = j.value("transmissionFactor", 0.0f); - thicknessFactor = j.value("thicknessFactor", 0.0f); - ior = j.value("ior", 1.45f); - isEmissive = j.at("isEmissive").get(); - - albedoColor = {j.at("albedoColor")[0], j.at("albedoColor")[1], j.at("albedoColor")[2]}; - } -} diff --git a/src/service/material/MaterialImporterService.cpp b/src/service/material/MaterialImporterService.cpp index 90fd6d6f..35d659ff 100644 --- a/src/service/material/MaterialImporterService.cpp +++ b/src/service/material/MaterialImporterService.cpp @@ -1,104 +1,91 @@ #include "MaterialImporterService.h" #include "../../context/ApplicationContext.h" -#include "MaterialFileData.h" -#include "../../dto/file/EntryMetadata.h" #include "../../enum/engine-definitions.h" -#include "../../util/FilesUtil.h" +#include "../../repository/world/components/PrimitiveComponent.h" #include - #include -#include "../../util/serialization-definitions.h" namespace Metal { - void MaterialImporterService::persistAllMaterials(const std::string &targetDir, const aiScene *scene, - std::unordered_map &materialMap, - const std::string &rootDirectory, - const std::stop_token &stopToken) const { + void MaterialImporterService::importMaterial(const std::string &targetDir, const aiMaterial *material, + const aiScene *scene, const std::string &rootDirectory, + PrimitiveComponent &primitive, + const std::stop_token &stopToken) const { namespace fs = std::filesystem; - LOG_INFO("Processing materials for scene..."); - for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { - if (stopToken.stop_requested()) return; - const aiMaterial *material = scene->mMaterials[i]; - auto materialData = MaterialFileData{}; - - const auto importAssimpTexture = [& - ](const aiString &assimpPath, const std::string &nameHint) -> std::string { - if (assimpPath.length == 0) return ""; - const std::string p = assimpPath.C_Str(); - // Embedded textures are referenced as "*". - if (!p.empty() && p[0] == '*') { - try { - const unsigned int embeddedIndex = static_cast(std::stoul(p.substr(1))); - if (scene && embeddedIndex < scene->mNumTextures) { - return CTX.textureImporter.importEmbeddedTexture( - targetDir, scene->mTextures[embeddedIndex], nameHint); - } - } catch (std::exception &e) { - LOG_ERROR("Failed to import texture: " + std::string(e.what())); - return ""; - } - return ""; - } + const auto importAssimpTexture = [&](const aiString &assimpPath, const std::string &nameHint) -> std::string { + if (assimpPath.length == 0) return ""; + const std::string p = assimpPath.C_Str(); - fs::path resolved = fs::path(p); - if (!resolved.is_absolute()) { - resolved = fs::path(rootDirectory) / resolved; - } - resolved = resolved.lexically_normal(); + // Embedded textures are referenced as "*". + if (!p.empty() && p[0] == '*') { try { - return CTX.textureImporter.importData(targetDir, resolved.string(), nullptr, stopToken); + const unsigned int embeddedIndex = static_cast(std::stoul(p.substr(1))); + if (scene && embeddedIndex < scene->mNumTextures) { + return CTX.textureImporter.importEmbeddedTexture( + targetDir, scene->mTextures[embeddedIndex], nameHint); + } } catch (std::exception &e) { - LOG_ERROR("Failed to import texture " + resolved.string() + ": " + e.what()); + LOG_ERROR("Failed to import texture: " + std::string(e.what())); return ""; } - }; - - const auto trySetFromType = [&](std::string &slot, aiTextureType type, const std::string &nameHint) { - if (!slot.empty()) return; - if (material->GetTextureCount(type) == 0) return; - aiString texturePath; - if (material->GetTexture(type, 0, &texturePath) == AI_SUCCESS) { - slot = importAssimpTexture(texturePath, nameHint); - } - }; - - // Albedo - trySetFromType(materialData.albedo, aiTextureType_BASE_COLOR, "albedo"); - trySetFromType(materialData.albedo, aiTextureType_DIFFUSE, "albedo"); - - // Normal - trySetFromType(materialData.normal, aiTextureType_NORMALS, "normal"); - trySetFromType(materialData.normal, aiTextureType_NORMAL_CAMERA, "normal"); - - // Metallic / Roughness - trySetFromType(materialData.metallic, aiTextureType_METALNESS, "metallic"); - trySetFromType(materialData.roughness, aiTextureType_DIFFUSE_ROUGHNESS, "roughness"); + return ""; + } + fs::path resolved = fs::path(p); + if (!resolved.is_absolute()) { + resolved = fs::path(rootDirectory) / resolved; + } + resolved = resolved.lexically_normal(); + try { + return CTX.textureImporter.importData(targetDir, resolved.string(), nullptr, stopToken); + } catch (std::exception &e) { + LOG_ERROR("Failed to import texture " + resolved.string() + ": " + e.what()); + return ""; + } + }; - // If we didn't import any textures, don't create/persist a material at all. - if (materialData.albedo.empty() && materialData.normal.empty() && materialData.roughness.empty() && - materialData.metallic.empty()) { - LOG_INFO("Skipping material " + std::to_string(i) + ": no textures associated"); - continue; + const auto trySetFromType = [&](std::string &slot, aiTextureType type, const std::string &nameHint) { + if (!slot.empty()) return; + if (material->GetTextureCount(type) == 0) return; + aiString texturePath; + if (material->GetTexture(type, 0, &texturePath) == AI_SUCCESS) { + slot = importAssimpTexture(texturePath, nameHint); } + }; - std::string materialId; - { - EntryMetadata materialMetadata{}; - materialMetadata.type = EntryType::MATERIAL; - materialMetadata.name = "Material " + std::to_string(i); + // Albedo + trySetFromType(primitive.albedo, aiTextureType_BASE_COLOR, "albedo"); + trySetFromType(primitive.albedo, aiTextureType_DIFFUSE, "albedo"); - std::string materialBlobPath = CTX.getAssetDirectory() + FORMAT_FILE_MATERIAL(materialMetadata.getId()); - DUMP_TEMPLATE(materialBlobPath, materialData) - materialMetadata.size = fs::file_size(materialBlobPath); + // Metallic / Roughness + trySetFromType(primitive.metallic, aiTextureType_METALNESS, "metallic"); + trySetFromType(primitive.roughness, aiTextureType_DIFFUSE_ROUGHNESS, "roughness"); - DUMP_TEMPLATE(targetDir + '/' + FORMAT_FILE_METADATA(materialMetadata.getId()), materialMetadata) - materialId = materialMetadata.getId(); - } - materialMap.insert({i, materialId}); + // Factors & Colors + aiColor4D color; + if (material->Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) { + primitive.albedoColor = {color.r, color.g, color.b}; + } - LOG_INFO("Persisted material: " + materialId); + if (material->Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) { + primitive.isEmissive = (color.r > 0 || color.g > 0 || color.b > 0); } + + // float factor; + // if (material->Get(AI_MATKEY_METALLIC_FACTOR, factor) == AI_SUCCESS) { + // primitive.metallicFactor = factor; + // } + // + // if (material->Get(AI_MATKEY_ROUGHNESS_FACTOR, factor) == AI_SUCCESS) { + // primitive.roughnessFactor = factor; + // } + // + // if (material->Get(AI_MATKEY_TRANSMISSION_FACTOR, factor) == AI_SUCCESS) { + // primitive.transmissionFactor = factor; + // } + // + // if (material->Get(AI_MATKEY_REFRACTI, factor) == AI_SUCCESS) { + // primitive.ior = factor; + // } } } diff --git a/src/service/material/MaterialImporterService.h b/src/service/material/MaterialImporterService.h index d2e4c7a3..52c9aedd 100644 --- a/src/service/material/MaterialImporterService.h +++ b/src/service/material/MaterialImporterService.h @@ -9,13 +9,13 @@ #include "../abstract/AbstractResourceService.h" namespace Metal { + struct PrimitiveComponent; + class MaterialImporterService final : public AbstractRuntimeComponent { public: - - void persistAllMaterials(const std::string &targetDir, const aiScene *scene, - std::unordered_map &materialMap, - const std::string &rootDirectory, - const std::stop_token &stopToken = {}) const; + void importMaterial(const std::string &targetDir, const aiMaterial *material, const aiScene *scene, + const std::string &rootDirectory, PrimitiveComponent &primitive, + const std::stop_token &stopToken = {}) const; }; } diff --git a/src/service/material/MaterialInstance.h b/src/service/material/MaterialInstance.h deleted file mode 100644 index c27318fd..00000000 --- a/src/service/material/MaterialInstance.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MATERIALINSTANCE_H -#define MATERIALINSTANCE_H -#include -#include -#include - -#include "../../repository/abstract/RuntimeResource.h" -#include "../../service/descriptor/DescriptorInstance.h" - -namespace Metal { - struct MaterialInstance final : RuntimeResource { - explicit MaterialInstance(const std::string &id) : RuntimeResource(id) { - } - - std::vector textures{}; - unsigned int materialIndex = 0; - - std::vector &getDependencies() override { - return textures; - } - }; -} // Metal - -#endif //MATERIALINSTANCE_H diff --git a/src/service/material/MaterialService.cpp b/src/service/material/MaterialService.cpp index eb553e29..80c72174 100644 --- a/src/service/material/MaterialService.cpp +++ b/src/service/material/MaterialService.cpp @@ -1,111 +1,42 @@ #include "MaterialService.h" -#include "../../enum/engine-definitions.h" -#include "MaterialFileData.h" - -#include "../../context/vulkan/VulkanContext.h" -#include "../../util/FilesUtil.h" #include "../../util/serialization-definitions.h" +#include "../../dto/buffers/MeshMetadata.h" -#include -#include "../../dto/buffers/MaterialData.h" -#include "../buffer/BufferInstance.h" - -#include "MaterialInstance.h" #include "../../context/ApplicationContext.h" -#include "../../enum/EngineResourceIDs.h" namespace Metal { - MaterialInstance *MaterialService::create(const std::string &id) { - MaterialFileData *data = stream(id); - if (data == nullptr) { - return nullptr; - } - - auto *instance = createResourceInstance(id); - instance->materialIndex = nextMaterialIndex++; - MaterialData materialData{}; - materialData.albedo = data->albedoColor; - materialData.roughness = data->roughnessFactor; - materialData.metallic = data->metallicFactor; - materialData.transmission = data->transmissionFactor; - materialData.thickness = data->thicknessFactor; - materialData.ior = data->ior; - materialData.isEmissive = data->isEmissive ? 1 : 0; - - materialData.useAlbedoTexture = !data->albedo.empty(); - materialData.useNormalTexture = !data->normal.empty(); - materialData.useRoughnessTexture = !data->roughness.empty(); - materialData.useMetallicTexture = !data->metallic.empty(); + void MaterialService::load(MeshMetadata &materialData, PrimitiveComponent &data) { + materialData.albedo = data.albedoColor; + materialData.roughness = data.roughnessFactor; + materialData.metallic = data.metallicFactor; + materialData.transmission = data.transmissionFactor; + materialData.thickness = data.thicknessFactor; + materialData.ior = data.ior; + materialData.isEmissive = data.isEmissive ? 1 : 0; materialData.albedoTextureId = 0; - materialData.normalTextureId = 0; materialData.roughnessTextureId = 0; materialData.metallicTextureId = 0; - if (!data->albedo.empty()) { - auto *tex = CTX.textureService.create(data->albedo); + if (!data.albedo.empty()) { + auto *tex = CTX.textureService.stream(data.albedo); if (tex != nullptr) { - materialData.albedoTextureId = CTX.textureService.getTextureIndex(data->albedo); + materialData.albedoTextureId = CTX.textureService.getTextureIndex(data.albedo); } } - if (!data->normal.empty()) { - auto *tex = CTX.textureService.create(data->normal); + if (!data.roughness.empty()) { + auto *tex = CTX.textureService.stream(data.roughness); if (tex != nullptr) { - materialData.normalTextureId = CTX.textureService.getTextureIndex(data->normal); + materialData.roughnessTextureId = CTX.textureService.getTextureIndex(data.roughness); } } - if (!data->roughness.empty()) { - auto *tex = CTX.textureService.create(data->roughness); + if (!data.metallic.empty()) { + auto *tex = CTX.textureService.stream(data.metallic); if (tex != nullptr) { - materialData.roughnessTextureId = CTX.textureService.getTextureIndex(data->roughness); + materialData.metallicTextureId = CTX.textureService.getTextureIndex(data.metallic); } } - if (!data->metallic.empty()) { - auto *tex = CTX.textureService.create(data->metallic); - if (tex != nullptr) { - materialData.metallicTextureId = CTX.textureService.getTextureIndex(data->metallic); - } - } - - materials[instance->materialIndex] = materialData; - - auto *materialBuffer = CTX.engineContext.currentFrame->getResourceAs(RID_MATERIAL_BUFFER); - materialBuffer->update(materials.data()); - - delete data; - - return instance; - } - - MaterialFileData *MaterialService::stream(const std::string &id) const { - auto pathToFile = CTX.getAssetDirectory() + FORMAT_FILE_MATERIAL(id); - if (std::filesystem::exists(pathToFile)) { - auto *data = new MaterialFileData; - PARSE_TEMPLATE(*data, pathToFile); - return data; - } - return nullptr; - } - - unsigned int MaterialService::getMaterialIndex(const std::string &id) { - if (id.empty()) { - return 0; - } - if (resources.contains(id)) { - return dynamic_cast(resources.at(id))->materialIndex; - } - auto *instance = create(id); - if (instance != nullptr) { - return instance->materialIndex; - } - return 0; - } - - void MaterialService::disposeResource(MaterialInstance *resource) { - // Materials are currently just entries in a global buffer, - // they don't hold many resources themselves, but they do have dependencies - // which are handled by StreamingService. } } // Metal diff --git a/src/service/material/MaterialService.h b/src/service/material/MaterialService.h index 98eaffa5..fce5458e 100644 --- a/src/service/material/MaterialService.h +++ b/src/service/material/MaterialService.h @@ -1,26 +1,13 @@ #ifndef MATERIALSERVICE_H #define MATERIALSERVICE_H -#include "MaterialFileData.h" -#include "MaterialInstance.h" -#include "../../service/abstract/AbstractResourceService.h" -#include "../../service/abstract/IStreamable.h" - -#include "../../enum/engine-definitions.h" -#include -#include "../../dto/buffers/MaterialData.h" namespace Metal { - class MaterialService final : public IStreamable { - unsigned int nextMaterialIndex = 1; - std::vector materials {MAX_MATERIALS}; - public: - MaterialInstance *create(const std::string &id) override; - - MaterialFileData *stream(const std::string &id) const; + struct PrimitiveComponent; + struct MeshMetadata; - unsigned int getMaterialIndex(const std::string &id); - - void disposeResource(MaterialInstance *resource) override; + class MaterialService final { + public: + void load(MeshMetadata &data, PrimitiveComponent &component); }; } // Metal diff --git a/src/service/mesh/EntityAssetData.h b/src/service/mesh/EntityAssetData.h deleted file mode 100644 index d3e64bde..00000000 --- a/src/service/mesh/EntityAssetData.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef ENTITYASSETDATA_H -#define ENTITYASSETDATA_H -#include - -#include "../../util/Serializable.h" - -namespace Metal { - struct EntityAssetData final : Serializable { - std::string name{}; - std::string meshId{}; - std::string materialId{}; - int parentEntity = -1; - int id; - - nlohmann::json toJson() const override { - nlohmann::json j; - j["id"] = id; - j["name"] = name; - j["meshId"] = meshId; - j["materialId"] = materialId; - j["parentEntity"] = parentEntity; - return j; - } - - void fromJson(const nlohmann::json& j) override { - id = j.at("id").get(); - name = j.at("name").get(); - meshId = j.at("meshId").get(); - materialId = j.at("materialId").get(); - parentEntity = j.at("parentEntity").get(); - } - }; -} -#endif //ENTITYASSETDATA_H diff --git a/src/service/mesh/MeshImporterService.cpp b/src/service/mesh/MeshImporterService.cpp index 509ed8ef..f8c2a980 100644 --- a/src/service/mesh/MeshImporterService.cpp +++ b/src/service/mesh/MeshImporterService.cpp @@ -31,8 +31,7 @@ namespace Metal { } void MeshImporterService::persistAllMeshes(const std::string &targetDir, const aiScene *scene, - std::unordered_map &meshMap, - std::unordered_map &meshMaterialMap, + std::unordered_map &meshMap, const std::stop_token &stopToken) const { LOG_INFO("Processing meshes for scene..."); for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { @@ -78,8 +77,7 @@ namespace Metal { } } std::string id = persistMesh(targetDir, meshData); - meshMap.insert({i, id}); - meshMaterialMap.insert({id, assimpMesh->mMaterialIndex}); + meshMap.insert({i, {id, meshData.gizmoCenter}}); LOG_INFO("Persisted mesh: " + meshData.name + " (" + id + ")"); } } diff --git a/src/service/mesh/MeshImporterService.h b/src/service/mesh/MeshImporterService.h index 293f81e1..7e707e86 100644 --- a/src/service/mesh/MeshImporterService.h +++ b/src/service/mesh/MeshImporterService.h @@ -6,16 +6,20 @@ #include #include #include +#include namespace Metal { + struct MeshId { + std::string id; + glm::vec3 gizmoCenter; + }; struct MeshData; class MeshImporterService final : public AbstractRuntimeComponent { public: void persistAllMeshes(const std::string &targetDir, const aiScene *scene, - std::unordered_map &meshMap, - std::unordered_map &meshMaterialMap, + std::unordered_map &meshMap, const std::stop_token &stopToken = {}) const; private: diff --git a/src/service/mesh/MeshService.cpp b/src/service/mesh/MeshService.cpp index 4a8117ab..cf7fbe17 100644 --- a/src/service/mesh/MeshService.cpp +++ b/src/service/mesh/MeshService.cpp @@ -2,7 +2,6 @@ #include "MeshInstance.h" #include "MeshData.h" #include "SceneData.h" -#include "EntityAssetData.h" #include "../../context/vulkan/VulkanContext.h" #include "../../util/FilesUtil.h" @@ -12,12 +11,12 @@ #include #include "../../context/ApplicationContext.h" -#include "../../repository/world/components/MeshComponent.h" +#include "../../repository/world/components/PrimitiveComponent.h" #include "../../repository/world/components/TransformComponent.h" namespace Metal { MeshInstance *MeshService::create(const std::string &id) { - MeshData *data = stream(id); + MeshData *data = loadMeshData(id); if (data == nullptr) { return nullptr; } @@ -45,7 +44,18 @@ namespace Metal { return instance; } - MeshData *MeshService::stream(const std::string &id) const { + MeshInstance *MeshService::stream(const std::string &id) { + if (id.empty()) { + return nullptr; + } + auto *resource = getResource(id); + if (resource != nullptr) { + return resource; + } + return create(id); + } + + MeshData *MeshService::loadMeshData(const std::string &id) const { auto pathToFile = CTX.getAssetDirectory() + FORMAT_FILE_MESH(id); if (std::filesystem::exists(pathToFile)) { auto *data = new MeshData; @@ -57,53 +67,6 @@ namespace Metal { return nullptr; } - EntityID MeshService::createMeshEntity(const std::string &name, const std::string &meshId, - const std::string &materialId) const { - const auto id = CTX.worldRepository.createEntity(); - CTX.worldRepository.createComponent(id, ComponentTypes::ComponentType::MESH); - const auto entity = static_cast(id); - auto &mesh = CTX.worldRepository.registry.get(entity); - mesh.meshId = meshId; - mesh.materialId = materialId; - - MeshData *data = stream(meshId); - if (data != nullptr) { - auto &transform = CTX.worldRepository.registry.get(entity); - transform.gizmoCenter = data->gizmoCenter; - delete data; - } - - CTX.worldRepository.getEntity(id)->name = name; - return id; - } - - void MeshService::createSceneEntities(const std::string &id) const { - auto &repo = CTX.worldRepository; - SceneData data; - auto pathToFile = CTX.getAssetDirectory() + FORMAT_FILE_SCENE(id); - PARSE_TEMPLATE(data, pathToFile) - - std::unordered_map entities; - - for (auto &entity: data.entities) { - if (!entity.meshId.empty()) { - entities.insert({entity.id, createMeshEntity(entity.name, entity.meshId, entity.materialId)}); - } else { - const auto entityId = repo.createEntity(); - entities.insert({entity.id, entityId}); - repo.getEntity(entityId)->name = entity.name; - repo.getEntity(entityId)->initialize(true); - } - } - - for (auto &entity: data.entities) { - if (entity.parentEntity < 0 || !entities.contains(entity.parentEntity)) { - continue; - } - repo.linkEntities(entities.at(entity.parentEntity), entities.at(entity.id)); - } - } - void MeshService::disposeResource(MeshInstance *resource) { LOG_INFO("Disposing of mesh instance"); CTX.rayTracingService.markDirty(); diff --git a/src/service/mesh/MeshService.h b/src/service/mesh/MeshService.h index d5104ba1..68535a20 100644 --- a/src/service/mesh/MeshService.h +++ b/src/service/mesh/MeshService.h @@ -1,24 +1,21 @@ #ifndef MESHSERVICE_H #define MESHSERVICE_H #include "../../service/abstract/AbstractResourceService.h" -#include "../../service/abstract/IStreamable.h" #include "MeshInstance.h" #include "../../enum/engine-definitions.h" namespace Metal { struct MeshData; struct MeshInstance; + struct EntityAssetData; - class MeshService final : public IStreamable { + class MeshService final : public AbstractResourceService { public: - MeshInstance *create(const std::string &id) override; + MeshInstance *create(const std::string &id); - MeshData *stream(const std::string &id) const; + MeshInstance *stream(const std::string &id); - EntityID createMeshEntity(const std::string &name, const std::string &meshId, - const std::string &materialId) const; - - void createSceneEntities(const std::string &id) const; + MeshData *loadMeshData(const std::string &id) const; void disposeResource(MeshInstance *resource) override; diff --git a/src/service/mesh/SceneData.h b/src/service/mesh/SceneData.h index 45c16af8..852bbd8f 100644 --- a/src/service/mesh/SceneData.h +++ b/src/service/mesh/SceneData.h @@ -1,32 +1,34 @@ #ifndef SCENEDESCRIPTION_H #define SCENEDESCRIPTION_H #include + +#include "SceneEntityData.h" #include "../../util/Serializable.h" -#include "EntityAssetData.h" namespace Metal { + struct SceneData final : Serializable { - std::vector entities; + std::vector entities; std::string name; nlohmann::json toJson() const override { nlohmann::json j; j["name"] = name; nlohmann::json e = nlohmann::json::array(); - for (const auto& ent : entities) { + for (const auto &ent: entities) { e.push_back(ent.toJson()); } j["entities"] = e; return j; } - void fromJson(const nlohmann::json& j) override { + void fromJson(const nlohmann::json &j) override { name = j.at("name").get(); entities.clear(); - for (const auto& ent : j.at("entities")) { - EntityAssetData ead; - ead.fromJson(ent); - entities.push_back(ead); + for (const auto &ent: j.at("entities")) { + SceneEntityData sed; + sed.fromJson(ent); + entities.push_back(sed); } } }; diff --git a/src/service/mesh/SceneEntityData.h b/src/service/mesh/SceneEntityData.h new file mode 100644 index 00000000..0e60b9f8 --- /dev/null +++ b/src/service/mesh/SceneEntityData.h @@ -0,0 +1,34 @@ +#ifndef METAL_ENGINE_SCENEENTITYDATA_H +#define METAL_ENGINE_SCENEENTITYDATA_H +#include +#include "../../repository/world/components/PrimitiveComponent.h" +#include "../../repository/world/components/TransformComponent.h" +#include "../../repository/world/impl/MetadataComponent.h" + +namespace Metal { + + struct SceneEntityData final : Serializable { + MetadataComponent entity; + TransformComponent transform; + std::optional primitive; + + nlohmann::json toJson() const override { + nlohmann::json j; + j["entity"] = entity.toJson(); + j["transform"] = transform.toJson(); + if (primitive) j["primitive"] = primitive->toJson(); + return j; + } + + void fromJson(const nlohmann::json &j) override { + entity.fromJson(j.at("entity")); + transform.fromJson(j.at("transform")); + if (j.contains("primitive")) { + primitive = PrimitiveComponent(); + primitive->fromJson(j.at("primitive")); + } + } + }; +} + +#endif //METAL_ENGINE_SCENEENTITYDATA_H \ No newline at end of file diff --git a/src/service/mesh/SceneImporterService.cpp b/src/service/mesh/SceneImporterService.cpp index 5aa9b819..08144c8a 100644 --- a/src/service/mesh/SceneImporterService.cpp +++ b/src/service/mesh/SceneImporterService.cpp @@ -2,8 +2,8 @@ #include "../../dto/file/FSEntry.h" #include "MeshData.h" -#include "EntityAssetData.h" #include "SceneData.h" +#include "../material/MaterialImporterService.h" #include #include #include @@ -16,16 +16,13 @@ #include "../../dto/file/SceneImportSettingsDTO.h" namespace Metal { - std::string SceneImporterService::importData(const std::string &targetDir, const std::string &pathToFile, const std::shared_ptr &settings, const std::stop_token &stopToken) { - Assimp::Importer importer; unsigned int flags = aiProcess_GlobalScale | aiProcess_FindInstances | aiProcess_PreTransformVertices; - auto sceneSettings = std::dynamic_pointer_cast(settings); - if (sceneSettings) { + if (auto sceneSettings = std::dynamic_pointer_cast(settings)) { if (sceneSettings->triangulate) flags |= aiProcess_Triangulate; if (sceneSettings->flipUVs) flags |= aiProcess_FlipUVs; if (sceneSettings->genSmoothNormals) flags |= aiProcess_GenSmoothNormals; @@ -38,7 +35,7 @@ namespace Metal { const aiScene *scene = importer.ReadFile(pathToFile, flags); if (stopToken.stop_requested()) { - throw std::runtime_error("Import cancelled"); + throw std::runtime_error("Import cancelled"); } if (!scene || !scene->HasMeshes()) { @@ -54,37 +51,36 @@ namespace Metal { std::string sceneBlobPath = CTX.getAssetDirectory() + FORMAT_FILE_SCENE(sceneMetadata.getId()); - - std::unordered_map meshMap{}; - std::unordered_map meshMaterialMap{}; + std::unordered_map meshMap{}; if (stopToken.stop_requested()) { throw std::runtime_error("Import cancelled"); } - CTX.meshImporterService.persistAllMeshes(targetDir, scene, meshMap, meshMaterialMap, stopToken); + CTX.meshImporterService.persistAllMeshes(targetDir, scene, meshMap, stopToken); if (stopToken.stop_requested()) { throw std::runtime_error("Import cancelled"); } - std::unordered_map materialsMap{}; fs::path absolutePath = fs::absolute(pathToFile); - fs::path directoryPath = absolutePath.parent_path(); + std::string directoryPath = absolutePath.parent_path().string(); - CTX.materialImporterService.persistAllMaterials(targetDir, scene, materialsMap, directoryPath.string(), - stopToken); + ProcessNode(sceneData, scene, scene->mRootNode, targetDir, directoryPath, meshMap, stopToken); + ProcessLights(sceneData, scene); if (stopToken.stop_requested()) { throw std::runtime_error("Import cancelled"); } - int increment = 0; - ProcessNode(increment, sceneData, scene->mRootNode, -1, meshMap, meshMaterialMap, materialsMap, stopToken); - - if (stopToken.stop_requested()) { - throw std::runtime_error("Import cancelled"); + std::vector entities{}; + for (SceneEntityData &entity: sceneData.entities) { + if (!entity.primitive) { + continue; + } + entities.push_back(entity); } + sceneData.entities = entities; DUMP_TEMPLATE(sceneBlobPath, sceneData) sceneMetadata.size = fs::file_size(sceneBlobPath); DUMP_TEMPLATE(targetDir + '/' + FORMAT_FILE_METADATA(sceneMetadata.getId()), sceneMetadata) @@ -92,51 +88,60 @@ namespace Metal { return sceneMetadata.getId(); } - void SceneImporterService::ProcessNode(int &increment, SceneData &scene, const aiNode *node, int parentId, - const std::unordered_map &meshMap, - const std::unordered_map &meshMaterialMap, - const std::unordered_map &materialsMap, + void SceneImporterService::ProcessNode(SceneData &scene, const aiScene *aiScene, const aiNode *node, + const std::string &targetDir, const std::string &rootDirectory, + const std::unordered_map &meshMap, const std::stop_token &stopToken) { if (stopToken.stop_requested()) return; auto ¤tNode = scene.entities.emplace_back(); - currentNode.name = node->mName.data; - currentNode.id = increment; - increment++; - currentNode.parentEntity = parentId; + currentNode.entity.name = node->mName.data; + + // Extract transform + aiVector3D scaling, pos; + aiQuaternion rotation; + node->mTransformation.Decompose(scaling, rotation, pos); + currentNode.transform.translation = {pos.x, pos.y, pos.z}; + currentNode.transform.rotation = {rotation.w, rotation.x, rotation.y, rotation.z}; + currentNode.transform.scale = {scaling.x, scaling.y, scaling.z}; + + ProcessMeshes(scene, aiScene, node, targetDir, rootDirectory, meshMap, stopToken); - // IMPORTANT: `scene.entities` is a `std::vector`. Any further `emplace_back` may reallocate and - // invalidate references (including `currentNode`). Capture the needed values by copy. - const int currentNodeId = currentNode.id; - const std::string currentNodeName = currentNode.name; + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + ProcessNode(scene, aiScene, node->mChildren[i], targetDir, rootDirectory, meshMap, stopToken); + } + } + void SceneImporterService::ProcessMeshes(SceneData &scene, const aiScene *aiScene, const aiNode *node, + const std::string &targetDir, const std::string &rootDirectory, + const std::unordered_map &meshMap, + const std::stop_token &stopToken) { for (unsigned int i = 0; i < node->mNumMeshes; ++i) { if (stopToken.stop_requested()) return; unsigned int meshIndex = node->mMeshes[i]; const auto it = meshMap.find(meshIndex); - if (it == meshMap.end()) { - // Mesh reference missing; skip linking to avoid terminating import. - continue; - } + if (it == meshMap.end()) continue; auto &childMeshNode = scene.entities.emplace_back(); - childMeshNode.meshId = it->second; - childMeshNode.name = currentNodeName + " (" + std::to_string(meshIndex) + ")"; - childMeshNode.parentEntity = currentNodeId; - childMeshNode.id = increment; - if (meshMaterialMap.contains(childMeshNode.meshId)) { - unsigned int matIndex = meshMaterialMap.at(childMeshNode.meshId); - if (materialsMap.contains(matIndex)) { - childMeshNode.materialId = materialsMap.at(matIndex); - } - } - increment++; + childMeshNode.primitive = PrimitiveComponent(); + childMeshNode.primitive->meshId = it->second.id; + childMeshNode.transform.gizmoCenter = it->second.gizmoCenter; + + const aiMesh *assimpMesh = aiScene->mMeshes[meshIndex]; + childMeshNode.entity.name = assimpMesh->mName.length > 0 ? assimpMesh->mName.data : "Mesh"; + + const aiMaterial *material = aiScene->mMaterials[assimpMesh->mMaterialIndex]; + CTX.materialImporterService.importMaterial(targetDir, material, aiScene, rootDirectory, + *childMeshNode.primitive, stopToken); } + } - for (unsigned int i = 0; i < node->mNumChildren; ++i) { - if (stopToken.stop_requested()) return; - ProcessNode(increment, scene, node->mChildren[i], currentNodeId, meshMap, meshMaterialMap, materialsMap, - stopToken); + void SceneImporterService::ProcessLights(SceneData &scene, const aiScene *aiScene) { + for (unsigned int i = 0; i < aiScene->mNumLights; ++i) { + aiLight *light = aiScene->mLights[i]; + auto &lightNode = scene.entities.emplace_back(); + lightNode.entity.name = light->mName.data; + lightNode.transform.translation = {light->mPosition.x, light->mPosition.y, light->mPosition.z}; } } diff --git a/src/service/mesh/SceneImporterService.h b/src/service/mesh/SceneImporterService.h index cc05bcde..39b6d495 100644 --- a/src/service/mesh/SceneImporterService.h +++ b/src/service/mesh/SceneImporterService.h @@ -8,19 +8,28 @@ #include namespace Metal { - struct MaterialFileData; + struct MeshId; + struct MaterialData; struct MeshData; struct SceneData; class SceneImporterService final : public AbstractImporter { - static void ProcessNode(int &increment, SceneData &scene, const aiNode *node, int parentId, - const std::unordered_map &meshMap, - const std::unordered_map &meshMaterialMap, - const std::unordered_map &materialsMap, + static void ProcessNode(SceneData &scene, const aiScene *aiScene, const aiNode *node, + const std::string &targetDir, const std::string &rootDirectory, + const std::unordered_map &meshMap, const std::stop_token &stopToken); + static void ProcessMeshes(SceneData &scene, const aiScene *aiScene, const aiNode *node, + const std::string &targetDir, const std::string &rootDirectory, + const std::unordered_map &meshMap, + const std::stop_token &stopToken); + + static void ProcessLights(SceneData &scene, const aiScene *aiScene); + public: - std::string importData(const std::string &targetDir, const std::string &pathToFile, const std::shared_ptr &settings, const std::stop_token &stopToken) override; + std::string importData(const std::string &targetDir, const std::string &pathToFile, + const std::shared_ptr &settings, + const std::stop_token &stopToken) override; std::vector getSupportedTypes() override; }; diff --git a/src/service/picking/PickingService.cpp b/src/service/picking/PickingService.cpp index 879f29aa..235ac849 100644 --- a/src/service/picking/PickingService.cpp +++ b/src/service/picking/PickingService.cpp @@ -5,7 +5,7 @@ #include "../../context/ApplicationContext.h" namespace Metal { - std::optional PickingService::pickEntityFromGBuffer(TextureInstance *attachment, const uint32_t pixelX, + std::optional PickingService::pickEntityFromGBuffer(TextureInstance *attachment, const uint32_t pixelX, const uint32_t pixelY) const { constexpr VkDeviceSize imageSize = 4 * sizeof(float); @@ -66,11 +66,11 @@ namespace Metal { const unsigned int renderIndex = static_cast(idValue + 0.5f) - 1; - auto view = CTX.worldRepository.registry.view(); + auto view = CTX.worldRepository.registry.view(); for (auto entity: view) { - auto &mesh = view.get(entity); + auto &mesh = view.get(entity); if (mesh.renderIndex == renderIndex) { - return static_cast(entity); + return entity; } } diff --git a/src/service/picking/PickingService.h b/src/service/picking/PickingService.h index 66176460..d86177d0 100644 --- a/src/service/picking/PickingService.h +++ b/src/service/picking/PickingService.h @@ -9,7 +9,7 @@ namespace Metal { struct TextureInstance; class PickingService final : public AbstractRuntimeComponent { public: - [[nodiscard]] std::optional pickEntityFromGBuffer(TextureInstance *attachment, uint32_t pixelX, uint32_t pixelY) const; + [[nodiscard]] std::optional pickEntityFromGBuffer(TextureInstance *attachment, uint32_t pixelX, uint32_t pixelY) const; }; } // Metal diff --git a/src/service/raytracing/RayTracingService.cpp b/src/service/raytracing/RayTracingService.cpp index 51f7b451..fd2b6de0 100644 --- a/src/service/raytracing/RayTracingService.cpp +++ b/src/service/raytracing/RayTracingService.cpp @@ -33,27 +33,31 @@ namespace Metal { } } } + + // TODO - EVENT SYSTEM BASED ON WORLD CHANGE AND ENTITY CHANGE void RayTracingService::onSync() { - if (!needsRebuild) { + if (needsMaterialUpdate) { updateMeshMaterials(); + needsMaterialUpdate = false; + } + if (!needsRebuild) { return; } - + anyMeshes = false; // Check if any mesh is present and streamed - bool hasMeshes = false; - auto view = CTX.worldRepository.registry.view(); + auto view = CTX.worldRepository.registry.view(); for (auto entity: view) { - if (CTX.worldRepository.hiddenEntities.contains(static_cast(entity))) continue; - auto &meshComp = view.get(entity); + if (CTX.worldRepository.hiddenEntities.contains(entity)) continue; + auto &meshComp = view.get(entity); if (meshComp.meshId.empty()) continue; - auto *instance = CTX.streamingService.streamMesh(meshComp.meshId); + auto *instance = CTX.meshService.stream(meshComp.meshId); if (instance != nullptr && instance->dataBuffer != nullptr && instance->indexBuffer != nullptr) { - hasMeshes = true; + anyMeshes = true; break; } } - if (!hasMeshes) { + if (!anyMeshes) { // No meshes – destroy all structures and set descriptor to null destroyAccelerationStructures(); // destroys BLAS and TLAS (waits for idle) updateDescriptorSets(VK_NULL_HANDLE); @@ -80,26 +84,21 @@ namespace Metal { } bool RayTracingService::isReady() const { - return accelerationStructureBuilt && tlas != VK_NULL_HANDLE; + return accelerationStructureBuilt && anyMeshes && tlas != VK_NULL_HANDLE; } void RayTracingService::updateMeshMaterials() { - if (!accelerationStructureBuilt || meshMetadata.empty()) return; - bool changed = false; - auto view = CTX.worldRepository.registry.view(); + auto view = CTX.worldRepository.registry.view(); for (auto entity: view) { - if (CTX.worldRepository.hiddenEntities.contains(static_cast(entity))) continue; - auto &meshComp = view.get(entity); + if (CTX.worldRepository.hiddenEntities.contains(entity)) continue; + auto &meshComp = view.get(entity); if (meshComp.meshId.empty()) continue; if (meshComp.renderIndex < meshMetadata.size()) { - unsigned int materialIndex = CTX.materialService.getMaterialIndex(meshComp.materialId); - if (meshMetadata[meshComp.renderIndex].materialIndex != materialIndex) { - meshMetadata[meshComp.renderIndex].materialIndex = materialIndex; - changed = true; - } + CTX.materialService.load(meshMetadata[meshComp.renderIndex], meshComp); + changed = true; } } @@ -145,14 +144,14 @@ namespace Metal { std::unordered_map uniqueMeshes; - auto view = CTX.worldRepository.registry.view(); + auto view = CTX.worldRepository.registry.view(); for (auto entity: view) { - if (CTX.worldRepository.hiddenEntities.contains(static_cast(entity))) continue; - auto &meshComp = view.get(entity); + if (CTX.worldRepository.hiddenEntities.contains(entity)) continue; + auto &meshComp = view.get(entity); if (meshComp.meshId.empty()) continue; if (uniqueMeshes.contains(meshComp.meshId)) continue; - auto *instance = CTX.streamingService.streamMesh(meshComp.meshId); + auto *instance = CTX.meshService.stream(meshComp.meshId); if (instance == nullptr || instance->dataBuffer == nullptr || instance->indexBuffer == nullptr) { continue; } @@ -268,7 +267,7 @@ namespace Metal { } std::vector instances; - auto view = CTX.worldRepository.registry.view(); + auto view = CTX.worldRepository.registry.view(); unsigned int currentInstanceIndex = 0; for (auto entity: view) { @@ -276,8 +275,8 @@ namespace Metal { LOG_ERROR("Max mesh instances reached for ray tracing: " + std::to_string(MAX_MESH_INSTANCES)); break; } - if (CTX.worldRepository.hiddenEntities.contains(static_cast(entity))) continue; - auto &meshComp = view.get(entity); + if (CTX.worldRepository.hiddenEntities.contains(entity)) continue; + auto &meshComp = view.get(entity); if (meshComp.meshId.empty()) continue; auto it = blasEntries.find(meshComp.meshId); @@ -302,13 +301,11 @@ namespace Metal { } } - uint32_t materialIndex = CTX.materialService.getMaterialIndex(meshComp.materialId); - VkDeviceAddress vertexAddress = getDeviceAddress(vulkan, it->second.vertexData->vkBuffer); VkDeviceAddress indexAddress = getDeviceAddress(vulkan, it->second.indexData->vkBuffer); meshComp.renderIndex = currentInstanceIndex; - meshMetadata.push_back({meshComp.renderIndex, materialIndex, vertexAddress, indexAddress}); + meshMetadata.push_back({meshComp.renderIndex, vertexAddress, indexAddress}); VkAccelerationStructureInstanceKHR instance{}; instance.transform = transform; @@ -324,13 +321,8 @@ namespace Metal { if (instances.empty()) return; - if (CTX.engineContext.currentFrame != nullptr) { - auto *meshMetadataBuffer = CTX.engineContext.currentFrame->getResourceAs( - RID_MESH_METADATA_BUFFER); - if (meshMetadataBuffer != nullptr) { - meshMetadataBuffer->update(meshMetadata.data()); - } - } + + updateMeshMaterials(); instancesBuffer = CTX.bufferService.createBuffer( "tlas_instances", diff --git a/src/service/raytracing/RayTracingService.h b/src/service/raytracing/RayTracingService.h index e4949fcd..bfa42ac6 100644 --- a/src/service/raytracing/RayTracingService.h +++ b/src/service/raytracing/RayTracingService.h @@ -21,6 +21,7 @@ namespace Metal { BufferInstance *vertexData = nullptr; BufferInstance *indexData = nullptr; }; + bool anyMeshes = false; // One BLAS per unique mesh ID std::unordered_map blasEntries; @@ -37,17 +38,24 @@ namespace Metal { bool accelerationStructureBuilt = false; bool needsRebuild = true; + bool needsMaterialUpdate = false; void updateDescriptorSets(VkAccelerationStructureKHR asHandle); void buildBLAS(); void buildTLAS(); - void updateMeshMaterials(); void destroyTLAS(); + void updateMeshMaterials(); + public: + + void setNeedsMaterialUpdate(bool val) { + needsMaterialUpdate = val; + } + void destroyAccelerationStructures(); void onSync() override; diff --git a/src/service/selection/SelectionService.cpp b/src/service/selection/SelectionService.cpp index 78c88251..23d4c8ff 100644 --- a/src/service/selection/SelectionService.cpp +++ b/src/service/selection/SelectionService.cpp @@ -4,13 +4,11 @@ #include "../../repository/world/components/TransformComponent.h" namespace Metal { - void SelectionService::addSelected(EntityID entity) const { + void SelectionService::addSelected(entt::entity entity) const { auto &editorRepository = CTX.editorRepository; if (editorRepository.selected.empty() || entity == EMPTY_ENTITY) { editorRepository.mainSelection = entity; - if (editorRepository.mainSelection == WorldRepository::ROOT_ID) { - editorRepository.mainSelection = EMPTY_ENTITY; - } else if (editorRepository.mainSelection != EMPTY_ENTITY) { + if (editorRepository.mainSelection != EMPTY_ENTITY) { updatePrimitiveSelected(); } } @@ -26,10 +24,10 @@ namespace Metal { editorRepository.primitiveSelected = nullptr; } - void SelectionService::addAllSelected(const std::vector &all) const { + void SelectionService::addAllSelected(const std::vector &all) const { auto &editorRepository = CTX.editorRepository; editorRepository.selected.clear(); - const EntityID first = all.size() > 0 ? all[0] : EMPTY_ENTITY; + const entt::entity first = all.size() > 0 ? all[0] : EMPTY_ENTITY; editorRepository.mainSelection = first; updatePrimitiveSelected(); for (auto a: all) { @@ -41,14 +39,13 @@ namespace Metal { auto &editorRepository = CTX.editorRepository; auto &repo = CTX.worldRepository; const auto entityId = editorRepository.mainSelection; - const auto entity = static_cast(entityId); - if (entityId == EMPTY_ENTITY || !repo.registry.valid(entity)) { + if (entityId == EMPTY_ENTITY || !repo.registry.valid(entityId)) { return; } - if (repo.registry.all_of(entity)) { - editorRepository.primitiveSelected = &repo.registry.get(entity); + if (repo.registry.all_of(entityId)) { + editorRepository.primitiveSelected = &repo.registry.get(entityId); } } diff --git a/src/service/selection/SelectionService.h b/src/service/selection/SelectionService.h index 2382345e..60cb3dd8 100644 --- a/src/service/selection/SelectionService.h +++ b/src/service/selection/SelectionService.h @@ -11,11 +11,11 @@ namespace Metal { class SelectionService final : public AbstractRuntimeComponent { public: - void addSelected(EntityID entity) const; + void addSelected(entt::entity entity) const; void clearSelection() const; - void addAllSelected(const std::vector &all) const; + void addAllSelected(const std::vector &all) const; void updatePrimitiveSelected() const; }; diff --git a/src/service/texture/TextureService.cpp b/src/service/texture/TextureService.cpp index 414c9f33..d5eacf08 100644 --- a/src/service/texture/TextureService.cpp +++ b/src/service/texture/TextureService.cpp @@ -124,7 +124,7 @@ namespace Metal { createImageWithInfo(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image); } - TextureData *TextureService::stream(const std::string &id) const { + TextureData *TextureService::loadTextureData(const std::string &id) const { auto pathToFile = CTX.getAssetDirectory() + FORMAT_FILE_TEXTURE(id); if (std::filesystem::exists(pathToFile)) { int width, height, channels; @@ -137,6 +137,17 @@ namespace Metal { return nullptr; } + TextureInstance *TextureService::stream(const std::string &id) { + if (id.empty()) { + return nullptr; + } + auto *resource = getResource(id); + if (resource != nullptr) { + return resource; + } + return create(id); + } + TextureInstance *TextureService::loadTexture(const std::string &id, const std::string &pathToImage, bool generateMipMaps, VkFormat imageFormat) { @@ -365,7 +376,7 @@ namespace Metal { write.descriptorCount = 1; VkDescriptorImageInfo imageInfo{}; - imageInfo.sampler = CTX.vulkanContext.vkImageSampler; + imageInfo.sampler = CTX.vulkanContext.vkTextureSampler; imageInfo.imageView = texture->vkImageView; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; write.pImageInfo = &imageInfo; @@ -390,4 +401,25 @@ namespace Metal { CTX.descriptorSetService.disposeResource(resource->imageDescriptor); } } + + void TextureService::createSampler(bool linear, VkSampler &vkImageSampler, VkSamplerAddressMode addressMode) { + VkSamplerCreateInfo samplerCreateInfo{}; + samplerCreateInfo.magFilter = linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + samplerCreateInfo.minFilter = linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + samplerCreateInfo.mipmapMode = linear ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerCreateInfo.addressModeU = addressMode; + samplerCreateInfo.addressModeV = addressMode; + samplerCreateInfo.addressModeW = addressMode; + samplerCreateInfo.mipLodBias = 0.0f; + samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER; + samplerCreateInfo.minLod = 0.0f; + samplerCreateInfo.maxLod = 1; + // TODO - ENABLE/DISABLE ANISOTROPY + samplerCreateInfo.maxAnisotropy = 8; + samplerCreateInfo.anisotropyEnable = VK_TRUE; + samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + VulkanUtils::CheckVKResult(vkCreateSampler(CTX.vulkanContext.device.device, &samplerCreateInfo, nullptr, + &vkImageSampler)); + } + } // Metal diff --git a/src/service/texture/TextureService.h b/src/service/texture/TextureService.h index df076111..40d00e1f 100644 --- a/src/service/texture/TextureService.h +++ b/src/service/texture/TextureService.h @@ -5,13 +5,13 @@ #include #include "TextureData.h" -#include "../abstract/IStreamable.h" +#include "../abstract/AbstractResourceService.h" #include "TextureInstance.h" namespace Metal { struct TextureInstance; - class TextureService final : public IStreamable { + class TextureService final : public AbstractResourceService { unsigned int nextTextureIndex = 1; std::unordered_map textureIndices{}; @@ -32,19 +32,23 @@ namespace Metal { void generateMipmaps(const TextureInstance *image) const; public: - [[nodiscard]] TextureData *stream(const std::string &id) const; + [[nodiscard]] TextureData *loadTextureData(const std::string &id) const; + + TextureInstance *stream(const std::string &id); TextureInstance *loadTexture(const std::string &id, const std::string &pathToImage, bool generateMipMaps = false, VkFormat imageFormat = VK_FORMAT_R8G8B8A8_SRGB); - TextureInstance *create(const std::string &id) override; + TextureInstance *create(const std::string &id); TextureInstance *createForCompute(const std::string &id, unsigned int width, unsigned int height, VkFormat format = VK_FORMAT_R16G16B16A16_SFLOAT); unsigned int getTextureIndex(const std::string &id); void disposeResource(TextureInstance *resource) override; + + void createSampler(bool linear, VkSampler &vkImageSampler, VkSamplerAddressMode addressMode); }; } // Metal diff --git a/src/service/transform/TransformService.cpp b/src/service/transform/TransformService.cpp index 9e670c1c..e977dc2f 100644 --- a/src/service/transform/TransformService.cpp +++ b/src/service/transform/TransformService.cpp @@ -8,26 +8,11 @@ namespace Metal { void TransformService::onSync() { - traverse(WorldRepository::ROOT_ID, false); - } - - void TransformService::traverse(const EntityID entityId, bool parentHasChanged) { - const auto entity = static_cast(entityId); - TransformComponent *st = CTX.worldRepository.registry.all_of(entity) - ? &CTX.worldRepository.registry.get(entity) - : nullptr; - if (st != nullptr && (st->isNotFrozen() || parentHasChanged)) { - TransformComponent *parentTransform = findParent(st->getEntityId()); - transform(st, parentTransform); - st->freezeVersion(); - parentHasChanged = true; - } - - const auto e = static_cast(entityId); - if (CTX.worldRepository.registry.all_of(e)) { - const auto &hierarchy = CTX.worldRepository.registry.get(e); - for (auto child: hierarchy.children) { - traverse(child, parentHasChanged); + for (auto entity : CTX.worldRepository.registry.view()) { + TransformComponent &st = CTX.worldRepository.registry.get(entity); + if (st.isNotFrozen()) { + transform(&st, nullptr); + st.freezeVersion(); } } } @@ -39,11 +24,9 @@ namespace Metal { auxMat4 = glm::identity(); } if (!st->forceTransform && st->isStatic) { - LOG_WARN("Entity will not be transformed because it is set to static " + std::to_string(st->getEntityId())); + LOG_WARN("Entity will not be transformed because it is set to static " + std::to_string(entt::to_integral(st->getEntityId()))); return; } - translation = glm::vec3(st->model[3]); - auto *previousTile = CTX.worldGridRepository.getOrCreateTile(translation); auxMat42 = glm::identity(); auxMat42 = glm::translate(auxMat42, st->translation); // Translation @@ -53,34 +36,8 @@ namespace Metal { st->model = auxMat4 * auxMat42; st->freezeVersion(); - translation = glm::vec3(st->model[3]); - auto *newTile = CTX.worldGridRepository.getOrCreateTile(translation); - - CTX.worldGridRepository.moveBetweenTiles(st->getEntityId(), previousTile, newTile); - if (CTX.worldRepository.registry.all_of(static_cast::entity_type>(st->getEntityId()))) { + if (CTX.worldRepository.registry.all_of(st->getEntityId())) { CTX.rayTracingService.markDirty(); } } - - TransformComponent *TransformService::findParent(EntityID id) const { - while (id != EMPTY_ENTITY && id != WorldRepository::ROOT_ID) { - const auto e = static_cast(id); - if (!CTX.worldRepository.registry.valid(e)) break; - const auto &hierarchy = CTX.worldRepository.registry.get(e); - id = hierarchy.parent; - const auto parent = static_cast(id); - TransformComponent *t = (CTX.worldRepository.registry.valid(parent) && CTX.worldRepository.registry.all_of(parent)) - ? &CTX.worldRepository.registry.get(parent) - : nullptr; - if (t != nullptr) { - return t; - } - } - return nullptr; - } - - float TransformService::getDistanceFromCamera(glm::vec3 &translation) { - distanceAux = CTX.worldRepository.camera.position; - return glm::length(distanceAux - translation); - } } // Metal diff --git a/src/service/transform/TransformService.h b/src/service/transform/TransformService.h index c77260c3..37ea9b5a 100644 --- a/src/service/transform/TransformService.h +++ b/src/service/transform/TransformService.h @@ -17,19 +17,10 @@ namespace Metal { glm::mat4x4 auxMat42{}; public: - explicit TransformService() - : AbstractRuntimeComponent() { - } void onSync() override; - void traverse(EntityID entityId, bool parentHasChanged); - void transform(TransformComponent *st, const TransformComponent *parentTransform); - - [[nodiscard]] TransformComponent *findParent(EntityID id) const; - - float getDistanceFromCamera(glm::vec3 &translation); }; } // Metal diff --git a/src/service/volumes/VolumeService.cpp b/src/service/volumes/VolumeService.cpp index c833ff38..5c03305b 100644 --- a/src/service/volumes/VolumeService.cpp +++ b/src/service/volumes/VolumeService.cpp @@ -7,8 +7,7 @@ namespace Metal { void VolumeService::registerVolumes() { auto view = CTX.worldRepository.registry.view(); - for (auto [entity, l, t]: view.each()) { - const auto entityId = static_cast(entity); + for (auto [entityId, l, t]: view.each()) { if (CTX.worldRepository.hiddenEntities.contains(entityId)) { continue; } @@ -24,6 +23,7 @@ namespace Metal { } } + // TODO - ADD EVENT SYSTEM THAT TRIGGERS THIS UPDATE void VolumeService::onSync() { items.clear(); diff --git a/src/service/volumes/VolumeService.h b/src/service/volumes/VolumeService.h index 4ef7fb97..c2377b45 100644 --- a/src/service/volumes/VolumeService.h +++ b/src/service/volumes/VolumeService.h @@ -12,9 +12,6 @@ namespace Metal { void registerVolumes(); public: - explicit VolumeService() - : AbstractRuntimeComponent() { - } void onSync() override; diff --git a/src/service/voxel/VoxelImporterService.cpp b/src/service/voxel/VoxelImporterService.cpp index 2c304ff5..6923f58e 100644 --- a/src/service/voxel/VoxelImporterService.cpp +++ b/src/service/voxel/VoxelImporterService.cpp @@ -51,47 +51,47 @@ namespace Metal { openvdb::initialize(); }); - auto *targetTile = CTX.worldGridRepository.getTile(glm::vec3(0, 0, 0)); int resolution = 12; - auto builder = SparseVoxelOctreeBuilder(targetTile->boundingBox, 32); - - try { - openvdb::io::File file(sourcePath); - file.open(); - openvdb::GridPtrVecPtr gridsPtr = file.getGrids(); - file.close(); - if (!gridsPtr) { - throw std::runtime_error("No grids found in VDB file."); - } - - if (stopToken.stop_requested()) { - return 0; - } - - for (const auto &gridPtr: *gridsPtr) { - if (auto floatGrid = openvdb::gridPtrCast(gridPtr)) { - for (auto iter = floatGrid->beginValueOn(); iter; ++iter) { - if (stopToken.stop_requested()) { - return 0; - } - const openvdb::Coord xyz = iter.getCoord(); - const openvdb::Vec3d worldPos = floatGrid->transform().indexToWorld(xyz); - const glm::vec3 volumePoint(worldPos.x(), worldPos.y(), worldPos.z()); - - const glm::vec3 albedo(0.5f); - const glm::vec3 normal(0.5f); - const VoxelData data{albedo, normal, true}; - - builder.insert(resolution, volumePoint, data); - } - break; - } - } - } catch (const std::exception &e) { - throw std::runtime_error("VDB conversion failed: " + std::string(e.what())); - } - - return serialize(builder, outPath); + // auto builder = SparseVoxelOctreeBuilder(BoundingBox{glm::vec3(-32, -32, -32), glm::vec3(32, 32, 32), glm::vec3(0, 0, 0)}, 32); + // + // try { + // openvdb::io::File file(sourcePath); + // file.open(); + // openvdb::GridPtrVecPtr gridsPtr = file.getGrids(); + // file.close(); + // if (!gridsPtr) { + // throw std::runtime_error("No grids found in VDB file."); + // } + // + // if (stopToken.stop_requested()) { + // return 0; + // } + // + // for (const auto &gridPtr: *gridsPtr) { + // if (auto floatGrid = openvdb::gridPtrCast(gridPtr)) { + // for (auto iter = floatGrid->beginValueOn(); iter; ++iter) { + // if (stopToken.stop_requested()) { + // return 0; + // } + // const openvdb::Coord xyz = iter.getCoord(); + // const openvdb::Vec3d worldPos = floatGrid->transform().indexToWorld(xyz); + // const glm::vec3 volumePoint(worldPos.x(), worldPos.y(), worldPos.z()); + // + // const glm::vec3 albedo(0.5f); + // const glm::vec3 normal(0.5f); + // const VoxelData data{albedo, normal, true}; + // + // builder.insert(resolution, volumePoint, data); + // } + // break; + // } + // } + // } catch (const std::exception &e) { + // throw std::runtime_error("VDB conversion failed: " + std::string(e.what())); + // } + + // return serialize(builder, outPath); + return 0; } void VoxelImporterService::FillStorage(SparseVoxelOctreeBuilder &builder, unsigned int &bufferIndex, diff --git a/src/service/voxel/VoxelService.h b/src/service/voxel/VoxelService.h index 64880d14..cd5450dc 100644 --- a/src/service/voxel/VoxelService.h +++ b/src/service/voxel/VoxelService.h @@ -1,15 +1,17 @@ #ifndef METAL_ENGINE_VOXELSERVICE_H #define METAL_ENGINE_VOXELSERVICE_H -#include "../abstract/IStreamable.h" +#include "../abstract/AbstractResourceService.h" #include "SVOInstance.h" namespace Metal { struct SVOInstance; - class VoxelService final : public IStreamable { + class VoxelService final : public AbstractResourceService { public: - SVOInstance *create(const std::string &id) override; + SVOInstance *create(const std::string &id); + + SVOInstance *stream(const std::string &id); void disposeResource(SVOInstance *resource) override; }; diff --git a/src/service/voxel/impl/SparseVoxelOctreeBuilder.h b/src/service/voxel/impl/SparseVoxelOctreeBuilder.h index ddaafb2f..470fdd9f 100644 --- a/src/service/voxel/impl/SparseVoxelOctreeBuilder.h +++ b/src/service/voxel/impl/SparseVoxelOctreeBuilder.h @@ -9,7 +9,7 @@ namespace Metal { struct SnapshotWorldTile; struct VoxelData; struct OctreeNode; - struct MeshComponent; + struct PrimitiveComponent; class SparseVoxelOctreeBuilder { OctreeNode root{}; diff --git a/src/service/world/WorldGridService.cpp b/src/service/world/WorldGridService.cpp deleted file mode 100644 index 951e2fb1..00000000 --- a/src/service/world/WorldGridService.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "WorldGridService.h" - -#include "../../context/ApplicationContext.h" -#include "../log/LogService.h" - -namespace Metal { - void WorldGridService::addMissingTiles() { - const int numberOfTiles = CTX.engineRepository.numberOfTiles; - if (const int squared = numberOfTiles * numberOfTiles; - squared > CTX.worldGridRepository.getTiles().size()) { - LOG_INFO("Adding missing tiles " + std::to_string(squared) + " " + std::to_string(CTX.worldGridRepository.getTiles().size())); - const int half = numberOfTiles / 2; - for (int x = -half; x < half; x++) { - for (int z = -half; z < half; z++) { - CTX.worldGridRepository.createIfAbsent(x, z); - changed = true; - } - } - } - } - - bool WorldGridService::IsTileOutsideBounds(WorldTile *tile, int half, int min) { - return tile->z >= half || tile->z <= min || tile->x >= half || tile->x <= min; - } - - void WorldGridService::removeExtraTiles() { - const int numberOfTiles = CTX.engineRepository.numberOfTiles; - if (const int squared = numberOfTiles * numberOfTiles; - squared < CTX.worldGridRepository.getTiles().size()) { - LOG_INFO("Removing extra tiles " + std::to_string(CTX.worldGridRepository.getTiles().size()) + " " + std::to_string(squared)); - - const int min = -numberOfTiles; - for (auto it = CTX.worldGridRepository.getTiles().begin(); - it != CTX.worldGridRepository.getTiles().end();) { - auto &tile = it->second; - if (IsTileOutsideBounds(&tile, numberOfTiles / 2, min)) { - LOG_INFO("Removing tile " + tile.id); - // TODO - ADD DISPOSAL OF THINGS RATED TO THE TILE LIKE TERRAIN, FOLIAGE, MATERIALS AND VOXELS - it = CTX.worldGridRepository.getTiles().erase(it); - changed = true; - } else { - ++it; - } - } - } - } - - void WorldGridService::onSync() { - if (!CTX.worldGridRepository.updateLoadedTiles()) { - return; - } - prevTile = CTX.worldGridRepository.getCurrentTile(); - addMissingTiles(); - removeExtraTiles(); - if (changed) { - changed = false; - for (auto &tile: CTX.worldGridRepository.getTiles()) { - CTX.worldGridRepository.updateAdjacentTiles(&tile.second); - } - } - } -} // Metal diff --git a/src/service/world/WorldGridService.h b/src/service/world/WorldGridService.h deleted file mode 100644 index 5f2b5322..00000000 --- a/src/service/world/WorldGridService.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef WORLDGRIDSERVICE_H -#define WORLDGRIDSERVICE_H -#include "../../common/AbstractRuntimeComponent.h" - -namespace Metal { - struct WorldTile; - - class WorldGridService final : public AbstractRuntimeComponent { - WorldTile *prevTile = nullptr; - bool changed = false; - - public: - explicit WorldGridService() - : AbstractRuntimeComponent() { - } - - void addMissingTiles(); - - static bool IsTileOutsideBounds(WorldTile *tile, int half, int min); - - void removeExtraTiles(); - - void onSync() override; - }; -} // Metal - -#endif //WORLDGRIDSERVICE_H diff --git a/src/util/ShaderUtil.cpp b/src/util/ShaderUtil.cpp index 4ff976fc..e75c5148 100644 --- a/src/util/ShaderUtil.cpp +++ b/src/util/ShaderUtil.cpp @@ -173,7 +173,6 @@ namespace Metal { for (auto &entry: LightTypes::getEntries()) { source = "#define " + entry.first + " " + std::to_string(entry.second) + "\n" + source; } - source = "#define TILE_SIZE " + std::to_string(TILE_SIZE) + std::string("\n") + source; source = "#define PI_2 6.28318530718\n" + source; source = "#define PI 3.14159265\n" + source; diff --git a/src/util/UIUtil.h b/src/util/UIUtil.h index 41305050..48312985 100644 --- a/src/util/UIUtil.h +++ b/src/util/UIUtil.h @@ -77,6 +77,89 @@ namespace Metal::UIUtil { ImGui::SameLine(); } + static bool DragFloatWithLabel(const std::string &id, float *value, const std::string &label, const ImVec4 &color, + float speed = 0.1f) { + bool changed = false; + ImGui::PushID(id.c_str()); + + const float framePadding = ImGui::GetStyle().FramePadding.x; + const float labelWidth = ImGui::CalcTextSize(label.c_str()).x + framePadding * 2.0f; + + ImGui::PushStyleColor(ImGuiCol_Button, color); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, color); + ImGui::Button(label.c_str(), ImVec2(labelWidth, 0)); + ImGui::PopStyleColor(3); + + ImGui::SameLine(0, 0); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + changed = ImGui::DragFloat("##v", value, speed); + + ImGui::PopID(); + return changed; + } + + static bool DrawVec2Control(const std::string &name, const std::string &id, float *values, float speed = 0.1f) { + bool changed = false; + ImGui::Text(name.c_str()); + ImGui::PushID(id.c_str()); + + if (ImGui::BeginTable("##table", 2, ImGuiTableFlags_NoSavedSettings)) { + ImGui::TableNextColumn(); + if (DragFloatWithLabel("x", &values[0], "X", ImVec4{0.8f, 0.1f, 0.15f, 1.0f}, speed)) changed = true; + ImGui::TableNextColumn(); + if (DragFloatWithLabel("y", &values[1], "Y", ImVec4{0.2f, 0.7f, 0.2f, 1.0f}, speed)) changed = true; + ImGui::EndTable(); + } + + ImGui::PopID(); + return changed; + } + + static bool DrawVec3Control(const std::string &name, const std::string &id, float *values, float speed = 0.1f) { + bool changed = false; + ImGui::Text(name.c_str()); + ImGui::PushID(id.c_str()); + + if (ImGui::BeginTable("##table", 3, ImGuiTableFlags_NoSavedSettings)) { + ImGui::TableNextColumn(); + if (DragFloatWithLabel("x", &values[0], "X", ImVec4{0.8f, 0.1f, 0.15f, 1.0f}, speed)) changed = true; + ImGui::TableNextColumn(); + if (DragFloatWithLabel("y", &values[1], "Y", ImVec4{0.2f, 0.7f, 0.2f, 1.0f}, speed)) changed = true; + ImGui::TableNextColumn(); + if (DragFloatWithLabel("z", &values[2], "Z", ImVec4{0.1f, 0.25f, 0.8f, 1.0f}, speed)) changed = true; + ImGui::EndTable(); + } + + ImGui::PopID(); + return changed; + } + + static bool DrawVec4Control(const std::string &name, const std::string &id, float *values, float speed = 0.1f) { + bool changed = false; + ImGui::Text(name.c_str()); + ImGui::PushID(id.c_str()); + + if (ImGui::BeginTable("##table", 4, ImGuiTableFlags_NoSavedSettings)) { + ImGui::TableNextColumn(); + if (DragFloatWithLabel("x", &values[0], "X", ImVec4{0.8f, 0.1f, 0.15f, 1.0f}, speed)) changed = true; + ImGui::TableNextColumn(); + if (DragFloatWithLabel("y", &values[1], "Y", ImVec4{0.2f, 0.7f, 0.2f, 1.0f}, speed)) changed = true; + ImGui::TableNextColumn(); + if (DragFloatWithLabel("z", &values[2], "Z", ImVec4{0.1f, 0.25f, 0.8f, 1.0f}, speed)) changed = true; + ImGui::TableNextColumn(); + if (DragFloatWithLabel("w", &values[3], "W", ImVec4{0.5f, 0.5f, 0.5f, 1.0f}, speed)) changed = true; + ImGui::EndTable(); + } + + ImGui::PopID(); + return changed; + } + + static bool DrawQuatControl(const std::string &name, const std::string &id, float *values, float speed = 0.1f) { + return DrawVec4Control(name, id, values, speed); + } + static std::string GetKeyChordName(ImGuiKeyChord keyChord) { std::string result; if (keyChord & ImGuiMod_Ctrl) result += "Ctrl+"; @@ -105,8 +188,6 @@ namespace Metal::UIUtil { return Icons::folder; case EntryType::SCENE: return Icons::inventory_2; - case EntryType::MATERIAL: - return Icons::format_paint; default: return ""; } }