Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/freeglut/src/fg_teapot.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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 */ | |
| 49 static GLfloat bernWire_0 [GLUT_WIRE_N_SUBDIV] [4]; | |
| 50 static GLfloat bernWire_1 [GLUT_WIRE_N_SUBDIV] [4]; | |
| 51 static GLfloat bernSolid_0[GLUT_SOLID_N_SUBDIV][4]; | |
| 52 static 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 */ | |
| 66 static GLushort vertIdxsTeapotS[GLUT_SOLID_TEAPOT_N_TRI*3]; | |
| 67 static GLfloat normsTeapotS [GLUT_SOLID_TEAPOT_N_VERT*3]; | |
| 68 static GLfloat vertsTeapotS [GLUT_SOLID_TEAPOT_N_VERT*3]; | |
| 69 static GLfloat texcsTeapotS [GLUT_SOLID_TEAPOT_N_VERT*2]; | |
| 70 static GLfloat lastScaleTeapotS = 0.f; | |
| 71 static GLboolean initedTeapotS = GL_FALSE; | |
| 72 | |
| 73 static GLushort vertIdxsTeapotW[GLUT_WIRE_TEAPOT_N_VERT*2]; | |
| 74 static GLfloat normsTeapotW [GLUT_WIRE_TEAPOT_N_VERT*3]; | |
| 75 static GLfloat vertsTeapotW [GLUT_WIRE_TEAPOT_N_VERT*3]; | |
| 76 static GLfloat lastScaleTeapotW = 0.f; | |
| 77 static 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 */ | |
| 92 static GLushort vertIdxsTeacupS[GLUT_SOLID_TEACUP_N_TRI*3]; | |
| 93 static GLfloat normsTeacupS [GLUT_SOLID_TEACUP_N_VERT*3]; | |
| 94 static GLfloat vertsTeacupS [GLUT_SOLID_TEACUP_N_VERT*3]; | |
| 95 static GLfloat texcsTeacupS [GLUT_SOLID_TEACUP_N_VERT*2]; | |
| 96 static GLfloat lastScaleTeacupS = 0.f; | |
| 97 static GLboolean initedTeacupS = GL_FALSE; | |
| 98 | |
| 99 static GLushort vertIdxsTeacupW[GLUT_WIRE_TEACUP_N_VERT*2]; | |
| 100 static GLfloat normsTeacupW [GLUT_WIRE_TEACUP_N_VERT*3]; | |
| 101 static GLfloat vertsTeacupW [GLUT_WIRE_TEACUP_N_VERT*3]; | |
| 102 static GLfloat lastScaleTeacupW = 0.f; | |
| 103 static 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 */ | |
| 118 static GLushort vertIdxsTeaspoonS[GLUT_SOLID_TEASPOON_N_TRI*3]; | |
| 119 static GLfloat normsTeaspoonS [GLUT_SOLID_TEASPOON_N_VERT*3]; | |
| 120 static GLfloat vertsTeaspoonS [GLUT_SOLID_TEASPOON_N_VERT*3]; | |
| 121 static GLfloat texcsTeaspoonS [GLUT_SOLID_TEASPOON_N_VERT*2]; | |
| 122 static GLfloat lastScaleTeaspoonS = 0.f; | |
| 123 static GLboolean initedTeaspoonS = GL_FALSE; | |
| 124 | |
| 125 static GLushort vertIdxsTeaspoonW[GLUT_WIRE_TEASPOON_N_VERT*2]; | |
| 126 static GLfloat normsTeaspoonW [GLUT_WIRE_TEASPOON_N_VERT*3]; | |
| 127 static GLfloat vertsTeaspoonW [GLUT_WIRE_TEASPOON_N_VERT*3]; | |
| 128 static GLfloat lastScaleTeaspoonW = 0.f; | |
| 129 static GLboolean initedTeaspoonW = GL_FALSE; | |
| 130 | |
| 131 | |
| 132 | |
| 133 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ | |
| 134 extern void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices, | |
| 135 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart); | |
| 136 extern 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 */ | |
| 141 static 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 | |
| 174 static 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) */ | |
| 186 static 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! */ | |
| 227 static 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! */ | |
| 295 static 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 | |
| 329 static 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 */ | |
| 481 void 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 */ | |
| 496 void 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 */ | |
| 512 void 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 */ | |
| 527 void 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 */ | |
| 543 void 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 */ | |
| 558 void 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 ***/ |
