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