1 /*
2 * model.c
3 * by Jon Kinsey, 2003
4 *
5 * Shadow model representation
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 3 or later of the GNU General Public License as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * $Id: model.c,v 1.22 2018/04/28 21:44:35 plm Exp $
22 */
23
24 #include "config.h"
25 #include "inc3d.h"
26
27 #define TOP_EDGE (-2)
28
29 typedef struct _position {
30 float x, y, z;
31 } position;
32
33 typedef struct _plane {
34 float a, b, c, d;
35 } plane;
36
37 typedef struct _winged_edge {
38 unsigned int e[2]; /* vertex index */
39 int w[2]; /* plane index */
40 } winged_edge;
41
42 void
initOccluder(Occluder * pOcc)43 initOccluder(Occluder * pOcc)
44 {
45 pOcc->handle = (OccModel *) malloc(sizeof(OccModel));
46 pOcc->handle->planes = g_array_new(FALSE, FALSE, sizeof(plane));
47 pOcc->handle->edges = g_array_new(FALSE, FALSE, sizeof(winged_edge));
48 pOcc->handle->points = g_array_new(FALSE, FALSE, sizeof(position));
49
50 pOcc->shadow_list = glGenLists(1);
51 pOcc->rotator = 0;
52 pOcc->show = 1;
53 }
54
55 void
freeOccluder(Occluder * pOcc)56 freeOccluder(Occluder * pOcc)
57 {
58 if (pOcc->handle) {
59 g_array_free(pOcc->handle->planes, TRUE);
60 g_array_free(pOcc->handle->edges, TRUE);
61 g_array_free(pOcc->handle->points, TRUE);
62 free(pOcc->handle);
63 pOcc->handle = NULL;
64 glDeleteLists(pOcc->shadow_list, 1);
65 }
66 }
67
68 void
copyOccluder(const Occluder * fromOcc,Occluder * toOcc)69 copyOccluder(const Occluder * fromOcc, Occluder * toOcc)
70 {
71 toOcc->handle = fromOcc->handle;
72 toOcc->show = fromOcc->show;
73 toOcc->rotator = fromOcc->rotator;
74 toOcc->shadow_list = glGenLists(1);
75 }
76
77 void
moveToOcc(const Occluder * pOcc)78 moveToOcc(const Occluder * pOcc)
79 {
80 glTranslatef(pOcc->trans[0], pOcc->trans[1], pOcc->trans[2]);
81
82 if (pOcc->rotator) {
83 glRotatef(pOcc->rot[0], 0.f, 1.f, 0.f);
84 glRotatef(pOcc->rot[1], 1.f, 0.f, 0.f);
85 glRotatef(pOcc->rot[2], 0.f, 0.f, 1.f);
86 }
87 }
88
89 static unsigned int
AddPos(GArray * points,float a,float b,float c)90 AddPos(GArray * points, float a, float b, float c)
91 {
92 unsigned int index;
93 position pos;
94 pos.x = a;
95 pos.y = b;
96 pos.z = c;
97
98 for (index = 0; index < points->len; index++) {
99 if (!memcmp(&pos, &g_array_index(points, position, index), sizeof(position)))
100 return index;
101 }
102
103 g_array_append_val(points, pos);
104 return points->len - 1;
105 }
106
107 static void
CreatePlane(plane * p,const position * p1,const position * p2,const position * p3)108 CreatePlane(plane * p, const position * p1, const position * p2, const position * p3)
109 {
110 float v0[3];
111 float v1[3];
112 float cr[3];
113 float l;
114
115 v0[0] = p2->x - p1->x;
116 v0[1] = p2->y - p1->y;
117 v0[2] = p2->z - p1->z;
118
119 v1[0] = p3->x - p1->x;
120 v1[1] = p3->y - p1->y;
121 v1[2] = p3->z - p1->z;
122
123 cr[0] = v0[1] * v1[2] - v0[2] * v1[1];
124 cr[1] = v0[2] * v1[0] - v0[0] * v1[2];
125 cr[2] = v0[0] * v1[1] - v0[1] * v1[0];
126
127 l = sqrtf(cr[0] * cr[0] + cr[1] * cr[1] + cr[2] * cr[2]);
128 if (l == 0) { /* degenerate triangle */
129 p->a = p->b = p->c = p->d = 0;
130 return;
131 }
132 p->a = cr[0] / l;
133 p->b = cr[1] / l;
134 p->c = cr[2] / l;
135
136 /* signed distance of a point on the plane from the origin */
137 p->d = -(p->a * p1->x + p->b * p1->y + p->c * p1->z);
138 }
139
140 static unsigned int
AddPlane(GArray * planes,const position * a,const position * b,const position * c)141 AddPlane(GArray * planes, const position * a, const position * b, const position * c)
142 {
143 unsigned int index;
144 plane p;
145 CreatePlane(&p, a, b, c);
146
147 for (index = 0; index < planes->len; index++) {
148 if (!memcmp(&p, &g_array_index(planes, plane, index), sizeof(plane)))
149 return index;
150 }
151
152 g_array_append_val(planes, p);
153 return planes->len - 1;
154 }
155
156 /* For testing */
157 #ifdef TEST_HARNESS
158 void
GenerateShadowEdges(const Occluder * pOcc)159 GenerateShadowEdges(const Occluder * pOcc)
160 {
161 unsigned int i, numEdges = pOcc->handle->edges->len;
162 for (i = 0; i < numEdges; i++) {
163 winged_edge *we = &g_array_index(pOcc->handle->edges, winged_edge, i);
164 position *pn0 = &g_array_index(pOcc->handle->points, position, we->e[0]);
165 position *pn1 = &g_array_index(pOcc->handle->points, position, we->e[1]);
166
167 glBegin(GL_LINES);
168 glVertex3f(pn0->x, pn0->y, pn0->z);
169 glVertex3f(pn1->x, pn1->y, pn1->z);
170 glEnd();
171
172 {
173 float xDiff = pn1->x - pn0->x;
174 float yDiff = pn1->y - pn0->y;
175 float zDiff = pn1->z - pn0->z;
176 float xPos = pn0->x + xDiff * .80f;
177 float yPos = pn0->y + yDiff * .80f;
178 float zPos = pn0->z + zDiff * .80f;
179 glBegin(GL_POINTS);
180 glVertex3f(xPos, yPos, zPos);
181 glEnd();
182
183 if (we->w[1] >= 0) {
184 xPos = pn0->x + xDiff * .20f;
185 yPos = pn0->y + yDiff * .20f;
186 zPos = pn0->z + zDiff * .20f;
187 glBegin(GL_POINTS);
188 glVertex3f(xPos, yPos, zPos);
189 glEnd();
190 }
191 }
192 }
193 }
194 #endif
195
196 static float
sqdDist(const GArray * planes,int pIndex,const float point[4])197 sqdDist(const GArray * planes, int pIndex, const float point[4])
198 {
199 plane *p = &g_array_index(planes, plane, pIndex);
200 return (p->a * point[0] + p->b * point[1] + p->c * point[2] + p->d * point[3]);
201 }
202
203 void
GenerateShadowVolume(const Occluder * pOcc,const float olight[4])204 GenerateShadowVolume(const Occluder * pOcc, const float olight[4])
205 {
206 unsigned int edgeOrder[2];
207 unsigned int i, numEdges = pOcc->handle->edges->len;
208
209 for (i = 0; i < numEdges; i++) {
210 winged_edge *we = &g_array_index(pOcc->handle->edges, winged_edge, i);
211
212 float f0 = sqdDist(pOcc->handle->planes, we->w[0], olight);
213 float f1;
214 if (we->w[1] >= 0)
215 f1 = sqdDist(pOcc->handle->planes, we->w[1], olight);
216 else {
217 if (we->w[1] == TOP_EDGE && f0 < 0)
218 continue;
219 f1 = -f0;
220 }
221
222 if (f0 >= 0 && f1 < 0) {
223 edgeOrder[0] = we->e[1];
224 edgeOrder[1] = we->e[0];
225 } else if (f1 >= 0 && f0 < 0) {
226 edgeOrder[0] = we->e[0];
227 edgeOrder[1] = we->e[1];
228 } else {
229 continue;
230 }
231
232 {
233 position *pn0 = &g_array_index(pOcc->handle->points, position, edgeOrder[0]);
234 position *pn1 = &g_array_index(pOcc->handle->points, position, edgeOrder[1]);
235
236 /* local segment */
237 glVertex3f(pn0->x, pn0->y, pn0->z);
238 glVertex3f(pn1->x, pn1->y, pn1->z);
239 /* segment projected to infinity (NB. w == 0) */
240 glVertex4f(pn1->x * olight[3] - olight[0],
241 pn1->y * olight[3] - olight[1], pn1->z * olight[3] - olight[2], 0.f);
242
243 glVertex4f(pn0->x * olight[3] - olight[0],
244 pn0->y * olight[3] - olight[1], pn0->z * olight[3] - olight[2], 0.f);
245 }
246 }
247 }
248
249 /* pair up edges */
250 static void
AddEdge(GArray * edges,const winged_edge * we)251 AddEdge(GArray * edges, const winged_edge * we)
252 {
253 unsigned int i, numEdges = edges->len;
254 for (i = 0; i < numEdges; i++) {
255 winged_edge *we0 = &g_array_index(edges, winged_edge, i);
256 /* facingness different between polys on edge! */
257 g_assert((we0->e[0] != we->e[0] || we0->e[1] != we->e[1]));
258
259 if (we0->e[0] == we->e[1] && we0->e[1] == we->e[0]) {
260 /* triple edge! bad... */
261 g_assert((we0->w[1] == -1));
262
263 we0->w[1] = we->w[0]; /* pair the edge and return */
264 return;
265 }
266 }
267 g_array_append_val(edges, *we); /* otherwise, add the new edge */
268 }
269
270 static void
addALine(Occluder * pOcc,float x,float y,float z,float x2,float y2,float z2,float x3,float y3,float z3,int otherEdge)271 addALine( /*lint -e{818} */ Occluder * pOcc, float x, float y, float z, float x2, float y2, float z2, float x3,
272 float y3, float z3, int otherEdge)
273 { /* Declaring pOcc as constant isn't useful as pointer member is modified (error 818) */
274 winged_edge we;
275 int planeNum;
276 unsigned int p1 = AddPos(pOcc->handle->points, x, y, z);
277 unsigned int p2 = AddPos(pOcc->handle->points, x2, y2, z2);
278
279 position pn3;
280 pn3.x = x3;
281 pn3.y = y3;
282 pn3.z = z3;
283
284 planeNum =
285 (int) AddPlane(pOcc->handle->planes, &g_array_index(pOcc->handle->points, position, p1),
286 &g_array_index(pOcc->handle->points, position, p2), &pn3);
287
288 we.e[0] = p1;
289 we.e[1] = p2;
290 we.w[0] = planeNum;
291 we.w[1] = otherEdge; /* subsequent attempt to add this edge will replace w[1] */
292 AddEdge(pOcc->handle->edges, &we);
293 }
294
295 static void
addLine(Occluder * pOcc,float x,float y,float z,float x2,float y2,float z2,float x3,float y3,float z3)296 addLine(Occluder * pOcc, float x, float y, float z, float x2, float y2, float z2, float x3, float y3, float z3)
297 {
298 addALine(pOcc, x, y, z, x2, y2, z2, x3, y3, z3, -1);
299 }
300
301 static void
addLineV(Occluder * pOcc,const float v1[3],const float v2[3],const float v3[3])302 addLineV(Occluder * pOcc, const float v1[3], const float v2[3], const float v3[3])
303 {
304 addLine(pOcc, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2]);
305 }
306
307 static void
addTopLine(Occluder * pOcc,float x,float y,float z,float x2,float y2,float z2)308 addTopLine(Occluder * pOcc, float x, float y, float z, float x2, float y2, float z2)
309 {
310 float z3;
311 z3 = z - .1f;
312
313 addALine(pOcc, x, y, z, x2, y2, z2, x, y, z3, TOP_EDGE);
314 }
315
316 void
addClosedSquare(Occluder * pOcc,float x,float y,float z,float w,float h,float d)317 addClosedSquare(Occluder * pOcc, float x, float y, float z, float w, float h, float d)
318 {
319 addLine(pOcc, x, y, z, x, y, z + d, x + .1f, y, z);
320 addLine(pOcc, x, y + h, z, x, y + h, z + d, x + .1f, y + h, z);
321 addLine(pOcc, x + w, y + h, z, x + w, y + h, z + d, x + w + .1f, y + h, z);
322 addLine(pOcc, x + w, y, z, x + w, y, z + d, x + w - .1f, y, z);
323
324 addLine(pOcc, x, y, z + d, x, y, z, x, y + .1f, z);
325 addLine(pOcc, x, y + h, z + d, x, y + h, z, x, y + h - .1f, z);
326 addLine(pOcc, x + w, y + h, z + d, x + w, y + h, z, x + w, y + h + .1f, z);
327 addLine(pOcc, x + w, y, z + d, x + w, y, z, x + w, y + .1f, z);
328
329 addTopLine(pOcc, x, y, z + d, x, y + h, z + d);
330 addTopLine(pOcc, x, y + h, z + d, x + w, y + h, z + d);
331 addTopLine(pOcc, x + w, y + h, z + d, x + w, y, z + d);
332 addTopLine(pOcc, x + w, y, z + d, x, y, z + d);
333 }
334
335 void
addSquare(Occluder * pOcc,float x,float y,float z,float w,float h,float d)336 addSquare(Occluder * pOcc, float x, float y, float z, float w, float h, float d)
337 {
338 addLine(pOcc, x, y, z, x, y, z + d, x + .1f, y, z);
339 addLine(pOcc, x, y + h, z, x, y + h, z + d, x + .1f, y + h, z);
340 addLine(pOcc, x + w, y + h, z, x + w, y + h, z + d, x + w - .1f, y + h, z);
341 addLine(pOcc, x + w, y, z, x + w, y, z + d, x + w - .1f, y, z);
342
343 addLine(pOcc, x, y, z + d, x, y, z, x, y + .1f, z);
344 addLine(pOcc, x, y + h, z + d, x, y + h, z, x, y + h - .1f, z);
345 addLine(pOcc, x + w, y + h, z + d, x + w, y + h, z, x + w, y + h - .1f, z);
346 addLine(pOcc, x + w, y, z + d, x + w, y, z, x + w, y + .1f, z);
347
348 addTopLine(pOcc, x, y + h, z + d, x, y, z + d);
349 addTopLine(pOcc, x + w, y + h, z + d, x, y + h, z + d);
350 addTopLine(pOcc, x + w, y, z + d, x + w, y + h, z + d);
351 addTopLine(pOcc, x, y, z + d, x + w, y, z + d);
352 }
353
354 void
addSquareCentered(Occluder * pOcc,float x,float y,float z,float w,float h,float d)355 addSquareCentered(Occluder * pOcc, float x, float y, float z, float w, float h, float d)
356 {
357 x -= w / 2.0f;
358 y -= h / 2.0f;
359 z -= d / 2.0f;
360
361 addSquare(pOcc, x, y, z, w, h, d);
362 }
363
364 void
addWonkyCube(Occluder * pOcc,float x,float y,float z,float w,float h,float d,float s,int full)365 addWonkyCube(Occluder * pOcc, float x, float y, float z, float w, float h, float d, float s, int full)
366 {
367 if (full == 0) {
368 addLine(pOcc, x, y + h, z, x, y, z, x, y, z + .1f);
369 addLine(pOcc, x, y, z, x, y + h, z, x + .1f, y, z);
370
371 addLine(pOcc, x, y, z, x, y, z + d, x + .1f, y, z);
372 addLine(pOcc, x, y + h, z, x, y + h, z + d, x + .1f, y + h, z);
373 addLine(pOcc, x, y, z + d, x, y, z, x, y + .1f, z);
374 addLine(pOcc, x, y + h, z + d, x, y + h, z, x, y + h - .1f, z);
375
376 addLine(pOcc, x, y + h, z + d, x, y, z + d, x, y, z + d - .1f);
377 addLine(pOcc, x, y, z + d, x, y + h, z + d, x + .1f, y, z + d);
378 }
379 /* Bottom */
380 addLine(pOcc, x + w, y + h, z + s, x, y + h, z, x, y + h, z + .1f);
381 addLine(pOcc, x, y, z, x + w, y, z + s, x + w, y, z + s + .1f);
382
383 addLine(pOcc, x, y + h, z, x + w, y + h, z + s, x, y + h - .1f, z);
384 addLine(pOcc, x + w, y, z + s, x, y, z, x + w, y + .1f, z + s);
385
386 if (full == 2) {
387 /* Sides */
388 addLine(pOcc, x + w, y + h, z + s, x + w, y + h, z + s + d, x + w - .1f, y + h, z + s);
389 addLine(pOcc, x + w, y, z + s, x + w, y, z + s + d, x + w - .1f, y, z + s);
390 addLine(pOcc, x + w, y + h, z + s + d, x + w, y + h, z + s, x + w, y + h - .1f, z + s);
391 addLine(pOcc, x + w, y, z + s + d, x + w, y, z + s, x + w, y + .1f, z + s);
392
393 addLine(pOcc, x + w, y, z + s, x + w, y + h, z + s, x + w, y + h, z + s + .1f);
394 addLine(pOcc, x + w, y + h, z + s, x + w, y, z + s, x + w - .1f, y + h, z + s);
395
396 addLine(pOcc, x + w, y, z + s + d, x + w, y + h, z + s + d, x + w, y + h, z + s + d - .1f);
397 addLine(pOcc, x + w, y + h, z + s + d, x + w, y, z + s + d, x + w - .1f, y + h, z + s + d);
398 }
399 /* Top */
400 addLine(pOcc, x + w, y + h, z + s + d, x, y + h, z + d, x, y + h, z + d - .1f);
401 addLine(pOcc, x, y, z + d, x + w, y, z + s + d, x + w, y, z + s + d - .1f);
402
403 addLine(pOcc, x, y + h, z + d, x + w, y + h, z + s + d, x, y + h - .1f, z + d);
404 addLine(pOcc, x + w, y, z + s + d, x, y, z + d, x + w, y + .1f, z + s + d);
405 }
406
407 void
addCube(Occluder * pOcc,float x,float y,float z,float w,float h,float d)408 addCube(Occluder * pOcc, float x, float y, float z, float w, float h, float d)
409 {
410 /* Bottom */
411 addLine(pOcc, x, y + h, z, x, y, z, x, y, z + .1f);
412 addLine(pOcc, x + w, y + h, z, x, y + h, z, x, y + h, z + .1f);
413 addLine(pOcc, x + w, y, z, x + w, y + h, z, x + w, y + h, z + .1f);
414 addLine(pOcc, x, y, z, x + w, y, z, x + w, y, z + .1f);
415
416 addLine(pOcc, x, y, z, x, y + h, z, x + .1f, y, z);
417 addLine(pOcc, x, y + h, z, x + w, y + h, z, x, y + h - .1f, z);
418 addLine(pOcc, x + w, y + h, z, x + w, y, z, x + w - .1f, y + h, z);
419 addLine(pOcc, x + w, y, z, x, y, z, x + w, y + .1f, z);
420
421 /* Sides */
422 addLine(pOcc, x, y, z, x, y, z + d, x + .1f, y, z);
423 addLine(pOcc, x, y + h, z, x, y + h, z + d, x + .1f, y + h, z);
424 addLine(pOcc, x + w, y + h, z, x + w, y + h, z + d, x + w - .1f, y + h, z);
425 addLine(pOcc, x + w, y, z, x + w, y, z + d, x + w - .1f, y, z);
426
427 addLine(pOcc, x, y, z + d, x, y, z, x, y + .1f, z);
428 addLine(pOcc, x, y + h, z + d, x, y + h, z, x, y + h - .1f, z);
429 addLine(pOcc, x + w, y + h, z + d, x + w, y + h, z, x + w, y + h - .1f, z);
430 addLine(pOcc, x + w, y, z + d, x + w, y, z, x + w, y + .1f, z);
431
432 /* Top */
433 addLine(pOcc, x, y + h, z + d, x, y, z + d, x, y, z + d - .1f);
434 addLine(pOcc, x + w, y + h, z + d, x, y + h, z + d, x, y + h, z + d - .1f);
435 addLine(pOcc, x + w, y, z + d, x + w, y + h, z + d, x + w, y + h, z + d - .1f);
436 addLine(pOcc, x, y, z + d, x + w, y, z + d, x + w, y, z + d - .1f);
437
438 addLine(pOcc, x, y, z + d, x, y + h, z + d, x + .1f, y, z + d);
439 addLine(pOcc, x, y + h, z + d, x + w, y + h, z + d, x, y + h - .1f, z + d);
440 addLine(pOcc, x + w, y + h, z + d, x + w, y, z + d, x + w - .1f, y + h, z + d);
441 addLine(pOcc, x + w, y, z + d, x, y, z + d, x + w, y + .1f, z + d);
442 }
443
444 #if 0 /* No longer used */
445 void
446 addCubeCentered(Occluder * pOcc, float x, float y, float z, float w, float h, float d)
447 {
448 x -= w / 2.0f;
449 y -= h / 2.0f;
450 z -= d / 2.0f;
451
452 addCube(pOcc, x, y, z, w, h, d);
453 }
454 #endif
455
456 void
addCylinder(Occluder * pOcc,float x,float y,float z,float r,float d,unsigned int numSteps)457 addCylinder(Occluder * pOcc, float x, float y, float z, float r, float d, unsigned int numSteps)
458 {
459 float step = (2 * (float) G_PI) / numSteps;
460 float *xPts = (float *) malloc(sizeof(float) * numSteps);
461 float *yPts = (float *) malloc(sizeof(float) * numSteps);
462 unsigned int i;
463 g_assert(xPts && yPts);
464
465 for (i = 0; i < numSteps; i++) {
466 float ang = step * i + (step / 2.0f);
467 xPts[i] = sinf(ang) * r;
468 yPts[i] = cosf(ang) * r;
469 }
470 for (i = 0; i < numSteps; i++) {
471 unsigned int next = ((i + 1) == numSteps) ? 0 : i + 1;
472 unsigned int prev = (i == 0) ? numSteps - 1 : i - 1;
473
474 addLine(pOcc, x + xPts[next], y + yPts[next], z + d, x + xPts[i], y + yPts[i], z + d,
475 x + xPts[next], y + yPts[next], z + d - .1f);
476 addLine(pOcc, x + xPts[i], y + yPts[i], z + d, x + xPts[next], y + yPts[next], z + d, x, y, z + d);
477
478 addLine(pOcc, x + xPts[i], y + yPts[i], z, x + xPts[next], y + yPts[next], z,
479 x + xPts[i], y + yPts[i], z + .1f);
480 addLine(pOcc, x + xPts[next], y + yPts[next], z, x + xPts[i], y + yPts[i], z, x, y, z);
481
482 addLine(pOcc, x + xPts[i], y + yPts[i], z, x + xPts[i], y + yPts[i], z + d, x + xPts[prev], y + yPts[prev], z);
483 addLine(pOcc, x + xPts[i], y + yPts[i], z + d, x + xPts[i], y + yPts[i], z, x + xPts[next], y + yPts[next], z);
484 }
485 free(xPts);
486 free(yPts);
487 }
488
489 void
addHalfTube(Occluder * pOcc,float r,float h,unsigned int numSteps)490 addHalfTube(Occluder * pOcc, float r, float h, unsigned int numSteps)
491 {
492 float *xPts, *yPts;
493 float step;
494 unsigned int i;
495
496 if (numSteps == 0) {
497 g_assert_not_reached();
498 return;
499 }
500
501 step = ((2 * (float) G_PI) / numSteps) / 2.0f;
502
503 xPts = (float *) malloc(sizeof(float) * (numSteps + 1));
504 yPts = (float *) malloc(sizeof(float) * (numSteps + 1));
505 g_assert(xPts && yPts);
506
507 for (i = 0; i <= numSteps; i++) {
508 float ang = step * i - (float) G_PI_2;
509 xPts[i] = sinf(ang) * r;
510 yPts[i] = cosf(ang) * r;
511 }
512 for (i = 0; i < numSteps; i++) {
513 addLine(pOcc, xPts[i + 1], h, yPts[i + 1], xPts[i], h, yPts[i], xPts[i + 1], h - .1f, yPts[i + 1]);
514 addLine(pOcc, xPts[i], h, yPts[i], xPts[i + 1], h, yPts[i + 1], 0.f, h, 0.f);
515
516 addLine(pOcc, xPts[i], 0.f, yPts[i], xPts[i + 1], 0.f, yPts[i + 1], xPts[i], .1f, yPts[i]);
517 addLine(pOcc, xPts[i + 1], 0.f, yPts[i + 1], xPts[i], 0.f, yPts[i], 0.f, 0.f, 0.f);
518
519 if (i == 0)
520 addLine(pOcc, xPts[i], 0.f, yPts[i], xPts[i], h, yPts[i], xPts[i], 0.f, yPts[i] - .1f);
521 else
522 addLine(pOcc, xPts[i], 0.f, yPts[i], xPts[i], h, yPts[i], xPts[i - 1], 0.f, yPts[i - 1]);
523
524 addLine(pOcc, xPts[i], h, yPts[i], xPts[i], 0.f, yPts[i], xPts[i + 1], 0.f, yPts[i + 1]);
525 }
526 addLine(pOcc, xPts[i], 0.f, yPts[i], xPts[i], h, yPts[i], xPts[i - 1], 0.f, yPts[i - 1]);
527 addLine(pOcc, xPts[i], h, yPts[i], xPts[i], 0.f, yPts[i], xPts[i], 0.f, yPts[i] - .1f);
528
529 free(xPts);
530 free(yPts);
531 }
532
533 static float
GetValue(float x,float y,float d,unsigned int c,unsigned int a,unsigned int b)534 GetValue(float x, float y, float d, unsigned int c, unsigned int a, unsigned int b)
535 { /* Map (x, y, d) to corner c, face a return b co-ord */
536 unsigned int i = c / 4, j = (c / 2) % 2, k = c % 2;
537 unsigned int minus, val;
538 if ((i + j + k) % 2)
539 val = ((7 - (b + a)) % 3) + 1;
540 else
541 val = ((b + 3 - a) % 3) + 1;
542
543 minus = ((k && b == 0) || (j && b == 1) || (i && b == 2));
544
545 switch (val) {
546 case 1:
547 return minus ? -x : x;
548 case 2:
549 return minus ? -y : y;
550 case 3:
551 return minus ? -d : d;
552 default:
553 return 0;
554 }
555 }
556
557 static void
GetCoords(float x,float y,float d,unsigned int c,unsigned int f,float v[3])558 GetCoords(float x, float y, float d, unsigned int c, unsigned int f, float v[3])
559 { /* Map (x, y, d) to corner c, face f put result in v */
560 v[0] = GetValue(x, y, d, c, f, 0);
561 v[1] = GetValue(x, y, d, c, f, 1);
562 v[2] = GetValue(x, y, d, c, f, 2);
563 }
564
565 void
addDice(Occluder * pOcc,float size)566 addDice(Occluder * pOcc, float size)
567 { /* Hard-coded numSteps to keep model simple + doesn't work correctly when > 8... */
568 unsigned int numSteps = 8;
569 float step = (2 * (float) G_PI) / numSteps;
570 float *xPts = (float *) malloc(sizeof(float) * numSteps);
571 float *yPts = (float *) malloc(sizeof(float) * numSteps);
572 unsigned int i, c, f;
573 g_assert(xPts && yPts);
574
575 for (i = 0; i < numSteps; i++) {
576 float ang = step * i;
577 xPts[i] = sinf(ang) * size;
578 yPts[i] = cosf(ang) * size;
579 }
580
581 for (c = 0; c < 8; c++) {
582 for (f = 0; f < 3; f++) {
583 for (i = 0; i < numSteps / 4; i++) {
584 unsigned int prevFace = (f + 2) % 3;
585 unsigned int nextFace = (f + 1) % 3;
586 unsigned int oppPoint = numSteps / 4 - i;
587
588 float v1[3], v2[3], v3[3];
589 GetCoords(xPts[i], yPts[i], size, c, f, v1);
590 GetCoords(xPts[i + 1], yPts[i + 1], size, c, f, v2);
591
592 GetCoords(0.f, 0.f, size, c, f, v3);
593 addLineV(pOcc, v1, v2, v3);
594
595 if (i == 0)
596 GetCoords(xPts[oppPoint - 1], yPts[oppPoint - 1], size, c, prevFace, v3);
597 else
598 GetCoords(xPts[oppPoint], yPts[oppPoint], size, c, nextFace, v3);
599 addLineV(pOcc, v2, v1, v3);
600
601 if (i > 0) {
602 addLineV(pOcc, v1, v3, v2);
603
604 GetCoords(xPts[i], yPts[i], size, c, prevFace, v2);
605 addLineV(pOcc, v3, v1, v2);
606 }
607 }
608 }
609 }
610
611 free(xPts);
612 free(yPts);
613 }
614