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