1 // 2 // Copyright (c) 2008-2017 the Urho3D project. 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 // 22 23 #pragma once 24 25 #include "../Container/List.h" 26 #include "../Graphics/Drawable.h" 27 #include "../Graphics/Skeleton.h" 28 #include "../Math/Frustum.h" 29 30 namespace Urho3D 31 { 32 33 class IndexBuffer; 34 class VertexBuffer; 35 36 /// %Decal vertex. 37 struct DecalVertex 38 { 39 /// Construct with defaults. DecalVertexDecalVertex40 DecalVertex() 41 { 42 } 43 44 /// Construct with position and normal. DecalVertexDecalVertex45 DecalVertex(const Vector3& position, const Vector3& normal) : 46 position_(position), 47 normal_(normal) 48 { 49 } 50 51 /// Construct with position, normal and skinning information. DecalVertexDecalVertex52 DecalVertex(const Vector3& position, const Vector3& normal, const float* blendWeights, const unsigned char* blendIndices) : 53 position_(position), 54 normal_(normal) 55 { 56 for (unsigned i = 0; i < 4; ++i) 57 { 58 blendWeights_[i] = blendWeights[i]; 59 blendIndices_[i] = blendIndices[i]; 60 } 61 } 62 63 /// Position. 64 Vector3 position_; 65 /// Normal. 66 Vector3 normal_; 67 /// Texture coordinates. 68 Vector2 texCoord_; 69 /// Tangent. 70 Vector4 tangent_; 71 /// Blend weights. 72 float blendWeights_[4]; 73 /// Blend indices. 74 unsigned char blendIndices_[4]; 75 }; 76 77 /// One decal in a decal set. 78 struct Decal 79 { 80 /// Construct with defaults. DecalDecal81 Decal() : 82 timer_(0.0f), 83 timeToLive_(0.0f) 84 { 85 } 86 87 /// Add a vertex. 88 void AddVertex(const DecalVertex& vertex); 89 /// Calculate local-space bounding box. 90 void CalculateBoundingBox(); 91 92 /// Decal age timer. 93 float timer_; 94 /// Maximum time to live in seconds (0 = infinite) 95 float timeToLive_; 96 /// Local-space bounding box. 97 BoundingBox boundingBox_; 98 /// Decal vertices. 99 PODVector<DecalVertex> vertices_; 100 /// Decal indices. 101 PODVector<unsigned short> indices_; 102 }; 103 104 /// %Decal renderer component. 105 class URHO3D_API DecalSet : public Drawable 106 { 107 URHO3D_OBJECT(DecalSet, Drawable); 108 109 public: 110 /// Construct. 111 DecalSet(Context* context); 112 /// Destruct. 113 virtual ~DecalSet(); 114 /// Register object factory. 115 static void RegisterObject(Context* context); 116 117 /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update. 118 virtual void ApplyAttributes(); 119 /// Handle enabled/disabled state change. 120 virtual void OnSetEnabled(); 121 /// Process octree raycast. May be called from a worker thread. 122 virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results); 123 /// Calculate distance and prepare batches for rendering. May be called from worker thread(s), possibly re-entrantly. 124 virtual void UpdateBatches(const FrameInfo& frame); 125 /// Prepare geometry for rendering. Called from a worker thread if possible (no GPU update.) 126 virtual void UpdateGeometry(const FrameInfo& frame); 127 /// Return whether a geometry update is necessary, and if it can happen in a worker thread. 128 virtual UpdateGeometryType GetUpdateGeometryType(); 129 130 /// Set material. The material should use a small negative depth bias to avoid Z-fighting. 131 void SetMaterial(Material* material); 132 /// Set maximum number of decal vertices. 133 void SetMaxVertices(unsigned num); 134 /// Set maximum number of decal vertex indices. 135 void SetMaxIndices(unsigned num); 136 /// Set whether to optimize GPU buffer sizes according to current amount of decals. Default false, which will size the buffers according to the maximum vertices/indices. When true, buffers will be reallocated whenever decals are added/removed, which can be worse for performance. 137 void SetOptimizeBufferSize(bool enable); 138 /// Add a decal at world coordinates, using a target drawable's geometry for reference. If the decal needs to move with the target, the decal component should be created to the target's node. Return true if successful. 139 bool AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio, 140 float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive = 0.0f, float normalCutoff = 0.1f, 141 unsigned subGeometry = M_MAX_UNSIGNED); 142 /// Remove n oldest decals. 143 void RemoveDecals(unsigned num); 144 /// Remove all decals. 145 void RemoveAllDecals(); 146 147 /// Return material. 148 Material* GetMaterial() const; 149 150 /// Return number of decals. GetNumDecals()151 unsigned GetNumDecals() const { return decals_.Size(); } 152 153 /// Retur number of vertices in the decals. GetNumVertices()154 unsigned GetNumVertices() const { return numVertices_; } 155 156 /// Retur number of vertex indices in the decals. GetNumIndices()157 unsigned GetNumIndices() const { return numIndices_; } 158 159 /// Return maximum number of decal vertices. GetMaxVertices()160 unsigned GetMaxVertices() const { return maxVertices_; } 161 162 /// Return maximum number of decal vertex indices. GetMaxIndices()163 unsigned GetMaxIndices() const { return maxIndices_; } 164 165 /// Return whether is optimizing GPU buffer sizes according to current amount of decals. GetOptimizeBufferSize()166 bool GetOptimizeBufferSize() const { return optimizeBufferSize_; } 167 168 /// Set material attribute. 169 void SetMaterialAttr(const ResourceRef& value); 170 /// Set decals attribute. 171 void SetDecalsAttr(const PODVector<unsigned char>& value); 172 /// Return material attribute. 173 ResourceRef GetMaterialAttr() const; 174 /// Return decals attribute. 175 PODVector<unsigned char> GetDecalsAttr() const; 176 177 protected: 178 /// Recalculate the world-space bounding box. 179 virtual void OnWorldBoundingBoxUpdate(); 180 /// Handle node transform being dirtied. 181 virtual void OnMarkedDirty(Node* node); 182 183 private: 184 /// Get triangle faces from the target geometry. 185 void GetFaces(Vector<PODVector<DecalVertex> >& faces, Drawable* target, unsigned batchIndex, const Frustum& frustum, 186 const Vector3& decalNormal, float normalCutoff); 187 /// Get triangle face from the target geometry. 188 void GetFace 189 (Vector<PODVector<DecalVertex> >& faces, Drawable* target, unsigned batchIndex, unsigned i0, unsigned i1, unsigned i2, 190 const unsigned char* positionData, const unsigned char* normalData, const unsigned char* skinningData, 191 unsigned positionStride, unsigned normalStride, unsigned skinningStride, const Frustum& frustum, 192 const Vector3& decalNormal, float normalCutoff); 193 /// Get bones referenced by skinning data and remap the skinning indices. Return true if successful. 194 bool GetBones(Drawable* target, unsigned batchIndex, const float* blendWeights, const unsigned char* blendIndices, 195 unsigned char* newBlendIndices); 196 /// Calculate UV coordinates for the decal. 197 void CalculateUVs 198 (Decal& decal, const Matrix3x4& view, const Matrix4& projection, const Vector2& topLeftUV, const Vector2& bottomRightUV); 199 /// Transform decal's vertices from the target geometry to the decal set local space. 200 void TransformVertices(Decal& decal, const Matrix3x4& transform); 201 /// Remove a decal by iterator and return iterator to the next decal. 202 List<Decal>::Iterator RemoveDecal(List<Decal>::Iterator i); 203 /// Mark decals and the bounding box dirty. 204 void MarkDecalsDirty(); 205 /// Recalculate the local-space bounding box. 206 void CalculateBoundingBox(); 207 /// Rewrite decal vertex and index buffers. 208 void UpdateBuffers(); 209 /// Recalculate skinning. 210 void UpdateSkinning(); 211 /// Update the batch (geometry type, shader data.) 212 void UpdateBatch(); 213 /// Find bones after loading. 214 void AssignBoneNodes(); 215 /// Subscribe/unsubscribe from scene post-update as necessary. 216 void UpdateEventSubscription(bool checkAllDecals); 217 /// Handle scene post-update event. 218 void HandleScenePostUpdate(StringHash eventType, VariantMap& eventData); 219 220 /// Geometry. 221 SharedPtr<Geometry> geometry_; 222 /// Vertex buffer. 223 SharedPtr<VertexBuffer> vertexBuffer_; 224 /// Index buffer. 225 SharedPtr<IndexBuffer> indexBuffer_; 226 /// Decals. 227 List<Decal> decals_; 228 /// Bones used for skinned decals. 229 Vector<Bone> bones_; 230 /// Skinning matrices. 231 PODVector<Matrix3x4> skinMatrices_; 232 /// Vertices in the current decals. 233 unsigned numVertices_; 234 /// Indices in the current decals. 235 unsigned numIndices_; 236 /// Maximum vertices. 237 unsigned maxVertices_; 238 /// Maximum indices. 239 unsigned maxIndices_; 240 /// Optimize buffer sizes flag. 241 bool optimizeBufferSize_; 242 /// Skinned mode flag. 243 bool skinned_; 244 /// Vertex buffer needs rewrite / resizing flag. 245 bool bufferDirty_; 246 /// Bounding box needs update flag. 247 bool boundingBoxDirty_; 248 /// Skinning dirty flag. 249 bool skinningDirty_; 250 /// Bone nodes assignment pending flag. 251 bool assignBonesPending_; 252 /// Subscribed to scene post update event flag. 253 bool subscribed_; 254 }; 255 256 } 257