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 "Math/BsVector3.h"
7
8namespace bs
9{
10 /** @addtogroup Utility-Core
11 * @{
12 */
13
14 /** Normal packed in a 32-bit structure. */
15 union PackedNormal
16 {
17 struct
18 {
19 UINT8 x;
20 UINT8 y;
21 UINT8 z;
22 UINT8 w;
23 };
24
25 UINT32 packed;
26 };
27
28 /** Performs various operations on mesh geometry. */
29 class BS_CORE_EXPORT MeshUtility
30 {
31 public:
32 /**
33 * Calculates per-vertex normals based on the provided vertices and indices.
34 *
35 * @param[in] vertices Set of vertices containing vertex positions.
36 * @param[in] indices Set of indices containing indexes into vertex array for each triangle.
37 * @param[in] numVertices Number of vertices in the @p vertices array.
38 * @param[in] numIndices Number of indices in the @p indices array. Must be a multiple of three.
39 * @param[out] normals Pre-allocated buffer that will contain the calculated normals. Must be the same size
40 * as the vertex array.
41 * @param[in] indexSize Size of a single index in the indices array, in bytes.
42 *
43 * @note
44 * Vertices should be split before calling this method if there are any discontinuities. (for example a vertex on a
45 * corner of a cube should be split into three vertices used by three triangles in order for the normals to be
46 * valid.)
47 */
48 static void calculateNormals(Vector3* vertices, UINT8* indices, UINT32 numVertices,
49 UINT32 numIndices, Vector3* normals, UINT32 indexSize = 4);
50
51 /**
52 * Calculates per-vertex tangents and bitangents based on the provided vertices, uv coordinates and indices.
53 *
54 * @param[in] vertices Set of vertices containing vertex positions.
55 * @param[in] normals Set of normals to use when calculating tangents. Must the the same length as the
56 * number of vertices.
57 * @param[in] uv Set of UV coordinates to use when calculating tangents. Must the the same length as
58 * the number of vertices.
59 * @param[in] indices Set of indices containing indexes into vertex array for each triangle.
60 * @param[in] numVertices Number of vertices in the @p vertices, @p normals and @p uv arrays.
61 * @param[in] numIndices Number of indices in the @p indices array. Must be a multiple of three.
62 * @param[out] tangents Pre-allocated buffer that will contain the calculated tangents. Must be the same
63 * size as the vertex array.
64 * @param[out] bitangents Pre-allocated buffer that will contain the calculated bitangents. Must be the same
65 * size as the vertex array.
66 * @param[in] indexSize Size of a single index in the indices array, in bytes.
67 * @param[in] vertexStride Number of bytes to advance the @p vertices, @p normals and @p uv arrays with each
68 * vertex. If set to zero them each array is advanced according to its own size.
69 *
70 * @note
71 * Vertices should be split before calling this method if there are any discontinuities. (for example a vertex on a
72 * corner of a cube should be split into three vertices used by three triangles in order for the normals to be
73 * valid.)
74 */
75 static void calculateTangents(Vector3* vertices, Vector3* normals, Vector2* uv, UINT8* indices, UINT32 numVertices,
76 UINT32 numIndices, Vector3* tangents, Vector3* bitangents, UINT32 indexSize = 4, UINT32 vertexStride = 0);
77
78 /**
79 * Calculates per-vertex tangent space (normal, tangent, bitangent) based on the provided vertices, uv coordinates
80 * and indices.
81 *
82 * @param[in] vertices Set of vertices containing vertex positions.
83 * @param[in] uv Set of UV coordinates to use when calculating tangents.
84 * @param[in] indices Set of indices containing indexes into vertex array for each triangle.
85 * @param[in] numVertices Number of vertices in the "vertices" array.
86 * @param[in] numIndices Number of indices in the "indices" array. Must be a multiple of three.
87 * @param[out] normals Pre-allocated buffer that will contain the calculated normals. Must be the same size
88 * as the vertex array.
89 * @param[out] tangents Pre-allocated buffer that will contain the calculated tangents. Must be the same size
90 * as the vertex array.
91 * @param[out] bitangents Pre-allocated buffer that will contain the calculated bitangents. Must be the same size
92 * as the vertex array.
93 * @param[in] indexSize Size of a single index in the indices array, in bytes.
94 *
95 * @note
96 * Vertices should be split before calling this method if there are any discontinuities. (for example. a vertex on
97 * a corner of a cube should be split into three vertices used by three triangles in order for the normals to be
98 * valid.)
99 */
100 static void calculateTangentSpace(Vector3* vertices, Vector2* uv, UINT8* indices, UINT32 numVertices,
101 UINT32 numIndices, Vector3* normals, Vector3* tangents, Vector3* bitangents, UINT32 indexSize = 4);
102
103 /**
104 * Clips a set of two-dimensional vertices and uv coordinates against a set of arbitrary planes.
105 *
106 * @param[in] vertices A set of vertices in Vector2 format. Each vertex should be @p vertexStride bytes
107 * from each other.
108 * @param[in] uvs A set of UV coordinates in Vector2 format. Each coordinate should be
109 * @p vertexStride bytes from each other. Can be null if UV is not needed.
110 * @param[in] numTris Number of triangles to clip (must be number of vertices/uvs / 3).
111 * @param[in] vertexStride Distance in bytes between two separate vertex or UV values in the provided
112 * @p vertices and @p uvs buffers.
113 * @param[in] clipPlanes A set of planes to clip the vertices against. Since the vertices are
114 * two-dimensional the plane's Z coordinate should be zero.
115 * @param[in] writeCallback Callback that will be triggered when clipped vertices and UV coordinates are
116 * generated and need to be stored. Vertices are always generate in tuples of
117 * three, forming a single triangle.
118 */
119 static void clip2D(UINT8* vertices, UINT8* uvs, UINT32 numTris, UINT32 vertexStride, const Vector<Plane>& clipPlanes,
120 const std::function<void(Vector2*, Vector2*, UINT32)>& writeCallback);
121
122 /**
123 * Clips a set of three-dimensional vertices and uv coordinates against a set of arbitrary planes.
124 *
125 * @param[in] vertices A set of vertices in Vector3 format. Each vertex should be @p vertexStride bytes
126 * from each other.
127 * @param[in] uvs A set of UV coordinates in Vector2 format. Each coordinate should be
128 * @p vertexStride bytes from each other. Can be null if UV is not needed.
129 * @param[in] numTris Number of triangles to clip (must be number of vertices/uvs / 3).
130 * @param[in] vertexStride Distance in bytes between two separate vertex or UV values in the provided
131 * @p vertices and @p uvs buffers.
132 * @param[in] clipPlanes A set of planes to clip the vertices against.
133 * @param[in] writeCallback Callback that will be triggered when clipped vertices and UV coordinates are
134 * generated and need to be stored. Vertices are always generate in tuples of
135 * three, forming a single triangle.
136 */
137 static void clip3D(UINT8* vertices, UINT8* uvs, UINT32 numTris, UINT32 vertexStride, const Vector<Plane>& clipPlanes,
138 const std::function<void(Vector3*, Vector2*, UINT32)>& writeCallback);
139
140 /**
141 * Encodes normals from 32-bit float format into 4D 8-bit packed format.
142 *
143 * @param[in] source Buffer containing data to encode. Must have @p count entries.
144 * @param[out] destination Buffer to output the data to. Must have @p count entries, each 32-bits.
145 * @param[in] count Number of entries in the @p source and @p destination arrays.
146 * @param[in] inStride Distance between two entries in the @p source buffer, in bytes.
147 * @param[in] outStride Distance between two entries in the @p destination buffer, in bytes.
148 */
149 static void packNormals(Vector3* source, UINT8* destination, UINT32 count, UINT32 inStride, UINT32 outStride);
150
151 /**
152 * Encodes normals from 32-bit float format into 4D 8-bit packed format.
153 *
154 * @param[in] source Buffer containing data to encode. Must have @p count entries.
155 * @param[out] destination Buffer to output the data to. Must have @p count entries, each 32-bits.
156 * @param[in] count Number of entries in the @p source and @p destination arrays.
157 * @param[in] inStride Distance between two entries in the @p source buffer, in bytes.
158 * @param[in] outStride Distance between two entries in the @p destination buffer, in bytes.
159 */
160 static void packNormals(Vector4* source, UINT8* destination, UINT32 count, UINT32 inStride, UINT32 outStride);
161
162 /**
163 * Decodes normals from 4D 8-bit packed format into a 32-bit float format.
164 *
165 * @param[in] source Buffer containing data to encode. Must have @p count entries, each 32-bits.
166 * @param[out] destination Buffer to output the data to. Must have @p count entries.
167 * @param[in] count Number of entries in the @p source and @p destination arrays.
168 * @param[in] stride Distance between two entries in the @p source buffer, in bytes.
169 */
170 static void unpackNormals(UINT8* source, Vector3* destination, UINT32 count, UINT32 stride);
171
172 /**
173 * Decodes normals from 4D 8-bit packed format into a 32-bit float format.
174 *
175 * @param[in] source Buffer containing data to encode. Must have @p count entries, each 32-bits.
176 * @param[out] destination Buffer to output the data to. Must have @p count entries.
177 * @param[in] count Number of entries in the @p source and @p destination arrays.
178 * @param[in] stride Distance between two entries in the @p source buffer, in bytes.
179 */
180 static void unpackNormals(UINT8* source, Vector4* destination, UINT32 count, UINT32 stride);
181
182 /** Decodes a normal from 4D 8-bit packed format into a 32-bit float format. */
183 static Vector3 unpackNormal(const UINT8* source)
184 {
185 const PackedNormal& packed = *(PackedNormal*)source;
186 Vector3 output;
187
188 const float inv = (1.0f / 255.0f) * 2.0f;
189 output.x = (packed.x * inv - 1.0f);
190 output.y = (packed.y * inv - 1.0f);
191 output.z = (packed.z * inv - 1.0f);
192
193 return output;
194 }
195 };
196
197 /** @} */
198}
199