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