diff --git a/WickedEngine/WickedEngine_SHARED.vcxitems b/WickedEngine/WickedEngine_SHARED.vcxitems
index 916c8d764..e2471c055 100644
--- a/WickedEngine/WickedEngine_SHARED.vcxitems
+++ b/WickedEngine/WickedEngine_SHARED.vcxitems
@@ -254,6 +254,7 @@
+
@@ -354,6 +355,8 @@
+
+
@@ -692,6 +695,7 @@
+
diff --git a/WickedEngine/WickedEngine_SHARED.vcxitems.filters b/WickedEngine/WickedEngine_SHARED.vcxitems.filters
index c95387e59..8e344751e 100644
--- a/WickedEngine/WickedEngine_SHARED.vcxitems.filters
+++ b/WickedEngine/WickedEngine_SHARED.vcxitems.filters
@@ -61,6 +61,9 @@
{052d6b54-4254-4260-ba34-79b6fb943b4a}
+
+ {f9156b5b-9cc8-436c-9faa-536f7dce4f27}
+
@@ -1131,6 +1134,15 @@
ENGINE\Scripting\LuaBindings
+
+ ENGINE\System
+
+
+ ENGINE\System
+
+
+ ENGINE\System
+
@@ -1925,6 +1937,9 @@
ENGINE\Scripting\LuaBindings
+
+ ENGINE\System
+
diff --git a/WickedEngine/wiECS.h b/WickedEngine/wiECS.h
new file mode 100644
index 000000000..4038aedcd
--- /dev/null
+++ b/WickedEngine/wiECS.h
@@ -0,0 +1,234 @@
+#ifndef _ENTITY_COMPONENT_SYSTEM_H_
+#define _ENTITY_COMPONENT_SYSTEM_H_
+
+#include
+#include
+#include
+#include
+
+namespace wiECS
+{
+ typedef uint64_t Entity;
+
+ template
+ class ComponentManager
+ {
+ public:
+
+ // reservedCount : how much components can be held initially before growing the container
+ ComponentManager(size_t reservedCount = 0)
+ {
+ components.reserve(reservedCount);
+ entities.reserve(reservedCount);
+ lookup.reserve(reservedCount);
+ indices.reserve(reservedCount);
+ }
+
+ // The iterator is an indirection to the components. Components will be moved around to remain compacted, but iterator will always be able to reference a component.
+ struct iterator
+ {
+ size_t value = ~0;
+
+ inline iterator operator=(iterator other) { value = other.value; return *this; }
+ inline bool operator==(iterator other) const { return value == other.value; }
+ inline bool operator!=(iterator other) const { return value != other.value; }
+ inline iterator& operator++() { value++; return *this; }
+ inline iterator operator++(int v) { iterator temp = *this; ++*this; return temp; }
+ inline iterator& operator--() { value--; return *this; }
+ inline iterator operator--(int v) { iterator temp = *this; --*this; return temp; }
+ };
+
+ // Clear the whole container, invalidate all iterators
+ inline void Clear()
+ {
+ components.clear();
+ entities.clear();
+ lookup.clear();
+ indices.clear();
+ dead.clear();
+ }
+
+ // Get the beginning of the iteration sequence (iterator is safe but uses indirection):
+ inline iterator Begin() const
+ {
+ iterator it;
+ it.value = 0;
+ return it;
+ }
+
+ // Get the end of the iteration sequence (iterator is safe but uses indirection):
+ inline iterator End() const
+ {
+ iterator it;
+ it.value = indices.size();
+ return it;
+ }
+
+ // Check if an iterator is referencing a component or not (iterator is safe but uses indirection):
+ inline bool IsValid(iterator it) const
+ {
+ return it.value < indices.size() && indices[it.value] < components.size();
+ }
+
+ // Check if an iterator is referencing a specific entity or not (iterator is safe but uses indirection):
+ inline bool IsValid(iterator it, Entity entity) const
+ {
+ assert(entities.size() == components.size());
+ return IsValid(it) && entities[indices[it.value]] == entity;
+ }
+
+ // Create a new component and retrieve iterator (iterator is safe but uses indirection):
+ inline iterator Create(Entity entity)
+ {
+ // Only one of this component type per entity is allowed!
+ assert(!IsValid(Find(entity)));
+
+ iterator it;
+
+ if (dead.empty())
+ {
+ // There are no dead elements, so we must have the same amount of components as indices:
+ assert(components.size() == indices.size());
+
+ // Any new component and index will just be pushed onto the end:
+ it.value = components.size();
+ indices.push_back(it.value);
+ }
+ else
+ {
+ // We have dead elements, which means components was popped, but indices only swapped, so there must be less components than indices:
+ assert(components.size() < indices.size());
+
+ // Essentially we pop the last dead iterator and update its value to the new component (that will always be pushed to the end of components):
+ it = dead.back();
+ dead.pop_back();
+ indices[it.value] = components.size();
+ }
+
+ // Entity count must always be the same as the number of coponents!
+ assert(entities.size() == components.size());
+ assert(lookup.size() == components.size());
+
+ // New components are always pushed to the end:
+ components.push_back(T());
+
+ // Also push corresponding entity:
+ entities.push_back(entity);
+
+ // Update the entity lookup table:
+ lookup[entity] = it;
+
+ return it;
+ }
+
+ // Remove a component of a certain entity if it exists (referencing by Entity involves multiple indirection):
+ inline void Remove(Entity entity)
+ {
+ iterator it = Find(entity);
+ if (IsValid(it))
+ {
+ Remove(it);
+ }
+ }
+
+ // Remove a component referenced by a certain iterator (iterator is safe but uses indirection):
+ inline void Remove(iterator it)
+ {
+ // Iterator should be valid:
+ assert(IsValid(it));
+
+ // Directly index into components and entities array:
+ const size_t index = indices[it.value];
+
+ // Remove the corresponding entry from the lookup table:
+ const Entity entity = entities[index];
+ lookup.erase(entity);
+
+ // Swap out the dead element with the last one, and shrink the container:
+ components[index] = std::move(components.back()); // try to use move instead of copy
+ components.pop_back();
+ entities[index] = entities.back();
+ entities.pop_back();
+
+ // Because the last element of the container was moved to the position of the removed element, we update its iterator accordingly:
+ indices[components.size()] = index;
+
+ //The current iterator is marked as dead:
+ indices[it.value] = ~0;
+ dead.push_back(it);
+ }
+
+ // Swap two components' data that are referenced by iterators (iterator is safe but uses indirection):
+ inline void Swap(iterator a, iterator b)
+ {
+ const size_t index_a = indices[a.value];
+ const size_t index_b = indices[b.value];
+
+ const size_t index_tmp = index_a;
+ const Entity entity_tmp = entities[index_a];
+ const T component_tmp = std::move(components[index_a]);
+
+ indices[a.value] = index_b;
+ entities[index_a] = entities[index_b];
+ components[index_a] = std::move(components[index_b]);
+
+ indices[b.value] = index_tmp;
+ entities[index_b] = entity_tmp;
+ components[index_b] = std::move(component_tmp);
+ }
+
+ // Find a specific component of a certain entity if exists (referencing by Entity involves multiple indirection):
+ inline iterator Find(Entity entity) const
+ {
+ auto it = lookup.find(entity);
+ if (it != lookup.end())
+ {
+ return it->second;
+ }
+
+ return End();
+ }
+
+ // Retrieve a component specified by an iterator (iterator is safe but uses indirection):
+ inline T& GetComponent(iterator it)
+ {
+ assert(IsValid(it));
+ return components[indices[it.value]];
+ }
+ // Retrieve an entity specified by an iterator (iterator is safe but uses indirection):
+ inline Entity GetEntity(iterator it) const
+ {
+ assert(IsValid(it));
+ return entities[indices[it.value]];
+ }
+
+ // Retrieve the number of existing entries:
+ inline size_t GetCount() const { return components.size(); }
+
+ // Directly index a specific component without indirection:
+ // 0 <= index < GetCount()
+ inline T& GetComponent(size_t index) const { return components[index]; }
+
+ // Directly index a specific component without indirection:
+ // 0 <= index < GetCount()
+ inline Entity GetEntity(size_t index) const { return entities[index]; }
+
+ // Directly index a specific component without indirection:
+ // 0 <= index < GetCount()
+ inline T& operator[](size_t index) { return components[index]; }
+
+ private:
+ // This is a linear array of alive components:
+ std::vector components;
+ // This is a linear array of entities corresponding to each alive component:
+ std::vector entities;
+ // This is a lookup table for entities:
+ std::unordered_map lookup;
+ // This is the indirection of iterator->component index:
+ std::vector indices;
+ // The indices will also contain dead elements, and those are saved here:
+ std::vector dead;
+ };
+}
+
+#endif // _ENTITY_COMPONENT_SYSTEM_H_
diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h
index c088bf85d..f641a8c87 100644
--- a/WickedEngine/wiRenderer.h
+++ b/WickedEngine/wiRenderer.h
@@ -34,14 +34,12 @@ namespace wiSceneComponents
struct ForceField;
}
-class Lines;
class Cube;
class Translator;
class wiParticle;
class wiEmittedParticle;
class wiHairParticle;
class wiSprite;
-class wiSPTree;
class TaskThread;
class PHYSICS;
class wiRenderTarget;
diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp
new file mode 100644
index 000000000..7743c383f
--- /dev/null
+++ b/WickedEngine/wiSceneSystem.cpp
@@ -0,0 +1,53 @@
+#include "wiSceneSystem.h"
+
+namespace wiSceneSystem
+{
+ void Scene::Update(float dt)
+ {
+ // Update Transform components:
+ for (size_t i = 0; i < transforms.GetCount(); ++i)
+ {
+ auto& transform = transforms[i];
+
+ const bool parented = transforms.IsValid(transform.parent_ref);
+
+ if (transform.dirty || parented)
+ {
+ transform.dirty = false;
+
+ XMVECTOR scale_local = XMLoadFloat3(&transform.scale_local);
+ XMVECTOR rotation_local = XMLoadFloat4(&transform.rotation_local);
+ XMVECTOR translation_local = XMLoadFloat3(&transform.translation_local);
+ XMMATRIX world =
+ XMMatrixScalingFromVector(scale_local) *
+ XMMatrixRotationQuaternion(rotation_local) *
+ XMMatrixTranslationFromVector(translation_local);
+
+ if (parented)
+ {
+ auto& parent = transforms.GetComponent(transform.parent_ref);
+ XMMATRIX world_parent = XMLoadFloat4x4(&parent.world);
+ XMMATRIX bindMatrix = XMLoadFloat4x4(&transform.world_parent_bind);
+ world = world * bindMatrix * world_parent;
+ }
+
+ transform.world_prev = transform.world;
+ XMStoreFloat4x4(&transform.world, world);
+ }
+
+ }
+
+ // Update Bone components:
+ for (size_t i = 0; i < bones.GetCount(); ++i)
+ {
+ auto& bone = bones[i];
+ auto& transform = transforms.GetComponent(bone.transform_ref);
+
+ XMMATRIX inverseBindPoseMatrix = XMLoadFloat4x4(&bone.inverseBindPoseMatrix);
+ XMMATRIX world = XMLoadFloat4x4(&transform.world);
+ XMMATRIX skinningMatrix = inverseBindPoseMatrix * world;
+ XMStoreFloat4x4(&bone.skinningMatrix, skinningMatrix);
+ }
+
+ }
+}
diff --git a/WickedEngine/wiSceneSystem.h b/WickedEngine/wiSceneSystem.h
new file mode 100644
index 000000000..45b871bc4
--- /dev/null
+++ b/WickedEngine/wiSceneSystem.h
@@ -0,0 +1,510 @@
+#pragma once
+#include "CommonInclude.h"
+#include "wiEnums.h"
+#include "wiImageEffects.h"
+#include "wiIntersectables.h"
+#include "ShaderInterop.h"
+#include "wiFrustum.h"
+
+#include "wiECS.h"
+#include "wiSceneSystem_Decl.h"
+
+#include
+
+namespace wiSceneSystem
+{
+
+ struct Node
+ {
+ uint32_t layerMask = ~0;
+ std::string name;
+ };
+
+ struct Transform
+ {
+ wiECS::ComponentManager::iterator parent_ref;
+
+ XMFLOAT3 scale_local = XMFLOAT3(1, 1, 1);
+ XMFLOAT4 rotation_local = XMFLOAT4(0, 0, 0, 1);
+ XMFLOAT3 translation_local = XMFLOAT3(0, 0, 0);
+
+ bool dirty = true;
+ XMFLOAT4X4 world; // uninitialized on purpose
+ XMFLOAT4X4 world_prev; // uninitialized on purpose
+ XMFLOAT4X4 world_parent_bind; // uninitialized on purpose
+ };
+
+ struct Material
+ {
+ wiECS::ComponentManager::iterator node_ref;
+
+ bool dirty = true;
+
+ STENCILREF engineStencilRef;
+ uint8_t userStencilRef;
+ BLENDMODE blendFlag;
+
+ XMFLOAT4 baseColor; // + alpha (.w)
+ XMFLOAT4 texMulAdd;
+ float roughness;
+ float reflectance;
+ float metalness;
+ float emissive;
+ float refractionIndex;
+ float subsurfaceScattering;
+ float normalMapStrength;
+ float parallaxOcclusionMapping;
+
+ float alphaRef;
+
+ bool cast_shadow;
+ bool planar_reflections;
+ bool water;
+
+ std::string baseColorMapName;
+ wiGraphicsTypes::Texture2D* baseColorMap = nullptr;
+
+ std::string surfaceMapName;
+ wiGraphicsTypes::Texture2D* surfaceMap = nullptr;
+
+ std::string normalMapName;
+ wiGraphicsTypes::Texture2D* normalMap = nullptr;
+
+ std::string displacementMapName;
+ wiGraphicsTypes::Texture2D* displacementMap = nullptr;
+
+ wiGraphicsTypes::GPUBuffer* constantBuffer = nullptr;
+
+ inline void SetUserStencilRef(uint8_t value)
+ {
+ assert(value < 128);
+ userStencilRef = value & 0x0F;
+ }
+ inline UINT GetStencilRef()
+ {
+ return (userStencilRef << 4) | static_cast(engineStencilRef);
+ }
+
+ wiGraphicsTypes::Texture2D* GetBaseColorMap() const;
+ wiGraphicsTypes::Texture2D* GetNormalMap() const;
+ wiGraphicsTypes::Texture2D* GetSurfaceMap() const;
+ wiGraphicsTypes::Texture2D* GetDisplacementMap() const;
+ };
+
+ struct Mesh
+ {
+ struct Vertex_FULL
+ {
+ XMFLOAT4 pos; //pos, wind
+ XMFLOAT4 nor; //normal, unused
+ XMFLOAT4 tex; //tex, matIndex, unused
+ XMFLOAT4 ind; //bone indices
+ XMFLOAT4 wei; //bone weights
+
+ Vertex_FULL() {
+ pos = XMFLOAT4(0, 0, 0, 0);
+ nor = XMFLOAT4(0, 0, 0, 1);
+ tex = XMFLOAT4(0, 0, 0, 0);
+ ind = XMFLOAT4(0, 0, 0, 0);
+ wei = XMFLOAT4(0, 0, 0, 0);
+ };
+ Vertex_FULL(const XMFLOAT3& newPos) {
+ pos = XMFLOAT4(newPos.x, newPos.y, newPos.z, 1);
+ nor = XMFLOAT4(0, 0, 0, 1);
+ tex = XMFLOAT4(0, 0, 0, 0);
+ ind = XMFLOAT4(0, 0, 0, 0);
+ wei = XMFLOAT4(0, 0, 0, 0);
+ }
+ };
+ struct Vertex_POS
+ {
+ XMFLOAT3 pos;
+ uint32_t normal_wind_matID;
+
+ Vertex_POS() :pos(XMFLOAT3(0.0f, 0.0f, 0.0f)), normal_wind_matID(0) {}
+ Vertex_POS(const Vertex_FULL& vert)
+ {
+ pos.x = vert.pos.x;
+ pos.y = vert.pos.y;
+ pos.z = vert.pos.z;
+ MakeFromParams(XMFLOAT3(vert.nor.x, vert.nor.y, vert.nor.z), vert.pos.w, static_cast(vert.tex.z));
+ }
+ inline XMVECTOR LoadPOS() const
+ {
+ return XMLoadFloat3(&pos);
+ }
+ inline XMVECTOR LoadNOR() const
+ {
+ return XMLoadFloat3(&GetNor_FULL());
+ }
+ inline void MakeFromParams(const XMFLOAT3& normal)
+ {
+ normal_wind_matID = normal_wind_matID & 0xFF000000; // reset only the normals
+
+ normal_wind_matID |= (uint32_t)((normal.x * 0.5f + 0.5f) * 255.0f) << 0;
+ normal_wind_matID |= (uint32_t)((normal.y * 0.5f + 0.5f) * 255.0f) << 8;
+ normal_wind_matID |= (uint32_t)((normal.z * 0.5f + 0.5f) * 255.0f) << 16;
+ }
+ inline void MakeFromParams(const XMFLOAT3& normal, float wind, uint32_t materialIndex)
+ {
+ assert(materialIndex < 16); // subset materialIndex is packed onto 4 bits
+
+ normal_wind_matID = 0;
+
+ normal_wind_matID |= (uint32_t)((normal.x * 0.5f + 0.5f) * 255.0f) << 0;
+ normal_wind_matID |= (uint32_t)((normal.y * 0.5f + 0.5f) * 255.0f) << 8;
+ normal_wind_matID |= (uint32_t)((normal.z * 0.5f + 0.5f) * 255.0f) << 16;
+ normal_wind_matID |= ((uint32_t)(wind * 15.0f) & 0x0000000F) << 24;
+ normal_wind_matID |= (materialIndex & 0x0000000F) << 28;
+ }
+ inline XMFLOAT3 GetNor_FULL() const
+ {
+ XMFLOAT3 nor_FULL(0, 0, 0);
+
+ nor_FULL.x = (float)((normal_wind_matID >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f;
+ nor_FULL.y = (float)((normal_wind_matID >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f;
+ nor_FULL.z = (float)((normal_wind_matID >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f;
+
+ return nor_FULL;
+ }
+ inline float GetWind() const
+ {
+ return (float)((normal_wind_matID >> 24) & 0x0000000F) / 15.0f;
+ }
+ inline uint32_t GetMaterialIndex() const
+ {
+ return (normal_wind_matID >> 28) & 0x0000000F;
+ }
+
+ static const wiGraphicsTypes::FORMAT FORMAT = wiGraphicsTypes::FORMAT::FORMAT_R32G32B32A32_FLOAT;
+ };
+ struct Vertex_TEX
+ {
+ XMHALF2 tex;
+
+ Vertex_TEX() :tex(XMHALF2(0.0f, 0.0f)) {}
+ Vertex_TEX(const Vertex_FULL& vert)
+ {
+ tex = XMHALF2(vert.tex.x, vert.tex.y);
+ }
+
+ static const wiGraphicsTypes::FORMAT FORMAT = wiGraphicsTypes::FORMAT::FORMAT_R16G16_FLOAT;
+ };
+ struct Vertex_BON
+ {
+ uint64_t ind;
+ uint64_t wei;
+
+ Vertex_BON()
+ {
+ ind = 0;
+ wei = 0;
+ }
+ Vertex_BON(const Vertex_FULL& vert)
+ {
+ ind = 0;
+ wei = 0;
+
+ ind |= (uint64_t)vert.ind.x << 0;
+ ind |= (uint64_t)vert.ind.y << 16;
+ ind |= (uint64_t)vert.ind.z << 32;
+ ind |= (uint64_t)vert.ind.w << 48;
+
+ wei |= (uint64_t)(vert.wei.x * 65535.0f) << 0;
+ wei |= (uint64_t)(vert.wei.y * 65535.0f) << 16;
+ wei |= (uint64_t)(vert.wei.z * 65535.0f) << 32;
+ wei |= (uint64_t)(vert.wei.w * 65535.0f) << 48;
+ }
+ inline XMFLOAT4 GetInd_FULL() const
+ {
+ XMFLOAT4 ind_FULL(0, 0, 0, 0);
+
+ ind_FULL.x = (float)((ind >> 0) & 0x0000FFFF);
+ ind_FULL.y = (float)((ind >> 16) & 0x0000FFFF);
+ ind_FULL.z = (float)((ind >> 32) & 0x0000FFFF);
+ ind_FULL.w = (float)((ind >> 48) & 0x0000FFFF);
+
+ return ind_FULL;
+ }
+ inline XMFLOAT4 GetWei_FULL() const
+ {
+ XMFLOAT4 wei_FULL(0, 0, 0, 0);
+
+ wei_FULL.x = (float)((wei >> 0) & 0x0000FFFF) / 65535.0f;
+ wei_FULL.y = (float)((wei >> 16) & 0x0000FFFF) / 65535.0f;
+ wei_FULL.z = (float)((wei >> 32) & 0x0000FFFF) / 65535.0f;
+ wei_FULL.w = (float)((wei >> 48) & 0x0000FFFF) / 65535.0f;
+
+ return wei_FULL;
+ }
+ };
+
+ std::vector vertices_FULL;
+ std::vector vertices_POS; // position(xyz), normal+wind(w as uint)
+ std::vector vertices_TEX; // texcoords
+ std::vector vertices_BON; // bone indices, bone weights
+ std::vector vertices_Transformed_POS; // for soft body simulation
+ std::vector vertices_Transformed_PRE; // for soft body simulation
+ std::vector indices;
+ std::vector physicsverts;
+ std::vector physicsindices;
+ std::vector physicalmapGP;
+
+ struct MeshSubset
+ {
+ wiECS::ComponentManager material_ref;
+ UINT indexBufferOffset;
+
+ std::vector subsetIndices;
+
+ MeshSubset();
+ ~MeshSubset();
+ };
+ std::vector subsets;
+
+ wiGraphicsTypes::GPUBuffer* indexBuffer;
+ wiGraphicsTypes::GPUBuffer* vertexBuffer_POS;
+ wiGraphicsTypes::GPUBuffer* vertexBuffer_TEX;
+ wiGraphicsTypes::GPUBuffer* vertexBuffer_BON;
+ wiGraphicsTypes::GPUBuffer* streamoutBuffer_POS;
+ wiGraphicsTypes::GPUBuffer* streamoutBuffer_PRE;
+
+ // Dynamic vertexbuffers write into a global pool, these will be the offsets into that:
+ UINT bufferOffset_POS;
+ UINT bufferOffset_PRE;
+
+ wiGraphicsTypes::INDEXBUFFER_FORMAT indexFormat;
+
+ bool renderable = true;
+ bool doubleSided = false;
+ bool renderDataComplete = false;
+
+ AABB aabb;
+
+ wiECS::ComponentManager::iterator armature_ref;
+
+ };
+
+ struct Object
+ {
+ wiECS::ComponentManager::iterator node_ref;
+ wiECS::ComponentManager::iterator transform_ref;
+ wiECS::ComponentManager::iterator mesh_ref;
+
+ bool renderable;
+ int cascadeMask = 0; // which shadow cascades to skip (0: skip none, 1: skip first, etc...)
+ AABB aabb;
+ XMFLOAT4 color;
+
+ // occlusion result history bitfield (32 bit->32 frame history)
+ uint32_t occlusionHistory;
+ // occlusion query pool index
+ int occlusionQueryID;
+ };
+
+ struct Bone
+ {
+ wiECS::ComponentManager::iterator node_ref;
+ wiECS::ComponentManager::iterator transform_ref;
+
+ XMFLOAT4X4 inverseBindPoseMatrix;
+ XMFLOAT4X4 skinningMatrix;
+ };
+
+ struct Armature
+ {
+ wiECS::ComponentManager::iterator node_ref;
+ wiECS::ComponentManager::iterator transform_ref;
+
+ std::vector::iterator> bone_refs;
+
+ GFX_STRUCT ShaderBoneType
+ {
+ XMFLOAT4A pose0;
+ XMFLOAT4A pose1;
+ XMFLOAT4A pose2;
+
+ void Create(const XMFLOAT4X4& matIn)
+ {
+ pose0 = XMFLOAT4A(matIn._11, matIn._21, matIn._31, matIn._41);
+ pose1 = XMFLOAT4A(matIn._12, matIn._22, matIn._32, matIn._42);
+ pose2 = XMFLOAT4A(matIn._13, matIn._23, matIn._33, matIn._43);
+ }
+
+ ALIGN_16
+ };
+ std::vector boneData;
+ wiGraphicsTypes::GPUBuffer boneBuffer;
+
+ // This will be used to eg. mirror the whole skin, without modifying the armature transform itself
+ // It will affect the skin only, so the mesh vertices should be mirrored as well to work correctly!
+ XMFLOAT4X4 skinningRemap;
+ };
+
+ struct Light
+ {
+ wiECS::ComponentManager::iterator node_ref;
+ wiECS::ComponentManager::iterator transform_ref;
+
+ enum LightType {
+ DIRECTIONAL = ENTITY_TYPE_DIRECTIONALLIGHT,
+ POINT = ENTITY_TYPE_POINTLIGHT,
+ SPOT = ENTITY_TYPE_SPOTLIGHT,
+ SPHERE = ENTITY_TYPE_SPHERELIGHT,
+ DISC = ENTITY_TYPE_DISCLIGHT,
+ RECTANGLE = ENTITY_TYPE_RECTANGLELIGHT,
+ TUBE = ENTITY_TYPE_TUBELIGHT,
+ LIGHTTYPE_COUNT,
+ };
+
+ XMFLOAT4 color;
+ XMFLOAT4 enerDis;
+ bool volumetrics = false;
+ bool noHalo;
+ bool shadow;
+ std::vector lensFlareRimTextures;
+ std::vector lensFlareNames;
+
+ static wiGraphicsTypes::Texture2D* shadowMapArray_2D;
+ static wiGraphicsTypes::Texture2D* shadowMapArray_Cube;
+ static wiGraphicsTypes::Texture2D* shadowMapArray_Transparent;
+ int shadowMap_index;
+ int entityArray_index;
+
+ std::vector shadowMaterices;
+
+ float shadowBias;
+
+ // area light props:
+ float radius, width, height;
+ };
+
+ struct Camera
+ {
+ wiECS::ComponentManager::iterator node_ref;
+ wiECS::ComponentManager::iterator transform_ref;
+
+ XMFLOAT4X4 View, Projection, VP;
+ XMFLOAT3 Eye, At, Up;
+ float width, height;
+ float zNearP, zFarP;
+ float fov;
+ Frustum frustum;
+ XMFLOAT4X4 InvView, InvProjection, InvVP;
+ XMFLOAT4X4 realProjection; // because reverse zbuffering projection complicates things...
+
+ XMVECTOR GetEye() const
+ {
+ return XMLoadFloat3(&Eye);
+ }
+ XMVECTOR GetAt() const
+ {
+ return XMLoadFloat3(&At);
+ }
+ XMVECTOR GetUp() const
+ {
+ return XMLoadFloat3(&Up);
+ }
+ XMVECTOR GetRight() const
+ {
+ return XMVector3Cross(GetAt(), GetUp());
+ }
+ XMMATRIX GetView() const
+ {
+ return XMLoadFloat4x4(&View);
+ }
+ XMMATRIX GetInvView() const
+ {
+ return XMLoadFloat4x4(&InvView);
+ }
+ XMMATRIX GetProjection() const
+ {
+ return XMLoadFloat4x4(&Projection);
+ }
+ XMMATRIX GetInvProjection() const
+ {
+ return XMLoadFloat4x4(&InvProjection);
+ }
+ XMMATRIX GetViewProjection() const
+ {
+ return XMLoadFloat4x4(&VP);
+ }
+ XMMATRIX GetInvViewProjection() const
+ {
+ return XMLoadFloat4x4(&InvVP);
+ }
+ };
+
+ struct EnvironmentProbe
+ {
+ wiECS::ComponentManager::iterator node_ref;
+ wiECS::ComponentManager::iterator transform_ref;
+ int textureIndex = -1;
+ bool realTime = false;
+ bool isUpToDate = false;
+ };
+
+ struct ForceField
+ {
+ wiECS::ComponentManager::iterator node_ref;
+ wiECS::ComponentManager::iterator transform_ref;
+ };
+
+ struct Decal
+ {
+ wiECS::ComponentManager::iterator node_ref;
+ wiECS::ComponentManager::iterator transform_ref;
+ wiECS::ComponentManager::iterator material_ref;
+
+ XMFLOAT4 atlasMulAdd = XMFLOAT4(0, 0, 0, 0);
+ };
+
+ struct Model
+ {
+ wiECS::ComponentManager::iterator node_ref;
+ wiECS::ComponentManager::iterator transform_ref;
+
+ std::vector::iterator> material_refs;
+ std::vector::iterator> mesh_refs;
+ std::vector::iterator> object_refs;
+ std::vector::iterator> armature_refs;
+ std::vector::iterator> light_refs;
+ std::vector::iterator> probe_refs;
+ std::vector::iterator> force_refs;
+ std::vector::iterator> decal_refs;
+ std::vector::iterator> camera_refs;
+ };
+
+ struct Scene
+ {
+ wiECS::ComponentManager nodes;
+ wiECS::ComponentManager transforms;
+ wiECS::ComponentManager materials;
+ wiECS::ComponentManager meshes;
+ wiECS::ComponentManager