From c30fe35661b0b55222e7598394f4e104a504780c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Sat, 27 Aug 2022 09:41:03 +0200 Subject: [PATCH] New animation properties support (#535) * new animation properties support * material param animations * camera component window, camera component lerp * camera aperture debug * some documentation updates --- .../WickedEngine-Documentation.md | 23 +- Editor/AnimationWindow.cpp | 423 +++++++- Editor/CMakeLists.txt | 1 + Editor/CameraComponentWindow.cpp | 210 ++++ Editor/CameraComponentWindow.h | 25 + Editor/ComponentsWindow.cpp | 28 +- Editor/ComponentsWindow.h | 2 + Editor/Editor.cpp | 25 + Editor/Editor_SOURCE.vcxitems | 2 + Editor/Editor_SOURCE.vcxitems.filters | 2 + Editor/SoundWindow.cpp | 4 +- WickedEngine/wiRenderer.cpp | 171 ++-- WickedEngine/wiScene.cpp | 938 ++++++++++++------ WickedEngine/wiScene.h | 58 +- WickedEngine/wiVersion.cpp | 2 +- 15 files changed, 1460 insertions(+), 454 deletions(-) create mode 100644 Editor/CameraComponentWindow.cpp create mode 100644 Editor/CameraComponentWindow.h diff --git a/Content/Documentation/WickedEngine-Documentation.md b/Content/Documentation/WickedEngine-Documentation.md index 55fa34a75..bf4d96903 100644 --- a/Content/Documentation/WickedEngine-Documentation.md +++ b/Content/Documentation/WickedEngine-Documentation.md @@ -32,11 +32,14 @@ This is a reference for the C++ features of Wicked Engine 15. [EnvironmentProbeComponent](#environmentprobecomponent) 16. [ForceFieldComponent](#forcefieldcomponent) 17. [DecalComponent](#decalcomponent) + 18. [AnimationDataComponent](#animationdatacomponent) 18. [AnimationComponent](#animationcomponent) 19. [WeatherComponent](#weathercomponent) 20. [SoundComponent](#soundcomponent) 21. [InverseKinematicsComponent](#inversekinematicscomponent) 22. [SpringComponent](#springcomponent) + 22. [ColliderComponent](#collidercomponent) + 22. [ScriptComponent](#scriptcomponent) 23. [Scene](#scene) 3. [Job System](#job-system) 4. [Initializer](#initializer) @@ -345,6 +348,9 @@ It is expected that an entity that has EnvironmentProbeComponent, also has Trans [[Header]](../../WickedEngine/wiScene.h) [[Cpp]](../../WickedEngine/wiScene.cpp) It is expected that an entity that has DecalComponent, also has TransformComponent and [AABB](#aabb) (axis aligned bounding box) component. +#### AnimationDataComponent +[[Header]](../../WickedEngine/wiScene.h) [[Cpp]](../../WickedEngine/wiScene.cpp) + #### AnimationComponent [[Header]](../../WickedEngine/wiScene.h) [[Cpp]](../../WickedEngine/wiScene.cpp) @@ -366,6 +372,14 @@ If animations are also playing on the affected entities, the IK system will over [[Header]](../../WickedEngine/wiScene.h) [[Cpp]](../../WickedEngine/wiScene.cpp) An entity can have a `SpringComponent` to achieve a "jiggle" or "soft" animation effect programatically. The effect will work automatically if the transform is changed by animation system for example, or in any other way. The parameter `stiffness` specifies how fast the transform tries to go back to its initial position. The parameter `damping` specifies how fast the transform comes to rest position. The `wind_affection` parameter specifies how much the global wind applies to the spring. +#### ColiderComponent +[[Header]](../../WickedEngine/wiScene.h) [[Cpp]](../../WickedEngine/wiScene.cpp) +The collider component will specify a collider shape to be used in simple fake physics simulations. It will affect Springs and GPU particle effect. + +#### ScriptComponent +[[Header]](../../WickedEngine/wiScene.h) [[Cpp]](../../WickedEngine/wiScene.cpp) +ScriptComponent can reference a lua script and run it every frame, while also providing some additional data to script like a local GetEntity() function. The script can be written to reference additional component data by using its unique GetEntity() function. A ScriptComponent can also call other scripts, which can be used to implement multiple scripts on one entity. + #### Scene [[Header]](../../WickedEngine/wiScene.h) [[Cpp]](../../WickedEngine/wiScene.cpp) A scene is a collection of component arrays. The scene is updating all the components in an efficient manner using the [job system](#job-system). It can be serialized and saved/loaded from disk efficiently. @@ -519,7 +533,7 @@ Unordered Access Views, in other words resources with read-write access. `GPUBuf - Constant buffers
Only `GPUBuffer`s can be set as constant buffers if they were created with a `BindFlags` in their description that has the `CONSTANT_BUFFER` bit set. The resource can't be a constant buffer at the same time when it is also a shader resource or a UAV or a vertex buffer or an index buffer. Use the `GraphicsDevice::BindConstantBuffer()` function to bind constant buffers. - Samplers
-Only `Sampler` can be bound as sampler. Use the `GraphicsDevice::BindSampler()` function to bind samplers. Additionally, you can specify auto samplers and common samplers and avoid binding them every time. +Only `Sampler` can be bound as sampler. Use the `GraphicsDevice::BindSampler()` function to bind samplers. There are some limitations on the maximum value of slots that can be used, these are defined as compile time constants in [Graphics device SharedInternals](../WickedEngine/wiGraphicsDevice_SharedInternals.h). The user can modify these and recompile the engine if the predefined slots are not enough. This could slightly affect performance. @@ -590,13 +604,8 @@ Shaders still need to be created with `GraphicsDevice::CreateShader()` in a simi - `PS`: Pixel Shader - `CS`: Compute Shader - `LIB`: Library shader -- `ShaderStage::COUNT`: Invalid Shader. This can be used to enumerate through all shader stages like: -```cpp -device->BindResource(, myTexture, 5, cmd); // Binds myTexture to slot 5 -``` - -Depending on the graphics device implementation, the shader code must be different format. For example, DirectX expects HLSL shaders, Vulkan expects SPIR-V shaders. The engine can only use precompiled shader bytecodes, shader compilation from high level source code is not supported. Usually shaders are compiled into bytecode and saved to files (with .cso extension) by Visual Studio if they are included in the project. These files can be loaded to memory and provided as input buffers to the CreateShader() function. +Depending on the graphics device implementation, the shader code must be different format. For example, DirectX expects DXIL shaders, Vulkan expects SPIR-V shaders. The engine can compile HLSL shader source code to DXIL or SPIRV format with the [Shader Compiler](#shader-compiler). ##### Render Passes Render passes are defining regions in GPU execution where a number of render targets or depth buffers will be used to render into them. Render targets and depth buffers are defined as `RenderPassAttachment`s. The `RenderPassAttachment`s have a pointer to the texture, state the resource type (`RENDERTARGET`, `DEPTH_STENCIL` or `RESOLVE`), state the [subresource](#subresources) index, the load and store operations, and the layout transitions for the textures. diff --git a/Editor/AnimationWindow.cpp b/Editor/AnimationWindow.cpp index 258c0ae0b..86d40e854 100644 --- a/Editor/AnimationWindow.cpp +++ b/Editor/AnimationWindow.cpp @@ -9,9 +9,9 @@ void AnimationWindow::Create(EditorComponent* _editor) { editor = _editor; wi::gui::Window::Create(ICON_ANIMATION " Animation", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE); - SetSize(XMFLOAT2(520, 410)); + SetSize(XMFLOAT2(520, 430)); - closeButton.SetTooltip("Delete Animation"); + closeButton.SetTooltip("Delete AnimationComponent"); OnClose([=](wi::gui::EventArgs args) { wi::Archive& archive = editor->AdvanceHistory(); @@ -201,6 +201,22 @@ void AnimationWindow::Create(EditorComponent* _editor) recordCombo.AddItem("Light [range] " ICON_POINTLIGHT); recordCombo.AddItem("Light [inner cone] " ICON_POINTLIGHT); recordCombo.AddItem("Light [outer cone] " ICON_POINTLIGHT); + recordCombo.AddItem("Sound [play] " ICON_SOUND); + recordCombo.AddItem("Sound [stop] " ICON_SOUND); + recordCombo.AddItem("Sound [volume] " ICON_SOUND); + recordCombo.AddItem("Emitter [emit count] " ICON_EMITTER); + recordCombo.AddItem("Camera [fov] " ICON_CAMERA); + recordCombo.AddItem("Camera [focal length] " ICON_CAMERA); + recordCombo.AddItem("Camera [aperture size] " ICON_CAMERA); + recordCombo.AddItem("Camera [aperture shape] " ICON_CAMERA); + recordCombo.AddItem("Script [play] " ICON_SCRIPT); + recordCombo.AddItem("Script [stop] " ICON_SCRIPT); + recordCombo.AddItem("Material [color] " ICON_MATERIAL); + recordCombo.AddItem("Material [emissive] " ICON_MATERIAL); + recordCombo.AddItem("Material [roughness] " ICON_MATERIAL); + recordCombo.AddItem("Material [metalness] " ICON_MATERIAL); + recordCombo.AddItem("Material [reflectance] " ICON_MATERIAL); + recordCombo.AddItem("Material [texmuladd] " ICON_MATERIAL); recordCombo.AddItem("Close loop " ICON_LOOP, ~0ull); recordCombo.OnSelect([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -235,18 +251,29 @@ void AnimationWindow::Create(EditorComponent* _editor) // Duplicate first frame to current position: animation_data->keyframe_times.push_back(current_time); - switch (channel.path) + const AnimationComponent::AnimationChannel::PathDataType path_data_type = channel.GetPathDataType(); + + switch (path_data_type) { - case wi::scene::AnimationComponent::AnimationChannel::TRANSLATION: - case wi::scene::AnimationComponent::AnimationChannel::SCALE: - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_COLOR: + case AnimationComponent::AnimationChannel::PathDataType::Float: + { + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst]); + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float2: + { + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 2 + 0]); + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 2 + 1]); + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float3: { animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 3 + 0]); animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 3 + 1]); animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 3 + 2]); } break; - case wi::scene::AnimationComponent::AnimationChannel::ROTATION: + case AnimationComponent::AnimationChannel::PathDataType::Float4: { animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 4 + 0]); animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 4 + 1]); @@ -254,7 +281,7 @@ void AnimationWindow::Create(EditorComponent* _editor) animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 4 + 3]); } break; - case wi::scene::AnimationComponent::AnimationChannel::WEIGHTS: + case AnimationComponent::AnimationChannel::PathDataType::Weights: { const MeshComponent* mesh = scene.meshes.GetComponent(channel.target); if (mesh == nullptr && scene.objects.Contains(channel.target)) @@ -274,14 +301,6 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_INTENSITY: - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_RANGE: - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_INNERCONE: - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_OUTERCONE: - { - animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst]); - } - break; default: break; } @@ -328,6 +347,54 @@ void AnimationWindow::Create(EditorComponent* _editor) case 9: paths.push_back(AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE); break; + case 10: + paths.push_back(AnimationComponent::AnimationChannel::Path::SOUND_PLAY); + break; + case 11: + paths.push_back(AnimationComponent::AnimationChannel::Path::SOUND_STOP); + break; + case 12: + paths.push_back(AnimationComponent::AnimationChannel::Path::SOUND_VOLUME); + break; + case 13: + paths.push_back(AnimationComponent::AnimationChannel::Path::EMITTER_EMITCOUNT); + break; + case 14: + paths.push_back(AnimationComponent::AnimationChannel::Path::CAMERA_FOV); + break; + case 15: + paths.push_back(AnimationComponent::AnimationChannel::Path::CAMERA_FOCAL_LENGTH); + break; + case 16: + paths.push_back(AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SIZE); + break; + case 17: + paths.push_back(AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SHAPE); + break; + case 18: + paths.push_back(AnimationComponent::AnimationChannel::Path::SCRIPT_PLAY); + break; + case 19: + paths.push_back(AnimationComponent::AnimationChannel::Path::SCRIPT_STOP); + break; + case 20: + paths.push_back(AnimationComponent::AnimationChannel::Path::MATERIAL_COLOR); + break; + case 21: + paths.push_back(AnimationComponent::AnimationChannel::Path::MATERIAL_EMISSIVE); + break; + case 22: + paths.push_back(AnimationComponent::AnimationChannel::Path::MATERIAL_ROUGHNESS); + break; + case 23: + paths.push_back(AnimationComponent::AnimationChannel::Path::MATERIAL_METALNESS); + break; + case 24: + paths.push_back(AnimationComponent::AnimationChannel::Path::MATERIAL_REFLECTANCE); + break; + case 25: + paths.push_back(AnimationComponent::AnimationChannel::Path::MATERIAL_TEXMULADD); + break; } for (auto path : paths) @@ -367,7 +434,7 @@ void AnimationWindow::Create(EditorComponent* _editor) switch (channel.path) { - case wi::scene::AnimationComponent::AnimationChannel::TRANSLATION: + case wi::scene::AnimationComponent::AnimationChannel::Path::TRANSLATION: { const TransformComponent* transform = scene.transforms.GetComponent(channel.target); if (transform != nullptr) @@ -383,7 +450,7 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case wi::scene::AnimationComponent::AnimationChannel::ROTATION: + case wi::scene::AnimationComponent::AnimationChannel::Path::ROTATION: { const TransformComponent* transform = scene.transforms.GetComponent(channel.target); if (transform != nullptr) @@ -400,7 +467,7 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case wi::scene::AnimationComponent::AnimationChannel::SCALE: + case wi::scene::AnimationComponent::AnimationChannel::Path::SCALE: { const TransformComponent* transform = scene.transforms.GetComponent(channel.target); if (transform != nullptr) @@ -416,7 +483,7 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case wi::scene::AnimationComponent::AnimationChannel::WEIGHTS: + case wi::scene::AnimationComponent::AnimationChannel::Path::WEIGHTS: { const MeshComponent* mesh = scene.meshes.GetComponent(channel.target); if (mesh == nullptr && scene.objects.Contains(selected.entity)) @@ -440,7 +507,7 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_COLOR: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_COLOR: { const LightComponent* light = scene.lights.GetComponent(channel.target); if (light != nullptr) @@ -456,7 +523,7 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_INTENSITY: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY: { const LightComponent* light = scene.lights.GetComponent(channel.target); if (light != nullptr) @@ -470,7 +537,7 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_RANGE: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_RANGE: { const LightComponent* light = scene.lights.GetComponent(channel.target); if (light != nullptr) @@ -484,7 +551,7 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_INNERCONE: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE: { const LightComponent* light = scene.lights.GetComponent(channel.target); if (light != nullptr) @@ -498,7 +565,7 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_OUTERCONE: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE: { const LightComponent* light = scene.lights.GetComponent(channel.target); if (light != nullptr) @@ -512,6 +579,214 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; + case wi::scene::AnimationComponent::AnimationChannel::Path::SOUND_PLAY: + case wi::scene::AnimationComponent::AnimationChannel::Path::SOUND_STOP: + { + const SoundComponent* sound = scene.sounds.GetComponent(channel.target); + if (sound != nullptr) + { + // no data + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::SOUND_VOLUME: + { + const SoundComponent* sound = scene.sounds.GetComponent(channel.target); + if (sound != nullptr) + { + animation_data->keyframe_data.push_back(sound->volume); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::EMITTER_EMITCOUNT: + { + const wi::EmittedParticleSystem* emitter = scene.emitters.GetComponent(channel.target); + if (emitter != nullptr) + { + animation_data->keyframe_data.push_back(emitter->count); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_FOV: + { + const CameraComponent* camera = scene.cameras.GetComponent(channel.target); + if (camera != nullptr) + { + animation_data->keyframe_data.push_back(camera->fov); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_FOCAL_LENGTH: + { + const CameraComponent* camera = scene.cameras.GetComponent(channel.target); + if (camera != nullptr) + { + animation_data->keyframe_data.push_back(camera->focal_length); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SIZE: + { + const CameraComponent* camera = scene.cameras.GetComponent(channel.target); + if (camera != nullptr) + { + animation_data->keyframe_data.push_back(camera->aperture_size); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SHAPE: + { + const CameraComponent* camera = scene.cameras.GetComponent(channel.target); + if (camera != nullptr) + { + animation_data->keyframe_data.push_back(camera->aperture_shape.x); + animation_data->keyframe_data.push_back(camera->aperture_shape.y); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::SCRIPT_PLAY: + case wi::scene::AnimationComponent::AnimationChannel::Path::SCRIPT_STOP: + { + const ScriptComponent* script = scene.scripts.GetComponent(channel.target); + if (script != nullptr) + { + // no data + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_COLOR: + { + const MaterialComponent* material = scene.materials.GetComponent(channel.target); + if (material != nullptr) + { + animation_data->keyframe_data.push_back(material->baseColor.x); + animation_data->keyframe_data.push_back(material->baseColor.y); + animation_data->keyframe_data.push_back(material->baseColor.z); + animation_data->keyframe_data.push_back(material->baseColor.w); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_EMISSIVE: + { + const MaterialComponent* material = scene.materials.GetComponent(channel.target); + if (material != nullptr) + { + animation_data->keyframe_data.push_back(material->emissiveColor.x); + animation_data->keyframe_data.push_back(material->emissiveColor.y); + animation_data->keyframe_data.push_back(material->emissiveColor.z); + animation_data->keyframe_data.push_back(material->emissiveColor.w); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_ROUGHNESS: + { + const MaterialComponent* material = scene.materials.GetComponent(channel.target); + if (material != nullptr) + { + animation_data->keyframe_data.push_back(material->roughness); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_METALNESS: + { + const MaterialComponent* material = scene.materials.GetComponent(channel.target); + if (material != nullptr) + { + animation_data->keyframe_data.push_back(material->metalness); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_REFLECTANCE: + { + const MaterialComponent* material = scene.materials.GetComponent(channel.target); + if (material != nullptr) + { + animation_data->keyframe_data.push_back(material->reflectance); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_TEXMULADD: + { + const MaterialComponent* material = scene.materials.GetComponent(channel.target); + if (material != nullptr) + { + animation_data->keyframe_data.push_back(material->texMulAdd.x); + animation_data->keyframe_data.push_back(material->texMulAdd.y); + animation_data->keyframe_data.push_back(material->texMulAdd.z); + animation_data->keyframe_data.push_back(material->texMulAdd.w); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; default: break; } @@ -562,22 +837,34 @@ void AnimationWindow::Create(EditorComponent* _editor) const AnimationComponent::AnimationChannel& channel = animation->channels[channelIndex]; const AnimationComponent::AnimationSampler& sam = animation->samplers[channel.samplerIndex]; AnimationDataComponent* animation_data = scene.animation_datas.GetComponent(sam.data); + if (animation_data != nullptr && animation_data->keyframe_times.size() > timeIndex) { // specific keyframe deletion: - switch (channel.path) + const AnimationComponent::AnimationChannel::PathDataType path_data_type = channel.GetPathDataType(); + + switch (path_data_type) { - case AnimationComponent::AnimationChannel::Path::TRANSLATION: - case AnimationComponent::AnimationChannel::Path::SCALE: - case AnimationComponent::AnimationChannel::Path::LIGHT_COLOR: + case AnimationComponent::AnimationChannel::PathDataType::Event: + animation_data->keyframe_times.erase(animation_data->keyframe_times.begin() + timeIndex); + break; + case AnimationComponent::AnimationChannel::PathDataType::Float: + animation_data->keyframe_times.erase(animation_data->keyframe_times.begin() + timeIndex); + animation_data->keyframe_data.erase(animation_data->keyframe_data.begin() + timeIndex); + break; + case AnimationComponent::AnimationChannel::PathDataType::Float2: + animation_data->keyframe_times.erase(animation_data->keyframe_times.begin() + timeIndex); + animation_data->keyframe_data.erase(animation_data->keyframe_data.begin() + timeIndex * 2, animation_data->keyframe_data.begin() + timeIndex * 2 + 2); + break; + case AnimationComponent::AnimationChannel::PathDataType::Float3: animation_data->keyframe_times.erase(animation_data->keyframe_times.begin() + timeIndex); animation_data->keyframe_data.erase(animation_data->keyframe_data.begin() + timeIndex * 3, animation_data->keyframe_data.begin() + timeIndex * 3 + 3); break; - case AnimationComponent::AnimationChannel::Path::ROTATION: + case AnimationComponent::AnimationChannel::PathDataType::Float4: animation_data->keyframe_times.erase(animation_data->keyframe_times.begin() + timeIndex); animation_data->keyframe_data.erase(animation_data->keyframe_data.begin() + timeIndex * 4, animation_data->keyframe_data.begin() + timeIndex * 4 + 4); break; - case AnimationComponent::AnimationChannel::Path::WEIGHTS: + case AnimationComponent::AnimationChannel::PathDataType::Weights: { MeshComponent* mesh = scene.meshes.GetComponent(channel.target); if (mesh == nullptr && scene.objects.Contains(channel.target)) @@ -593,12 +880,6 @@ void AnimationWindow::Create(EditorComponent* _editor) } } break; - case AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY: - case AnimationComponent::AnimationChannel::Path::LIGHT_RANGE: - case AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE: - case AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE: - animation_data->keyframe_times.erase(animation_data->keyframe_times.begin() + timeIndex); - break; default: break; } @@ -702,33 +983,81 @@ void AnimationWindow::RefreshKeyframesList() wi::gui::TreeList::Item item; switch (channel.path) { - case wi::scene::AnimationComponent::AnimationChannel::TRANSLATION: + case wi::scene::AnimationComponent::AnimationChannel::Path::TRANSLATION: item.name += ICON_TRANSLATE " "; break; - case wi::scene::AnimationComponent::AnimationChannel::ROTATION: + case wi::scene::AnimationComponent::AnimationChannel::Path::ROTATION: item.name += ICON_ROTATE " "; break; - case wi::scene::AnimationComponent::AnimationChannel::SCALE: + case wi::scene::AnimationComponent::AnimationChannel::Path::SCALE: item.name += ICON_SCALE " "; break; - case wi::scene::AnimationComponent::AnimationChannel::WEIGHTS: + case wi::scene::AnimationComponent::AnimationChannel::Path::WEIGHTS: item.name += ICON_MESH " "; break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_COLOR: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_COLOR: item.name += ICON_POINTLIGHT " [color] "; break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_INTENSITY: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY: item.name += ICON_POINTLIGHT " [intensity] "; break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_RANGE: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_RANGE: item.name += ICON_POINTLIGHT " [range] "; break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_INNERCONE: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE: item.name += ICON_POINTLIGHT " [inner cone] "; break; - case wi::scene::AnimationComponent::AnimationChannel::LIGHT_OUTERCONE: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE: item.name += ICON_POINTLIGHT " [outer cone] "; break; + case wi::scene::AnimationComponent::AnimationChannel::Path::SOUND_PLAY: + item.name += ICON_SOUND " [play] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::SOUND_STOP: + item.name += ICON_SOUND " [stop] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::SOUND_VOLUME: + item.name += ICON_SOUND " [volume] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::EMITTER_EMITCOUNT: + item.name += ICON_EMITTER " [emit count] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_FOV: + item.name += ICON_CAMERA " [fov] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_FOCAL_LENGTH: + item.name += ICON_CAMERA " [focal length] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SIZE: + item.name += ICON_CAMERA " [aperture size] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SHAPE: + item.name += ICON_CAMERA " [aperture shape] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::SCRIPT_PLAY: + item.name += ICON_SCRIPT " [play] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::SCRIPT_STOP: + item.name += ICON_SCRIPT " [stop] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_COLOR: + item.name += ICON_MATERIAL " [color] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_EMISSIVE: + item.name += ICON_MATERIAL " [emissive] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_ROUGHNESS: + item.name += ICON_MATERIAL " [roughness] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_METALNESS: + item.name += ICON_MATERIAL " [metalness] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_REFLECTANCE: + item.name += ICON_MATERIAL " [reflectance] "; + break; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_TEXMULADD: + item.name += ICON_MATERIAL " [texmuladd] "; + break; default: break; } @@ -782,7 +1111,7 @@ void AnimationWindow::ResizeLayout() float jump = 20; const float margin_left = 80; - const float margin_right = 40; + const float margin_right = 50; auto add = [&](wi::gui::Widget& widget) { if (!widget.IsVisible()) diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index 73dc36bc5..d048851d7 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -4,6 +4,7 @@ set (SOURCE_FILES #$<$:App_${PLATFORM}.cpp> AnimationWindow.cpp CameraWindow.cpp + CameraComponentWindow.cpp DecalWindow.cpp Editor.cpp EmitterWindow.cpp diff --git a/Editor/CameraComponentWindow.cpp b/Editor/CameraComponentWindow.cpp new file mode 100644 index 000000000..02da29f09 --- /dev/null +++ b/Editor/CameraComponentWindow.cpp @@ -0,0 +1,210 @@ +#include "stdafx.h" +#include "CameraComponentWindow.h" +#include "Editor.h" + +using namespace wi::ecs; +using namespace wi::scene; + +void CameraComponentWindow::Create(EditorComponent* _editor) +{ + editor = _editor; + wi::gui::Window::Create(ICON_CAMERA " Camera", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE); + editor->GetCurrentEditorScene().camera_transform.MatrixTransform(editor->GetCurrentEditorScene().camera.GetInvView()); + editor->GetCurrentEditorScene().camera_transform.UpdateTransform(); + + SetSize(XMFLOAT2(320, 200)); + + closeButton.SetTooltip("Delete CameraComponent"); + OnClose([=](wi::gui::EventArgs args) { + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_COMPONENT_DATA; + editor->RecordEntity(archive, entity); + + editor->GetCurrentScene().cameras.Remove(entity); + + editor->RecordEntity(archive, entity); + + editor->optionsWnd.RefreshEntityTree(); + }); + + float x = 140; + float y = 0; + float hei = 18; + float step = hei + 2; + float wid = 120; + + farPlaneSlider.Create(100, 10000, 5000, 100000, "Far Plane: "); + farPlaneSlider.SetTooltip("Controls the camera's far clip plane, geometry farther than this will be clipped."); + farPlaneSlider.SetSize(XMFLOAT2(wid, hei)); + farPlaneSlider.SetPos(XMFLOAT2(x, y)); + farPlaneSlider.SetValue(editor->GetCurrentEditorScene().camera.zFarP); + farPlaneSlider.OnSlide([=](wi::gui::EventArgs args) { + Scene& scene = editor->GetCurrentScene(); + CameraComponent* camera = scene.cameras.GetComponent(entity); + if (camera == nullptr) + return; + camera->zFarP = args.fValue; + camera->SetDirty(); + }); + AddWidget(&farPlaneSlider); + + nearPlaneSlider.Create(0.01f, 10, 0.1f, 10000, "Near Plane: "); + nearPlaneSlider.SetTooltip("Controls the camera's near clip plane, geometry closer than this will be clipped."); + nearPlaneSlider.SetSize(XMFLOAT2(wid, hei)); + nearPlaneSlider.SetPos(XMFLOAT2(x, y += step)); + nearPlaneSlider.SetValue(editor->GetCurrentEditorScene().camera.zNearP); + nearPlaneSlider.OnSlide([=](wi::gui::EventArgs args) { + Scene& scene = editor->GetCurrentScene(); + CameraComponent* camera = scene.cameras.GetComponent(entity); + if (camera == nullptr) + return; + camera->zNearP = args.fValue; + camera->SetDirty(); + }); + AddWidget(&nearPlaneSlider); + + fovSlider.Create(1, 179, 60, 10000, "FOV: "); + fovSlider.SetTooltip("Controls the camera's top-down field of view (in degrees)"); + fovSlider.SetSize(XMFLOAT2(wid, hei)); + fovSlider.SetPos(XMFLOAT2(x, y += step)); + fovSlider.SetValue(editor->GetCurrentEditorScene().camera.fov / XM_PI * 180.f); + fovSlider.OnSlide([=](wi::gui::EventArgs args) { + Scene& scene = editor->GetCurrentScene(); + CameraComponent* camera = scene.cameras.GetComponent(entity); + if (camera == nullptr) + return; + camera->fov = args.fValue / 180.f * XM_PI; + camera->SetDirty(); + }); + AddWidget(&fovSlider); + + focalLengthSlider.Create(0.001f, 100, 1, 10000, "Focal Length: "); + focalLengthSlider.SetTooltip("Controls the depth of field effect's focus distance"); + focalLengthSlider.SetSize(XMFLOAT2(wid, hei)); + focalLengthSlider.SetPos(XMFLOAT2(x, y += step)); + focalLengthSlider.OnSlide([=](wi::gui::EventArgs args) { + Scene& scene = editor->GetCurrentScene(); + CameraComponent* camera = scene.cameras.GetComponent(entity); + if (camera == nullptr) + return; + camera->focal_length = args.fValue; + camera->SetDirty(); + }); + AddWidget(&focalLengthSlider); + + apertureSizeSlider.Create(0, 1, 0, 10000, "Aperture Size: "); + apertureSizeSlider.SetTooltip("Controls the depth of field effect's strength"); + apertureSizeSlider.SetSize(XMFLOAT2(wid, hei)); + apertureSizeSlider.SetPos(XMFLOAT2(x, y += step)); + apertureSizeSlider.OnSlide([=](wi::gui::EventArgs args) { + Scene& scene = editor->GetCurrentScene(); + CameraComponent* camera = scene.cameras.GetComponent(entity); + if (camera == nullptr) + return; + camera->aperture_size = args.fValue; + camera->SetDirty(); + }); + AddWidget(&apertureSizeSlider); + + apertureShapeXSlider.Create(0, 2, 1, 10000, "Aperture Shape X: "); + apertureShapeXSlider.SetTooltip("Controls the depth of field effect's bokeh shape"); + apertureShapeXSlider.SetSize(XMFLOAT2(wid, hei)); + apertureShapeXSlider.SetPos(XMFLOAT2(x, y += step)); + apertureShapeXSlider.OnSlide([=](wi::gui::EventArgs args) { + Scene& scene = editor->GetCurrentScene(); + CameraComponent* camera = scene.cameras.GetComponent(entity); + if (camera == nullptr) + return; + camera->aperture_shape.x = args.fValue; + camera->SetDirty(); + }); + AddWidget(&apertureShapeXSlider); + + apertureShapeYSlider.Create(0, 2, 1, 10000, "Aperture Shape Y: "); + apertureShapeYSlider.SetTooltip("Controls the depth of field effect's bokeh shape"); + apertureShapeYSlider.SetSize(XMFLOAT2(wid, hei)); + apertureShapeYSlider.SetPos(XMFLOAT2(x, y += step)); + apertureShapeYSlider.OnSlide([=](wi::gui::EventArgs args) { + Scene& scene = editor->GetCurrentScene(); + CameraComponent* camera = scene.cameras.GetComponent(entity); + if (camera == nullptr) + return; + camera->aperture_shape.y = args.fValue; + camera->SetDirty(); + }); + AddWidget(&apertureShapeYSlider); + + + SetEntity(INVALID_ENTITY); + + SetPos(XMFLOAT2(100, 100)); + + SetMinimized(true); +} + +void CameraComponentWindow::SetEntity(Entity entity) +{ + this->entity = entity; + + Scene& scene = editor->GetCurrentScene(); + const CameraComponent* camera = scene.cameras.GetComponent(entity); + + if (camera != nullptr) + { + farPlaneSlider.SetValue(camera->zFarP); + nearPlaneSlider.SetValue(camera->zNearP); + fovSlider.SetValue(camera->fov * 180.0f / XM_PI); + focalLengthSlider.SetValue(camera->focal_length); + apertureSizeSlider.SetValue(camera->aperture_size); + apertureShapeXSlider.SetValue(camera->aperture_shape.x); + apertureShapeYSlider.SetValue(camera->aperture_shape.y); + } +} + +void CameraComponentWindow::ResizeLayout() +{ + wi::gui::Window::ResizeLayout(); + const float padding = 4; + const float width = GetWidgetAreaSize().x; + float y = padding; + float jump = 20; + + auto add = [&](wi::gui::Widget& widget) { + if (!widget.IsVisible()) + return; + const float margin_left = 140; + const float margin_right = 45; + widget.SetPos(XMFLOAT2(margin_left, y)); + widget.SetSize(XMFLOAT2(width - margin_left - margin_right, widget.GetScale().y)); + y += widget.GetSize().y; + y += padding; + }; + auto add_right = [&](wi::gui::Widget& widget) { + if (!widget.IsVisible()) + return; + const float margin_right = 45; + widget.SetPos(XMFLOAT2(width - margin_right - widget.GetSize().x, y)); + y += widget.GetSize().y; + y += padding; + }; + auto add_fullwidth = [&](wi::gui::Widget& widget) { + if (!widget.IsVisible()) + return; + const float margin_left = padding; + const float margin_right = padding; + widget.SetPos(XMFLOAT2(margin_left, y)); + widget.SetSize(XMFLOAT2(width - margin_left - margin_right, widget.GetScale().y)); + y += widget.GetSize().y; + y += padding; + }; + + add(farPlaneSlider); + add(nearPlaneSlider); + add(fovSlider); + add(focalLengthSlider); + add(apertureSizeSlider); + add(apertureShapeXSlider); + add(apertureShapeYSlider); + +} diff --git a/Editor/CameraComponentWindow.h b/Editor/CameraComponentWindow.h new file mode 100644 index 000000000..e5f9536e8 --- /dev/null +++ b/Editor/CameraComponentWindow.h @@ -0,0 +1,25 @@ +#pragma once +#include "WickedEngine.h" + +class EditorComponent; + +class CameraComponentWindow : public wi::gui::Window +{ +public: + void Create(EditorComponent* editor); + + EditorComponent* editor = nullptr; + wi::ecs::Entity entity = wi::ecs::INVALID_ENTITY; + void SetEntity(wi::ecs::Entity entity); + + wi::gui::Slider farPlaneSlider; + wi::gui::Slider nearPlaneSlider; + wi::gui::Slider fovSlider; + wi::gui::Slider focalLengthSlider; + wi::gui::Slider apertureSizeSlider; + wi::gui::Slider apertureShapeXSlider; + wi::gui::Slider apertureShapeYSlider; + + void ResizeLayout() override; +}; + diff --git a/Editor/ComponentsWindow.cpp b/Editor/ComponentsWindow.cpp index 94acb8da0..4f71ace64 100644 --- a/Editor/ComponentsWindow.cpp +++ b/Editor/ComponentsWindow.cpp @@ -37,13 +37,14 @@ void ComponentsWindow::Create(EditorComponent* _editor) softWnd.Create(editor); colliderWnd.Create(editor); hierarchyWnd.Create(editor); + cameraComponentWnd.Create(editor); newComponentCombo.Create("Add: "); newComponentCombo.selected_font.anim.typewriter.looped = true; newComponentCombo.selected_font.anim.typewriter.time = 2; newComponentCombo.selected_font.anim.typewriter.character_start = 1; - newComponentCombo.SetTooltip("Add a component to the first selected entity."); + newComponentCombo.SetTooltip("Add a component to the last selected entity."); newComponentCombo.SetInvalidSelectionText("..."); newComponentCombo.AddItem("Name", 0); newComponentCombo.AddItem("Layer " ICON_LAYER, 1); @@ -65,12 +66,13 @@ void ComponentsWindow::Create(EditorComponent* _editor) newComponentCombo.AddItem("Rigid Body " ICON_RIGIDBODY, 16); newComponentCombo.AddItem("Soft Body " ICON_SOFTBODY, 17); newComponentCombo.AddItem("Collider " ICON_COLLIDER, 18); + newComponentCombo.AddItem("Camera " ICON_CAMERA, 20); newComponentCombo.OnSelect([=](wi::gui::EventArgs args) { newComponentCombo.SetSelectedWithoutCallback(-1); if (editor->translator.selected.empty()) return; Scene& scene = editor->GetCurrentScene(); - Entity entity = editor->translator.selected.front().entity; + Entity entity = editor->translator.selected.back().entity; if (entity == INVALID_ENTITY) { assert(0); @@ -160,6 +162,10 @@ void ComponentsWindow::Create(EditorComponent* _editor) if (scene.hierarchy.Contains(entity)) return; break; + case 20: + if (scene.cameras.Contains(entity)) + return; + break; default: return; } @@ -253,6 +259,9 @@ void ComponentsWindow::Create(EditorComponent* _editor) case 19: scene.hierarchy.Create(entity); break; + case 20: + scene.cameras.Create(entity); + break; default: break; } @@ -287,6 +296,7 @@ void ComponentsWindow::Create(EditorComponent* _editor) AddWidget(&softWnd); AddWidget(&colliderWnd); AddWidget(&hierarchyWnd); + AddWidget(&cameraComponentWnd); materialWnd.SetVisible(false); weatherWnd.SetVisible(false); @@ -310,6 +320,7 @@ void ComponentsWindow::Create(EditorComponent* _editor) softWnd.SetVisible(false); colliderWnd.SetVisible(false); hierarchyWnd.SetVisible(false); + cameraComponentWnd.SetVisible(false); SetSize(editor->optionsWnd.GetSize()); @@ -627,6 +638,19 @@ void ComponentsWindow::ResizeLayout() colliderWnd.SetVisible(false); } + if (scene.cameras.Contains(cameraComponentWnd.entity)) + { + cameraComponentWnd.SetVisible(true); + cameraComponentWnd.SetPos(pos); + cameraComponentWnd.SetSize(XMFLOAT2(width, cameraComponentWnd.GetScale().y)); + pos.y += cameraComponentWnd.GetSize().y; + pos.y += padding; + } + else + { + cameraComponentWnd.SetVisible(false); + } + if (scene.scripts.Contains(scriptWnd.entity)) { scriptWnd.SetVisible(true); diff --git a/Editor/ComponentsWindow.h b/Editor/ComponentsWindow.h index 72015810c..f840dfa67 100644 --- a/Editor/ComponentsWindow.h +++ b/Editor/ComponentsWindow.h @@ -22,6 +22,7 @@ #include "SoftBodyWindow.h" #include "ColliderWindow.h" #include "HierarchyWindow.h" +#include "CameraComponentWindow.h" class EditorComponent; @@ -57,4 +58,5 @@ public: SoftBodyWindow softWnd; ColliderWindow colliderWnd; HierarchyWindow hierarchyWnd; + CameraComponentWindow cameraComponentWnd; }; diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index 75ca0ea1a..421e68dbb 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -346,6 +346,7 @@ void EditorComponent::Load() componentsWnd.softWnd.SetEntity(INVALID_ENTITY); componentsWnd.colliderWnd.SetEntity(INVALID_ENTITY); componentsWnd.hierarchyWnd.SetEntity(INVALID_ENTITY); + componentsWnd.cameraComponentWnd.SetEntity(INVALID_ENTITY); optionsWnd.RefreshEntityTree(); ResetHistory(); @@ -1299,6 +1300,7 @@ void EditorComponent::Update(float dt) componentsWnd.softWnd.SetEntity(INVALID_ENTITY); componentsWnd.colliderWnd.SetEntity(INVALID_ENTITY); componentsWnd.hierarchyWnd.SetEntity(INVALID_ENTITY); + componentsWnd.cameraComponentWnd.SetEntity(INVALID_ENTITY); } else { @@ -1335,6 +1337,7 @@ void EditorComponent::Update(float dt) componentsWnd.rigidWnd.SetEntity(picked.entity); componentsWnd.colliderWnd.SetEntity(picked.entity); componentsWnd.hierarchyWnd.SetEntity(picked.entity); + componentsWnd.cameraComponentWnd.SetEntity(picked.entity); if (picked.subsetIndex >= 0) { @@ -1416,6 +1419,12 @@ void EditorComponent::Update(float dt) editorscene.camera_transform.Lerp(editorscene.camera_transform, *proxy, 1.0f - optionsWnd.cameraWnd.followSlider.GetValue()); editorscene.camera_transform.UpdateTransform(); } + + CameraComponent* proxy_camera = scene.cameras.GetComponent(optionsWnd.cameraWnd.entity); + if (proxy_camera != nullptr) + { + editorscene.camera.Lerp(editorscene.camera, *proxy_camera, 1.0f - optionsWnd.cameraWnd.followSlider.GetValue()); + } } camera.TransformCamera(editorscene.camera_transform); @@ -2264,6 +2273,22 @@ void EditorComponent::AddSelected(Entity entity) } void EditorComponent::AddSelected(const PickResult& picked) { + wi::scene::Scene& scene = GetCurrentScene(); + if (picked.subsetIndex >= 0) + { + const ObjectComponent* object = scene.objects.GetComponent(picked.entity); + if (object != nullptr) // maybe it was deleted... + { + AddSelected(object->meshID); + + const MeshComponent* mesh = scene.meshes.GetComponent(object->meshID); + if (mesh != nullptr && (int)mesh->subsets.size() > picked.subsetIndex) + { + AddSelected(mesh->subsets[picked.subsetIndex].materialID); + } + } + } + bool removal = false; for (size_t i = 0; i < translator.selected.size(); ++i) { diff --git a/Editor/Editor_SOURCE.vcxitems b/Editor/Editor_SOURCE.vcxitems index bf370772b..5a272a35d 100644 --- a/Editor/Editor_SOURCE.vcxitems +++ b/Editor/Editor_SOURCE.vcxitems @@ -15,6 +15,7 @@ + @@ -130,6 +131,7 @@ + diff --git a/Editor/Editor_SOURCE.vcxitems.filters b/Editor/Editor_SOURCE.vcxitems.filters index b9b1df101..5bad7a874 100644 --- a/Editor/Editor_SOURCE.vcxitems.filters +++ b/Editor/Editor_SOURCE.vcxitems.filters @@ -81,6 +81,7 @@ + @@ -126,6 +127,7 @@ + diff --git a/Editor/SoundWindow.cpp b/Editor/SoundWindow.cpp index 965cea8f9..7156a9b2e 100644 --- a/Editor/SoundWindow.cpp +++ b/Editor/SoundWindow.cpp @@ -72,12 +72,12 @@ void SoundWindow::Create(EditorComponent* _editor) if (sound->IsPlaying()) { sound->Stop(); - playstopButton.SetText("Play"); + playstopButton.SetText(ICON_PLAY); } else { sound->Play(); - playstopButton.SetText("Stop"); + playstopButton.SetText(ICON_STOP); } } }); diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 16ad92faa..5c0bc1cc2 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -5142,6 +5142,107 @@ void DrawDebugWorld( BindCommonResources(cmd); + if (debugCameras) + { + device->EventBegin("DebugCameras", cmd); + + static GPUBuffer wirecamVB; + static GPUBuffer wirecamIB; + if (!wirecamVB.IsValid()) + { + XMFLOAT4 verts[] = { + XMFLOAT4(-0.1f,-0.1f,-1,1), XMFLOAT4(1,1,1,1), + XMFLOAT4(0.1f,-0.1f,-1,1), XMFLOAT4(1,1,1,1), + XMFLOAT4(0.1f,0.1f,-1,1), XMFLOAT4(1,1,1,1), + XMFLOAT4(-0.1f,0.1f,-1,1), XMFLOAT4(1,1,1,1), + XMFLOAT4(-1,-1,1,1), XMFLOAT4(1,1,1,1), + XMFLOAT4(1,-1,1,1), XMFLOAT4(1,1,1,1), + XMFLOAT4(1,1,1,1), XMFLOAT4(1,1,1,1), + XMFLOAT4(-1,1,1,1), XMFLOAT4(1,1,1,1), + XMFLOAT4(0,1.5f,1,1), XMFLOAT4(1,1,1,1), + XMFLOAT4(0,0,-1,1), XMFLOAT4(1,1,1,1), + }; + + GPUBufferDesc bd; + bd.usage = Usage::DEFAULT; + bd.size = sizeof(verts); + bd.bind_flags = BindFlag::VERTEX_BUFFER; + device->CreateBuffer(&bd, verts, &wirecamVB); + + uint16_t indices[] = { + 0,1,1,2,0,3,0,4,1,5,4,5, + 5,6,4,7,2,6,3,7,2,3,6,7, + 6,8,7,8, + 0,2,1,3 + }; + + bd.usage = Usage::DEFAULT; + bd.size = sizeof(indices); + bd.bind_flags = BindFlag::INDEX_BUFFER; + device->CreateBuffer(&bd, indices, &wirecamIB); + } + + device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE], cmd); + + const GPUBuffer* vbs[] = { + &wirecamVB, + }; + const uint32_t strides[] = { + sizeof(XMFLOAT4) + sizeof(XMFLOAT4), + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, nullptr, cmd); + device->BindIndexBuffer(&wirecamIB, IndexBufferFormat::UINT16, 0, cmd); + + MiscCB sb; + sb.g_xColor = XMFLOAT4(1, 1, 1, 1); + + for (size_t i = 0; i < scene.cameras.GetCount(); ++i) + { + const CameraComponent& cam = scene.cameras[i]; + + const float aspect = cam.width / cam.height; + XMStoreFloat4x4(&sb.g_xTransform, XMMatrixScaling(aspect * 0.5f, 0.5f, 0.5f) * cam.GetInvView() * camera.GetViewProjection()); + + device->BindDynamicConstantBuffer(sb, CB_GETBINDSLOT(MiscCB), cmd); + + device->DrawIndexed(32, 0, 0, cmd); + + if (cam.aperture_size > 0) + { + // focal length line: + RenderableLine linne; + linne.color_start = linne.color_end = XMFLOAT4(1, 1, 1, 1); + linne.start = cam.Eye; + XMVECTOR L = cam.GetEye() + cam.GetAt() * cam.focal_length; + XMStoreFloat3(&linne.end, L); + DrawLine(linne); + + // aperture size/shape circle: + int segmentcount = 36; + for (int j = 0; j < segmentcount; ++j) + { + const float angle0 = float(j) / float(segmentcount) * XM_2PI; + const float angle1 = float(j + 1) / float(segmentcount) * XM_2PI; + linne.start = XMFLOAT3(std::sin(angle0), std::cos(angle0), 0); + linne.end = XMFLOAT3(std::sin(angle1), std::cos(angle1), 0); + XMVECTOR S = XMLoadFloat3(&linne.start); + XMVECTOR E = XMLoadFloat3(&linne.end); + XMMATRIX R = XMLoadFloat3x3(&cam.rotationMatrix); + XMMATRIX APERTURE = R * XMMatrixScaling(cam.aperture_size * cam.aperture_shape.x, cam.aperture_size * cam.aperture_shape.y, cam.aperture_size); + S = XMVector3TransformNormal(S, APERTURE); + E = XMVector3TransformNormal(E, APERTURE); + S += L; + E += L; + XMStoreFloat3(&linne.start, S); + XMStoreFloat3(&linne.end, E); + DrawLine(linne); + } + } + } + + device->EventEnd(cmd); + } + if (GetToDrawDebugColliders()) { for (size_t i = 0; i < scene.colliders.GetCount(); ++i) @@ -6140,76 +6241,6 @@ void DrawDebugWorld( device->EventEnd(cmd); } - - if (debugCameras) - { - device->EventBegin("DebugCameras", cmd); - - static GPUBuffer wirecamVB; - static GPUBuffer wirecamIB; - if (!wirecamVB.IsValid()) - { - XMFLOAT4 verts[] = { - XMFLOAT4(-0.1f,-0.1f,-1,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(0.1f,-0.1f,-1,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(0.1f,0.1f,-1,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-0.1f,0.1f,-1,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-1,-1,1,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(1,-1,1,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(1,1,1,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-1,1,1,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(0,1.5f,1,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(0,0,-1,1), XMFLOAT4(1,1,1,1), - }; - - GPUBufferDesc bd; - bd.usage = Usage::DEFAULT; - bd.size = sizeof(verts); - bd.bind_flags = BindFlag::VERTEX_BUFFER; - device->CreateBuffer(&bd, verts, &wirecamVB); - - uint16_t indices[] = { - 0,1,1,2,0,3,0,4,1,5,4,5, - 5,6,4,7,2,6,3,7,2,3,6,7, - 6,8,7,8, - 0,2,1,3 - }; - - bd.usage = Usage::DEFAULT; - bd.size = sizeof(indices); - bd.bind_flags = BindFlag::INDEX_BUFFER; - device->CreateBuffer(&bd, indices, &wirecamIB); - } - - device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE], cmd); - - const GPUBuffer* vbs[] = { - &wirecamVB, - }; - const uint32_t strides[] = { - sizeof(XMFLOAT4) + sizeof(XMFLOAT4), - }; - device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, nullptr, cmd); - device->BindIndexBuffer(&wirecamIB, IndexBufferFormat::UINT16, 0, cmd); - - MiscCB sb; - sb.g_xColor = XMFLOAT4(1, 1, 1, 1); - - for (size_t i = 0; i < scene.cameras.GetCount(); ++i) - { - const CameraComponent& cam = scene.cameras[i]; - - const float aspect = cam.width / cam.height; - XMStoreFloat4x4(&sb.g_xTransform, XMMatrixScaling(aspect * 0.5f, 0.5f, 0.5f) * cam.GetInvView()*camera.GetViewProjection()); - - device->BindDynamicConstantBuffer(sb, CB_GETBINDSLOT(MiscCB), cmd); - - device->DrawIndexed(32, 0, 0, cmd); - } - - device->EventEnd(cmd); - } - if (GetRaytraceDebugBVHVisualizerEnabled()) { //PE: Check if debug BVH is possible. or it will crash. diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index e890fc620..f13d8206e 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -1325,6 +1325,63 @@ namespace wi::scene descriptor_srv = device->GetDescriptorIndex(&boneBuffer, SubresourceType::SRV); } + AnimationComponent::AnimationChannel::PathDataType AnimationComponent::AnimationChannel::GetPathDataType() const + { + switch (path) + { + case wi::scene::AnimationComponent::AnimationChannel::Path::TRANSLATION: + return PathDataType::Float3; + case wi::scene::AnimationComponent::AnimationChannel::Path::ROTATION: + return PathDataType::Float4; + case wi::scene::AnimationComponent::AnimationChannel::Path::SCALE: + return PathDataType::Float3; + case wi::scene::AnimationComponent::AnimationChannel::Path::WEIGHTS: + return PathDataType::Weights; + + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_COLOR: + return PathDataType::Float3; + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_RANGE: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE: + case wi::scene::AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE: + return PathDataType::Float; + + case wi::scene::AnimationComponent::AnimationChannel::Path::SOUND_PLAY: + case wi::scene::AnimationComponent::AnimationChannel::Path::SOUND_STOP: + return PathDataType::Event; + case wi::scene::AnimationComponent::AnimationChannel::Path::SOUND_VOLUME: + return PathDataType::Float; + + case wi::scene::AnimationComponent::AnimationChannel::Path::EMITTER_EMITCOUNT: + return PathDataType::Float; + + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_FOV: + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_FOCAL_LENGTH: + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SIZE: + return PathDataType::Float; + case wi::scene::AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SHAPE: + return PathDataType::Float2; + + case wi::scene::AnimationComponent::AnimationChannel::Path::SCRIPT_PLAY: + case wi::scene::AnimationComponent::AnimationChannel::Path::SCRIPT_STOP: + return PathDataType::Event; + + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_COLOR: + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_EMISSIVE: + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_TEXMULADD: + return PathDataType::Float4; + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_ROUGHNESS: + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_REFLECTANCE: + case wi::scene::AnimationComponent::AnimationChannel::Path::MATERIAL_METALNESS: + return PathDataType::Float; + + default: + assert(0); + break; + } + return PathDataType::Event; + } + void SoftBodyPhysicsComponent::CreateFromMesh(const MeshComponent& mesh) { vertex_positions_simulation.resize(mesh.vertex_positions.size()); @@ -1466,6 +1523,19 @@ namespace wi::scene UpdateCamera(); } + void CameraComponent::Lerp(const CameraComponent& a, const CameraComponent& b, float t) + { + SetDirty(); + + width = wi::math::Lerp(a.width, b.width, t); + height = wi::math::Lerp(a.height, b.height, t); + zNearP = wi::math::Lerp(a.zNearP, b.zNearP, t); + zFarP = wi::math::Lerp(a.zFarP, b.zFarP, t); + fov = wi::math::Lerp(a.fov, b.fov, t); + focal_length = wi::math::Lerp(a.focal_length, b.focal_length, t); + aperture_size = wi::math::Lerp(a.aperture_size, b.aperture_size, t); + aperture_shape = wi::math::Lerp(a.aperture_shape, b.aperture_shape, t); + } void ScriptComponent::CreateFromFile(const std::string& filename) { @@ -2667,6 +2737,8 @@ namespace wi::scene continue; } + const AnimationComponent::AnimationChannel::PathDataType path_data_type = channel.GetPathDataType(); + float timeFirst = std::numeric_limits::max(); float timeLast = std::numeric_limits::min(); int keyLeft = 0; float timeLeft = std::numeric_limits::min(); @@ -2695,23 +2767,65 @@ namespace wi::scene keyRight = k; } } - if (animation.timer < timeFirst || animation.timer > timeLast) + if (path_data_type != AnimationComponent::AnimationChannel::PathDataType::Event) { - // timer is outside range of keyframes, don't update animation: - continue; + if (animation.timer < timeFirst || animation.timer > timeLast) + { + // timer is outside range of keyframes, don't update animation: + continue; + } + } + else + { + timeLeft = std::max(timeLeft, timeFirst); + timeRight = std::max(timeRight, timeLast); } const float left = animationdata->keyframe_times[keyLeft]; const float right = animationdata->keyframe_times[keyRight]; - TransformComponent transform; - LightComponent light; + union Interpolator + { + XMFLOAT4 f4 = {}; + XMFLOAT3 f3; + XMFLOAT2 f2; + float f; + } interpolator; TransformComponent* target_transform = nullptr; MeshComponent* target_mesh = nullptr; LightComponent* target_light = nullptr; + SoundComponent* target_sound = nullptr; + EmittedParticleSystem* target_emitter = nullptr; + CameraComponent* target_camera = nullptr; + ScriptComponent* target_script = nullptr; + MaterialComponent* target_material = nullptr; - if (channel.path == AnimationComponent::AnimationChannel::Path::WEIGHTS) + if ( + channel.path == AnimationComponent::AnimationChannel::Path::TRANSLATION || + channel.path == AnimationComponent::AnimationChannel::Path::ROTATION || + channel.path == AnimationComponent::AnimationChannel::Path::SCALE + ) + { + target_transform = transforms.GetComponent(channel.target); + if (target_transform == nullptr) + continue; + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::TRANSLATION: + interpolator.f3 = target_transform->translation_local; + break; + case AnimationComponent::AnimationChannel::Path::ROTATION: + interpolator.f4 = target_transform->rotation_local; + break; + case AnimationComponent::AnimationChannel::Path::SCALE: + interpolator.f3 = target_transform->scale_local; + break; + default: + break; + } + } + else if (channel.path == AnimationComponent::AnimationChannel::Path::WEIGHTS) { ObjectComponent* object = objects.GetComponent(channel.target); if (object == nullptr) @@ -2722,356 +2836,409 @@ namespace wi::scene animation.morph_weights_temp.resize(target_mesh->morph_targets.size()); } else if ( - channel.path == AnimationComponent::AnimationChannel::Path::LIGHT_COLOR || - channel.path == AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY || - channel.path == AnimationComponent::AnimationChannel::Path::LIGHT_RANGE || - channel.path == AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE || - channel.path == AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE + channel.path >= AnimationComponent::AnimationChannel::Path::LIGHT_COLOR && + channel.path < AnimationComponent::AnimationChannel::Path::_LIGHT_RANGE_END ) { target_light = lights.GetComponent(channel.target); if (target_light == nullptr) continue; - light = *target_light; + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::LIGHT_COLOR: + interpolator.f3 = target_light->color; + break; + case AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY: + interpolator.f = target_light->intensity; + break; + case AnimationComponent::AnimationChannel::Path::LIGHT_RANGE: + interpolator.f = target_light->range; + break; + case AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE: + interpolator.f = target_light->innerConeAngle; + break; + case AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE: + interpolator.f = target_light->outerConeAngle; + break; + default: + break; + } + } + else if ( + channel.path >= AnimationComponent::AnimationChannel::Path::SOUND_PLAY && + channel.path < AnimationComponent::AnimationChannel::Path::_SOUND_RANGE_END + ) + { + target_sound = sounds.GetComponent(channel.target); + if (target_sound == nullptr) + continue; + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::SOUND_VOLUME: + interpolator.f = target_sound->volume; + break; + default: + break; + } + } + else if ( + channel.path >= AnimationComponent::AnimationChannel::Path::EMITTER_EMITCOUNT && + channel.path < AnimationComponent::AnimationChannel::Path::_EMITTER_RANGE_END + ) + { + target_emitter = emitters.GetComponent(channel.target); + if (target_emitter == nullptr) + continue; + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::EMITTER_EMITCOUNT: + interpolator.f = target_emitter->count; + break; + default: + break; + } + } + else if ( + channel.path >= AnimationComponent::AnimationChannel::Path::CAMERA_FOV && + channel.path < AnimationComponent::AnimationChannel::Path::_CAMERA_RANGE_END + ) + { + target_camera = cameras.GetComponent(channel.target); + if (target_camera == nullptr) + continue; + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::CAMERA_FOV: + interpolator.f = target_camera->fov; + break; + case AnimationComponent::AnimationChannel::Path::CAMERA_FOCAL_LENGTH: + interpolator.f = target_camera->focal_length; + break; + case AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SIZE: + interpolator.f = target_camera->aperture_size; + break; + case AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SHAPE: + interpolator.f2 = target_camera->aperture_shape; + break; + default: + break; + } + } + else if ( + channel.path >= AnimationComponent::AnimationChannel::Path::SCRIPT_PLAY && + channel.path < AnimationComponent::AnimationChannel::Path::_SCRIPT_RANGE_END + ) + { + target_script = scripts.GetComponent(channel.target); + if (target_script == nullptr) + continue; + } + else if ( + channel.path >= AnimationComponent::AnimationChannel::Path::MATERIAL_COLOR && + channel.path < AnimationComponent::AnimationChannel::Path::_MATERIAL_RANGE_END + ) + { + target_material = materials.GetComponent(channel.target); + if (target_material == nullptr) + continue; + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::MATERIAL_COLOR: + interpolator.f4 = target_material->baseColor; + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_EMISSIVE: + interpolator.f4 = target_material->emissiveColor; + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_ROUGHNESS: + interpolator.f = target_material->roughness; + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_METALNESS: + interpolator.f = target_material->metalness; + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_REFLECTANCE: + interpolator.f = target_material->reflectance; + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_TEXMULADD: + interpolator.f4 = target_material->texMulAdd; + break; + default: + break; + } } else { - target_transform = transforms.GetComponent(channel.target); - if (target_transform == nullptr) - continue; - transform = *target_transform; + assert(0); + continue; } - switch (sampler.mode) + if (path_data_type == AnimationComponent::AnimationChannel::PathDataType::Event) { - default: - case AnimationComponent::AnimationSampler::Mode::STEP: + // No path data, only event trigger: + if (keyLeft == channel.next_event && animation.timer >= timeLeft) + { + channel.next_event++; + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::SOUND_PLAY: + target_sound->Play(); + break; + case AnimationComponent::AnimationChannel::Path::SOUND_STOP: + target_sound->Stop(); + break; + case AnimationComponent::AnimationChannel::Path::SCRIPT_PLAY: + target_script->Play(); + break; + case AnimationComponent::AnimationChannel::Path::SCRIPT_STOP: + target_script->Stop(); + break; + default: + break; + } + } + } + else { - // Nearest neighbor method: - const int key = wi::math::InverseLerp(timeLeft, timeRight, animation.timer) > 0.5f ? keyRight : keyLeft; - switch (channel.path) + // Path data interpolation: + switch (sampler.mode) { default: - case AnimationComponent::AnimationChannel::Path::TRANSLATION: + case AnimationComponent::AnimationSampler::Mode::STEP: { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3); - transform.translation_local = ((const XMFLOAT3*)animationdata->keyframe_data.data())[key]; - } - break; - case AnimationComponent::AnimationChannel::Path::ROTATION: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 4); - transform.rotation_local = ((const XMFLOAT4*)animationdata->keyframe_data.data())[key]; - } - break; - case AnimationComponent::AnimationChannel::Path::SCALE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3); - transform.scale_local = ((const XMFLOAT3*)animationdata->keyframe_data.data())[key]; - } - break; - case AnimationComponent::AnimationChannel::Path::WEIGHTS: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * animation.morph_weights_temp.size()); - for (size_t j = 0; j < animation.morph_weights_temp.size(); ++j) + // Nearest neighbor method: + const int key = wi::math::InverseLerp(timeLeft, timeRight, animation.timer) > 0.5f ? keyRight : keyLeft; + switch (path_data_type) { - animation.morph_weights_temp[j] = animationdata->keyframe_data[key * animation.morph_weights_temp.size() + j]; + default: + case AnimationComponent::AnimationChannel::PathDataType::Float: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); + interpolator.f = animationdata->keyframe_data[key]; + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float2: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 2); + interpolator.f2 = ((const XMFLOAT2*)animationdata->keyframe_data.data())[key]; + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float3: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3); + interpolator.f3 = ((const XMFLOAT3*)animationdata->keyframe_data.data())[key]; + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float4: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 4); + interpolator.f4 = ((const XMFLOAT4*)animationdata->keyframe_data.data())[key]; + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Weights: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * animation.morph_weights_temp.size()); + for (size_t j = 0; j < animation.morph_weights_temp.size(); ++j) + { + animation.morph_weights_temp[j] = animationdata->keyframe_data[key * animation.morph_weights_temp.size() + j]; + } + } + break; } } break; - case AnimationComponent::AnimationChannel::Path::LIGHT_COLOR: + case AnimationComponent::AnimationSampler::Mode::LINEAR: { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3); - light.color = ((const XMFLOAT3*)animationdata->keyframe_data.data())[key]; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - light.intensity = animationdata->keyframe_data[key]; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_RANGE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - light.range = animationdata->keyframe_data[key]; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - light.innerConeAngle = animationdata->keyframe_data[key]; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - light.outerConeAngle = animationdata->keyframe_data[key]; - } - break; - } - } - break; - case AnimationComponent::AnimationSampler::Mode::LINEAR: - { - // Linear interpolation method: - float t; - if (keyLeft == keyRight) - { - t = 0; - } - else - { - t = (animation.timer - left) / (right - left); - } - - switch (channel.path) - { - default: - case AnimationComponent::AnimationChannel::Path::TRANSLATION: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3); - const XMFLOAT3* data = (const XMFLOAT3*)animationdata->keyframe_data.data(); - XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft]); - XMVECTOR vRight = XMLoadFloat3(&data[keyRight]); - XMVECTOR vAnim = XMVectorLerp(vLeft, vRight, t); - XMStoreFloat3(&transform.translation_local, vAnim); - } - break; - case AnimationComponent::AnimationChannel::Path::ROTATION: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 4); - const XMFLOAT4* data = (const XMFLOAT4*)animationdata->keyframe_data.data(); - XMVECTOR vLeft = XMLoadFloat4(&data[keyLeft]); - XMVECTOR vRight = XMLoadFloat4(&data[keyRight]); - XMVECTOR vAnim = XMQuaternionSlerp(vLeft, vRight, t); - vAnim = XMQuaternionNormalize(vAnim); - XMStoreFloat4(&transform.rotation_local, vAnim); - } - break; - case AnimationComponent::AnimationChannel::Path::SCALE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3); - const XMFLOAT3* data = (const XMFLOAT3*)animationdata->keyframe_data.data(); - XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft]); - XMVECTOR vRight = XMLoadFloat3(&data[keyRight]); - XMVECTOR vAnim = XMVectorLerp(vLeft, vRight, t); - XMStoreFloat3(&transform.scale_local, vAnim); - } - break; - case AnimationComponent::AnimationChannel::Path::WEIGHTS: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * animation.morph_weights_temp.size()); - for (size_t j = 0; j < animation.morph_weights_temp.size(); ++j) + // Linear interpolation method: + float t; + if (keyLeft == keyRight) { - float vLeft = animationdata->keyframe_data[keyLeft * animation.morph_weights_temp.size() + j]; - float vRight = animationdata->keyframe_data[keyRight * animation.morph_weights_temp.size() + j]; + t = 0; + } + else + { + t = (animation.timer - left) / (right - left); + } + + switch (path_data_type) + { + default: + case AnimationComponent::AnimationChannel::PathDataType::Float: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); + float vLeft = animationdata->keyframe_data[keyLeft]; + float vRight = animationdata->keyframe_data[keyRight]; float vAnim = wi::math::Lerp(vLeft, vRight, t); - animation.morph_weights_temp[j] = vAnim; + interpolator.f = vAnim; } - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_COLOR: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3); - const XMFLOAT3* data = (const XMFLOAT3*)animationdata->keyframe_data.data(); - XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft]); - XMVECTOR vRight = XMLoadFloat3(&data[keyRight]); - XMVECTOR vAnim = XMVectorLerp(vLeft, vRight, t); - XMStoreFloat3(&light.color, vAnim); - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - float vLeft = animationdata->keyframe_data[keyLeft]; - float vRight = animationdata->keyframe_data[keyRight]; - float vAnim = wi::math::Lerp(vLeft, vRight, t); - light.intensity = vAnim; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_RANGE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - float vLeft = animationdata->keyframe_data[keyLeft]; - float vRight = animationdata->keyframe_data[keyRight]; - float vAnim = wi::math::Lerp(vLeft, vRight, t); - light.range = vAnim; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - float vLeft = animationdata->keyframe_data[keyLeft]; - float vRight = animationdata->keyframe_data[keyRight]; - float vAnim = wi::math::Lerp(vLeft, vRight, t); - light.innerConeAngle = vAnim; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - float vLeft = animationdata->keyframe_data[keyLeft]; - float vRight = animationdata->keyframe_data[keyRight]; - float vAnim = wi::math::Lerp(vLeft, vRight, t); - light.outerConeAngle = vAnim; - } - break; - } - } - break; - case AnimationComponent::AnimationSampler::Mode::CUBICSPLINE: - { - // Cubic Spline interpolation method: - float t; - if (keyLeft == keyRight) - { - t = 0; - } - else - { - t = (animation.timer - left) / (right - left); - } - - const float t2 = t * t; - const float t3 = t2 * t; - - switch (channel.path) - { - default: - case AnimationComponent::AnimationChannel::Path::TRANSLATION: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3 * 3); - const XMFLOAT3* data = (const XMFLOAT3*)animationdata->keyframe_data.data(); - XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft * 3 + 1]); - XMVECTOR vLeftTanOut = dt * XMLoadFloat3(&data[keyLeft * 3 + 2]); - XMVECTOR vRightTanIn = dt * XMLoadFloat3(&data[keyRight * 3 + 0]); - XMVECTOR vRight = XMLoadFloat3(&data[keyRight * 3 + 1]); - XMVECTOR vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; - XMStoreFloat3(&transform.translation_local, vAnim); - } - break; - case AnimationComponent::AnimationChannel::Path::ROTATION: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 4 * 3); - const XMFLOAT4* data = (const XMFLOAT4*)animationdata->keyframe_data.data(); - XMVECTOR vLeft = XMLoadFloat4(&data[keyLeft * 3 + 1]); - XMVECTOR vLeftTanOut = dt * XMLoadFloat4(&data[keyLeft * 3 + 2]); - XMVECTOR vRightTanIn = dt * XMLoadFloat4(&data[keyRight * 3 + 0]); - XMVECTOR vRight = XMLoadFloat4(&data[keyRight * 3 + 1]); - XMVECTOR vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; - vAnim = XMQuaternionNormalize(vAnim); - XMStoreFloat4(&transform.rotation_local, vAnim); - } - break; - case AnimationComponent::AnimationChannel::Path::SCALE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3 * 3); - const XMFLOAT3* data = (const XMFLOAT3*)animationdata->keyframe_data.data(); - XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft * 3 + 1]); - XMVECTOR vLeftTanOut = dt * XMLoadFloat3(&data[keyLeft * 3 + 2]); - XMVECTOR vRightTanIn = dt * XMLoadFloat3(&data[keyRight * 3 + 0]); - XMVECTOR vRight = XMLoadFloat3(&data[keyRight * 3 + 1]); - XMVECTOR vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; - XMStoreFloat3(&transform.scale_local, vAnim); - } - break; - case AnimationComponent::AnimationChannel::Path::WEIGHTS: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * animation.morph_weights_temp.size() * 3); - for (size_t j = 0; j < animation.morph_weights_temp.size(); ++j) + break; + case AnimationComponent::AnimationChannel::PathDataType::Float2: { - float vLeft = animationdata->keyframe_data[(keyLeft * animation.morph_weights_temp.size() + j) * 3 + 1]; - float vLeftTanOut = animationdata->keyframe_data[(keyLeft * animation.morph_weights_temp.size() + j) * 3 + 2]; - float vRightTanIn = animationdata->keyframe_data[(keyRight * animation.morph_weights_temp.size() + j) * 3 + 0]; - float vRight = animationdata->keyframe_data[(keyRight * animation.morph_weights_temp.size() + j) * 3 + 1]; - float vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; - animation.morph_weights_temp[j] = vAnim; + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 2); + const XMFLOAT2* data = (const XMFLOAT2*)animationdata->keyframe_data.data(); + XMVECTOR vLeft = XMLoadFloat2(&data[keyLeft]); + XMVECTOR vRight = XMLoadFloat2(&data[keyRight]); + XMVECTOR vAnim = XMVectorLerp(vLeft, vRight, t); + XMStoreFloat2(&interpolator.f2, vAnim); + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float3: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3); + const XMFLOAT3* data = (const XMFLOAT3*)animationdata->keyframe_data.data(); + XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft]); + XMVECTOR vRight = XMLoadFloat3(&data[keyRight]); + XMVECTOR vAnim = XMVectorLerp(vLeft, vRight, t); + XMStoreFloat3(&interpolator.f3, vAnim); + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float4: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 4); + const XMFLOAT4* data = (const XMFLOAT4*)animationdata->keyframe_data.data(); + XMVECTOR vLeft = XMLoadFloat4(&data[keyLeft]); + XMVECTOR vRight = XMLoadFloat4(&data[keyRight]); + XMVECTOR vAnim = XMQuaternionSlerp(vLeft, vRight, t); + vAnim = XMQuaternionNormalize(vAnim); + XMStoreFloat4(&interpolator.f4, vAnim); + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Weights: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * animation.morph_weights_temp.size()); + for (size_t j = 0; j < animation.morph_weights_temp.size(); ++j) + { + float vLeft = animationdata->keyframe_data[keyLeft * animation.morph_weights_temp.size() + j]; + float vRight = animationdata->keyframe_data[keyRight * animation.morph_weights_temp.size() + j]; + float vAnim = wi::math::Lerp(vLeft, vRight, t); + animation.morph_weights_temp[j] = vAnim; + } + } + break; } } break; - case AnimationComponent::AnimationChannel::Path::LIGHT_COLOR: + case AnimationComponent::AnimationSampler::Mode::CUBICSPLINE: { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3 * 3); - const XMFLOAT3* data = (const XMFLOAT3*)animationdata->keyframe_data.data(); - XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft * 3 + 1]); - XMVECTOR vLeftTanOut = dt * XMLoadFloat3(&data[keyLeft * 3 + 2]); - XMVECTOR vRightTanIn = dt * XMLoadFloat3(&data[keyRight * 3 + 0]); - XMVECTOR vRight = XMLoadFloat3(&data[keyRight * 3 + 1]); - XMVECTOR vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; - XMStoreFloat3(&light.color, vAnim); - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - float vLeft = animationdata->keyframe_data[keyLeft * 3 + 1]; - float vLeftTanOut = animationdata->keyframe_data[keyLeft * 3 + 2]; - float vRightTanIn = animationdata->keyframe_data[keyRight * 3 + 0]; - float vRight = animationdata->keyframe_data[keyRight * 3 + 1]; - float vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; - light.intensity = vAnim; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_RANGE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - float vLeft = animationdata->keyframe_data[keyLeft * 3 + 1]; - float vLeftTanOut = animationdata->keyframe_data[keyLeft * 3 + 2]; - float vRightTanIn = animationdata->keyframe_data[keyRight * 3 + 0]; - float vRight = animationdata->keyframe_data[keyRight * 3 + 1]; - float vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; - light.range = vAnim; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - float vLeft = animationdata->keyframe_data[keyLeft * 3 + 1]; - float vLeftTanOut = animationdata->keyframe_data[keyLeft * 3 + 2]; - float vRightTanIn = animationdata->keyframe_data[keyRight * 3 + 0]; - float vRight = animationdata->keyframe_data[keyRight * 3 + 1]; - float vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; - light.innerConeAngle = vAnim; - } - break; - case AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE: - { - assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); - float vLeft = animationdata->keyframe_data[keyLeft * 3 + 1]; - float vLeftTanOut = animationdata->keyframe_data[keyLeft * 3 + 2]; - float vRightTanIn = animationdata->keyframe_data[keyRight * 3 + 0]; - float vRight = animationdata->keyframe_data[keyRight * 3 + 1]; - float vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; - light.outerConeAngle = vAnim; + // Cubic Spline interpolation method: + float t; + if (keyLeft == keyRight) + { + t = 0; + } + else + { + t = (animation.timer - left) / (right - left); + } + + const float t2 = t * t; + const float t3 = t2 * t; + + switch (path_data_type) + { + default: + case AnimationComponent::AnimationChannel::PathDataType::Float: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size()); + float vLeft = animationdata->keyframe_data[keyLeft * 3 + 1]; + float vLeftTanOut = animationdata->keyframe_data[keyLeft * 3 + 2]; + float vRightTanIn = animationdata->keyframe_data[keyRight * 3 + 0]; + float vRight = animationdata->keyframe_data[keyRight * 3 + 1]; + float vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; + interpolator.f = vAnim; + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float2: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 2 * 3); + const XMFLOAT2* data = (const XMFLOAT2*)animationdata->keyframe_data.data(); + XMVECTOR vLeft = XMLoadFloat2(&data[keyLeft * 3 + 1]); + XMVECTOR vLeftTanOut = dt * XMLoadFloat2(&data[keyLeft * 3 + 2]); + XMVECTOR vRightTanIn = dt * XMLoadFloat2(&data[keyRight * 3 + 0]); + XMVECTOR vRight = XMLoadFloat2(&data[keyRight * 3 + 1]); + XMVECTOR vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; + XMStoreFloat2(&interpolator.f2, vAnim); + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float3: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 3 * 3); + const XMFLOAT3* data = (const XMFLOAT3*)animationdata->keyframe_data.data(); + XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft * 3 + 1]); + XMVECTOR vLeftTanOut = dt * XMLoadFloat3(&data[keyLeft * 3 + 2]); + XMVECTOR vRightTanIn = dt * XMLoadFloat3(&data[keyRight * 3 + 0]); + XMVECTOR vRight = XMLoadFloat3(&data[keyRight * 3 + 1]); + XMVECTOR vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; + XMStoreFloat3(&interpolator.f3, vAnim); + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Float4: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * 4 * 3); + const XMFLOAT4* data = (const XMFLOAT4*)animationdata->keyframe_data.data(); + XMVECTOR vLeft = XMLoadFloat4(&data[keyLeft * 3 + 1]); + XMVECTOR vLeftTanOut = dt * XMLoadFloat4(&data[keyLeft * 3 + 2]); + XMVECTOR vRightTanIn = dt * XMLoadFloat4(&data[keyRight * 3 + 0]); + XMVECTOR vRight = XMLoadFloat4(&data[keyRight * 3 + 1]); + XMVECTOR vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; + vAnim = XMQuaternionNormalize(vAnim); + XMStoreFloat4(&interpolator.f4, vAnim); + } + break; + case AnimationComponent::AnimationChannel::PathDataType::Weights: + { + assert(animationdata->keyframe_data.size() == animationdata->keyframe_times.size() * animation.morph_weights_temp.size() * 3); + for (size_t j = 0; j < animation.morph_weights_temp.size(); ++j) + { + float vLeft = animationdata->keyframe_data[(keyLeft * animation.morph_weights_temp.size() + j) * 3 + 1]; + float vLeftTanOut = animationdata->keyframe_data[(keyLeft * animation.morph_weights_temp.size() + j) * 3 + 2]; + float vRightTanIn = animationdata->keyframe_data[(keyRight * animation.morph_weights_temp.size() + j) * 3 + 0]; + float vRight = animationdata->keyframe_data[(keyRight * animation.morph_weights_temp.size() + j) * 3 + 1]; + float vAnim = (2 * t3 - 3 * t2 + 1) * vLeft + (t3 - 2 * t2 + t) * vLeftTanOut + (-2 * t3 + 3 * t2) * vRight + (t3 - t2) * vRightTanIn; + animation.morph_weights_temp[j] = vAnim; + } + } + break; + } } break; } } - break; - } + // The interpolated raw values will be blended on top of component values: const float t = animation.amount; if (target_transform != nullptr) { target_transform->SetDirty(); - const XMVECTOR aS = XMLoadFloat3(&target_transform->scale_local); - const XMVECTOR aR = XMLoadFloat4(&target_transform->rotation_local); - const XMVECTOR aT = XMLoadFloat3(&target_transform->translation_local); - - const XMVECTOR bS = XMLoadFloat3(&transform.scale_local); - const XMVECTOR bR = XMLoadFloat4(&transform.rotation_local); - const XMVECTOR bT = XMLoadFloat3(&transform.translation_local); - - const XMVECTOR S = XMVectorLerp(aS, bS, t); - const XMVECTOR R = XMQuaternionSlerp(aR, bR, t); - const XMVECTOR T = XMVectorLerp(aT, bT, t); - - XMStoreFloat3(&target_transform->scale_local, S); - XMStoreFloat4(&target_transform->rotation_local, R); - XMStoreFloat3(&target_transform->translation_local, T); + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::TRANSLATION: + { + const XMVECTOR aT = XMLoadFloat3(&target_transform->translation_local); + const XMVECTOR bT = XMLoadFloat3(&interpolator.f3); + const XMVECTOR T = XMVectorLerp(aT, bT, t); + XMStoreFloat3(&target_transform->translation_local, T); + } + break; + case AnimationComponent::AnimationChannel::Path::ROTATION: + { + const XMVECTOR aR = XMLoadFloat4(&target_transform->rotation_local); + const XMVECTOR bR = XMLoadFloat4(&interpolator.f4); + const XMVECTOR R = XMQuaternionSlerp(aR, bR, t); + XMStoreFloat4(&target_transform->rotation_local, R); + } + break; + case AnimationComponent::AnimationChannel::Path::SCALE: + { + const XMVECTOR aS = XMLoadFloat3(&target_transform->scale_local); + const XMVECTOR bS = XMLoadFloat3(&interpolator.f3); + const XMVECTOR S = XMVectorLerp(aS, bS, t); + XMStoreFloat3(&target_transform->scale_local, S); + } + break; + default: + break; + } } if (target_mesh != nullptr) @@ -3086,11 +3253,134 @@ namespace wi::scene if (target_light != nullptr) { - target_light->color = wi::math::Lerp(target_light->color, light.color, t); - target_light->intensity = wi::math::Lerp(target_light->intensity, light.intensity, t); - target_light->range = wi::math::Lerp(target_light->range, light.range, t); - target_light->innerConeAngle = wi::math::Lerp(target_light->innerConeAngle, light.innerConeAngle, t); - target_light->outerConeAngle = wi::math::Lerp(target_light->outerConeAngle, light.outerConeAngle, t); + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::LIGHT_COLOR: + { + target_light->color = wi::math::Lerp(target_light->color, interpolator.f3, t); + } + break; + case AnimationComponent::AnimationChannel::Path::LIGHT_INTENSITY: + { + target_light->intensity = wi::math::Lerp(target_light->intensity, interpolator.f, t); + } + break; + case AnimationComponent::AnimationChannel::Path::LIGHT_RANGE: + { + target_light->range = wi::math::Lerp(target_light->range, interpolator.f, t); + } + break; + case AnimationComponent::AnimationChannel::Path::LIGHT_INNERCONE: + { + target_light->innerConeAngle = wi::math::Lerp(target_light->innerConeAngle, interpolator.f, t); + } + break; + case AnimationComponent::AnimationChannel::Path::LIGHT_OUTERCONE: + { + target_light->outerConeAngle = wi::math::Lerp(target_light->outerConeAngle, interpolator.f, t); + } + break; + default: + break; + } + } + + if (target_sound != nullptr) + { + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::SOUND_VOLUME: + { + target_sound->volume = wi::math::Lerp(target_sound->volume, interpolator.f, t); + } + break; + default: + break; + } + } + + if (target_emitter != nullptr) + { + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::EMITTER_EMITCOUNT: + { + target_emitter->count = wi::math::Lerp(target_emitter->count, interpolator.f, t); + } + break; + default: + break; + } + } + + if (target_camera != nullptr) + { + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::CAMERA_FOV: + { + target_camera->fov = wi::math::Lerp(target_camera->fov, interpolator.f, t); + } + break; + case AnimationComponent::AnimationChannel::Path::CAMERA_FOCAL_LENGTH: + { + target_camera->focal_length = wi::math::Lerp(target_camera->focal_length, interpolator.f, t); + } + break; + case AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SIZE: + { + target_camera->aperture_size = wi::math::Lerp(target_camera->aperture_size, interpolator.f, t); + } + break; + case AnimationComponent::AnimationChannel::Path::CAMERA_APERTURE_SHAPE: + { + target_camera->aperture_shape = wi::math::Lerp(target_camera->aperture_shape, interpolator.f2, t); + } + break; + default: + break; + } + } + + if (target_material != nullptr) + { + target_material->SetDirty(); + + switch (channel.path) + { + case AnimationComponent::AnimationChannel::Path::MATERIAL_COLOR: + { + target_material->baseColor = wi::math::Lerp(target_material->baseColor, interpolator.f4, t); + } + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_EMISSIVE: + { + target_material->baseColor = wi::math::Lerp(target_material->emissiveColor, interpolator.f4, t); + } + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_ROUGHNESS: + { + target_material->roughness = wi::math::Lerp(target_material->roughness, interpolator.f, t); + } + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_METALNESS: + { + target_material->metalness = wi::math::Lerp(target_material->metalness, interpolator.f, t); + } + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_REFLECTANCE: + { + target_material->reflectance = wi::math::Lerp(target_material->reflectance, interpolator.f, t); + } + break; + case AnimationComponent::AnimationChannel::Path::MATERIAL_TEXMULADD: + { + target_material->texMulAdd = wi::math::Lerp(target_material->texMulAdd, interpolator.f4, t); + } + break; + default: + break; + } } } @@ -3103,6 +3393,10 @@ namespace wi::scene if (animation.IsLooped() && animation.timer > animation.end) { animation.timer = animation.start; + for (auto& channel : animation.channels) + { + channel.next_event = 0; + } } } } diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 19942ab4e..ad9879e82 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -993,6 +993,8 @@ namespace wi::scene inline bool IsDirty() const { return _flags & DIRTY; } inline bool IsCustomProjectionEnabled() const { return _flags & CUSTOM_PROJECTION; } + void Lerp(const CameraComponent& a, const CameraComponent& b, float t); + void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); }; @@ -1110,20 +1112,70 @@ namespace wi::scene wi::ecs::Entity target = wi::ecs::INVALID_ENTITY; int samplerIndex = -1; - enum Path + enum class Path { TRANSLATION, ROTATION, SCALE, WEIGHTS, + LIGHT_COLOR, LIGHT_INTENSITY, LIGHT_RANGE, LIGHT_INNERCONE, LIGHT_OUTERCONE, + // additional light paths can go here... + _LIGHT_RANGE_END = LIGHT_COLOR + 1000, + + SOUND_PLAY, + SOUND_STOP, + SOUND_VOLUME, + // additional sound paths can go here... + _SOUND_RANGE_END = SOUND_PLAY + 1000, + + EMITTER_EMITCOUNT, + // additional emitter paths can go here... + _EMITTER_RANGE_END = EMITTER_EMITCOUNT + 1000, + + CAMERA_FOV, + CAMERA_FOCAL_LENGTH, + CAMERA_APERTURE_SIZE, + CAMERA_APERTURE_SHAPE, + // additional camera paths can go here... + _CAMERA_RANGE_END = CAMERA_FOV + 1000, + + SCRIPT_PLAY, + SCRIPT_STOP, + // additional script paths can go here... + _SCRIPT_RANGE_END = SCRIPT_PLAY + 1000, + + MATERIAL_COLOR, + MATERIAL_EMISSIVE, + MATERIAL_ROUGHNESS, + MATERIAL_METALNESS, + MATERIAL_REFLECTANCE, + MATERIAL_TEXMULADD, + // additional material paths can go here... + _MATERIAL_RANGE_END = MATERIAL_COLOR + 1000, + UNKNOWN, - TYPE_FORCE_UINT32 = 0xFFFFFFFF - } path = TRANSLATION; + } path = Path::UNKNOWN; + + enum class PathDataType + { + Event, + Float, + Float2, + Float3, + Float4, + Weights, + + Count, + }; + PathDataType GetPathDataType() const; + + // Non-serialized attributes: + mutable int next_event = 0; }; struct AnimationSampler { diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 058f59d57..9bc942566 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 27; + const int revision = 28; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);