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