1 | /* -*- Mode: C; tab-width: 4 -*- |
---|
2 | Ported from xlockmore 4.03a12 to be a standalone program and thus usable |
---|
3 | with xscreensaver by Jamie Zawinski <jwz@jwz.org> on 15-May-97. |
---|
4 | |
---|
5 | Original copyright notice from xlock.c: |
---|
6 | |
---|
7 | * Copyright (c) 1988-91 by Patrick J. Naughton. |
---|
8 | * |
---|
9 | * Permission to use, copy, modify, and distribute this software and its |
---|
10 | * documentation for any purpose and without fee is hereby granted, |
---|
11 | * provided that the above copyright notice appear in all copies and that |
---|
12 | * both that copyright notice and this permission notice appear in |
---|
13 | * supporting documentation. |
---|
14 | * |
---|
15 | * This file is provided AS IS with no warranties of any kind. The author |
---|
16 | * shall have no liability with respect to the infringement of copyrights, |
---|
17 | * trade secrets or any patents by this file or any part thereof. In no |
---|
18 | * event will the author be liable for any lost revenue or profits or |
---|
19 | * other special, indirect and consequential damages. |
---|
20 | */ |
---|
21 | |
---|
22 | #if 0 |
---|
23 | static const char sccsid[] = "@(#)bouboule.c 4.00 97/01/01 xlockmore"; |
---|
24 | #endif |
---|
25 | |
---|
26 | /*- |
---|
27 | * bouboule.c (bouboule mode for xlockmore) |
---|
28 | * |
---|
29 | * Sort of starfield for xlockmore. I found that making a starfield for |
---|
30 | * a 3D engine and thought it could be a nice lock mode. For a real starfield, |
---|
31 | * I only scale the sort of sphere you see to the whole sky and clip the stars |
---|
32 | * to the camera screen. |
---|
33 | * |
---|
34 | * Code Copyright 1996 by Jeremie PETIT (jeremie_petit@geocities.com) |
---|
35 | * |
---|
36 | * Use: batchcount is the number of stars. |
---|
37 | * cycles is the maximum size for a star |
---|
38 | * |
---|
39 | * 15-May-97: jwz@jwz.org: turned into a standalone program. |
---|
40 | * 04-Sep-96: Added 3d support (Henrik Theiling, theiling@coli-uni-sb.de) |
---|
41 | * 20-Feb-96: Added tests so that already malloced objects are not |
---|
42 | * malloced twice, thanks to the report from <mccomb@interport.net> |
---|
43 | * 01-Feb-96: Patched by Jouk Jansen <joukj@alpha.chem.uva.nl> for VMS |
---|
44 | * Patched by <bagleyd@bigfoot.com> for TrueColor displays |
---|
45 | * 30-Jan-96: Wrote all that I wanted to. |
---|
46 | * |
---|
47 | * DONE: Build up a XArc list and Draw everything once with XFillArcs |
---|
48 | * That idea came from looking at swarm code. |
---|
49 | * DONE: Add an old arcs list for erasing. |
---|
50 | * DONE: Make center of starfield SinVariable. |
---|
51 | * DONE: Add some random in the sinvary() function. |
---|
52 | * DONE: check time for erasing the stars with the two methods and use the |
---|
53 | * better one. Note that sometimes the time difference between |
---|
54 | * beginning of erasing and its end is negative! I check this, and |
---|
55 | * do not use this result when it occurs. If all values are negative, |
---|
56 | * the erasing will continue being done in the currently tested mode. |
---|
57 | * DONE: Allow stars size customization. |
---|
58 | * DONE: Make sizey be no less than half sizex or no bigger than twice sizex. |
---|
59 | * |
---|
60 | * IDEA: A simple check can be performed to know which stars are "behind" |
---|
61 | * and which are "in front". So is possible to very simply change |
---|
62 | * the drawing mode for these two sorts of stars. BUT: this would lead |
---|
63 | * to a rewrite of the XArc list code because drawing should be done |
---|
64 | * in two steps: "behind" stars then "in front" stars. Also, what could |
---|
65 | * be the difference between the rendering of these two types of stars? |
---|
66 | * IDEA: Calculate the distance of each star to the "viewer" and render the |
---|
67 | * star accordingly to this distance. Same remarks as for previous |
---|
68 | * ideas can be pointed out. This would even lead to reget the old stars |
---|
69 | * drawing code, that has been replaced by the XFillArcs. On another |
---|
70 | * hand, this would allow particular stars (own color, shape...), as |
---|
71 | * far as they would be individually drawn. One should be careful to |
---|
72 | * draw them according to their distance, that is not drawing a far |
---|
73 | * star after a close one. |
---|
74 | */ |
---|
75 | |
---|
76 | #ifdef STANDALONE |
---|
77 | # define PROGCLASS "Bouboule" |
---|
78 | # define HACK_INIT init_bouboule |
---|
79 | # define HACK_DRAW draw_bouboule |
---|
80 | # define bouboule_opts xlockmore_opts |
---|
81 | # define DEFAULTS "*count: 100 \n" \ |
---|
82 | "*size: 15 \n" \ |
---|
83 | "*delay: 5000 \n" \ |
---|
84 | "*ncolors: 64 \n" \ |
---|
85 | "*use3d: False \n" \ |
---|
86 | "*delta3d: 1.5 \n" \ |
---|
87 | "*right3d: red \n" \ |
---|
88 | "*left3d: blue \n" \ |
---|
89 | "*both3d: magenta \n" \ |
---|
90 | "*none3d: black \n" |
---|
91 | |
---|
92 | # define SMOOTH_COLORS |
---|
93 | # include "xlockmore.h" /* from the xscreensaver distribution */ |
---|
94 | #else /* !STANDALONE */ |
---|
95 | # include "xlock.h" /* from the xlockmore distribution */ |
---|
96 | #endif /* !STANDALONE */ |
---|
97 | |
---|
98 | ModeSpecOpt bouboule_opts = { |
---|
99 | 0, NULL, 0, NULL, NULL }; |
---|
100 | |
---|
101 | #define USEOLDXARCS 1 /* If 1, we use old xarcs list for erasing. |
---|
102 | * else we just roughly erase the window. |
---|
103 | * This mainly depends on the number of stars, |
---|
104 | * because when they are many, it is faster to |
---|
105 | * erase the whole window than to erase each star |
---|
106 | */ |
---|
107 | |
---|
108 | #if HAVE_GETTIMEOFDAY |
---|
109 | #define ADAPT_ERASE 1 /* If 1, then we try ADAPT_CHECKS black XFillArcs, |
---|
110 | * and after, ADAPT_CHECKS XFillRectangle. |
---|
111 | * We check which method seems better, knowing that |
---|
112 | * XFillArcs is generally visually better. So we |
---|
113 | * consider that XFillArcs is still better if its time |
---|
114 | * is about XFillRectangle * ADAPT_ARC_PREFERED |
---|
115 | * We need gettimeofday |
---|
116 | * for this... Does it exist on other systems ? Do we |
---|
117 | * have to use another function for others ? |
---|
118 | * This value overrides USEOLDXARCS. |
---|
119 | */ |
---|
120 | |
---|
121 | #ifdef USE_XVMSUTILS |
---|
122 | # if 0 |
---|
123 | # include "../xvmsutils/unix_time.h" |
---|
124 | # else |
---|
125 | # include <X11/unix_time.h> |
---|
126 | # endif |
---|
127 | #endif |
---|
128 | |
---|
129 | #include <sys/time.h> |
---|
130 | |
---|
131 | #define ADAPT_CHECKS 50 |
---|
132 | #define ADAPT_ARC_PREFERED 150 /* Maybe the value that is the most important |
---|
133 | * for adapting to a system */ |
---|
134 | #endif |
---|
135 | |
---|
136 | #define dtor(x) (((x) * M_PI) / 180.0) /* Degrees to radians */ |
---|
137 | |
---|
138 | #define MINSTARS 1 |
---|
139 | #define MINSIZE 1 |
---|
140 | /* jwz: I think slower color changes look better */ |
---|
141 | #define COLOR_CHANGES 50 /* How often we change colors (1 = always) |
---|
142 | * This value should be tuned accordingly to |
---|
143 | * the number of stars */ |
---|
144 | #define MAX_SIZEX_SIZEY 2. /* This controls whether the sphere can be very |
---|
145 | * very large and have a small height (or the |
---|
146 | * opposite) or no. */ |
---|
147 | |
---|
148 | #define THETACANRAND 80 /* percentage of changes for the speed of |
---|
149 | * change of the 3 theta values */ |
---|
150 | #define SIZECANRAND 80 /* percentage of changes for the speed of |
---|
151 | * change of the sizex and sizey values */ |
---|
152 | #define POSCANRAND 80 /* percentage of changes for the speed of |
---|
153 | * change of the x and y values */ |
---|
154 | /* Note that these XXXCANRAND values can be 0, that is no rand acceleration * |
---|
155 | variation. */ |
---|
156 | |
---|
157 | #define VARRANDALPHA (NRAND((int) (M_PI * 1000.0))/1000.0) |
---|
158 | #define VARRANDSTEP (M_PI/(NRAND(100)+100.0)) |
---|
159 | #define VARRANDMIN (-70.0) |
---|
160 | #define VARRANDMAX 70.0 |
---|
161 | |
---|
162 | #define MINZVAL 100 /* stars can come this close */ |
---|
163 | #define SCREENZ 2000 /* this is where the screen is */ |
---|
164 | #define MAXZVAL 10000 /* stars can go this far away */ |
---|
165 | |
---|
166 | #define GETZDIFF(z) ((MI_DELTA3D(mi))*20.0*(1.0-(SCREENZ)/(z+1000))) |
---|
167 | #define MAXDIFF MAX(-GETZDIFF(MINZVAL),GETZDIFF(MAXZVAL)) |
---|
168 | |
---|
169 | /* These values are the variation parameters of the acceleration variation * |
---|
170 | of the SinVariables that are randomized. */ |
---|
171 | |
---|
172 | /******************************/ |
---|
173 | typedef struct SinVariableStruct |
---|
174 | /******************************/ |
---|
175 | { |
---|
176 | double alpha; /* |
---|
177 | * Alpha is the current state of the sinvariable |
---|
178 | * alpha should be initialized to a value between |
---|
179 | * 0.0 and 2 * M_PI |
---|
180 | */ |
---|
181 | double step; /* |
---|
182 | * Speed of evolution of alpha. It should be a reasonable |
---|
183 | * fraction of 2 * M_PI. This value directly influence |
---|
184 | * the variable speed of variation. |
---|
185 | */ |
---|
186 | double minimum; /* Minimum value for the variable */ |
---|
187 | double maximum; /* Maximum value for the variable */ |
---|
188 | double value; /* Current value */ |
---|
189 | int mayrand; /* Flag for knowing whether some randomization can be |
---|
190 | * applied to the variable */ |
---|
191 | struct SinVariableStruct *varrand; /* Evolving Variable: the variation of |
---|
192 | * alpha */ |
---|
193 | } SinVariable; |
---|
194 | |
---|
195 | /***********************/ |
---|
196 | typedef struct StarStruct |
---|
197 | /***********************/ |
---|
198 | { |
---|
199 | double x, y, z; /* Position of the star */ |
---|
200 | short size; /* Try to guess */ |
---|
201 | } Star; |
---|
202 | |
---|
203 | /****************************/ |
---|
204 | typedef struct StarFieldStruct |
---|
205 | /****************************/ |
---|
206 | { |
---|
207 | short width, height; /* width and height of the starfield window */ |
---|
208 | short max_star_size; /* Maximum radius for stars. stars radius will |
---|
209 | * vary from 1 to MAX_STAR_SIZE */ |
---|
210 | SinVariable x; /* Evolving variables: */ |
---|
211 | SinVariable y; /* Center of the field on the screen */ |
---|
212 | SinVariable z; |
---|
213 | SinVariable sizex; /* Evolving variable: half width of the field */ |
---|
214 | SinVariable sizey; /* Evolving variable: half height of the field */ |
---|
215 | SinVariable thetax; /* Evolving Variables: */ |
---|
216 | SinVariable thetay; /* rotation angles of the starfield */ |
---|
217 | SinVariable thetaz; /* around x, y and z local axis */ |
---|
218 | Star *star; /* List of stars */ |
---|
219 | XArc *xarc; /* Current List of arcs */ |
---|
220 | XArc *xarcleft; /* additional list for the left arcs */ |
---|
221 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
222 | XArc *oldxarc; /* Old list of arcs */ |
---|
223 | XArc *oldxarcleft; |
---|
224 | #endif |
---|
225 | unsigned long color; /* Current color of the starfield */ |
---|
226 | int colorp; /* Pointer to color of the starfield */ |
---|
227 | int NbStars; /* Number of stars */ |
---|
228 | short colorchange; /* Counter for the color change */ |
---|
229 | #if (ADAPT_ERASE == 1) |
---|
230 | short hasbeenchecked; |
---|
231 | long rect_time; |
---|
232 | long xarc_time; |
---|
233 | #endif |
---|
234 | } StarField; |
---|
235 | |
---|
236 | static StarField *starfield = NULL; |
---|
237 | |
---|
238 | /*********/ |
---|
239 | static void |
---|
240 | sinvary(SinVariable * v) |
---|
241 | /*********/ |
---|
242 | |
---|
243 | { |
---|
244 | v->value = v->minimum + |
---|
245 | (v->maximum - v->minimum) * (sin(v->alpha) + 1.0) / 2.0; |
---|
246 | |
---|
247 | if (v->mayrand == 0) |
---|
248 | v->alpha += v->step; |
---|
249 | else { |
---|
250 | int vaval = NRAND(100); |
---|
251 | |
---|
252 | if (vaval <= v->mayrand) |
---|
253 | sinvary(v->varrand); |
---|
254 | v->alpha += (100.0 + (v->varrand->value)) * v->step / 100.0; |
---|
255 | } |
---|
256 | |
---|
257 | if (v->alpha > 2 * M_PI) |
---|
258 | v->alpha -= 2 * M_PI; |
---|
259 | } |
---|
260 | |
---|
261 | /*************************************************/ |
---|
262 | static void |
---|
263 | sininit(SinVariable * v, |
---|
264 | double alpha, double step, double minimum, double maximum, |
---|
265 | short int mayrand) |
---|
266 | { |
---|
267 | v->alpha = alpha; |
---|
268 | v->step = step; |
---|
269 | v->minimum = minimum; |
---|
270 | v->maximum = maximum; |
---|
271 | v->mayrand = mayrand; |
---|
272 | if (mayrand != 0) { |
---|
273 | if (v->varrand == NULL) |
---|
274 | v->varrand = (SinVariable *) calloc(1, sizeof (SinVariable)); |
---|
275 | sininit(v->varrand, |
---|
276 | VARRANDALPHA, |
---|
277 | VARRANDSTEP, |
---|
278 | VARRANDMIN, |
---|
279 | VARRANDMAX, |
---|
280 | 0); |
---|
281 | sinvary(v->varrand); |
---|
282 | } |
---|
283 | /* We calculate the values at least once for initialization */ |
---|
284 | sinvary(v); |
---|
285 | } |
---|
286 | |
---|
287 | static void |
---|
288 | sinfree(SinVariable * point) |
---|
289 | { |
---|
290 | SinVariable *temp, *next; |
---|
291 | |
---|
292 | next = point->varrand; |
---|
293 | while (next) { |
---|
294 | temp = next; |
---|
295 | next = temp->varrand; |
---|
296 | (void) free((void *) temp); |
---|
297 | } |
---|
298 | } |
---|
299 | |
---|
300 | /***************/ |
---|
301 | void |
---|
302 | init_bouboule(ModeInfo * mi) |
---|
303 | /***************/ |
---|
304 | |
---|
305 | /*- |
---|
306 | * The stars init part was first inspirated from the net3d game starfield |
---|
307 | * code. But net3d starfield is not really 3d starfield, and I needed real 3d, |
---|
308 | * so only remains the net3d starfield initialization main idea, that is |
---|
309 | * the stars distribution on a sphere (theta and omega computing) |
---|
310 | */ |
---|
311 | { |
---|
312 | StarField *sp; |
---|
313 | int size = MI_SIZE(mi); |
---|
314 | int i; |
---|
315 | double theta, omega; |
---|
316 | |
---|
317 | if (starfield == NULL) { |
---|
318 | if ((starfield = (StarField *) calloc(MI_NUM_SCREENS(mi), |
---|
319 | sizeof (StarField))) == NULL) |
---|
320 | return; |
---|
321 | } |
---|
322 | sp = &starfield[MI_SCREEN(mi)]; |
---|
323 | |
---|
324 | sp->width = MI_WIN_WIDTH(mi); |
---|
325 | sp->height = MI_WIN_HEIGHT(mi); |
---|
326 | |
---|
327 | /* use the right `black' pixel values: */ |
---|
328 | if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) { |
---|
329 | XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_NONE_COLOR(mi)); |
---|
330 | XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), |
---|
331 | 0, 0, sp->width, sp->height); |
---|
332 | } else |
---|
333 | XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); |
---|
334 | |
---|
335 | if (size < -MINSIZE) |
---|
336 | sp->max_star_size = NRAND(-size - MINSIZE + 1) + MINSIZE; |
---|
337 | else if (size < MINSIZE) |
---|
338 | sp->max_star_size = MINSIZE; |
---|
339 | else |
---|
340 | sp->max_star_size = size; |
---|
341 | |
---|
342 | sp->NbStars = MI_BATCHCOUNT(mi); |
---|
343 | if (sp->NbStars < -MINSTARS) { |
---|
344 | if (sp->star) { |
---|
345 | (void) free((void *) sp->star); |
---|
346 | sp->star = NULL; |
---|
347 | } |
---|
348 | if (sp->xarc) { |
---|
349 | (void) free((void *) sp->xarc); |
---|
350 | sp->xarc = NULL; |
---|
351 | } |
---|
352 | if (sp->xarcleft) { |
---|
353 | (void) free((void *) sp->xarcleft); |
---|
354 | sp->xarcleft = NULL; |
---|
355 | } |
---|
356 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
357 | if (sp->oldxarc) { |
---|
358 | (void) free((void *) sp->oldxarc); |
---|
359 | sp->oldxarc = NULL; |
---|
360 | } |
---|
361 | if (sp->oldxarcleft) { |
---|
362 | (void) free((void *) sp->oldxarcleft); |
---|
363 | sp->oldxarcleft = NULL; |
---|
364 | } |
---|
365 | #endif |
---|
366 | sp->NbStars = NRAND(-sp->NbStars - MINSTARS + 1) + MINSTARS; |
---|
367 | } else if (sp->NbStars < MINSTARS) |
---|
368 | sp->NbStars = MINSTARS; |
---|
369 | |
---|
370 | /* We get memory for lists of objects */ |
---|
371 | if (sp->star == NULL) |
---|
372 | sp->star = (Star *) malloc(sp->NbStars * sizeof (Star)); |
---|
373 | if (sp->xarc == NULL) |
---|
374 | sp->xarc = (XArc *) malloc(sp->NbStars * sizeof (XArc)); |
---|
375 | if (MI_WIN_IS_USE3D(mi) && sp->xarcleft == NULL) |
---|
376 | sp->xarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc)); |
---|
377 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
378 | if (sp->oldxarc == NULL) |
---|
379 | sp->oldxarc = (XArc *) malloc(sp->NbStars * sizeof (XArc)); |
---|
380 | if (MI_WIN_IS_USE3D(mi) && sp->oldxarcleft == NULL) |
---|
381 | sp->oldxarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc)); |
---|
382 | #endif |
---|
383 | |
---|
384 | { |
---|
385 | /* We initialize evolving variables */ |
---|
386 | sininit(&sp->x, |
---|
387 | NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), |
---|
388 | ((double) sp->width) / 4.0, |
---|
389 | 3.0 * ((double) sp->width) / 4.0, |
---|
390 | POSCANRAND); |
---|
391 | sininit(&sp->y, |
---|
392 | NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), |
---|
393 | ((double) sp->height) / 4.0, |
---|
394 | 3.0 * ((double) sp->height) / 4.0, |
---|
395 | POSCANRAND); |
---|
396 | |
---|
397 | /* for z, we have to ensure that the bouboule does not get behind */ |
---|
398 | /* the eyes of the viewer. His/Her eyes are at 0. Because the */ |
---|
399 | /* bouboule uses the x-radius for the z-radius, too, we have to */ |
---|
400 | /* use the x-values. */ |
---|
401 | sininit(&sp->z, |
---|
402 | NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), |
---|
403 | ((double) sp->width / 2.0 + MINZVAL), |
---|
404 | ((double) sp->width / 2.0 + MAXZVAL), |
---|
405 | POSCANRAND); |
---|
406 | |
---|
407 | |
---|
408 | sininit(&sp->sizex, |
---|
409 | NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), |
---|
410 | MIN(((double) sp->width) - sp->x.value, |
---|
411 | sp->x.value) / 5.0, |
---|
412 | MIN(((double) sp->width) - sp->x.value, |
---|
413 | sp->x.value), |
---|
414 | SIZECANRAND); |
---|
415 | |
---|
416 | sininit(&sp->sizey, |
---|
417 | NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), |
---|
418 | MAX(sp->sizex.value / MAX_SIZEX_SIZEY, |
---|
419 | sp->sizey.maximum / 5.0), |
---|
420 | MIN(sp->sizex.value * MAX_SIZEX_SIZEY, |
---|
421 | MIN(((double) sp->height) - |
---|
422 | sp->y.value, |
---|
423 | sp->y.value)), |
---|
424 | SIZECANRAND); |
---|
425 | |
---|
426 | sininit(&sp->thetax, |
---|
427 | NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0), |
---|
428 | -M_PI, M_PI, |
---|
429 | THETACANRAND); |
---|
430 | sininit(&sp->thetay, |
---|
431 | NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0), |
---|
432 | -M_PI, M_PI, |
---|
433 | THETACANRAND); |
---|
434 | sininit(&sp->thetaz, |
---|
435 | NRAND(3142) / 1000.0, M_PI / (NRAND(400) + 400.0), |
---|
436 | -M_PI, M_PI, |
---|
437 | THETACANRAND); |
---|
438 | } |
---|
439 | for (i = 0; i < sp->NbStars; i++) { |
---|
440 | Star *star; |
---|
441 | XArc *arc = NULL, *arcleft = NULL; |
---|
442 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
443 | XArc *oarc = NULL, *oarcleft = NULL; |
---|
444 | #endif |
---|
445 | |
---|
446 | star = &(sp->star[i]); |
---|
447 | arc = &(sp->xarc[i]); |
---|
448 | if (MI_WIN_IS_USE3D(mi)) |
---|
449 | arcleft = &(sp->xarcleft[i]); |
---|
450 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
451 | oarc = &(sp->oldxarc[i]); |
---|
452 | if (MI_WIN_IS_USE3D(mi)) |
---|
453 | oarcleft = &(sp->oldxarcleft[i]); |
---|
454 | #endif |
---|
455 | /* Elevation and bearing of the star */ |
---|
456 | theta = dtor((NRAND(1800)) / 10.0 - 90.0); |
---|
457 | omega = dtor((NRAND(3600)) / 10.0 - 180.0); |
---|
458 | |
---|
459 | /* Stars coordinates in a 3D space */ |
---|
460 | star->x = cos(theta) * sin(omega); |
---|
461 | star->y = sin(omega) * sin(theta); |
---|
462 | star->z = cos(omega); |
---|
463 | |
---|
464 | /* We set the stars size */ |
---|
465 | star->size = NRAND(2 * sp->max_star_size); |
---|
466 | if (star->size < sp->max_star_size) |
---|
467 | star->size = 0; |
---|
468 | else |
---|
469 | star->size -= sp->max_star_size; |
---|
470 | |
---|
471 | /* We set default values for the XArc lists elements */ |
---|
472 | arc->x = arc->y = 0; |
---|
473 | if (MI_WIN_IS_USE3D(mi)) { |
---|
474 | arcleft->x = arcleft->y = 0; |
---|
475 | } |
---|
476 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
477 | oarc->x = oarc->y = 0; |
---|
478 | if (MI_WIN_IS_USE3D(mi)) { |
---|
479 | oarcleft->x = oarcleft->y = 0; |
---|
480 | } |
---|
481 | #endif |
---|
482 | arc->width = 2 + star->size; |
---|
483 | arc->height = 2 + star->size; |
---|
484 | if (MI_WIN_IS_USE3D(mi)) { |
---|
485 | arcleft->width = 2 + star->size; |
---|
486 | arcleft->height = 2 + star->size; |
---|
487 | } |
---|
488 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
489 | oarc->width = 2 + star->size; |
---|
490 | oarc->height = 2 + star->size; |
---|
491 | if (MI_WIN_IS_USE3D(mi)) { |
---|
492 | oarcleft->width = 2 + star->size; |
---|
493 | oarcleft->height = 2 + star->size; |
---|
494 | } |
---|
495 | #endif |
---|
496 | |
---|
497 | arc->angle1 = 0; |
---|
498 | arc->angle2 = 360 * 64; |
---|
499 | if (MI_WIN_IS_USE3D(mi)) { |
---|
500 | arcleft->angle1 = 0; |
---|
501 | arcleft->angle2 = 360 * 64; |
---|
502 | } |
---|
503 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
504 | oarc->angle1 = 0; |
---|
505 | oarc->angle2 = 360 * 64; /* ie. we draw whole disks: |
---|
506 | * from 0 to 360 degrees */ |
---|
507 | if (MI_WIN_IS_USE3D(mi)) { |
---|
508 | oarcleft->angle1 = 0; |
---|
509 | oarcleft->angle2 = 360 * 64; |
---|
510 | } |
---|
511 | #endif |
---|
512 | } |
---|
513 | |
---|
514 | if (MI_NPIXELS(mi) > 2) |
---|
515 | sp->colorp = NRAND(MI_NPIXELS(mi)); |
---|
516 | /* We set up the starfield color */ |
---|
517 | if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2) |
---|
518 | sp->color = MI_PIXEL(mi, sp->colorp); |
---|
519 | else |
---|
520 | sp->color = MI_WIN_WHITE_PIXEL(mi); |
---|
521 | |
---|
522 | #if (ADAPT_ERASE == 1) |
---|
523 | /* We initialize the adaptation code for screen erasing */ |
---|
524 | sp->hasbeenchecked = ADAPT_CHECKS * 2; |
---|
525 | sp->rect_time = 0; |
---|
526 | sp->xarc_time = 0; |
---|
527 | #endif |
---|
528 | } |
---|
529 | |
---|
530 | /****************/ |
---|
531 | void |
---|
532 | draw_bouboule(ModeInfo * mi) |
---|
533 | /****************/ |
---|
534 | |
---|
535 | { |
---|
536 | Display *display = MI_DISPLAY(mi); |
---|
537 | Window window = MI_WINDOW(mi); |
---|
538 | GC gc = MI_GC(mi); |
---|
539 | StarField *sp = &starfield[MI_SCREEN(mi)]; |
---|
540 | int i, diff = 0; |
---|
541 | double CX, CY, CZ, SX, SY, SZ; |
---|
542 | Star *star; |
---|
543 | XArc *arc = NULL, *arcleft = NULL; |
---|
544 | |
---|
545 | #if (ADAPT_ERASE == 1) |
---|
546 | struct timeval tv1; |
---|
547 | struct timeval tv2; |
---|
548 | |
---|
549 | #endif |
---|
550 | |
---|
551 | #if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1)) |
---|
552 | short x_1, y_1, x_2, y_2; |
---|
553 | |
---|
554 | /* bounding rectangle around the old starfield, |
---|
555 | * for erasing with the smallest rectangle |
---|
556 | * instead of filling the whole screen */ |
---|
557 | int maxdiff = 0; /* maximal distance between left and right */ |
---|
558 | |
---|
559 | /* star in 3d mode, otherwise 0 */ |
---|
560 | #endif |
---|
561 | |
---|
562 | #if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1)) |
---|
563 | if (MI_WIN_IS_USE3D(mi)) { |
---|
564 | maxdiff = (int) MAXDIFF; |
---|
565 | } |
---|
566 | x_1 = (int) sp->x.value - (int) sp->sizex.value - |
---|
567 | sp->max_star_size - maxdiff; |
---|
568 | y_1 = (int) sp->y.value - (int) sp->sizey.value - |
---|
569 | sp->max_star_size; |
---|
570 | x_2 = 2 * ((int) sp->sizex.value + sp->max_star_size + maxdiff); |
---|
571 | y_2 = 2 * ((int) sp->sizey.value + sp->max_star_size); |
---|
572 | #endif |
---|
573 | /* We make variables vary. */ |
---|
574 | sinvary(&sp->thetax); |
---|
575 | sinvary(&sp->thetay); |
---|
576 | sinvary(&sp->thetaz); |
---|
577 | |
---|
578 | sinvary(&sp->x); |
---|
579 | sinvary(&sp->y); |
---|
580 | if (MI_WIN_IS_USE3D(mi)) |
---|
581 | sinvary(&sp->z); |
---|
582 | |
---|
583 | /* A little trick to prevent the bouboule from being |
---|
584 | * bigger than the screen */ |
---|
585 | sp->sizex.maximum = |
---|
586 | MIN(((double) sp->width) - sp->x.value, |
---|
587 | sp->x.value); |
---|
588 | sp->sizex.minimum = sp->sizex.maximum / 3.0; |
---|
589 | |
---|
590 | /* Another trick to make the ball not too flat */ |
---|
591 | sp->sizey.minimum = |
---|
592 | MAX(sp->sizex.value / MAX_SIZEX_SIZEY, |
---|
593 | sp->sizey.maximum / 3.0); |
---|
594 | sp->sizey.maximum = |
---|
595 | MIN(sp->sizex.value * MAX_SIZEX_SIZEY, |
---|
596 | MIN(((double) sp->height) - sp->y.value, |
---|
597 | sp->y.value)); |
---|
598 | |
---|
599 | sinvary(&sp->sizex); |
---|
600 | sinvary(&sp->sizey); |
---|
601 | |
---|
602 | /* |
---|
603 | * We calculate the rotation matrix values. We just make the |
---|
604 | * rotation on the fly, without using a matrix. |
---|
605 | * Star positions are recorded as unit vectors pointing in various |
---|
606 | * directions. We just make them all rotate. |
---|
607 | */ |
---|
608 | CX = cos(sp->thetax.value); |
---|
609 | SX = sin(sp->thetax.value); |
---|
610 | CY = cos(sp->thetay.value); |
---|
611 | SY = sin(sp->thetay.value); |
---|
612 | CZ = cos(sp->thetaz.value); |
---|
613 | SZ = sin(sp->thetaz.value); |
---|
614 | |
---|
615 | for (i = 0; i < sp->NbStars; i++) { |
---|
616 | star = &(sp->star[i]); |
---|
617 | arc = &(sp->xarc[i]); |
---|
618 | if (MI_WIN_IS_USE3D(mi)) { |
---|
619 | arcleft = &(sp->xarcleft[i]); |
---|
620 | /* to help the eyes, the starfield is always as wide as */ |
---|
621 | /* deep, so .sizex.value can be used. */ |
---|
622 | diff = (int) GETZDIFF(sp->sizex.value * |
---|
623 | ((SY * CX) * star->x + (SX) * star->y + |
---|
624 | (CX * CY) * star->z) + sp->z.value); |
---|
625 | } |
---|
626 | arc->x = (short) ((sp->sizex.value * |
---|
627 | ((CY * CZ - SX * SY * SZ) * star->x + |
---|
628 | (-CX * SZ) * star->y + |
---|
629 | (SY * CZ + SZ * SX * CY) * star->z) + |
---|
630 | sp->x.value)); |
---|
631 | arc->y = (short) ((sp->sizey.value * |
---|
632 | ((CY * SZ + SX * SY * CZ) * star->x + |
---|
633 | (CX * CZ) * star->y + |
---|
634 | (SY * SZ - SX * CY * CZ) * star->z) + |
---|
635 | sp->y.value)); |
---|
636 | |
---|
637 | if (MI_WIN_IS_USE3D(mi)) { |
---|
638 | arcleft->x = (short) ((sp->sizex.value * |
---|
639 | ((CY * CZ - SX * SY * SZ) * star->x + |
---|
640 | (-CX * SZ) * star->y + |
---|
641 | (SY * CZ + SZ * SX * CY) * star->z) + |
---|
642 | sp->x.value)); |
---|
643 | arcleft->y = (short) ((sp->sizey.value * |
---|
644 | ((CY * SZ + SX * SY * CZ) * star->x + |
---|
645 | (CX * CZ) * star->y + |
---|
646 | (SY * SZ - SX * CY * CZ) * star->z) + |
---|
647 | sp->y.value)); |
---|
648 | arc->x += diff; |
---|
649 | arcleft->x -= diff; |
---|
650 | } |
---|
651 | if (star->size != 0) { |
---|
652 | arc->x -= star->size; |
---|
653 | arc->y -= star->size; |
---|
654 | if (MI_WIN_IS_USE3D(mi)) { |
---|
655 | arcleft->x -= star->size; |
---|
656 | arcleft->y -= star->size; |
---|
657 | } |
---|
658 | } |
---|
659 | } |
---|
660 | |
---|
661 | /* First, we erase the previous starfield */ |
---|
662 | if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) |
---|
663 | XSetForeground(display, gc, MI_NONE_COLOR(mi)); |
---|
664 | else |
---|
665 | XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi)); |
---|
666 | |
---|
667 | #if (ADAPT_ERASE == 1) |
---|
668 | if (sp->hasbeenchecked == 0) { |
---|
669 | /* We just calculate which method is the faster and eventually free |
---|
670 | * the oldxarc list */ |
---|
671 | if (sp->xarc_time > |
---|
672 | ADAPT_ARC_PREFERED * sp->rect_time) { |
---|
673 | sp->hasbeenchecked = -2; /* XFillRectangle mode */ |
---|
674 | (void) free((void *) sp->oldxarc); |
---|
675 | sp->oldxarc = NULL; |
---|
676 | if (MI_WIN_IS_USE3D(mi)) { |
---|
677 | (void) free((void *) sp->oldxarcleft); |
---|
678 | sp->oldxarcleft = NULL; |
---|
679 | } |
---|
680 | } else { |
---|
681 | sp->hasbeenchecked = -1; /* XFillArcs mode */ |
---|
682 | } |
---|
683 | } |
---|
684 | if (sp->hasbeenchecked == -2) { |
---|
685 | /* Erasing is done with XFillRectangle */ |
---|
686 | XFillRectangle(display, window, gc, |
---|
687 | x_1, y_1, x_2, y_2); |
---|
688 | } else if (sp->hasbeenchecked == -1) { |
---|
689 | /* Erasing is done with XFillArcs */ |
---|
690 | XFillArcs(display, window, gc, |
---|
691 | sp->oldxarc, sp->NbStars); |
---|
692 | if (MI_WIN_IS_USE3D(mi)) |
---|
693 | XFillArcs(display, window, gc, |
---|
694 | sp->oldxarcleft, sp->NbStars); |
---|
695 | } else { |
---|
696 | long usec; |
---|
697 | |
---|
698 | if (sp->hasbeenchecked > ADAPT_CHECKS) { |
---|
699 | #ifdef GETTIMEOFDAY_TWO_ARGS |
---|
700 | (void) gettimeofday(&tv1, NULL); |
---|
701 | #else |
---|
702 | (void) gettimeofday(&tv1); |
---|
703 | #endif |
---|
704 | XFillRectangle(display, window, gc, |
---|
705 | x_1, y_1, x_2, y_2); |
---|
706 | #ifdef GETTIMEOFDAY_TWO_ARGS |
---|
707 | (void) gettimeofday(&tv2, NULL); |
---|
708 | #else |
---|
709 | (void) gettimeofday(&tv2); |
---|
710 | #endif |
---|
711 | usec = (tv2.tv_sec - tv1.tv_sec) * 1000000; |
---|
712 | if (usec + tv2.tv_usec - tv1.tv_usec > 0) { |
---|
713 | sp->rect_time += usec + tv2.tv_usec - tv1.tv_usec; |
---|
714 | sp->hasbeenchecked--; |
---|
715 | } |
---|
716 | } else { |
---|
717 | #ifdef GETTIMEOFDAY_TWO_ARGS |
---|
718 | (void) gettimeofday(&tv1, NULL); |
---|
719 | #else |
---|
720 | (void) gettimeofday(&tv1); |
---|
721 | #endif |
---|
722 | XFillArcs(display, window, gc, |
---|
723 | sp->oldxarc, sp->NbStars); |
---|
724 | if (MI_WIN_IS_USE3D(mi)) |
---|
725 | XFillArcs(display, window, gc, |
---|
726 | sp->oldxarcleft, sp->NbStars); |
---|
727 | #ifdef GETTIMEOFDAY_TWO_ARGS |
---|
728 | (void) gettimeofday(&tv2, NULL); |
---|
729 | #else |
---|
730 | (void) gettimeofday(&tv2); |
---|
731 | #endif |
---|
732 | usec = (tv2.tv_sec - tv1.tv_sec) * 1000000; |
---|
733 | if (usec + tv2.tv_usec - tv1.tv_usec > 0) { |
---|
734 | sp->xarc_time += usec + tv2.tv_usec - tv1.tv_usec; |
---|
735 | sp->hasbeenchecked--; |
---|
736 | } |
---|
737 | } |
---|
738 | } |
---|
739 | #else |
---|
740 | #if (USEOLDXARCS == 1) |
---|
741 | XFillArcs(display, window, gc, |
---|
742 | sp->oldxarc, sp->NbStars); |
---|
743 | if (MI_WIN_IS_USE3D(mi)) |
---|
744 | XFillArcs(display, window, gc, |
---|
745 | sp->oldxarcleft, sp->NbStars); |
---|
746 | #else |
---|
747 | XFillRectangle(display, window, gc, |
---|
748 | x_1, y_1, x_2, y_2); |
---|
749 | #endif |
---|
750 | #endif |
---|
751 | |
---|
752 | /* Then we draw the new one */ |
---|
753 | if (MI_WIN_IS_USE3D(mi)) { |
---|
754 | if (MI_WIN_IS_INSTALL(mi)) |
---|
755 | XSetFunction(display, gc, GXor); |
---|
756 | XSetForeground(display, gc, MI_RIGHT_COLOR(mi)); |
---|
757 | XFillArcs(display, window, gc, sp->xarc, sp->NbStars); |
---|
758 | XSetForeground(display, gc, MI_LEFT_COLOR(mi)); |
---|
759 | XFillArcs(display, window, gc, sp->xarcleft, sp->NbStars); |
---|
760 | if (MI_WIN_IS_INSTALL(mi)) |
---|
761 | XSetFunction(display, gc, GXcopy); |
---|
762 | } else { |
---|
763 | XSetForeground(display, gc, sp->color); |
---|
764 | XFillArcs(display, window, gc, sp->xarc, sp->NbStars); |
---|
765 | } |
---|
766 | |
---|
767 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
768 | #if (ADAPT_ERASE == 1) |
---|
769 | if (sp->hasbeenchecked >= -1) { |
---|
770 | arc = sp->xarc; |
---|
771 | sp->xarc = sp->oldxarc; |
---|
772 | sp->oldxarc = arc; |
---|
773 | if (MI_WIN_IS_USE3D(mi)) { |
---|
774 | arcleft = sp->xarcleft; |
---|
775 | sp->xarcleft = sp->oldxarcleft; |
---|
776 | sp->oldxarcleft = arcleft; |
---|
777 | } |
---|
778 | } |
---|
779 | #else |
---|
780 | arc = sp->xarc; |
---|
781 | sp->xarc = sp->oldxarc; |
---|
782 | sp->oldxarc = arc; |
---|
783 | if (MI_WIN_IS_USE3D(mi)) { |
---|
784 | arcleft = sp->xarcleft; |
---|
785 | sp->xarcleft = sp->oldxarcleft; |
---|
786 | sp->oldxarcleft = arcleft; |
---|
787 | } |
---|
788 | #endif |
---|
789 | #endif |
---|
790 | |
---|
791 | /* We set up the color for the next drawing */ |
---|
792 | if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2 && |
---|
793 | (++sp->colorchange >= COLOR_CHANGES)) { |
---|
794 | sp->colorchange = 0; |
---|
795 | if (++sp->colorp >= MI_NPIXELS(mi)) |
---|
796 | sp->colorp = 0; |
---|
797 | sp->color = MI_PIXEL(mi, sp->colorp); |
---|
798 | } |
---|
799 | } |
---|
800 | |
---|
801 | void |
---|
802 | release_bouboule(ModeInfo * mi) |
---|
803 | { |
---|
804 | if (starfield != NULL) { |
---|
805 | int screen; |
---|
806 | |
---|
807 | for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { |
---|
808 | StarField *sp = &starfield[screen]; |
---|
809 | |
---|
810 | if (sp->star) |
---|
811 | (void) free((void *) sp->star); |
---|
812 | if (sp->xarc) |
---|
813 | (void) free((void *) sp->xarc); |
---|
814 | if (sp->xarcleft) |
---|
815 | (void) free((void *) sp->xarcleft); |
---|
816 | #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) |
---|
817 | if (sp->oldxarc) |
---|
818 | (void) free((void *) sp->oldxarc); |
---|
819 | if (sp->oldxarcleft) |
---|
820 | (void) free((void *) sp->oldxarcleft); |
---|
821 | #endif |
---|
822 | sinfree(&(sp->x)); |
---|
823 | sinfree(&(sp->y)); |
---|
824 | sinfree(&(sp->z)); |
---|
825 | sinfree(&(sp->sizex)); |
---|
826 | sinfree(&(sp->sizey)); |
---|
827 | sinfree(&(sp->thetax)); |
---|
828 | sinfree(&(sp->thetay)); |
---|
829 | sinfree(&(sp->thetaz)); |
---|
830 | } |
---|
831 | (void) free((void *) starfield); |
---|
832 | starfield = NULL; |
---|
833 | } |
---|
834 | } |
---|
835 | |
---|
836 | void |
---|
837 | refresh_bouboule(ModeInfo * mi) |
---|
838 | { |
---|
839 | /* Do nothing, it will refresh by itself */ |
---|
840 | } |
---|