OpenGL ES SDK for Android ARM Developer Center
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TorusModel.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2012-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "TorusModel.h"
22 #include "Common.h"
23 #include "Mathematics.h"
24 
25 #include <cassert>
26 
27 namespace MaliSDK
28 {
29  void TorusModel::generateNormals(unsigned int circlesCount, unsigned int pointsPerCircleCount, float* normals)
30  {
31  unsigned int normalSize = 3;
32  unsigned int index = 0;
33 
34  for (unsigned int horizontalIndex = 0; horizontalIndex < circlesCount; ++horizontalIndex)
35  {
36  /* Angle in radians on XZ plane. */
37  float phi = (float) horizontalIndex * 2.0f * M_PI / circlesCount;
38 
39  Vec3f horizontalTangent = {-sinf(phi), 0.0f, cosf(phi)};
40 
41  for (unsigned int verticalIndex = 0; verticalIndex < pointsPerCircleCount; ++verticalIndex)
42  {
43  /* Angle in radians on XY plane. */
44  float theta = (float) verticalIndex * 2.0f * M_PI / pointsPerCircleCount;
45 
46  Vec3f verticalTangent = {-cosf(phi) * sinf(theta), cosf(theta), -sinf(phi) * sinf(theta)};
47 
48  assert(index < circlesCount * pointsPerCircleCount * normalSize);
49 
50  normals[index++] = horizontalTangent.z * verticalTangent.y - horizontalTangent.y * verticalTangent.z;
51  normals[index++] = horizontalTangent.x * verticalTangent.z - horizontalTangent.z * verticalTangent.x;
52  normals[index++] = horizontalTangent.y * verticalTangent.x - horizontalTangent.x * verticalTangent.y;
53  }
54  }
55  }
56 
57  void TorusModel::calculateControlPointsIndices(unsigned int patchDimension, unsigned int patchInstancesCount, unsigned int controlPointsIndicesCount, unsigned int* controlPointsIndices)
58  {
59  if (controlPointsIndices == NULL)
60  {
61  LOGE("Cannot use null pointer while calculating control points indices.");
62 
63  return;
64  }
65 
66  /* Definition of needed constants. Torus continuity cannot be guaranteed with other parameters. */
67  const unsigned int pointsPerCircleCount = 12;
68  const unsigned int circlesCount = 12;
69  const unsigned int torusVerticesCount = pointsPerCircleCount * circlesCount;
70 
71  /* Index of a vertex from which a patch starts. */
72  unsigned int startIndex = 0;
73  /* Index of a circle from which vertex indices are currently taken. */
74  unsigned int currentCircle = 0;
75 
76  /* Index variable. */
77  unsigned int index = 0;
78 
79  /* Loop that creates patches for each instance of patch primitives. Successive patches wrap around torus horizontally. */
80  for (unsigned int instanceIndex = 0; instanceIndex < patchInstancesCount; ++instanceIndex)
81  {
82  /* Iterate in horizontal axis. */
83  for (unsigned int x = 0; x < patchDimension; ++x)
84  {
85  /* Determine index of current circle from which the vertex indices are taken. */
86  currentCircle = startIndex / pointsPerCircleCount;
87 
88  /* Iterate in vertical axis. */
89  for (unsigned int y = 0; y < patchDimension; ++y)
90  {
91  unsigned int currentIndex = startIndex + y;
92 
93  /* Make closing patches end up at the very first vertex of each circle. */
94  if (currentIndex >= pointsPerCircleCount * (currentCircle + 1))
95  {
96  currentIndex -= pointsPerCircleCount;
97  }
98 
99  controlPointsIndices[index++] = currentIndex;
100 
101  assert(index <= controlPointsIndicesCount);
102  }
103 
104  /* Get indices from the next circle. */
105  startIndex += pointsPerCircleCount;
106 
107  /* Make closing patches end up at the very first circle. */
108  if (startIndex >= torusVerticesCount)
109  {
110  startIndex -= torusVerticesCount;
111  }
112  }
113 
114  /* Neighbouring patches always share one edge, so start index of the next patch should start from the last column of the previous patch. */
115  startIndex -= pointsPerCircleCount;
116 
117  /* When the whole row is finished, move to the next one. */
118  if (currentCircle == 0)
119  {
120  startIndex += patchDimension - 1;
121  }
122  }
123  }
124  void TorusModel::calculatePatchData(unsigned int patchDensity, float* patchVertices, unsigned int* patchTriangleIndices)
125  {
126  if (patchVertices == NULL || patchTriangleIndices == NULL)
127  {
128  LOGE("Cannot use null pointers while calculating patch data.");
129 
130  return;
131  }
132 
133  /* Total number of components describing a patch (only U/V components are definied). */
134  const unsigned int patchComponentsCount = patchDensity * patchDensity * 2;
135  /* Number of indices that needs to be defined to draw quads consisted of triangles (6 points per quad needed) over the entire patch. */
136  const unsigned int patchTriangleIndicesCount = (patchDensity - 1) * (patchDensity - 1) * 6;
137 
138  /* Number of components in a single vertex. */
139  const unsigned int uvComponentsCount = 2;
140  /* Number of vertices needed to draw a quad as two separate triangles. */
141  const unsigned int verticesPerQuadCount = 6;
142 
143  /* Current index of a patch vertex. */
144  unsigned int uvIndex = 0;
145  /* Current index for indices array. */
146  unsigned int triangleVertexIndex = 0;
147 
148  for (unsigned int x = 0; x < patchDensity; ++x)
149  {
150  /* Horizontal component. */
151  float u = (float) x / (patchDensity - 1);
152 
153  for (unsigned int y = 0; y < patchDensity; ++y)
154  {
155  /* Vertical component. */
156  float v = (float) y / (patchDensity - 1);
157 
158  patchVertices[uvIndex++] = u;
159  patchVertices[uvIndex++] = v;
160 
161  assert(uvIndex <= patchComponentsCount);
162  }
163  }
164 
165  /*
166  * Indices are determined in the following manner:
167  *
168  * 0 -> 1 -> 16 -> 16 -> 1 -> 17 -> 1 -> 2 -> 17 -> 17 -> 2 -> 18 -> ...
169  *
170  * 2----18----34---...
171  * | / | / |
172  * | / | / |
173  * 1----17----33---...
174  * | / | / |
175  * | / | / |
176  * 0----16----32----...
177  */
178  for (unsigned int x = 0; x < patchDensity - 1; ++x)
179  {
180  for (unsigned int y = 0; y < patchDensity - 1; ++y)
181  {
182  patchTriangleIndices[triangleVertexIndex++] = patchDensity * x + y;
183  patchTriangleIndices[triangleVertexIndex++] = patchDensity * x + y + 1;
184  patchTriangleIndices[triangleVertexIndex++] = patchDensity * (x + 1) + y;
185 
186  patchTriangleIndices[triangleVertexIndex++] = patchDensity * (x + 1) + y;
187  patchTriangleIndices[triangleVertexIndex++] = patchDensity * x + y + 1;
188  patchTriangleIndices[triangleVertexIndex++] = patchDensity * (x + 1) + y + 1;
189 
190  assert(triangleVertexIndex <= patchTriangleIndicesCount);
191  }
192  }
193  }
194 
195  void TorusModel::calculateWireframeIndices(unsigned int circlesCount, unsigned int pointsPerCircleCount, unsigned int* indices)
196  {
197  const unsigned int torusVerticesCount = circlesCount * pointsPerCircleCount;
198 
199  for (unsigned int i = 0; i < circlesCount; ++i)
200  {
201  for (unsigned int j = 0; j < pointsPerCircleCount; ++j)
202  {
203  /* Starting point for vertical and horizontal lines. */
204  unsigned int lineStart = i * pointsPerCircleCount + j;
205  /* Horiznotal end of the currently determined line. */
206  unsigned int horizontalEnd = (i + 1) * pointsPerCircleCount + j;
207  /* Vertical end of the currently determined line. */
208  unsigned int verticalEnd = i * pointsPerCircleCount + j + 1;
209 
210  /* From the last circle, horizontal lines go to the first one. */
211  if (horizontalEnd >= torusVerticesCount)
212  {
213  horizontalEnd -= torusVerticesCount;
214  }
215 
216  /* From the last point in the circle, vertical lines go to the first one. */
217  if (verticalEnd >= (i + 1) * pointsPerCircleCount)
218  {
219  verticalEnd -= pointsPerCircleCount;
220  }
221 
222  /* Determine horizontal line indices. */
223  indices[(i * pointsPerCircleCount + j) * 4 ] = lineStart;
224  indices[(i * pointsPerCircleCount + j) * 4 + 1] = horizontalEnd;
225 
226  /* Determine vertical line indices. */
227  indices[(i * pointsPerCircleCount + j) * 4 + 2] = lineStart;
228  indices[(i * pointsPerCircleCount + j) * 4 + 3] = verticalEnd;
229  }
230  }
231  }
232 
233  /* [Generate torus model vertex coordinates] */
234  void TorusModel::generateVertices(float torusRadius, float circleRadius, unsigned int circlesCount, unsigned int pointsPerCircleCount, float* vertices)
235  {
236  if (vertices == NULL)
237  {
238  LOGE("Cannot use null pointer while calculating torus vertices.");
239 
240  return;
241  }
242 
243  /* Index variable. */
244  unsigned int componentIndex = 0;
245 
246  for (unsigned int horizontalIndex = 0; horizontalIndex < circlesCount; ++horizontalIndex)
247  {
248  /* Angle in radians on XZ plane. */
249  float xyAngle = (float) horizontalIndex * 2.0f * M_PI / circlesCount;
250 
251  for (unsigned int verticalIndex = 0; verticalIndex < pointsPerCircleCount; ++verticalIndex)
252  {
253  /* Angle in radians on XY plane. */
254  float theta = (float) verticalIndex * 2.0f * M_PI / pointsPerCircleCount;
255 
256  /* X coordinate. */
257  vertices[componentIndex++] = (torusRadius + circleRadius * cosf(theta)) * cosf(xyAngle);
258  /* Y coordinate. */
259  vertices[componentIndex++] = circleRadius * sinf(theta);
260  /* Z coordinate. */
261  vertices[componentIndex++] = (torusRadius + circleRadius * cosf(theta)) * sinf(xyAngle);
262  /* W coordinate. */
263  vertices[componentIndex++] = 1.0f;
264  }
265  }
266  }
267  /* [Generate torus model vertex coordinates] */
268 
269  void TorusModel::calculateTriangleStripIndices(unsigned int circlesCount, unsigned int pointsPerCircleCount, unsigned int* indices)
270  {
271  const unsigned int torusVerticesCount = circlesCount * pointsPerCircleCount;
272  const unsigned int torusIndicesCount = (2 * circlesCount + 1) * pointsPerCircleCount + 1;
273 
274  unsigned int counter = 0;
275  unsigned int currentIndex = 0;
276 
277  indices[counter++] = currentIndex;
278 
279  bool isLastStrip = false;
280 
281  for (unsigned int stripIndex = 0; stripIndex < pointsPerCircleCount; ++stripIndex)
282  {
283  assert(currentIndex == stripIndex);
284 
285  /* Set initial index for the current strip. */
286  currentIndex += 1;
287 
288  isLastStrip = currentIndex >= pointsPerCircleCount;
289 
290  assert(counter < torusIndicesCount);
291 
292  indices[counter++] = isLastStrip ? (currentIndex - pointsPerCircleCount) : currentIndex;
293 
294  for (unsigned int circleIndex = 0; circleIndex < circlesCount; ++circleIndex)
295  {
296  currentIndex = currentIndex + pointsPerCircleCount - 1;
297 
298  if (currentIndex >= torusVerticesCount)
299  {
300  currentIndex -= torusVerticesCount;
301  }
302 
303  assert(counter < torusIndicesCount);
304 
305  indices[counter++] = currentIndex;
306 
307  currentIndex += 1;
308 
309  assert(counter < torusIndicesCount);
310 
311  indices[counter++] = isLastStrip ? currentIndex - pointsPerCircleCount : currentIndex;
312  }
313  }
314  }
315 
316  void TorusModel::generateBezierVertices(float torusRadius, float circleRadius, float* vertices)
317  {
318  if (vertices == NULL)
319  {
320  LOGE("Cannot use null pointer while calculating torus vertices.");
321 
322  return;
323  }
324 
325  /* Coefficient relating radius of a circle to the distance between middle patch control point and the closest edge point. */
326  const float kappa = 4.0f * (sqrtf(2.0f) - 1.0f) / 3.0f;
327  /* Angle between circle radius connecting a patch edge point and a line segment connecting the circle center and a middle patch control point. */
328  const float alpha = atanf(kappa);
329  /* Length of a line segment connecting circle center and a middle control point. */
330  const float distortedCircleRadius = circleRadius * sqrt(1.0f + kappa * kappa);
331  /* Length of a line segment connecting torus center and a middle control poin. */
332  const float distortedTorusRadius = torusRadius * sqrt(1.0f + kappa * kappa);
333  /* Each circle is divided into 4 quadrants to simplify calculations. */
334  const int quadrantsCount = 4;
335  /* Number of circles in torus model. */
336  const int circlesCount = 12;
337  /* Number of points in one circle. */
338  const int pointsPerCircleCount = 12;
339 
340  /* Angle in horizontal plane XZ, used only to point on edge points. */
341  float phi = 0.0f;
342  /* Angle in vertical plane XY, used only to point on edge points. */
343  float theta = 0.0f;
344 
345  /* Index of currently calculated component. */
346  unsigned int componentIndex = 0;
347 
348  /* Iterate through all circles. */
349  for (int horizontalIndex = 0; horizontalIndex < circlesCount; ++horizontalIndex)
350  {
351  /* Index of a circle in a torus quadrant. */
352  const int currentCircleModulo = horizontalIndex % (quadrantsCount - 1);
353 
354  /* Temporary variables holding current values of radii and angles. */
355  float currentTorusRadius;
356  float currentCircleRadius;
357  float currentPhi;
358  float currentTheta;
359 
360  switch (currentCircleModulo)
361  {
362  case 0:
363  /* Edge points take non-distorted parameters. */
364  currentTorusRadius = torusRadius;
365  currentPhi = phi;
366  break;
367  case 1:
368  /* 1st middle point. Angle value is related to the angle of preceding edge point. */
369  currentTorusRadius = distortedTorusRadius;
370  currentPhi = phi + alpha;
371  break;
372  case 2:
373  /* Second middle point. Angle value is related to the angle of the following edge point. */
374  phi = (float) (horizontalIndex + 1) * M_PI / (2 * (quadrantsCount - 1));
375  currentTorusRadius = distortedTorusRadius;
376  currentPhi = phi - alpha;
377  break;
378  }
379 
380  for (int verticalIndex = 0; verticalIndex < pointsPerCircleCount; ++verticalIndex)
381  {
382  /* Index of a point in a circle quadrant. */
383  const int currentPointModulo = verticalIndex % (quadrantsCount - 1);
384 
385  switch (currentPointModulo)
386  {
387  case 0:
388  {
389  /* Edge points take non-distorted parameters. */
390  currentCircleRadius = circleRadius;
391  currentTheta = theta;
392  break;
393  }
394  case 1:
395  {
396  /* 1st middle point. Angle value is related to the angle of preceding edge point. */
397  currentCircleRadius = distortedCircleRadius;
398  currentTheta = theta + alpha;
399  break;
400  }
401  case 2:
402  {
403  /* Second middle point. Angle value is related to the angle of the following edge point. */
404  theta = (float) (verticalIndex + 1) * M_PI / (2 * (quadrantsCount - 1));
405  currentCircleRadius = distortedCircleRadius;
406  currentTheta = theta - alpha;
407  break;
408  }
409  }
410 
411  /* Store values in the array. */
412  vertices[componentIndex++] = (currentTorusRadius + currentCircleRadius * cosf(currentTheta)) * cosf(currentPhi);
413  vertices[componentIndex++] = currentCircleRadius * sinf(currentTheta);
414  vertices[componentIndex++] = (currentTorusRadius + currentCircleRadius * cosf(currentTheta)) * sinf(currentPhi);
415  vertices[componentIndex++] = 1.0f;
416  }
417  }
418  }
419 }
const GLfloat * v
Definition: gl2ext.h:2231
static void calculateControlPointsIndices(unsigned int patchDimension, unsigned int patchInstancesCount, unsigned int controlPointsIndicesCount, unsigned int *controlPointsIndices)
Determines an array of indices defining a mesh of control points for instanced torus patches...
Definition: TorusModel.cpp:58
float phi(vec3 p)
Definition: update.cs:59
static void calculateTriangleStripIndices(unsigned int circlesCount, unsigned int pointsPerCircleCount, unsigned int *indices)
Determines indices for DrawElements() call for shaded torus drawn in triangle strip mode...
Definition: TorusModel.cpp:268
const float vertices[]
Definition: Cube.h:30
GLuint counter
Definition: gl2ext.h:776
static void generateNormals(unsigned int circlesCount, unsigned int pointsPerCircleCount, float *normals)
Generates torus's normal vectors.
Definition: TorusModel.cpp:30
static void generateBezierVertices(float torusRadius, float circleRadius, float *vertices)
Generate torus vertices applying distortions to some of them.
Definition: TorusModel.cpp:315
GLuint index
Definition: gl2ext.h:300
static void calculateWireframeIndices(unsigned int circlesCount, unsigned int pointsPerCircleCount, unsigned int *indices)
Determines indices for glDrawElements() call for wireframed torus.
Definition: TorusModel.cpp:196
static void generateVertices(float torusRadius, float circleRadius, unsigned int circlesCount, unsigned int pointsPerCircleCount, float *vertices)
Generate vertices of the torus model.
Definition: TorusModel.cpp:234
GLsizei GLenum const void * indices
Definition: gl2ext.h:322
Mathematic functions.
GLfloat GLfloat f
Definition: gl2ext.h:2707
#define M_PI
The value of pi.
Definition: Mathematics.h:37
GLint GLint GLint GLint GLint x
Definition: gl2ext.h:574
#define LOGE(...)
Definition: AstcTextures.h:30
precision highp float
Definition: hiz_cull.cs:37
static void calculatePatchData(unsigned int patchDensity, float *patchVertices, unsigned int *patchTriangleIndices)
Determines patch data for an instanced torus model.
Definition: TorusModel.cpp:125
GLint y
Definition: gl2ext.h:179
GLfloat normals[]
Definition: Native.cpp:283