1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Mesh/BsMeshBase.h"
7#include "Mesh/BsMeshData.h"
8#include "RenderAPI/BsVertexData.h"
9#include "RenderAPI/BsSubMesh.h"
10#include "Math/BsBounds.h"
11
12namespace bs
13{
14 /** @addtogroup Resources
15 * @{
16 */
17
18 /** Descriptor object used for creation of a new Mesh object. */
19 struct BS_CORE_EXPORT MESH_DESC
20 {
21 MESH_DESC() { }
22
23 /** Number of vertices in the mesh. */
24 UINT32 numVertices = 0;
25
26 /** Number of indices in the mesh. */
27 UINT32 numIndices = 0;
28
29 /**
30 * Vertex description structure that describes how are vertices organized in the vertex buffer. When binding a mesh
31 * to the pipeline you must ensure vertex description at least partially matches the input description of the
32 * currently bound vertex GPU program.
33 */
34 SPtr<VertexDataDesc> vertexDesc;
35
36 /**
37 * Defines how are indices separated into sub-meshes, and how are those sub-meshes rendered. Sub-meshes may be
38 * rendered independently.
39 */
40 Vector<SubMesh> subMeshes;
41
42 /** Optimizes performance depending on planned usage of the mesh. */
43 INT32 usage = MU_STATIC;
44
45 /**
46 * Size of indices, use smaller size for better performance, however be careful not to go over the number of
47 * vertices limited by the size.
48 */
49 IndexType indexType = IT_32BIT;
50
51 /** Optional skeleton that can be used for skeletal animation of the mesh. */
52 SPtr<Skeleton> skeleton;
53
54 /** Optional set of morph shapes that can be used for per-vertex animation of the mesh. */
55 SPtr<MorphShapes> morphShapes;
56
57 static MESH_DESC DEFAULT;
58 };
59
60 /**
61 * Primary class for holding geometry. Stores data in the form of vertex buffers and optionally an index buffer, which
62 * may be bound to the pipeline for drawing. May contain multiple sub-meshes.
63 */
64 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Rendering) Mesh : public MeshBase
65 {
66 public:
67 virtual ~Mesh() = default;
68
69 /** @copydoc MeshBase::initialize */
70 void initialize() override;
71
72 /**
73 * Updates the mesh with new data. Provided data buffer will be locked until the operation completes.
74 *
75 * @param[in] data Data of valid size and format to write to the subresource.
76 * @param[in] discardEntireBuffer When true the existing contents of the resource you are updating will be
77 * discarded. This can make the operation faster. Resources with certain buffer
78 * types might require this flag to be in a specific state otherwise the operation
79 * will fail.
80 * @return Async operation object you can use to track operation completion.
81 *
82 * @note This is an @ref asyncMethod "asynchronous method".
83 */
84 AsyncOp writeData(const SPtr<MeshData>& data, bool discardEntireBuffer);
85
86 /**
87 * Reads internal mesh data to the provided previously allocated buffer. Provided data buffer will be locked until
88 * the operation completes.
89 *
90 * @param[out] data Pre-allocated buffer of proper vertex/index format and size where data will be read
91 * to. You can use allocBuffer() to allocate a buffer of a correct format and size.
92 * @return Async operation object you can use to track operation completion.
93 *
94 * @note This is an @ref asyncMethod "asynchronous method".
95 */
96 AsyncOp readData(const SPtr<MeshData>& data);
97
98 /**
99 * Allocates a buffer that exactly matches the size of this mesh. This is a helper function, primarily meant for
100 * creating buffers when reading from, or writing to a mesh.
101 *
102 * @note Thread safe.
103 */
104 SPtr<MeshData> allocBuffer() const;
105
106 /**
107 * Returns mesh data cached in the system memory. If the mesh wasn't created with CPU cached usage flag this
108 * method will not return any data. Caller should not modify the returned data.
109 *
110 * @note
111 * The data read is the cached mesh data. Any data written to the mesh from the GPU or core thread will not be
112 * reflected in this data. Use readData() if you require those changes.
113 */
114 SPtr<MeshData> getCachedData() const { return mCPUData; }
115
116 /** Gets the skeleton required for animation of this mesh, if any is available. */
117 BS_SCRIPT_EXPORT(pr:getter,n:Skeleton)
118 SPtr<Skeleton> getSkeleton() const { return mSkeleton; }
119
120 /** Returns an object containing all shapes used for morph animation, if any are available. */
121 BS_SCRIPT_EXPORT(pr:getter,n:MorphShapes)
122 SPtr<MorphShapes> getMorphShapes() const { return mMorphShapes; }
123
124 /** Retrieves a core implementation of a mesh usable only from the core thread. */
125 SPtr<ct::Mesh> getCore() const;
126
127 /** Returns a dummy mesh, containing just one triangle. Don't modify the returned mesh. */
128 static HMesh dummy();
129
130 protected:
131 friend class MeshManager;
132
133 Mesh(const MESH_DESC& desc);
134 Mesh(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc);
135
136 /** Updates bounds by calculating them from the vertices in the provided mesh data object. */
137 void updateBounds(const MeshData& meshData);
138
139 /** @copydoc CoreObject::createCore */
140 SPtr<ct::CoreObject> createCore() const override;
141
142 /**
143 * Creates buffers used for caching of CPU mesh data.
144 *
145 * @note Make sure to initialize all mesh properties before calling this.
146 */
147 void createCPUBuffer();
148
149 /** Updates the cached CPU buffers with new data. */
150 void updateCPUBuffer(UINT32 subresourceIdx, const MeshData& data);
151
152 mutable SPtr<MeshData> mCPUData;
153
154 SPtr<VertexDataDesc> mVertexDesc;
155 int mUsage = MU_STATIC;
156 IndexType mIndexType = IT_32BIT;
157 SPtr<Skeleton> mSkeleton; // Immutable
158 SPtr<MorphShapes> mMorphShapes; // Immutable
159
160 /************************************************************************/
161 /* SERIALIZATION */
162 /************************************************************************/
163 private:
164 Mesh(); // Serialization only
165
166 public:
167 friend class MeshRTTI;
168 static RTTITypeBase* getRTTIStatic();
169 RTTITypeBase* getRTTI() const override;
170
171 /************************************************************************/
172 /* STATICS */
173 /************************************************************************/
174
175 public:
176 /**
177 * Creates a new empty mesh. Created mesh will have no sub-meshes.
178 *
179 * @param[in] numVertices Number of vertices in the mesh.
180 * @param[in] numIndices Number of indices in the mesh.
181 * @param[in] vertexDesc Vertex description structure that describes how are vertices organized in the
182 * vertex buffer. When binding a mesh to the pipeline you must ensure vertex
183 * description at least partially matches the input description of the currently bound
184 * vertex GPU program.
185 * @param[in] usage Optimizes performance depending on planned usage of the mesh.
186 * @param[in] drawOp Determines how should the provided indices be interpreted by the pipeline. Default
187 * option is a triangle list, where three indices represent a single triangle.
188 * @param[in] indexType Size of indices, use smaller size for better performance, however be careful not to
189 * go over the number of vertices limited by the size.
190 */
191 static HMesh create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
192 int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
193
194 /**
195 * Creates a new empty mesh.
196 *
197 * @param[in] desc Descriptor containing the properties of the mesh to create.
198 */
199 static HMesh create(const MESH_DESC& desc);
200
201 /**
202 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
203 * by the mesh data exactly. Mesh will have no sub-meshes.
204 *
205 * @param[in] initialData Vertex and index data to initialize the mesh with.
206 * @param[in] desc Descriptor containing the properties of the mesh to create. Vertex and index count,
207 * vertex descriptor and index type properties are ignored and are read from provided
208 * mesh data instead.
209 */
210 static HMesh create(const SPtr<MeshData>& initialData, const MESH_DESC& desc);
211
212 /**
213 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
214 * by the mesh data exactly. Mesh will have no sub-meshes.
215 *
216 * @param[in] initialData Vertex and index data to initialize the mesh with.
217 * @param[in] usage Optimizes performance depending on planned usage of the mesh.
218 * @param[in] drawOp Determines how should the provided indices be interpreted by the pipeline. Default
219 * option is a triangle strip, where three indices represent a single triangle.
220 */
221 static HMesh create(const SPtr<MeshData>& initialData, int usage = MU_STATIC,
222 DrawOperationType drawOp = DOT_TRIANGLE_LIST);
223
224 /** @name Internal
225 * @{
226 */
227
228 /**
229 * @copydoc create(const MESH_DESC&)
230 *
231 * @note Internal method. Use create() for normal use.
232 */
233 static SPtr<Mesh> _createPtr(const MESH_DESC& desc);
234
235 /**
236 * @copydoc create(const SPtr<MeshData>&, const MESH_DESC&)
237 *
238 * @note Internal method. Use create() for normal use.
239 */
240 static SPtr<Mesh> _createPtr(const SPtr<MeshData>& initialData, const MESH_DESC& desc);
241
242 /**
243 * @copydoc create(const SPtr<MeshData>&, int, DrawOperationType)
244 *
245 * @note Internal method. Use create() for normal use.
246 */
247 static SPtr<Mesh> _createPtr(const SPtr<MeshData>& initialData, int usage = MU_STATIC,
248 DrawOperationType drawOp = DOT_TRIANGLE_LIST);
249
250 /**
251 * Creates a new empty and uninitialized mesh. You will need to manually initialize the mesh before using it.
252 *
253 * @note This should only be used for special cases like serialization and is not meant for normal use.
254 */
255 static SPtr<Mesh> createEmpty();
256
257 /** @} */
258 };
259
260 /** @} */
261
262 namespace ct
263 {
264 /** @addtogroup Resources-Internal
265 * @{
266 */
267
268 /**
269 * Core thread portion of a bs::Mesh.
270 *
271 * @note Core thread.
272 */
273 class BS_CORE_EXPORT Mesh : public MeshBase
274 {
275 public:
276 Mesh(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc, GpuDeviceFlags deviceMask);
277
278 ~Mesh();
279
280 /** @copydoc CoreObject::initialize */
281 void initialize() override;
282
283 /** @copydoc MeshBase::getVertexData */
284 SPtr<VertexData> getVertexData() const override;
285
286 /** @copydoc MeshBase::getIndexBuffer */
287 SPtr<IndexBuffer> getIndexBuffer() const override;
288
289 /** @copydoc MeshBase::getVertexDesc */
290 SPtr<VertexDataDesc> getVertexDesc() const override;
291
292 /** Returns a skeleton that can be used for animating the mesh. */
293 SPtr<Skeleton> getSkeleton() const { return mSkeleton; }
294
295 /** Returns an object containing all shapes used for morph animation, if any are available. */
296 SPtr<MorphShapes> getMorphShapes() const { return mMorphShapes; }
297
298 /**
299 * Updates the current mesh with the provided data.
300 *
301 * @param[in] data Data to update the mesh with.
302 * @param[in] discardEntireBuffer When true the existing contents of the resource you are updating will be
303 * discarded. This can make the operation faster. Resources with certain buffer
304 * types might require this flag to be in a specific state otherwise the operation
305 * will fail.
306 * @param[in] updateBounds If true the internal bounds of the mesh will be recalculated based on the
307 * provided data.
308 * @param[in] queueIdx Device queue to perform the write operation on. See @ref queuesDoc.
309 */
310 virtual void writeData(const MeshData& data, bool discardEntireBuffer, bool updateBounds = true,
311 UINT32 queueIdx = 0);
312
313 /**
314 * Reads the current mesh data into the provided @p data parameter. Data buffer needs to be pre-allocated.
315 *
316 * @param[out] data Pre-allocated buffer of proper vertex/index format and size where data will be
317 * read to. You can use Mesh::allocBuffer() to allocate a buffer of a correct
318 * format and size.
319 * @param[in] deviceIdx Index of the device whose memory to read. If the buffer doesn't exist on this
320 * device, no data will be read.
321 * @param[in] queueIdx Device queue to perform the read operation on. See @ref queuesDoc.
322 */
323 virtual void readData(MeshData& data, UINT32 deviceIdx = 0, UINT32 queueIdx = 0);
324
325 /**
326 * Creates a new empty mesh. Created mesh will have no sub-meshes.
327 *
328 * @param[in] numVertices Number of vertices in the mesh.
329 * @param[in] numIndices Number of indices in the mesh.
330 * @param[in] vertexDesc Vertex description structure that describes how are vertices organized in the
331 * vertex buffer. When binding a mesh to the pipeline you must ensure vertex
332 * description at least partially matches the input description of the currently
333 * bound vertex GPU program.
334 * @param[in] usage Optimizes performance depending on planned usage of the mesh.
335 * @param[in] drawOp Determines how should the provided indices be interpreted by the pipeline. Default
336 * option is a triangle list, where three indices represent a single triangle.
337 * @param[in] indexType Size of indices, use smaller size for better performance, however be careful not to
338 * go over the number of vertices limited by the size.
339 * @param[in] deviceMask Mask that determines on which GPU devices should the object be created on.
340 */
341 static SPtr<Mesh> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
342 int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT,
343 GpuDeviceFlags deviceMask = GDF_DEFAULT);
344
345 /**
346 * Creates a new empty mesh.
347 *
348 * @param[in] desc Descriptor containing the properties of the mesh to create.
349 * @param[in] deviceMask Mask that determines on which GPU devices should the object be created on.
350 */
351 static SPtr<Mesh> create(const MESH_DESC& desc, GpuDeviceFlags deviceMask = GDF_DEFAULT);
352
353 /**
354 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
355 * by the mesh data exactly.
356 *
357 * @param[in] initialData Vertex and index data to initialize the mesh with.
358 * @param[in] desc Descriptor containing the properties of the mesh to create. Vertex and index count,
359 * vertex descriptor and index type properties are ignored and are read from provided
360 * mesh data instead.
361 * @param[in] deviceMask Mask that determines on which GPU devices should the object be created on.
362 */
363 static SPtr<Mesh> create(const SPtr<MeshData>& initialData, const MESH_DESC& desc,
364 GpuDeviceFlags deviceMask = GDF_DEFAULT);
365
366 /**
367 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
368 * by the mesh data exactly. Mesh will have no sub-meshes.
369 *
370 * @param[in] initialData Vertex and index data to initialize the mesh with.
371 * @param[in] usage Optimizes performance depending on planned usage of the mesh.
372 * @param[in] drawOp Determines how should the provided indices be interpreted by the pipeline. Default
373 * option is a triangle strip, where three indices represent a single triangle.
374 * @param[in] deviceMask Mask that determines on which GPU devices should the object be created on.
375 */
376 static SPtr<Mesh> create(const SPtr<MeshData>& initialData, int usage = MU_STATIC,
377 DrawOperationType drawOp = DOT_TRIANGLE_LIST, GpuDeviceFlags deviceMask = GDF_DEFAULT);
378
379 protected:
380 friend class bs::Mesh;
381
382 /** Updates bounds by calculating them from the vertices in the provided mesh data object. */
383 void updateBounds(const MeshData& meshData);
384
385 SPtr<VertexData> mVertexData;
386 SPtr<IndexBuffer> mIndexBuffer;
387
388 SPtr<VertexDataDesc> mVertexDesc;
389 int mUsage;
390 IndexType mIndexType;
391 GpuDeviceFlags mDeviceMask;
392 SPtr<MeshData> mTempInitialMeshData;
393 SPtr<Skeleton> mSkeleton; // Immutable
394 SPtr<MorphShapes> mMorphShapes; // Immutable
395 };
396
397 /** @} */
398 }
399}