1/*
2 * fg_teapot.c
3 *
4 * Teapot(tm) rendering code.
5 *
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Creation date: Fri Dec 24 1999
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28/* notes:
29 * the (very little) required math is found here: http://www.gamasutra.com/view/feature/131848/tessellation_of_4x4_bezier_patches_.php?print=1
30 * a much more optimized version is here, didn't bother to implement that: http://www.gamasutra.com/view/feature/131794/an_indepth_look_at_bicubic_bezier_.php?print=1
31 */
32
33#include <GL/freeglut.h>
34#include "fg_internal.h"
35#include "fg_teapot_data.h"
36
37/* -- STATIC VARS: CACHES ---------------------------------------------------- */
38
39/* General defs */
40#define GLUT_SOLID_N_SUBDIV 8
41#define GLUT_WIRE_N_SUBDIV 10
42
43/* Bernstein coefficients only have to be precomputed once (number of patch subdivisions is fixed)
44 * Can thus define arrays for them here, they will be filled upon first use.
45 * 3rd order Bezier surfaces have 4 Bernstein coeffs.
46 * Have separate caches for solid and wire as they use a different number of subdivisions
47 * _0 is for Bernstein polynomials, _1 for their first derivative (which we need for normals)
48 */
49static GLfloat bernWire_0 [GLUT_WIRE_N_SUBDIV] [4];
50static GLfloat bernWire_1 [GLUT_WIRE_N_SUBDIV] [4];
51static GLfloat bernSolid_0[GLUT_SOLID_N_SUBDIV][4];
52static GLfloat bernSolid_1[GLUT_SOLID_N_SUBDIV][4];
53
54/* Teapot defs */
55#define GLUT_TEAPOT_N_PATCHES (6*4 + 4*2) /* 6 patches are reproduced (rotated) 4 times, 4 patches (flipped) 2 times */
56#define GLUT_SOLID_TEAPOT_N_VERT GLUT_SOLID_N_SUBDIV*GLUT_SOLID_N_SUBDIV * GLUT_TEAPOT_N_PATCHES /* N_SUBDIV^2 vertices per patch */
57#define GLUT_SOLID_TEAPOT_N_TRI (GLUT_SOLID_N_SUBDIV-1)*(GLUT_SOLID_N_SUBDIV-1) * GLUT_TEAPOT_N_PATCHES * 2 /* if e.g. 7x7 vertices for each patch, there are 6*6 squares for each patch. Each square is decomposed into 2 triangles */
58
59#define GLUT_WIRE_TEAPOT_N_VERT GLUT_WIRE_N_SUBDIV*GLUT_WIRE_N_SUBDIV * GLUT_TEAPOT_N_PATCHES /* N_SUBDIV^2 vertices per patch */
60
61/* Bit of caching:
62 * vertex indices and normals only need to be generated once for
63 * a given number of subdivisions as they don't change with scale.
64 * Vertices can be cached and reused if scale didn't change.
65 */
66static GLushort vertIdxsTeapotS[GLUT_SOLID_TEAPOT_N_TRI*3];
67static GLfloat normsTeapotS [GLUT_SOLID_TEAPOT_N_VERT*3];
68static GLfloat vertsTeapotS [GLUT_SOLID_TEAPOT_N_VERT*3];
69static GLfloat texcsTeapotS [GLUT_SOLID_TEAPOT_N_VERT*2];
70static GLfloat lastScaleTeapotS = 0.f;
71static GLboolean initedTeapotS = GL_FALSE;
72
73static GLushort vertIdxsTeapotW[GLUT_WIRE_TEAPOT_N_VERT*2];
74static GLfloat normsTeapotW [GLUT_WIRE_TEAPOT_N_VERT*3];
75static GLfloat vertsTeapotW [GLUT_WIRE_TEAPOT_N_VERT*3];
76static GLfloat lastScaleTeapotW = 0.f;
77static GLboolean initedTeapotW = GL_FALSE;
78
79
80/* Teacup defs */
81#define GLUT_TEACUP_N_PATCHES (6*4 + 1*2) /* 6 patches are reproduced (rotated) 4 times, 1 patch (flipped) 2 times */
82#define GLUT_SOLID_TEACUP_N_VERT GLUT_SOLID_N_SUBDIV*GLUT_SOLID_N_SUBDIV * GLUT_TEACUP_N_PATCHES /* N_SUBDIV^2 vertices per patch */
83#define GLUT_SOLID_TEACUP_N_TRI (GLUT_SOLID_N_SUBDIV-1)*(GLUT_SOLID_N_SUBDIV-1) * GLUT_TEACUP_N_PATCHES * 2 /* if e.g. 7x7 vertices for each patch, there are 6*6 squares for each patch. Each square is decomposed into 2 triangles */
84
85#define GLUT_WIRE_TEACUP_N_VERT GLUT_WIRE_N_SUBDIV*GLUT_WIRE_N_SUBDIV * GLUT_TEACUP_N_PATCHES /* N_SUBDIV^2 vertices per patch */
86
87/* Bit of caching:
88 * vertex indices and normals only need to be generated once for
89 * a given number of subdivisions as they don't change with scale.
90 * Vertices can be cached and reused if scale didn't change.
91 */
92static GLushort vertIdxsTeacupS[GLUT_SOLID_TEACUP_N_TRI*3];
93static GLfloat normsTeacupS [GLUT_SOLID_TEACUP_N_VERT*3];
94static GLfloat vertsTeacupS [GLUT_SOLID_TEACUP_N_VERT*3];
95static GLfloat texcsTeacupS [GLUT_SOLID_TEACUP_N_VERT*2];
96static GLfloat lastScaleTeacupS = 0.f;
97static GLboolean initedTeacupS = GL_FALSE;
98
99static GLushort vertIdxsTeacupW[GLUT_WIRE_TEACUP_N_VERT*2];
100static GLfloat normsTeacupW [GLUT_WIRE_TEACUP_N_VERT*3];
101static GLfloat vertsTeacupW [GLUT_WIRE_TEACUP_N_VERT*3];
102static GLfloat lastScaleTeacupW = 0.f;
103static GLboolean initedTeacupW = GL_FALSE;
104
105
106/* Teaspoon defs */
107#define GLUT_TEASPOON_N_PATCHES GLUT_TEASPOON_N_INPUT_PATCHES
108#define GLUT_SOLID_TEASPOON_N_VERT GLUT_SOLID_N_SUBDIV*GLUT_SOLID_N_SUBDIV * GLUT_TEASPOON_N_PATCHES /* N_SUBDIV^2 vertices per patch */
109#define GLUT_SOLID_TEASPOON_N_TRI (GLUT_SOLID_N_SUBDIV-1)*(GLUT_SOLID_N_SUBDIV-1) * GLUT_TEASPOON_N_PATCHES * 2 /* if e.g. 7x7 vertices for each patch, there are 6*6 squares for each patch. Each square is decomposed into 2 triangles */
110
111#define GLUT_WIRE_TEASPOON_N_VERT GLUT_WIRE_N_SUBDIV*GLUT_WIRE_N_SUBDIV * GLUT_TEASPOON_N_PATCHES /* N_SUBDIV^2 vertices per patch */
112
113/* Bit of caching:
114 * vertex indices and normals only need to be generated once for
115 * a given number of subdivisions as they don't change with scale.
116 * Vertices can be cached and reused if scale didn't change.
117 */
118static GLushort vertIdxsTeaspoonS[GLUT_SOLID_TEASPOON_N_TRI*3];
119static GLfloat normsTeaspoonS [GLUT_SOLID_TEASPOON_N_VERT*3];
120static GLfloat vertsTeaspoonS [GLUT_SOLID_TEASPOON_N_VERT*3];
121static GLfloat texcsTeaspoonS [GLUT_SOLID_TEASPOON_N_VERT*2];
122static GLfloat lastScaleTeaspoonS = 0.f;
123static GLboolean initedTeaspoonS = GL_FALSE;
124
125static GLushort vertIdxsTeaspoonW[GLUT_WIRE_TEASPOON_N_VERT*2];
126static GLfloat normsTeaspoonW [GLUT_WIRE_TEASPOON_N_VERT*3];
127static GLfloat vertsTeaspoonW [GLUT_WIRE_TEASPOON_N_VERT*3];
128static GLfloat lastScaleTeaspoonW = 0.f;
129static GLboolean initedTeaspoonW = GL_FALSE;
130
131
132
133/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
134extern void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
135 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
136extern void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
137 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
138 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2);
139
140/* evaluate 3rd order Bernstein polynomial and its 1st deriv */
141static void bernstein3(int i, GLfloat x, GLfloat *r0, GLfloat *r1)
142{
143 float invx = 1.f - x;
144
145 /* r0: zero order coeff, r1: first deriv coeff */
146 switch (i)
147 {
148 GLfloat temp;
149 case 0:
150 temp = invx*invx;
151 *r0 = invx * temp; /* invx * invx * invx */
152 *r1 = -3 * temp; /* -3 * invx * invx */
153 break;
154 case 1:
155 temp = invx*invx;
156 *r0 = 3 * x * temp; /* 3 * x * invx * invx */
157 *r1 = 3 * temp - 6 * x * invx; /* 3 * invx * invx - 6 * x * invx */
158 break;
159 case 2:
160 temp = x*x;
161 *r0 = 3 * temp * invx; /* 3 * x * x * invx */
162 *r1 = 6 * x * invx - 3 * temp; /* 6 * x * invx - 3 * x * x */
163 break;
164 case 3:
165 temp = x*x;
166 *r0 = x * temp; /* x * x * x */
167 *r1 = 3 * temp; /* 3 * x * x */
168 break;
169 default:
170 *r0 = *r1 = 0;
171 }
172}
173
174static void pregenBernstein(int nSubDivs, GLfloat (*bern_0)[4], GLfloat (*bern_1)[4])
175{
176 int s,i;
177 for (s=0; s<nSubDivs; s++)
178 {
179 GLfloat x = s/(nSubDivs-1.f);
180 for (i=0; i<4; i++) /* 3rd order polynomial */
181 bernstein3(i,x,bern_0[s]+i,bern_1[s]+i);
182 }
183}
184
185/* based on flag either rotate patches around y axis to other 3 quadrants (flag=4) or reflect patch across x-y plane (flag=2) */
186static void rotOrReflect(int flag, int nVals, int nSubDivs, GLfloat *vals)
187{
188 int u,i,o;
189
190 if (flag==4)
191 {
192 int i1=nVals, i2=nVals*2, i3=nVals*3;
193 for (o=0; o<nVals; o+=3)
194 {
195 /* 90° rotation */
196 vals[i1+o+0] = vals[o+2];
197 vals[i1+o+1] = vals[o+1];
198 vals[i1+o+2] = -vals[o+0];
199 /* 180° rotation */
200 vals[i2+o+0] = -vals[o+0];
201 vals[i2+o+1] = vals[o+1];
202 vals[i2+o+2] = -vals[o+2];
203 /* 270° rotation */
204 vals[i3+o+0] = -vals[o+2];
205 vals[i3+o+1] = vals[o+1];
206 vals[i3+o+2] = vals[o+0];
207 }
208 }
209 else if (flag==2)
210 {
211 /* copy over values, reversing row order to keep winding correct, and negating z to perform the flip */
212 for (u=0; u<nSubDivs; u++) /* per row */
213 {
214 int off = (nSubDivs-u-1)*nSubDivs*3; /* read last row first from the already existing rows */
215 o = nVals + u *nSubDivs*3; /* write last row as first row to output */
216 for (i=0; i<nSubDivs*3; i+=3, o+=3) /* each row has nSubDivs points consisting of three values */
217 {
218 vals[o+0] = vals[off+i+0];
219 vals[o+1] = vals[off+i+1];
220 vals[o+2] = -vals[off+i+2];
221 }
222 }
223 }
224}
225
226/* verts array should be initialized to 0! */
227static int evalBezierWithNorm(GLfloat cp[4][4][3], int nSubDivs, float (*bern_0)[4], float (*bern_1)[4], int flag, int normalFix, GLfloat *verts, GLfloat *norms)
228{
229 int nVerts = nSubDivs*nSubDivs;
230 int nVertVals = nVerts*3; /* number of values output for one patch, flag (2 or 4) indicates how many times we will write this to output */
231 int u,v,i,j,o;
232
233 /* generate vertices and coordinates for the patch */
234 for (u=0,o=0; u<nSubDivs; u++)
235 {
236 for (v=0; v<nSubDivs; v++, o+=3)
237 {
238 /* for normals, get two tangents at the vertex using partial derivatives of 2D Bezier grid */
239 float tan1[3]={0}, tan2[3]={0}, len;
240 for (i=0; i<=3; i++)
241 {
242 float vert_0[3]={0}, vert_1[3]={0};
243 for (j=0; j<=3; j++)
244 {
245 vert_0[0] += bern_0[v][j] * cp[i][j][0];
246 vert_0[1] += bern_0[v][j] * cp[i][j][1];
247 vert_0[2] += bern_0[v][j] * cp[i][j][2];
248
249 vert_1[0] += bern_1[v][j] * cp[i][j][0];
250 vert_1[1] += bern_1[v][j] * cp[i][j][1];
251 vert_1[2] += bern_1[v][j] * cp[i][j][2];
252 }
253
254 verts[o+0] += bern_0[u][i]*vert_0[0];
255 verts[o+1] += bern_0[u][i]*vert_0[1];
256 verts[o+2] += bern_0[u][i]*vert_0[2];
257
258 tan1[0] += bern_0[u][i]*vert_1[0];
259 tan1[1] += bern_0[u][i]*vert_1[1];
260 tan1[2] += bern_0[u][i]*vert_1[2];
261 tan2[0] += bern_1[u][i]*vert_0[0];
262 tan2[1] += bern_1[u][i]*vert_0[1];
263 tan2[2] += bern_1[u][i]*vert_0[2];
264 }
265 /* get normal through cross product of the two tangents of the vertex */
266 norms[o+0] = tan1[1] * tan2[2] - tan1[2] * tan2[1];
267 norms[o+1] = tan1[2] * tan2[0] - tan1[0] * tan2[2];
268 norms[o+2] = tan1[0] * tan2[1] - tan1[1] * tan2[0];
269 len = (GLfloat)sqrt(norms[o+0] * norms[o+0] + norms[o+1] * norms[o+1] + norms[o+2] * norms[o+2]);
270 norms[o+0] /= len;
271 norms[o+1] /= len;
272 norms[o+2] /= len;
273 }
274 }
275
276 /* Fix normal vector if needed */
277 if (normalFix)
278 {
279 for (o=0; o<nSubDivs*3; o+=3) /* whole first row (first nSubDivs normals) is broken: replace normals for the whole row */
280 {
281 norms[o+0] = 0.f;
282 norms[o+1] = normalFix==1? 1.f:-1.f;
283 norms[o+2] = 0.f;
284 }
285 }
286
287 /* now based on flag either rotate patches around y axis to other 3 quadrants (flag=4) or reflect patch across x-y plane (flag=2) */
288 rotOrReflect(flag, nVertVals, nSubDivs, verts);
289 rotOrReflect(flag, nVertVals, nSubDivs, norms);
290
291 return nVertVals*flag;
292}
293
294/* verts array should be initialized to 0! */
295static int evalBezier(GLfloat cp[4][4][3], int nSubDivs, float (*bern_0)[4], int flag, GLfloat *verts)
296{
297 int nVerts = nSubDivs*nSubDivs;
298 int nVertVals = nVerts*3; /* number of values output for one patch, flag (2 or 4) indicates how many times we will write this to output */
299 int u,v,i,j,o;
300
301 /* generate vertices and coordinates for the patch */
302 for (u=0,o=0; u<nSubDivs; u++)
303 {
304 for (v=0; v<nSubDivs; v++, o+=3)
305 {
306 for (i=0; i<=3; i++)
307 {
308 float vert_0[3]={0};
309 for (j=0; j<=3; j++)
310 {
311 vert_0[0] += bern_0[v][j] * cp[i][j][0];
312 vert_0[1] += bern_0[v][j] * cp[i][j][1];
313 vert_0[2] += bern_0[v][j] * cp[i][j][2];
314 }
315
316 verts[o+0] += bern_0[u][i]*vert_0[0];
317 verts[o+1] += bern_0[u][i]*vert_0[1];
318 verts[o+2] += bern_0[u][i]*vert_0[2];
319 }
320 }
321 }
322
323 /* now based on flag either rotate patches around y axis to other 3 quadrants (flag=4) or reflect patch across x-y plane (flag=2) */
324 rotOrReflect(flag, nVertVals, nSubDivs, verts);
325
326 return nVertVals*flag;
327}
328
329static void fghTeaset( GLfloat scale, GLboolean useWireMode,
330 GLfloat (*cpdata)[3], int (*patchdata)[16],
331 GLushort *vertIdxs,
332 GLfloat *verts, GLfloat *norms, GLfloat *texcs,
333 GLfloat *lastScale, GLboolean *inited,
334 GLboolean needNormalFix, GLboolean rotFlip, GLfloat zOffset,
335 int nVerts, int nInputPatches, int nPatches, int nTriangles )
336{
337 /* for internal use */
338 int p,o;
339 GLfloat cp[4][4][3];
340 /* to hold pointers to static vars/arrays */
341 GLfloat (*bern_0)[4], (*bern_1)[4];
342 int nSubDivs;
343
344 /* Get relevant static arrays and variables */
345 bern_0 = useWireMode ? bernWire_0 : bernSolid_0;
346 bern_1 = useWireMode ? bernWire_1 : bernSolid_1;
347 nSubDivs = useWireMode ? GLUT_WIRE_N_SUBDIV : GLUT_SOLID_N_SUBDIV;
348
349 /* check if need to generate vertices */
350 if (!*inited || scale != *lastScale)
351 {
352 /* set vertex array to all 0 (not necessary for normals and vertex indices) */
353 memset(verts,0,nVerts*3*sizeof(GLfloat));
354
355 /* pregen Berstein polynomials and their first derivatives (for normals) */
356 if (!*inited)
357 pregenBernstein(nSubDivs,bern_0,bern_1);
358
359 /* generate vertices and normals */
360 for (p=0, o=0; p<nInputPatches; p++)
361 {
362 /* set flags for evalBezier function */
363 int flag = rotFlip?p<6?4:2:1; /* For teapot and teacup, first six patches get 3 copies (rotations), others get 2 copies (flips). No rotating or flipping at all for teaspoon */
364 int normalFix = needNormalFix?p==3?1:p==5?2:0:0; /* For teapot, fix normal vectors for vertices on top of lid (patch 4) and on middle of bottom (patch 6). Different flag value as different normal needed */
365
366 /* collect control points */
367 int i;
368 for (i=0; i<16; i++)
369 {
370 /* Original code draws with a 270° rot around X axis, a scaling and a translation along the Z-axis.
371 * Incorporating these in the control points is much cheaper than transforming all the vertices.
372 * Original:
373 * glRotated( 270.0, 1.0, 0.0, 0.0 );
374 * glScaled( 0.5 * scale, 0.5 * scale, 0.5 * scale );
375 * glTranslated( 0.0, 0.0, -zOffset ); -> was 1.5 for teapot, but should be 1.575 to center it on the Z axis. Teacup and teaspoon have different offsets
376 */
377 cp[i/4][i%4][0] = cpdata[patchdata[p][i]][0] *scale/2.f;
378 cp[i/4][i%4][1] = (cpdata[patchdata[p][i]][2]-zOffset)*scale/2.f;
379 cp[i/4][i%4][2] = -cpdata[patchdata[p][i]][1] *scale/2.f;
380 }
381
382 /* eval bezier patch */
383 if (!*inited) /* first time, generate normals as well */
384 o += evalBezierWithNorm(cp,nSubDivs,bern_0,bern_1, flag, normalFix, verts+o,norms+o);
385 else /* only need to regen vertices */
386 o += evalBezier(cp,nSubDivs,bern_0, flag, verts+o);
387 }
388 *lastScale = scale;
389
390 if (!*inited)
391 {
392 int r,c;
393 /* generate texture coordinates if solid teapot/teacup/teaspoon */
394 if (!useWireMode)
395 {
396 /* generate for first patch */
397 for (r=0,o=0; r<nSubDivs; r++)
398 {
399 GLfloat u = r/(nSubDivs-1.f);
400 for (c=0; c<nSubDivs; c++, o+=2)
401 {
402 GLfloat v = c/(nSubDivs-1.f);
403 texcs[o+0] = u;
404 texcs[o+1] = v;
405 }
406 }
407 /* copy it over for all the other patches */
408 for (p=1; p<nPatches; p++)
409 memcpy(texcs+p*nSubDivs*nSubDivs*2,texcs,nSubDivs*nSubDivs*2*sizeof(GLfloat));
410 }
411
412 /* build vertex index array */
413 if (useWireMode)
414 {
415 /* build vertex indices to draw teapot/teacup/teaspoon as line strips */
416 /* first strips along increasing u, constant v */
417 for (p=0, o=0; p<nPatches; p++)
418 {
419 int idx = nSubDivs*nSubDivs*p;
420 for (c=0; c<nSubDivs; c++)
421 for (r=0; r<nSubDivs; r++, o++)
422 vertIdxs[o] = idx+r*nSubDivs+c;
423 }
424
425 /* then strips along increasing v, constant u */
426 for (p=0; p<nPatches; p++) /* don't reset o, we continue appending! */
427 {
428 int idx = nSubDivs*nSubDivs*p;
429 for (r=0; r<nSubDivs; r++)
430 {
431 int loc = r*nSubDivs;
432 for (c=0; c<nSubDivs; c++, o++)
433 vertIdxs[o] = idx+loc+c;
434 }
435 }
436 }
437 else
438 {
439 /* build vertex indices to draw teapot/teacup/teaspoon as triangles */
440 for (p=0,o=0; p<nPatches; p++)
441 {
442 int idx = nSubDivs*nSubDivs*p;
443 for (r=0; r<nSubDivs-1; r++)
444 {
445 int loc = r*nSubDivs;
446 for (c=0; c<nSubDivs-1; c++, o+=6)
447 {
448 /* ABC ACD, where B and C are one row lower */
449 int row1 = idx+loc+c;
450 int row2 = row1+nSubDivs;
451
452 vertIdxs[o+0] = row1+0;
453 vertIdxs[o+1] = row2+0;
454 vertIdxs[o+2] = row2+1;
455
456 vertIdxs[o+3] = row1+0;
457 vertIdxs[o+4] = row2+1;
458 vertIdxs[o+5] = row1+1;
459 }
460 }
461 }
462 }
463
464 *inited = GL_TRUE;
465 }
466 }
467
468 /* draw */
469 if (useWireMode)
470 fghDrawGeometryWire (verts, norms, nVerts, vertIdxs, nPatches*nSubDivs*2, nSubDivs, GL_LINE_STRIP, NULL,0,0);
471 else
472 fghDrawGeometrySolid(verts, norms, texcs, nVerts, vertIdxs,1,nTriangles*3);
473}
474
475
476/* -- INTERFACE FUNCTIONS -------------------------------------------------- */
477
478/*
479 * Renders a wired teapot...
480 */
481void FGAPIENTRY glutWireTeapot( double size )
482{
483 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTeapot" );
484 fghTeaset( (GLfloat)size, GL_TRUE,
485 cpdata_teapot, patchdata_teapot,
486 vertIdxsTeapotW,
487 vertsTeapotW, normsTeapotW, NULL,
488 &lastScaleTeapotW, &initedTeapotW,
489 GL_TRUE, GL_TRUE, 1.575f,
490 GLUT_WIRE_TEAPOT_N_VERT, GLUT_TEAPOT_N_INPUT_PATCHES, GLUT_TEAPOT_N_PATCHES, 0);
491}
492
493/*
494 * Renders a filled teapot...
495 */
496void FGAPIENTRY glutSolidTeapot( double size )
497{
498 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTeapot" );
499 fghTeaset( (GLfloat)size, GL_FALSE,
500 cpdata_teapot, patchdata_teapot,
501 vertIdxsTeapotS,
502 vertsTeapotS, normsTeapotS, texcsTeapotS,
503 &lastScaleTeapotS, &initedTeapotS,
504 GL_TRUE, GL_TRUE, 1.575f,
505 GLUT_SOLID_TEAPOT_N_VERT, GLUT_TEAPOT_N_INPUT_PATCHES, GLUT_TEAPOT_N_PATCHES, GLUT_SOLID_TEAPOT_N_TRI);
506}
507
508
509/*
510 * Renders a wired teacup...
511 */
512void FGAPIENTRY glutWireTeacup( double size )
513{
514 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTeacup" );
515 fghTeaset( (GLfloat)size/2.5f, GL_TRUE,
516 cpdata_teacup, patchdata_teacup,
517 vertIdxsTeacupW,
518 vertsTeacupW, normsTeacupW, NULL,
519 &lastScaleTeacupW, &initedTeacupW,
520 GL_FALSE, GL_TRUE, 1.5121f,
521 GLUT_WIRE_TEACUP_N_VERT, GLUT_TEACUP_N_INPUT_PATCHES, GLUT_TEACUP_N_PATCHES, 0);
522}
523
524/*
525 * Renders a filled teacup...
526 */
527void FGAPIENTRY glutSolidTeacup( double size )
528{
529 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTeacup" );
530 fghTeaset( (GLfloat)size/2.5f, GL_FALSE,
531 cpdata_teacup, patchdata_teacup,
532 vertIdxsTeacupS,
533 vertsTeacupS, normsTeacupS, texcsTeacupS,
534 &lastScaleTeacupS, &initedTeacupS,
535 GL_FALSE, GL_TRUE, 1.5121f,
536 GLUT_SOLID_TEACUP_N_VERT, GLUT_TEACUP_N_INPUT_PATCHES, GLUT_TEACUP_N_PATCHES, GLUT_SOLID_TEACUP_N_TRI);
537}
538
539
540/*
541 * Renders a wired teaspoon...
542 */
543void FGAPIENTRY glutWireTeaspoon( double size )
544{
545 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTeaspoon" );
546 fghTeaset( (GLfloat)size/2.5f, GL_TRUE,
547 cpdata_teaspoon, patchdata_teaspoon,
548 vertIdxsTeaspoonW,
549 vertsTeaspoonW, normsTeaspoonW, NULL,
550 &lastScaleTeaspoonW, &initedTeaspoonW,
551 GL_FALSE, GL_FALSE, -0.0315f,
552 GLUT_WIRE_TEASPOON_N_VERT, GLUT_TEASPOON_N_INPUT_PATCHES, GLUT_TEASPOON_N_PATCHES, 0);
553}
554
555/*
556 * Renders a filled teaspoon...
557 */
558void FGAPIENTRY glutSolidTeaspoon( double size )
559{
560 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTeaspoon" );
561 fghTeaset( (GLfloat)size/2.5f, GL_FALSE,
562 cpdata_teaspoon, patchdata_teaspoon,
563 vertIdxsTeaspoonS,
564 vertsTeaspoonS, normsTeaspoonS, texcsTeaspoonS,
565 &lastScaleTeaspoonS, &initedTeaspoonS,
566 GL_FALSE, GL_FALSE, -0.0315f,
567 GLUT_SOLID_TEASPOON_N_VERT, GLUT_TEASPOON_N_INPUT_PATCHES, GLUT_TEASPOON_N_PATCHES, GLUT_SOLID_TEASPOON_N_TRI);
568}
569
570/*** END OF FILE ***/
571