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