http://www.jwz.org/xscreensaver/xscreensaver-5.12.tar.gz
[xscreensaver] / hacks / glx / tangram.c
1 /* tangram, Copyright (c) 2005 Jeremy English <jhe@jeremyenglish.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software
4  * and its documentation for any purpose is hereby granted without
5  * fee, provided that the above copyright notice appear in all copies
6  * and that both that copyright notice and this permission notice
7  * appear in supporting documentation.  No representations are made
8  * about the suitability of this software for any purpose.  It is
9  * provided "as is" without express or implied warranty.
10  *
11  * Sun 10 July 2005 Changed the code that solves the puzzles.
12  *                  Also, limited the palette and added names. 
13  *
14  * Wed 13 July 2005 Added option to turn off rotation.
15  *                  Changed color and materials
16  */
17
18
19 #define DEFAULTS        "*delay:        10000            \n" \
20                         "*wireframe:    False         \n" \
21                         "*titleFont:  -*-helvetica-medium-r-normal-*-180-*\n" \
22                         "*titleFont2: -*-helvetica-medium-r-normal-*-120-*\n" \
23                         "*titleFont3: -*-helvetica-medium-r-normal-*-80-*\n"  \
24
25 # define refresh_tangram 0
26 # define release_tangram 0
27 # define tangram_handle_event 0
28 #undef countof
29 #define countof(x) (sizeof((x))/sizeof((*x)))
30
31 #include "xlockmore.h"
32
33 #include <ctype.h>
34
35
36 #ifdef USE_GL                   /* whole file */
37
38 #include <time.h>
39 #include <math.h>
40 #include "tangram_shapes.h"
41 #include "glxfonts.h"
42
43 typedef struct {
44     GLubyte r;
45     GLubyte g;
46     GLubyte b;
47 } color;
48
49 typedef struct {
50     GLfloat x;
51     GLfloat y;
52     GLfloat z;
53 } coord;
54
55 typedef struct {
56     coord crd;                  /* coordinates */
57     GLint r;                    /* rotation */
58     GLint fr;                   /* flip Rotate. Used to keep track during animation */
59     GLint dl;                   /* display List */
60     GLfloat dz;                 /* velocity */
61     GLfloat ddz;                /* Acceleration */
62     GLfloat solved;             /* shapes state */
63     Bool up;                    /* Move up the z axis? */
64 } tangram_shape;
65
66 typedef struct {
67     char *name;
68     tangram_shape ts[7];
69 } puzzle;
70
71 typedef enum {
72     no_shape = -1,
73     small_triangle1 = 0,
74     small_triangle2 = 1,
75     medium_triangle = 2,
76     large_triangle1 = 3,
77     large_triangle2 = 4,
78     square = 5,
79     rhomboid = 6
80 } shape_type;
81
82 #define SPEED 0.03
83 enum {
84     BOTTOM = 0,
85     DEF_WAIT = 500,
86     INIT_DZ = 2,
87     NUM_SHAPES = 7
88 };
89
90 typedef struct {
91     GLXContext *glx_context;
92     tangram_shape tsm1, tsm2, tm, tlg1, tlg2, sq, rh;
93     tangram_shape n_tsm1, n_tsm2, n_tm, n_tlg1, n_tlg2, n_sq, n_rh;
94     char *puzzle_name;
95     int csi;
96
97     int ncolors;
98     XColor *colors;
99     int ccolor;
100
101     XFontStruct *xfont1;
102     XFontStruct *xfont2;
103     XFontStruct *xfont3;
104     GLuint font1_dlist, font2_dlist, font3_dlist;
105     GLuint name_list;
106
107     GLfloat theta[3];
108     Bool going_down[3];
109
110     const char *pn;
111     int display_counter;
112
113 } tangram_configuration;
114
115 static tangram_configuration *tps = NULL;
116
117 #define DEF_VIEWING_TIME "5"
118 #define DEF_ROTATE "True"
119 #define DEF_X_CAMERA_ROTATE "0.2"
120 #define DEF_Y_CAMERA_ROTATE "0.5"
121 #define DEF_Z_CAMERA_ROTATE "0"
122 #define DEF_LABELS "True"
123
124 static GLuint viewing_time;
125 static Bool do_rotate;
126 static Bool do_labels;
127 static GLfloat x_camera_rotate;
128 static GLfloat y_camera_rotate;
129 static GLfloat z_camera_rotate;
130 static int wire;
131
132 static XrmOptionDescRec opts[] = {
133     {"-viewing_time", ".viewingTime", XrmoptionSepArg, 0},
134     {"-rotate", ".rotate", XrmoptionNoArg, "True"},
135     {"+rotate", ".rotate", XrmoptionNoArg, "False"},
136     {"-labels", ".labels", XrmoptionNoArg, "True"},
137     {"+labels", ".labels", XrmoptionNoArg, "False"},
138     {"-x_camera_rotate", ".xCameraRotate", XrmoptionSepArg, 0},
139     {"-y_camera_rotate", ".yCameraRotate", XrmoptionSepArg, 0},
140     {"-z_camera_rotate", ".zCameraRotate", XrmoptionSepArg, 0}
141 };
142
143 static argtype vars[] = {
144     {&viewing_time, "viewingTime", "ViewingTime", DEF_VIEWING_TIME, t_Int},
145     {&do_rotate, "rotate", "Rotate", DEF_ROTATE, t_Bool},
146     {&do_labels, "labels", "Labels", DEF_LABELS, t_Bool},
147     {&x_camera_rotate, "xCameraRotate", "XCameraRotate", DEF_X_CAMERA_ROTATE, t_Float},
148     {&y_camera_rotate, "yCameraRotate", "YCameraRotate", DEF_Y_CAMERA_ROTATE, t_Float},
149     {&z_camera_rotate, "zCameraRotate", "ZCameraRotate", DEF_Z_CAMERA_ROTATE, t_Float}
150 };
151
152 ENTRYPOINT ModeSpecOpt tangram_opts = { countof(opts), opts, countof(vars), vars, NULL };
153
154 static const puzzle solved[] = {
155   {"Teapot", {
156       {{-1.664000, -1.552000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
157       {{-1.696000, 0.944000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0,  False},
158       {{0.064000, -2.128000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0,  True},
159       {{-0.960000, -1.056000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, False},
160       {{1.104000, 0.960000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
161       {{-1.376000, -0.800000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
162       {{1.152000, 0.736000, 0}, 360, 0, 0, INIT_DZ, -SPEED, 0, True},
163     },
164   },
165   {"Candle", {
166       {{-0.016000, 2.176001, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, False},
167       {{0.016000, 2.960001, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
168       {{0.000000, 0.400000, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, False},
169       {{-2.015998, 2.208001, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, True},
170       {{2.000001, 2.208001, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
171       {{0.496000, 0.432000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
172       {{-0.016000, -0.672000, 0}, 335, 0, 0, INIT_DZ, -SPEED, 0, False},
173     },
174   },
175   {"Square", {
176       {{-0.048000, -0.016000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
177       {{0.704000, 0.736000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
178       {{-1.488000, 1.424001, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, True},
179       {{-0.016000, -0.016000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
180       {{0.000000, 0.000000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
181       {{0.688000, 0.720000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
182       {{-0.784000, 0.672000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
183     },
184   },
185   {"Crane", {
186       {{1.248001, 1.759999, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
187       {{1.024000, 3.071999, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
188       {{-0.975999, -2.096001, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
189       {{0.480000, -1.968001, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
190       {{1.056000, -0.496000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
191       {{-0.239999, -1.312001, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
192       {{-0.223999, -1.360001, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
193     },
194   },
195   {"Crane", {
196       {{0.320000, 1.360000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
197       {{0.704000, 3.072000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
198       {{-1.200000, -3.392000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
199       {{0.688000, -1.184000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
200       {{-0.768000, 0.192000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
201       {{-1.168000, -2.304000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
202       {{1.312000, 1.296000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
203     },
204   },
205   {"Duck", {
206       {{-1.391999, 1.424000, 0}, 65, 0, 0, INIT_DZ, -SPEED, 0, False},
207       {{0.768000, 2.000000, 0}, 99, 180, 0, INIT_DZ, -SPEED, 0, True},
208       {{2.688001, -1.872000, 0}, 270, 180, 0, INIT_DZ, -SPEED, 0, False},
209       {{-1.343999, 0.944000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
210       {{0.112000, -0.464000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
211       {{1.984001, -1.120000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
212       {{1.536001, 0.912000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, False},
213     },
214   },
215   {"Pelican", {
216       {{1.088000, 0.064001, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
217       {{0.864000, -1.279999, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, False},
218       {{-1.807999, 1.520000, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, True},
219       {{1.824001, -1.231998, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
220       {{-0.368000, 1.472000, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, True},
221       {{0.832000, -2.271998, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
222       {{1.776001, 0.816000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
223     },
224   },
225   {"Cat", {
226       {{0.416000, -2.432000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, False},
227       {{0.352000, -2.432000, 0}, 225, 180, 0, INIT_DZ, -SPEED, 0, True},
228       {{0.832000, -0.480000, 0}, 225, 180, 0, INIT_DZ, -SPEED, 0, False},
229       {{-1.632000, 3.056000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, True},
230       {{-1.616000, 1.040000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, False},
231       {{1.088000, -1.696000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
232       {{0.832000, -0.432000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
233     },
234   },
235   {"Coi", {
236       {{1.264000, -1.232000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
237       {{1.216000, 0.816000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, False},
238       {{-1.631999, 1.872000, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, True},
239       {{0.832000, 2.287999, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
240       {{-0.608000, 0.912000, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, True},
241       {{2.240001, -0.176000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
242       {{0.256000, -1.200000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
243     },
244   },
245   {"Man Skipping", {
246       {{1.727998, 2.303998, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
247       {{-1.120000, 3.376001, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, True},
248       {{0.879998, -3.008001, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
249       {{-1.072000, 2.559999, 0}, 360, 0, 0, INIT_DZ, -SPEED, 0, True},
250       {{-1.440000, 0.144000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, False},
251       {{-0.192001, -2.592001, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
252       {{0.015999, 0.176000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
253     },
254   },
255   {"Old Man", {
256       {{-0.400000, 1.744000, 0}, 58, 180, 0, INIT_DZ, -SPEED, 0, True},
257       {{0.704000, 0.128000, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, False},
258       {{0.656000, 0.320000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, True},
259       {{-0.112000, -0.384000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
260       {{-0.096000, -0.399999, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, True},
261       {{-0.736000, 0.352000, 0}, 123, 0, 0, INIT_DZ, -SPEED, 0, False},
262       {{-0.336000, 0.352000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
263     },
264   },
265   {"Spear Head", {
266       {{0.688000, -0.144000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, False},
267       {{-0.080000, 0.592000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
268       {{-0.048000, 0.592000, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, False},
269       {{-1.488000, -0.848000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
270       {{1.376000, -0.864000, 0}, 225, 180, 0, INIT_DZ, -SPEED, 0, False},
271       {{0.688000, -0.128000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
272       {{-1.504000, -0.832000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
273     },
274   },
275   {"Diamond", {
276       {{0.624000, -1.776000, 0}, 225, 180, 0, INIT_DZ, -SPEED, 0, True},
277       {{-0.144000, 0.432000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
278       {{-0.800000, -0.272000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, True},
279       {{-2.320000, -0.304000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, False},
280       {{2.048000, -0.320000, 0}, 225, 180, 0, INIT_DZ, -SPEED, 0, True},
281       {{-0.112000, 0.480000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
282       {{-0.832000, -0.320000, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, True},
283     },
284   },
285   {"Arrow", {
286       {{-2.048001, -1.232000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, False},
287       {{0.112000, 0.943999, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
288       {{-1.312001, -0.560000, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, False},
289       {{0.496000, 0.656000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
290       {{0.528000, 0.608000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, False},
291       {{-2.048001, -2.704000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
292       {{-1.312001, -0.512000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, False},
293     },
294   },
295   {"Lady", {
296       {{-0.720000, 3.440000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, True},
297       {{0.912000, -1.072000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
298       {{0.736000, 3.440000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, True},
299       {{0.720000, 1.984000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
300       {{-0.672000, 0.544000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, True},
301       {{-0.192000, -3.840000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
302       {{-0.528000, -2.480000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
303     },
304   },
305   {"Running Man", {
306       {{1.136000, 2.720000, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, False},
307       {{-2.304001, 1.776000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
308       {{-0.256000, 0.288000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, False},
309       {{-0.304000, 0.304000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
310       {{0.096000, -0.128000, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, False},
311       {{-0.656000, -2.832000, 0}, 105, 0, 0, INIT_DZ, -SPEED, 0, True},
312       {{0.784000, -0.096000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
313     },
314   },
315   {"Parallelogram", {
316       {{-1.104000, -1.455999, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
317       {{0.912000, -0.447999, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
318       {{-0.048000, -1.471999, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
319       {{-1.136000, -1.439999, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
320       {{0.944000, 1.552000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, True},
321       {{0.912000, 0.560000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
322       {{-0.112000, 1.568000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, True},
323     },
324   },
325   {"N", {
326       {{-1.615999, 0.064000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
327       {{-0.592000, 0.112000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
328       {{0.432000, 0.096000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, False},
329       {{-1.679999, -0.880000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
330       {{1.488001, 1.103999, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
331       {{-0.640000, 0.112000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
332       {{1.392001, -0.928000, 0}, 270, 180, 0, INIT_DZ, -SPEED, 0, False},
333     },
334   },
335   {"Farm House", {
336       {{2.112000, 1.504000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, True},
337       {{-1.040000, 1.472000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, False},
338       {{0.032000, -1.600000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
339       {{1.056000, 1.504000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
340       {{-0.992000, -0.528000, 0}, 0, 180, 0, INIT_DZ, -SPEED, 0, True},
341       {{2.080000, 0.512000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
342       {{-1.104000, 0.480000, 0}, 270, 180, 0, INIT_DZ, -SPEED, 0, True},
343     },
344   },
345   {"Vulture", {
346       {{0.912000, 1.728000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
347       {{-2.623998, -1.040000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
348       {{0.992000, 1.104000, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, False},
349       {{0.944000, -0.288000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
350       {{-0.448000, -1.760000, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, False},
351       {{-1.887998, -0.368000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
352       {{3.008002, 2.160000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
353     },
354   },
355   {"Swan", {
356       {{0.720000, 0.352000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
357       {{0.672000, -1.568000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
358       {{1.376000, 1.104000, 0}, 225, 180, 0, INIT_DZ, -SPEED, 0, True},
359       {{-1.151999, 1.488000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
360       {{0.320000, 2.096000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, True},
361       {{0.656000, 0.304000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
362       {{0.624000, -2.559999, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, True},
363     },
364   },
365   {"High Karate", {
366       {{-0.144000, 2.576000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
367       {{1.696001, -2.432000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
368       {{2.176001, -0.400000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, False},
369       {{-0.624000, -0.512000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
370       {{-0.576000, -1.152000, 0}, 0, 180, 0, INIT_DZ, -SPEED, 0, False},
371       {{-1.919999, -1.376000, 0}, 303, 0, 0, INIT_DZ, -SPEED, 0, True},
372       {{0.448000, -0.096001, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
373     },
374   },
375   {"Lazy", {
376       {{-2.416000, 1.120000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
377       {{-1.952000, -2.016000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, False},
378       {{-1.552000, -0.640000, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, True},
379       {{-0.016000, 1.840000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
380       {{1.456000, -1.072000, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, True},
381       {{0.848000, -0.816000, 0}, 332, 0, 0, INIT_DZ, -SPEED, 0, False},
382       {{-1.200000, -1.792000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
383     },
384   },
385   {"Bat", {
386       {{-0.304000, -0.352000, 0}, 259, 0, 0, INIT_DZ, -SPEED, 0, False},
387       {{0.304000, -1.344000, 0}, 105, 0, 0, INIT_DZ, -SPEED, 0, True},
388       {{1.312000, -1.024000, 0}, 300, 180, 0, INIT_DZ, -SPEED, 0, False},
389       {{1.952000, 0.240000, 0}, 195, 0, 0, INIT_DZ, -SPEED, 0, True},
390       {{-2.272000, 0.096000, 0}, 11, 180, 0, INIT_DZ, -SPEED, 0, False},
391       {{-0.112000, -1.056000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
392       {{-0.560000, -1.344000, 0}, 281, 180, 0, INIT_DZ, -SPEED, 0, False},
393     },
394   },
395   {"Sail Boat", {
396       {{0.544000, 2.000000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
397       {{0.880000, 0.160000, 0}, 360, 0, 0, INIT_DZ, -SPEED, 0, False},
398       {{0.656000, -1.503999, 0}, 220, 180, 0, INIT_DZ, -SPEED, 0, True},
399       {{-0.656000, -0.336000, 0}, 50, 0, 0, INIT_DZ, -SPEED, 0, False},
400       {{-0.688000, -0.288000, 0}, 310, 180, 0, INIT_DZ, -SPEED, 0, True},
401       {{0.864000, 1.232000, 0}, 360, 0, 0, INIT_DZ, -SPEED, 0, False},
402       {{0.496000, 2.016001, 0}, 225, 180, 0, INIT_DZ, -SPEED, 0, True},
403     },
404   },
405   {"Glenda", {
406       {{-2.016000, 2.080000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, False},
407       {{0.240001, 1.824000, 0}, 360, 0, 0, INIT_DZ, -SPEED, 0, True},
408       {{2.239999, -0.752000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, False},
409       {{-1.264000, 2.784000, 0}, 360, 0, 0, INIT_DZ, -SPEED, 0, True},
410       {{-1.248000, 0.736000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, False},
411       {{0.240001, 0.304000, 0}, 360, 0, 0, INIT_DZ, -SPEED, 0, True},
412       {{0.544000, -2.976001, 0}, 149, 0, 0, INIT_DZ, -SPEED, 0, False},
413     },
414   },
415   {"Cat", {
416       {{1.376000, -1.536001, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
417       {{1.488000, -1.552001, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, False},
418       {{0.352000, -0.048000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
419       {{-2.144000, 2.415999, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
420       {{-2.096000, 0.368000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
421       {{2.144000, -0.800000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
422       {{1.392000, -0.064000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
423     },
424   },
425   {"Lying Cat", {
426       {{2.480000, -0.912000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
427       {{2.592000, -0.928000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
428       {{0.352000, 1.280000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
429       {{-0.688000, 0.336000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
430       {{1.808000, -0.112000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
431       {{3.248000, -0.176000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
432       {{-1.472000, 1.024000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
433     },
434   },
435   {"Witch", {
436       {{-0.943999, -0.304000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
437       {{-0.144000, 0.288000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
438       {{1.360000, -2.304000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
439       {{1.328000, -0.848000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
440       {{1.008000, 1.584000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
441       {{0.512000, 2.688000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
442       {{-0.863999, -0.096000, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, True},
443     },
444   },
445   {"Laugh", {
446       {{0.703999, -0.160000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
447       {{-0.064000, -0.400000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
448       {{0.767999, -1.408000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
449       {{-1.232000, -1.328000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
450       {{-1.040000, 2.624000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
451       {{-0.288000, 1.264000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
452       {{-1.760001, -1.408000, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, False},
453     },
454   },
455   {"Standing Man", {
456       {{0.272000, 3.392000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
457       {{-0.144000, -1.328000, 0}, 331, 0, 0, INIT_DZ, -SPEED, 0, False},
458       {{1.216001, 0.272000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
459       {{0.736000, 0.208000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
460       {{0.432000, -3.440000, 0}, 151, 0, 0, INIT_DZ, -SPEED, 0, True},
461       {{0.720000, 2.320000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
462       {{-1.263998, 0.272000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
463     },
464   },
465   {"Walking Man", {
466       {{-1.056000, -3.456000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, False},
467       {{0.736000, 2.000000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
468       {{-1.488000, 1.760000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, False},
469       {{-0.432000, 0.016000, 0}, 0, 180, 0, INIT_DZ, -SPEED, 0, True},
470       {{-0.432000, -0.064000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
471       {{0.560000, -2.576000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
472       {{0.032000, 2.656000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
473     },
474   },
475   {"Repose", {
476       {{-2.800000, -2.304000, 0}, 101, 0, 0, INIT_DZ, -SPEED, 0, True},
477       {{1.888000, 2.032000, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, False},
478       {{-1.856000, 2.016000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
479       {{0.352000, -0.144000, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, False},
480       {{-2.848000, 0.976000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, True},
481       {{-1.424000, -1.104000, 0}, 236, 0, 0, INIT_DZ, -SPEED, 0, False},
482       {{-1.792000, 2.016000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
483     },
484   },
485   {"Shape", {
486       {{1.263999, 1.600001, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
487       {{1.311999, -1.568000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, True},
488       {{-0.736000, 0.576000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, False},
489       {{-0.736000, -2.591999, 0}, 360, 180, 0, INIT_DZ, -SPEED, 0, True},
490       {{-0.768000, 2.640001, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
491       {{-0.784000, -0.528000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
492       {{-0.736000, 0.496000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
493     },
494   },
495   {"Shape", {
496       {{-0.816000, 1.392000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
497       {{-0.832000, -1.807999, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, False},
498       {{1.216000, -0.752000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
499       {{1.232000, -2.815999, 0}, 270, 180, 0, INIT_DZ, -SPEED, 0, False},
500       {{1.248000, 2.400000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
501       {{-0.864000, 1.392000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
502       {{0.240000, 1.328000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, True},
503     },
504   },
505   {"Lightning", {
506       {{0.176000, -2.448000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, False},
507       {{-1.888000, 2.880000, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, True},
508       {{-1.856000, 1.824000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, False},
509       {{-1.872000, -1.392000, 0}, 0, 180, 0, INIT_DZ, -SPEED, 0, True},
510       {{1.264000, -0.432000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
511       {{2.320001, -2.432000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
512       {{-1.872000, 1.728000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, False},
513     },
514   },
515   {"E", {
516       {{0.928000, 1.664000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
517       {{0.896000, -1.519998, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, False},
518       {{-1.136000, 0.608000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
519       {{-1.152000, -2.559998, 0}, 0, 180, 0, INIT_DZ, -SPEED, 0, False},
520       {{-1.152000, 2.672002, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, True},
521       {{0.960000, -0.384000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
522       {{-1.136000, 0.528000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, True},
523     },
524   },
525   {"Dagger", {
526       {{-0.096000, 0.448000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
527       {{0.640000, 2.656000, 0}, 225, 180, 0, INIT_DZ, -SPEED, 0, True},
528       {{-0.064000, -3.104000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
529       {{-0.767999, 1.184000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, True},
530       {{-0.080000, 0.416000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
531       {{0.416000, -2.064000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
532       {{-0.112000, 3.328001, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
533     },
534   },
535   {"Knight", {
536       {{-0.368000, 0.400000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
537       {{1.871998, -1.808000, 0}, 225, 180, 0, INIT_DZ, -SPEED, 0, False},
538       {{-1.056000, -0.368000, 0}, 0, 0, 0, INIT_DZ, -SPEED, 0, True},
539       {{-1.056000, -1.840000, 0}, 45, 180, 0, INIT_DZ, -SPEED, 0, False},
540       {{-0.352000, 1.440000, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, True},
541       {{0.128000, 0.432000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
542       {{1.119999, -1.120000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
543     },
544   },
545   {"Candy", {
546       {{-1.039999, 1.136000, 0}, 360, 0, 0, INIT_DZ, -SPEED, 0, False},
547       {{1.024000, 0.096000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, True},
548       {{-0.016000, 0.048000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
549       {{-0.016000, -1.008000, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, True},
550       {{-0.016000, 1.216000, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, False},
551       {{1.024000, 0.144000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
552       {{-0.032000, 1.088000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, False},
553     },
554   },
555   {"King", {
556       {{-0.688000, 1.904000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
557       {{0.800000, 1.904000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
558       {{0.512000, -1.392000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, True},
559       {{1.488000, 1.120000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, False},
560       {{-1.392000, 1.120000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
561       {{0.496000, -1.312000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
562       {{0.480000, -1.376000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
563     },
564   },
565   {"Top", {
566       {{-1.055999, -0.800000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, False},
567       {{-1.103999, 0.208000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
568       {{0.000000, -0.784000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
569       {{0.016000, 0.272000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
570       {{-0.032000, 0.288000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
571       {{0.480000, -1.855999, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, True},
572       {{2.096001, 0.224000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
573     },
574   },
575   {"Dog", {
576       {{-2.896000, -0.128000, 0}, 45, 0, 0, INIT_DZ, -SPEED, 0, True},
577       {{-0.800000, 0.992000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, False},
578       {{-1.152000, -0.416000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
579       {{-0.016000, 0.656000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
580       {{1.456000, -0.736000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
581       {{2.864000, 0.736000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
582       {{-0.048000, 1.664000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, True},
583     },
584   },
585   {"Moose Head", {
586       {{2.944000, -0.288000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, False},
587       {{1.936000, -0.224000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, True},
588       {{-0.112000, 1.808000, 0}, 315, 0, 0, INIT_DZ, -SPEED, 0, False},
589       {{-2.128000, 0.768000, 0}, 90, 180, 0, INIT_DZ, -SPEED, 0, True},
590       {{1.888000, 0.768000, 0}, 180, 180, 0, INIT_DZ, -SPEED, 0, False},
591       {{-0.112000, -0.688000, 0}, 135, 0, 0, INIT_DZ, -SPEED, 0, True},
592       {{-3.184000, -1.216000, 0}, 360, 180, 0, INIT_DZ, -SPEED, 0, False},
593     },
594   },
595   {"Negative Square", {
596       {{-1.520000, -0.624000, 0}, 270, 0, 0, INIT_DZ, -SPEED, 0, True},
597       {{-1.520000, 0.480000, 0}, 180, 0, 0, INIT_DZ, -SPEED, 0, False},
598       {{2.352000, 0.480000, 0}, 225, 0, 0, INIT_DZ, -SPEED, 0, True},
599       {{-0.080000, -3.040000, 0}, 315, 180, 0, INIT_DZ, -SPEED, 0, False},
600       {{-0.096000, 2.944000, 0}, 135, 180, 0, INIT_DZ, -SPEED, 0, True},
601       {{-2.528000, -0.576000, 0}, 90, 0, 0, INIT_DZ, -SPEED, 0, False},
602       {{1.360000, -1.600000, 0}, 360, 180, INIT_DZ, -SPEED, 0, True},
603     }}
604 };
605 \f
606
607 static void get_solved_puzzle(ModeInfo * mi,
608                               tangram_shape * tsm1, tangram_shape * tsm2,
609                               tangram_shape * tm, tangram_shape * tlg1,
610                               tangram_shape * tlg2, tangram_shape * sq,
611                               tangram_shape * rh)
612 {
613     tangram_configuration *tp = &tps[MI_SCREEN(mi)];
614     int sz = sizeof(solved) / sizeof(solved[0]);
615     int r;
616
617     /* we don't want to see the same puzzle twice */
618     do {
619         r = random() % sz;
620     } while (r == tp->csi);
621     tp->csi = r;
622
623     *tsm1 = solved[r].ts[small_triangle1];
624     *tsm2 = solved[r].ts[small_triangle2];
625     *tm = solved[r].ts[medium_triangle];
626     *tlg1 = solved[r].ts[large_triangle1];
627     *tlg2 = solved[r].ts[large_triangle2];
628     *sq = solved[r].ts[square];
629     *rh = solved[r].ts[rhomboid];
630
631     tp->puzzle_name = solved[r].name;
632 }
633
634 static int approach_number(int goal, int current, int step)
635 {
636
637     int i = 0;
638
639     if (goal > current) {
640         while (i < step) {
641             current++;
642             if (goal <= current)
643                 break;
644             i++;
645         }
646     } else if (goal < current) {
647         while (i < step) {
648             current--;
649             if (goal >= current)
650                 break;
651             i++;
652         }
653     }
654
655     return current;
656 }
657
658 /* gt - floating point greater than comparison */
659 static Bool gt(GLfloat x1, GLfloat x2, GLfloat per)
660 {
661     if ((x1 > x2) && (fabs(x1 - x2) > per))
662         return True;
663     else
664         return False;
665 }
666
667 /* lt - floating point less than comparison */
668 static Bool lt(GLfloat x1, GLfloat x2, GLfloat per)
669 {
670     if ((x1 < x2) && (fabs(x1 - x2) > per))
671         return True;
672     else
673         return False;
674 }
675
676 static GLfloat approach_float(GLfloat goal, GLfloat current,
677                               Bool * changed, GLfloat per)
678 {
679     *changed = False;
680     if (gt(goal, current, per)) {
681         current += per;
682         *changed = True;
683     } else if (lt(goal, current, per)) {
684         current -= per;
685         *changed = True;
686     }
687     return current;
688 }
689
690 #if 0
691 static void print_shape(char *s, tangram_shape sh)
692 {
693     fprintf(stderr, "%s\n", s);
694     fprintf(stderr, "(%f, %f, %f)\n", sh.crd.x, sh.crd.y, sh.crd.z);
695     fprintf(stderr, "%d\n", sh.r);
696     fprintf(stderr, "%d\n", sh.fr);
697     fprintf(stderr, "\n");
698 }
699 #endif
700 \f
701
702 static void reset_shape(tangram_shape * ts)
703 {
704     GLfloat r = random() % 10;
705     GLfloat f = r / 10;
706     ts->crd.z = BOTTOM;
707     ts->dz = INIT_DZ + f;
708     ts->ddz = -SPEED;
709 }
710
711 static void bounce(tangram_shape * ts)
712 {
713     ts->crd.z *= -1;            /* ignore this */
714     ts->dz += ts->ddz;
715     ts->crd.z += ts->dz * SPEED;
716     if (ts->crd.z < BOTTOM) {
717         reset_shape(ts);
718     }
719
720     ts->crd.z *= -1;            /* ignore this */
721 }
722
723 static void draw_tangram_shape(tangram_shape ts)
724 {
725     glPushMatrix();
726
727     if (!do_rotate) {
728         ts.up = True;
729     }
730
731     glTranslatef(ts.crd.x, ts.crd.y, ts.up ? ts.crd.z : -ts.crd.z);
732     glRotated(90, 1, 0, 0);
733     glRotated(ts.fr, 1, 0, 0);
734     glRotated(ts.r, 0, 1, 0);
735     glCallList(ts.dl);
736     glPopMatrix();
737 }
738
739 static void load_fonts(ModeInfo * mi)
740 {
741     tangram_configuration *tp = &tps[MI_SCREEN(mi)];
742     load_font(mi->dpy, "titleFont", &tp->xfont1, &tp->font1_dlist);
743     load_font(mi->dpy, "titleFont2", &tp->xfont2, &tp->font2_dlist);
744     load_font(mi->dpy, "titleFont3", &tp->xfont3, &tp->font3_dlist);
745 }
746
747 static void draw_shapes(ModeInfo * mi)
748 {
749     tangram_configuration *tp = &tps[MI_SCREEN(mi)];
750
751     draw_tangram_shape(tp->tsm1);
752
753     draw_tangram_shape(tp->tsm2);
754     draw_tangram_shape(tp->tm);
755     draw_tangram_shape(tp->tlg1);
756     draw_tangram_shape(tp->tlg2);
757     draw_tangram_shape(tp->sq);
758     draw_tangram_shape(tp->rh);
759     if (do_labels) glCallList(tp->name_list);
760 }
761
762 static void set_perspective(void)
763 {
764     glPushMatrix();
765     glMatrixMode(GL_PROJECTION);
766     glLoadIdentity();
767     gluPerspective(60, -1, 0.1, 50);
768     gluLookAt(0, 5, -5, 0, 0, 0, 0, -1, 0);
769     glMatrixMode(GL_MODELVIEW);
770     glPopMatrix();
771
772 }
773
774 ENTRYPOINT void reshape_tangram(ModeInfo * mi, int w, int h)
775 {
776     glViewport(0, 0, w, h);
777     set_perspective();
778     glLoadIdentity();
779 }
780
781 static void set_camera(tangram_configuration *tp)
782 {
783     glPushMatrix();
784     glMatrixMode(GL_PROJECTION);
785     glLoadIdentity();
786     gluPerspective(60, -1, 0.1, 50);
787
788
789     gluLookAt(0, 5, -5, 0, 0, 0, 0, -1, 0);
790
791     if (do_rotate) {
792         glRotatef(tp->theta[0], 1, 0, 0);
793         glRotatef(tp->theta[1], 0, 1, 0);
794         glRotatef(tp->theta[2], 0, 0, 1);
795     }
796
797     glMatrixMode(GL_MODELVIEW);
798     glPopMatrix();
799
800
801     if (tp->going_down[0] && tp->theta[0] < 0) {
802
803         tp->going_down[0] = False;
804     } else if ((!tp->going_down[0]) && tp->theta[0] > 90) {
805
806         tp->going_down[0] = True;
807     }
808
809     if (tp->theta[1] > 360.0)
810         tp->theta[1] -= 360.0;
811
812     if (tp->theta[2] > 360.0)
813         tp->theta[2] -= 360.0;
814
815     if (tp->going_down[0])
816       tp->theta[0] -= x_camera_rotate;
817     else
818       tp->theta[0] += x_camera_rotate;
819
820     tp->theta[1] += y_camera_rotate;
821     tp->theta[2] += z_camera_rotate;
822 }
823
824 static void init_shapes(ModeInfo * mi)
825 {
826     int wire = MI_IS_WIREFRAME(mi);
827     tangram_configuration *tp = &tps[MI_SCREEN(mi)];
828     get_solved_puzzle(mi, &tp->tsm1, &tp->tsm2, &tp->tm, &tp->tlg1,
829                       &tp->tlg2, &tp->sq, &tp->rh);
830     get_solved_puzzle(mi, &tp->n_tsm1, &tp->n_tsm2, &tp->n_tm, &tp->n_tlg1,
831                       &tp->n_tlg2, &tp->n_sq, &tp->n_rh);
832     tp->tsm1.dl = get_sm_tri_dl(wire);
833     tp->tsm2.dl = get_sm_tri_dl(wire);
834     tp->tm.dl = get_md_tri_dl(wire);
835     tp->tlg1.dl = get_lg_tri_dl(wire);
836     tp->tlg2.dl = get_lg_tri_dl(wire);
837     tp->sq.dl = get_square_dl(wire);
838     tp->rh.dl = get_rhomboid_dl(wire);
839 }
840
841 static void gl_init(ModeInfo * mi)
842 {
843
844     int wire = MI_IS_WIREFRAME(mi);
845
846     GLfloat y = do_rotate ? -10 : 3;
847     GLfloat x = do_rotate ? 5 : 10;
848     GLfloat pos[4] = { 0, 0, -5, 1.00 };
849     GLfloat pos2[4] = { 0, 0, 5, 1.00 };
850     GLfloat dif2[4] = { 1, 1, 1, 1 };
851
852     pos[0] = -x;
853     pos[1] = y;
854
855     pos2[1] = x;
856     pos2[1] = y;
857
858     if (!wire) {
859         glEnable(GL_LIGHTING);
860         glLightfv(GL_LIGHT0, GL_POSITION, pos);
861         glEnable(GL_LIGHT0);
862         if (do_rotate) {
863             glLightfv(GL_LIGHT1, GL_POSITION, pos2);
864             glLightfv(GL_LIGHT1, GL_DIFFUSE, dif2);
865             glEnable(GL_LIGHT1);
866         }
867         glEnable(GL_DEPTH_TEST);
868     }
869
870 }
871
872 ENTRYPOINT void init_tangram(ModeInfo * mi)
873 {
874     tangram_configuration *tp;
875
876     if (!tps) {
877         tps = (tangram_configuration *)
878             calloc(MI_NUM_SCREENS(mi), sizeof(tangram_configuration));
879         if (!tps) {
880             fprintf(stderr, "%s: out of memory\n", progname);
881             exit(1);
882         }
883     }
884
885     tp = &tps[MI_SCREEN(mi)];
886
887     if ((tp->glx_context = init_GL(mi)) != NULL) {
888         gl_init(mi);
889     }
890
891     wire = MI_IS_WIREFRAME(mi);
892
893     tp->name_list = glGenLists(1);
894
895     load_fonts(mi);
896     init_shapes(mi);
897
898     tp->theta[0] = tp->theta[1] = tp->theta[2] = 1;
899
900 }
901
902 static Bool all_solved(tangram_shape * ls[])
903 {
904     int i;
905     Bool b = True;
906     for (i = 0; i < NUM_SHAPES; i++) {
907         b = (b && ls[i]->solved);
908     }
909     return b;
910 }
911
912 static void solve(tangram_shape * new_s, tangram_shape * old_s)
913 {
914     Bool moved_x, moved_y, moved_r, moved_fr, z_ok;
915
916     old_s->fr = approach_number(new_s->fr, old_s->fr, 2);
917     moved_fr = (old_s->fr != new_s->fr);
918
919     old_s->r = approach_number(new_s->r, old_s->r, 2);
920     moved_r = (old_s->r != new_s->r);
921
922     old_s->crd.x =
923         approach_float(new_s->crd.x, old_s->crd.x, &moved_x, 0.1);
924     if (!moved_x)
925         old_s->crd.x = new_s->crd.x;
926
927     old_s->crd.y =
928         approach_float(new_s->crd.y, old_s->crd.y, &moved_y, 0.1);
929     if (!moved_y)
930         old_s->crd.y = new_s->crd.y;
931
932     z_ok = (-old_s->crd.z <= BOTTOM);
933
934     old_s->solved = (moved_x == False && moved_y == False &&
935                      moved_r == False && moved_fr == False &&
936                      z_ok == True);
937 }
938
939 static void set_not_solved(tangram_shape * ls[])
940 {
941     int i;
942     for (i = 0; i < NUM_SHAPES; i++)
943         ls[i]->solved = False;
944 }
945 \f
946
947 ENTRYPOINT void draw_tangram(ModeInfo * mi)
948 {
949     Display *dpy = MI_DISPLAY(mi);
950     Window window = MI_WINDOW(mi);
951     tangram_configuration *tp = &tps[MI_SCREEN(mi)];
952
953     tangram_shape *ls[NUM_SHAPES];
954     tangram_shape *nls[NUM_SHAPES];
955
956
957     int i;
958     int MAX_DISPLAY;
959
960     GLfloat color[4] = { 0.0, 0.0, 0.0, 1.0 };
961     GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
962     MAX_DISPLAY = viewing_time * 100;
963
964     if (! tp->glx_context)
965       return;
966     glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tp->glx_context));
967
968     ls[small_triangle1] = &tp->tsm1;
969     ls[small_triangle2] = &tp->tsm2;
970     ls[medium_triangle] = &tp->tm;
971     ls[large_triangle1] = &tp->tlg1;
972     ls[large_triangle2] = &tp->tlg2;
973     ls[square] = &tp->sq;
974     ls[rhomboid] = &tp->rh;
975
976     nls[small_triangle1] = &tp->n_tsm1;
977     nls[small_triangle2] = &tp->n_tsm2;
978     nls[medium_triangle] = &tp->n_tm;
979     nls[large_triangle1] = &tp->n_tlg1;
980     nls[large_triangle2] = &tp->n_tlg2;
981     nls[square] = &tp->n_sq;
982     nls[rhomboid] = &tp->n_rh;
983
984     set_camera(tp);
985
986     if (tp->display_counter <= 0) {
987         for (i = 0; i < NUM_SHAPES; i++) {
988             if (ls[i]->solved) {
989                 if (all_solved(ls)) {
990                     tp->display_counter = MAX_DISPLAY;
991                     tp->pn = tp->puzzle_name;
992                     get_solved_puzzle(mi, nls[small_triangle1],
993                                       nls[small_triangle2],
994                                       nls[medium_triangle],
995                                       nls[large_triangle1],
996                                       nls[large_triangle2], nls[square],
997                                       nls[rhomboid]);
998                     tp->ncolors = 128;
999                     tp->colors =
1000                         (XColor *) calloc(tp->ncolors, sizeof(XColor));
1001
1002                     make_random_colormap(0, 0, 0,
1003                                          tp->colors, &tp->ncolors,
1004                                          True, False, 0, False);
1005
1006
1007                     color[0] = tp->colors[0].red / 65536.0;
1008                     color[1] = tp->colors[1].green / 65536.0;
1009                     color[2] = tp->colors[2].blue / 65536.0;
1010
1011
1012                     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
1013                                  color);
1014
1015                     set_not_solved(ls);
1016                     break;
1017                 }
1018             } else {
1019                 tp->pn = "";
1020                 bounce(ls[i]);
1021                 solve(nls[i], ls[i]);
1022             }
1023         }
1024     } else {
1025         tp->display_counter--;
1026     }
1027
1028     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1029     glPushMatrix();
1030
1031     glLoadIdentity();
1032     if (do_labels)
1033       {
1034         XFontStruct *f;
1035         GLuint fl;
1036         glNewList(tp->name_list, GL_COMPILE);
1037         if (MI_WIDTH(mi) >= 500 && MI_HEIGHT(mi) >= 375)
1038             f = tp->xfont1, fl = tp->font1_dlist;
1039         else if (MI_WIDTH(mi) >= 350 && MI_HEIGHT(mi) >= 260)
1040             f = tp->xfont2, fl = tp->font2_dlist;
1041         else
1042             f = tp->xfont3, fl = tp->font3_dlist;
1043
1044         glColor3f(0.8, 0.8, 0);
1045         print_gl_string(mi->dpy, f, fl,
1046                         mi->xgwa.width, mi->xgwa.height,
1047                         10, mi->xgwa.height - 10, tp->pn, False);
1048         glEndList();
1049       }
1050
1051     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white);
1052     glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 128);
1053
1054     draw_shapes(mi);
1055
1056     glFlush();
1057     glPopMatrix();
1058     glXSwapBuffers(dpy, window);
1059 }
1060
1061 XSCREENSAVER_MODULE ("Tangram", tangram)
1062
1063 #endif                          /* USE_GL */