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 
23 #include "Platform.h"
24 #include "Mathematics.h"
25 
26 #include <cassert>
27 
28 namespace MaliSDK
29 {
30  void TorusModel::generateNormals(unsigned int circlesCount, unsigned int pointsPerCircleCount, float* normals)
31  {
32  unsigned int normalSize = 3;
33  unsigned int index = 0;
34 
35  for (unsigned int horizontalIndex = 0; horizontalIndex < circlesCount; ++horizontalIndex)
36  {
37  /* Angle in radians on XZ plane. */
38  float phi = (float) horizontalIndex * 2.0f * M_PI / circlesCount;
39 
40  Vec3f horizontalTangent = {-sinf(phi), 0.0f, cosf(phi)};
41 
42  for (unsigned int verticalIndex = 0; verticalIndex < pointsPerCircleCount; ++verticalIndex)
43  {
44  /* Angle in radians on XY plane. */
45  float theta = (float) verticalIndex * 2.0f * M_PI / pointsPerCircleCount;
46 
47  Vec3f verticalTangent = {-cosf(phi) * sinf(theta), cosf(theta), -sinf(phi) * sinf(theta)};
48 
49  assert(index < circlesCount * pointsPerCircleCount * normalSize);
50 
51  normals[index++] = horizontalTangent.z * verticalTangent.y - horizontalTangent.y * verticalTangent.z;
52  normals[index++] = horizontalTangent.x * verticalTangent.z - horizontalTangent.z * verticalTangent.x;
53  normals[index++] = horizontalTangent.y * verticalTangent.x - horizontalTangent.x * verticalTangent.y;
54  }
55  }
56  }
57 
58  void TorusModel::calculateControlPointsIndices(unsigned int patchDimension, unsigned int patchInstancesCount, unsigned int controlPointsIndicesCount, unsigned int* controlPointsIndices)
59  {
60  if (controlPointsIndices == NULL)
61  {
62  LOGE("Cannot use null pointer while calculating control points indices.");
63 
64  return;
65  }
66 
67  /* Definition of needed constants. Torus continuity cannot be guaranteed with other parameters. */
68  const unsigned int pointsPerCircleCount = 12;
69  const unsigned int circlesCount = 12;
70  const unsigned int torusVerticesCount = pointsPerCircleCount * circlesCount;
71 
72  /* Index of a vertex from which a patch starts. */
73  unsigned int startIndex = 0;
74  /* Index of a circle from which vertex indices are currently taken. */
75  unsigned int currentCircle = 0;
76 
77  /* Index variable. */
78  unsigned int index = 0;
79 
80  /* Loop that creates patches for each instance of patch primitives. Successive patches wrap around torus horizontally. */
81  for (unsigned int instanceIndex = 0; instanceIndex < patchInstancesCount; ++instanceIndex)
82  {
83  /* Iterate in horizontal axis. */
84  for (unsigned int x = 0; x < patchDimension; ++x)
85  {
86  /* Determine index of current circle from which the vertex indices are taken. */
87  currentCircle = startIndex / pointsPerCircleCount;
88 
89  /* Iterate in vertical axis. */
90  for (unsigned int y = 0; y < patchDimension; ++y)
91  {
92  unsigned int currentIndex = startIndex + y;
93 
94  /* Make closing patches end up at the very first vertex of each circle. */
95  if (currentIndex >= pointsPerCircleCount * (currentCircle + 1))
96  {
97  currentIndex -= pointsPerCircleCount;
98  }
99 
100  controlPointsIndices[index++] = currentIndex;
101 
102  assert(index <= controlPointsIndicesCount);
103  }
104 
105  /* Get indices from the next circle. */
106  startIndex += pointsPerCircleCount;
107 
108  /* Make closing patches end up at the very first circle. */
109  if (startIndex >= torusVerticesCount)
110  {
111  startIndex -= torusVerticesCount;
112  }
113  }
114 
115  /* Neighbouring patches always share one edge, so start index of the next patch should start from the last column of the previous patch. */
116  startIndex -= pointsPerCircleCount;
117 
118  /* When the whole row is finished, move to the next one. */
119  if (currentCircle == 0)
120  {
121  startIndex += patchDimension - 1;
122  }
123  }
124  }
125  void TorusModel::calculatePatchData(unsigned int patchDensity, float* patchVertices, unsigned int* patchTriangleIndices)
126  {
127  if (patchVertices == NULL || patchTriangleIndices == NULL)
128  {
129  LOGE("Cannot use null pointers while calculating patch data.");
130 
131  return;
132  }
133 
134  /* Total number of components describing a patch (only U/V components are definied). */
135  const unsigned int patchComponentsCount = patchDensity * patchDensity * 2;
136  /* Number of indices that needs to be defined to draw quads consisted of triangles (6 points per quad needed) over the entire patch. */
137  const unsigned int patchTriangleIndicesCount = (patchDensity - 1) * (patchDensity - 1) * 6;
138 
139  /* Number of components in a single vertex. */
140  const unsigned int uvComponentsCount = 2;
141  /* Number of vertices needed to draw a quad as two separate triangles. */
142  const unsigned int verticesPerQuadCount = 6;
143 
144  /* Current index of a patch vertex. */
145  unsigned int uvIndex = 0;
146  /* Current index for indices array. */
147  unsigned int triangleVertexIndex = 0;
148 
149  for (unsigned int x = 0; x < patchDensity; ++x)
150  {
151  /* Horizontal component. */
152  float u = (float) x / (patchDensity - 1);
153 
154  for (unsigned int y = 0; y < patchDensity; ++y)
155  {
156  /* Vertical component. */
157  float v = (float) y / (patchDensity - 1);
158 
159  patchVertices[uvIndex++] = u;
160  patchVertices[uvIndex++] = v;
161 
162  assert(uvIndex <= patchComponentsCount);
163  }
164  }
165 
166  /*
167  * Indices are determined in the following manner:
168  *
169  * 0 -> 1 -> 16 -> 16 -> 1 -> 17 -> 1 -> 2 -> 17 -> 17 -> 2 -> 18 -> ...
170  *
171  * 2----18----34---...
172  * | / | / |
173  * | / | / |
174  * 1----17----33---...
175  * | / | / |
176  * | / | / |
177  * 0----16----32----...
178  */
179  for (unsigned int x = 0; x < patchDensity - 1; ++x)
180  {
181  for (unsigned int y = 0; y < patchDensity - 1; ++y)
182  {
183  patchTriangleIndices[triangleVertexIndex++] = patchDensity * x + y;
184  patchTriangleIndices[triangleVertexIndex++] = patchDensity * x + y + 1;
185  patchTriangleIndices[triangleVertexIndex++] = patchDensity * (x + 1) + y;
186 
187  patchTriangleIndices[triangleVertexIndex++] = patchDensity * (x + 1) + y;
188  patchTriangleIndices[triangleVertexIndex++] = patchDensity * x + y + 1;
189  patchTriangleIndices[triangleVertexIndex++] = patchDensity * (x + 1) + y + 1;
190 
191  assert(triangleVertexIndex <= patchTriangleIndicesCount);
192  }
193  }
194  }
195 
196  void TorusModel::calculateWireframeIndices(unsigned int circlesCount, unsigned int pointsPerCircleCount, unsigned int* indices)
197  {
198  const unsigned int torusVerticesCount = circlesCount * pointsPerCircleCount;
199 
200  for (unsigned int i = 0; i < circlesCount; ++i)
201  {
202  for (unsigned int j = 0; j < pointsPerCircleCount; ++j)
203  {
204  /* Starting point for vertical and horizontal lines. */
205  unsigned int lineStart = i * pointsPerCircleCount + j;
206  /* Horiznotal end of the currently determined line. */
207  unsigned int horizontalEnd = (i + 1) * pointsPerCircleCount + j;
208  /* Vertical end of the currently determined line. */
209  unsigned int verticalEnd = i * pointsPerCircleCount + j + 1;
210 
211  /* From the last circle, horizontal lines go to the first one. */
212  if (horizontalEnd >= torusVerticesCount)
213  {
214  horizontalEnd -= torusVerticesCount;
215  }
216 
217  /* From the last point in the circle, vertical lines go to the first one. */
218  if (verticalEnd >= (i + 1) * pointsPerCircleCount)
219  {
220  verticalEnd -= pointsPerCircleCount;
221  }
222 
223  /* Determine horizontal line indices. */
224  indices[(i * pointsPerCircleCount + j) * 4 ] = lineStart;
225  indices[(i * pointsPerCircleCount + j) * 4 + 1] = horizontalEnd;
226 
227  /* Determine vertical line indices. */
228  indices[(i * pointsPerCircleCount + j) * 4 + 2] = lineStart;
229  indices[(i * pointsPerCircleCount + j) * 4 + 3] = verticalEnd;
230  }
231  }
232  }
233 
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 
268  void TorusModel::calculateTriangleStripIndices(unsigned int circlesCount, unsigned int pointsPerCircleCount, unsigned int* indices)
269  {
270  const unsigned int torusVerticesCount = circlesCount * pointsPerCircleCount;
271  const unsigned int torusIndicesCount = (2 * circlesCount + 1) * pointsPerCircleCount + 1;
272 
273  unsigned int counter = 0;
274  unsigned int currentIndex = 0;
275 
276  indices[counter++] = currentIndex;
277 
278  bool isLastStrip = false;
279 
280  for (unsigned int stripIndex = 0; stripIndex < pointsPerCircleCount; ++stripIndex)
281  {
282  assert(currentIndex == stripIndex);
283 
284  /* Set initial index for the current strip. */
285  currentIndex += 1;
286 
287  isLastStrip = currentIndex >= pointsPerCircleCount;
288 
289  assert(counter < torusIndicesCount);
290 
291  indices[counter++] = isLastStrip ? (currentIndex - pointsPerCircleCount) : currentIndex;
292 
293  for (unsigned int circleIndex = 0; circleIndex < circlesCount; ++circleIndex)
294  {
295  currentIndex = currentIndex + pointsPerCircleCount - 1;
296 
297  if (currentIndex >= torusVerticesCount)
298  {
299  currentIndex -= torusVerticesCount;
300  }
301 
302  assert(counter < torusIndicesCount);
303 
304  indices[counter++] = currentIndex;
305 
306  currentIndex += 1;
307 
308  assert(counter < torusIndicesCount);
309 
310  indices[counter++] = isLastStrip ? currentIndex - pointsPerCircleCount : currentIndex;
311  }
312  }
313  }
314 
315  void TorusModel::generateBezierVertices(float torusRadius, float circleRadius, float* vertices)
316  {
317  if (vertices == NULL)
318  {
319  LOGE("Cannot use null pointer while calculating torus vertices.");
320 
321  return;
322  }
323 
324  /* Coefficient relating radius of a circle to the distance between middle patch control point and the closest edge point. */
325  const float kappa = 4.0f * (sqrtf(2.0f) - 1.0f) / 3.0f;
326  /* Angle between circle radius connecting a patch edge point and a line segment connecting the circle center and a middle patch control point. */
327  const float alpha = atanf(kappa);
328  /* Length of a line segment connecting circle center and a middle control point. */
329  const float distortedCircleRadius = circleRadius * sqrt(1.0f + kappa * kappa);
330  /* Length of a line segment connecting torus center and a middle control poin. */
331  const float distortedTorusRadius = torusRadius * sqrt(1.0f + kappa * kappa);
332  /* Each circle is divided into 4 quadrants to simplify calculations. */
333  const int quadrantsCount = 4;
334  /* Number of circles in torus model. */
335  const int circlesCount = 12;
336  /* Number of points in one circle. */
337  const int pointsPerCircleCount = 12;
338 
339  /* Angle in horizontal plane XZ, used only to point on edge points. */
340  float phi = 0.0f;
341  /* Angle in vertical plane XY, used only to point on edge points. */
342  float theta = 0.0f;
343 
344  /* Index of currently calculated component. */
345  unsigned int componentIndex = 0;
346 
347  /* Iterate through all circles. */
348  for (int horizontalIndex = 0; horizontalIndex < circlesCount; ++horizontalIndex)
349  {
350  /* Index of a circle in a torus quadrant. */
351  const int currentCircleModulo = horizontalIndex % (quadrantsCount - 1);
352 
353  /* Temporary variables holding current values of radii and angles. */
354  float currentTorusRadius;
355  float currentCircleRadius;
356  float currentPhi;
357  float currentTheta;
358 
359  switch (currentCircleModulo)
360  {
361  case 0:
362  /* Edge points take non-distorted parameters. */
363  currentTorusRadius = torusRadius;
364  currentPhi = phi;
365  break;
366  case 1:
367  /* 1st middle point. Angle value is related to the angle of preceding edge point. */
368  currentTorusRadius = distortedTorusRadius;
369  currentPhi = phi + alpha;
370  break;
371  case 2:
372  /* Second middle point. Angle value is related to the angle of the following edge point. */
373  phi = (float) (horizontalIndex + 1) * M_PI / (2 * (quadrantsCount - 1));
374  currentTorusRadius = distortedTorusRadius;
375  currentPhi = phi - alpha;
376  break;
377  }
378 
379  for (int verticalIndex = 0; verticalIndex < pointsPerCircleCount; ++verticalIndex)
380  {
381  /* Index of a point in a circle quadrant. */
382  const int currentPointModulo = verticalIndex % (quadrantsCount - 1);
383 
384  switch (currentPointModulo)
385  {
386  case 0:
387  /* Edge points take non-distorted parameters. */
388  currentCircleRadius = circleRadius;
389  currentTheta = theta;
390  break;
391  case 1:
392  /* 1st middle point. Angle value is related to the angle of preceding edge point. */
393  currentCircleRadius = distortedCircleRadius;
394  currentTheta = theta + alpha;
395  break;
396  case 2:
397  /* Second middle point. Angle value is related to the angle of the following edge point. */
398  theta = (float) (verticalIndex + 1) * M_PI / (2 * (quadrantsCount - 1));
399  currentCircleRadius = distortedCircleRadius;
400  currentTheta = theta - alpha;
401  }
402 
403  /* Store values in the array. */
404  vertices[componentIndex++] = (currentTorusRadius + currentCircleRadius * cosf(currentTheta)) * cosf(currentPhi);
405  vertices[componentIndex++] = currentCircleRadius * sinf(currentTheta);
406  vertices[componentIndex++] = (currentTorusRadius + currentCircleRadius * cosf(currentTheta)) * sinf(currentPhi);
407  vertices[componentIndex++] = 1.0f;
408  }
409  }
410  }
411 }
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
A 3D floating point vector.
Definition: VectorTypes.h:83
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
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