1 /* Author: Mauro Persano (mauro_persano@yahoo.com) 27 Nov 2005
2 *
3 * Todo:
4 * - support for 4-bit / packed 24-bit visuals.
5 *
6 * Revision history:
7 * 06-Dec-2005: fixed stupid off-by-one buf; (preliminar) monochrome support.
8 * 05-Dec-2005: more speed ups.
9 * 27-Nov-2005: speed ups.
10 * 21-Nov-2005: initial version
11 */
12
13 #ifdef STANDALONE
14 # define MODE_fzort
15 # define DEFAULTS "*delay: 0 \n" \
16
17 # define free_fzort 0
18 # define reshape_fzort 0
19 # define fzort_handle_event 0
20 # define UNIFORM_COLORS
21 # include "xlockmore.h" /* xscreensaver distribution */
22 #else /* STANDALONE */
23 # include "xlock.h" /* xlockmore distribution */
24 #endif /* STANDALONE */
25
26 #ifdef MODE_fzort
27
28 #include <sys/types.h>
29 #include <sys/time.h>
30 #include "xshm.h"
31
32 ENTRYPOINT ModeSpecOpt fzort_opts =
33 {0, (XrmOptionDescRec *)NULL, 0, (argtype *)NULL, (OptionStruct *)NULL };
34
35 #ifdef USE_MODULES
36 ModStruct fzort_description =
37 { "fzort", "init_fzort", "draw_fzort", "release_fzort",
38 "refresh_fzort", "init_fzort", (char *) NULL, &fzort_opts,
39 10000, 1, 1, 1, 64, 1.0, "",
40 "Shows a metallic-looking fzort.", 0, NULL };
41 #endif
42
43 #define MESH_DENSITY 22
44 /* #define MESH_DENSITY 44 */
45
46 #define MAX_WIDTH 800
47 #define MAX_HEIGHT 800
48 #define TEXTURE_SIZE 256 /* use a power of 2 preferably */
49
50 extern int XShmGetEventBase(Display *);
51
52 #define MAX_POLY_VTX 20
53
54 struct vector {
55 float x, y, z;
56 };
57
58 struct matrix {
59 float m11, m12, m13, m14;
60 float m21, m22, m23, m24;
61 float m31, m32, m33, m34;
62 };
63
64 struct vertex {
65 struct vector p;
66 struct vector normal;
67 };
68
69 struct pvertex {
70 struct vector p;
71 int x_scr, y_scr;
72 long u_txt, v_txt;
73 };
74
75 struct polygon {
76 int nvtx;
77 int vtx_index[MAX_POLY_VTX];
78 struct vector normal;
79 };
80
81 struct mesh {
82 int npoly, nvtx;
83 struct vertex *vtx;
84 struct polygon *poly;
85 };
86
87 struct box {
88 int x_min, y_min, x_max, y_max;
89 };
90
91 struct clip_limits {
92 int x_min;
93 int x_max;
94 int y_min;
95 int y_max;
96 };
97
98 struct raster {
99 int width;
100 int height;
101 int pitch;
102 int bpp;
103 void *bits;
104 };
105
106 struct render_order {
107 float z;
108 unsigned zi;
109 struct polygon *poly;
110 };
111
112 typedef struct fzort_ctx {
113 Bool initialized;
114
115 int palette[256];
116
117 XShmSegmentInfo shm_info;
118 XImage *image;
119
120 struct clip_limits clip;
121 struct raster raster;
122 struct mesh *mesh;
123 void *texture;
124
125 /* render ctx */
126 float lx, ly, cx, cy;
127 void(*fill_triangle_fn)(struct fzort_ctx *, struct pvertex *,
128 struct pvertex *, struct pvertex *);
129 struct pvertex *pvtx;
130 struct render_order *order_in, *order_out;
131
132 long start_ticks;
133
134 struct box cur_box, prev_box;
135 int first_frame;
136 } fzort_ctx;
137
138 static fzort_ctx *fzorts = (fzort_ctx *) NULL;
139 static unsigned char texture8[TEXTURE_SIZE*TEXTURE_SIZE];
140 static int texture_initialized = False;
141
142 /* ordered dithering matrix */
143
144 static unsigned int dither6[8][8] = {
145 { 1, 59, 15, 55, 2, 56, 12, 52, },
146 { 33, 17, 47, 31, 34, 18, 44, 28, },
147 { 9, 49, 5, 63, 10, 50, 6, 60, },
148 { 41, 25, 37, 21, 42, 26, 38, 22, },
149 { 3, 57, 13, 53, 0, 58, 14, 54, },
150 { 35, 19, 45, 29, 32, 16, 46, 30, },
151 { 11, 51, 7, 61, 8, 48, 4, 62, },
152 { 43, 27, 39, 23, 40, 24, 36, 20 } };
153
154 /*
155 * f i x p o i n t
156 */
157
158 #if defined(__GNUC__) && defined(__i386__)
159 #define FP_SHIFT 16
160 #else
161 #define FP_SHIFT 10
162 #endif
163
164 #define FP_SHIFT_COMPL (32 - FP_SHIFT)
165 #define FP_MULTIPLIER (1L << FP_SHIFT)
166 #define FP_ONE (1L << FP_SHIFT)
167 #define FP_HALF (1L << (FP_SHIFT - 1))
168 #define INT_TO_FP(a) ((a) << FP_SHIFT)
169 #define FP_TO_INT(f) ((f) >> FP_SHIFT)
170 #define FLOAT_TO_FP(f) ((long)((f) * (float)FP_MULTIPLIER))
171 #define FP_TO_FLOAT(f) ((float)(f) / (float)FP_MULTIPLIER)
172 #define FRAC_PART(f) ((f) & (FP_MULTIPLIER - 1))
173 #define FP_CEIL(f) (((f) + FP_MULTIPLIER - 1) & \
174 ~(FP_MULTIPLIER - 1))
175 #define FP_FLOOR(f) ((f) & ~(FP_MULTIPLIER - 1))
176 #define FP_ICEIL(f) (((f) + FP_ONE - 1) >> FP_SHIFT)
177 #define FP_IFLOOR(f) ((f) >> FP_SHIFT)
178
179 /* a / b */
180 #if defined(__GNUC__) && defined(__i386__)
181 static inline long
fp_div(long a,long b)182 fp_div(long a, long b)
183 {
184 long c;
185 __asm__ volatile("movl %%eax,%%edx; shll %3,%%eax; sarl %4,%%edx; idivl %2"
186 : "=a"(c)
187 : "0"(a), "m"(b), "i"(FP_SHIFT), "i"(32 - FP_SHIFT)
188 : "edx");
189 return c;
190 }
191 #else
192 static inline long
fp_div(long a,long b)193 fp_div(long a, long b)
194 {
195 return (a << FP_SHIFT)/b;
196 }
197 #endif
198
199 /* a * b */
200 #if defined(__GNUC__) && defined(__i386__)
201 static inline long
fp_mul(long a,long b)202 fp_mul(long a, long b)
203 {
204 long c;
205 __asm__ volatile("imull %2; shrdl %3,%%edx,%%eax"
206 : "=a"(c)
207 : "0"(a), "m"(b), "i"(FP_SHIFT)
208 : "edx");
209 return c;
210 }
211 #else
212 static inline long
fp_mul(long a,long b)213 fp_mul(long a, long b)
214 {
215 return (a*b) >> FP_SHIFT;
216 }
217 #endif
218
219 /* s + a * b */
220 #if defined(__GNUC__) && defined(__i386__)
221 static inline long
fp_mul_add(long s,long a,long b)222 fp_mul_add(long s, long a, long b)
223 {
224 long c;
225 __asm__ volatile("imull %2; shrdl %3,%%edx,%%eax; addl %4,%%eax"
226 : "=a"(c)
227 : "0"(a), "m"(b), "i"(FP_SHIFT), "m"(s)
228 : "edx");
229 return c;
230 }
231 #else
232 static inline long
fp_mul_add(long s,long a,long b)233 fp_mul_add(long s, long a, long b)
234 {
235 return s + ((a*b) >> FP_SHIFT);
236 }
237 #endif
238
239
240 /*
241 * v e c t o r
242 */
243
244 static inline void
vec_copy(struct vector * r,struct vector * a)245 vec_copy(struct vector *r, struct vector *a)
246 {
247 memcpy(r, a, sizeof *r);
248 }
249
250 static inline void
vec_set(struct vector * r,float x,float y,float z)251 vec_set(struct vector *r, float x, float y, float z)
252 {
253 r->x = x;
254 r->y = y;
255 r->z = z;
256 }
257
258 static inline void
vec_neg_copy(struct vector * r,struct vector * a)259 vec_neg_copy(struct vector *r, struct vector *a)
260 {
261 r->x = -a->x;
262 r->y = -a->y;
263 r->z = -a->z;
264 }
265
266 static inline void
vec_neg(struct vector * r)267 vec_neg(struct vector *r)
268 {
269 vec_neg_copy(r, r);
270 }
271
272 static inline void
vec_add(struct vector * r,struct vector * a,struct vector * b)273 vec_add(struct vector *r, struct vector *a, struct vector *b)
274 {
275 r->x = a->x + b->x;
276 r->y = a->y + b->y;
277 r->z = a->z + b->z;
278 }
279
280 static inline void
vec_add_to(struct vector * a,struct vector * b)281 vec_add_to(struct vector *a, struct vector *b)
282 {
283 a->x += b->x;
284 a->y += b->y;
285 a->z += b->z;
286 }
287
288 static inline void
vec_sub(struct vector * r,struct vector * a,struct vector * b)289 vec_sub(struct vector *r, struct vector *a, struct vector *b)
290 {
291 r->x = a->x - b->x;
292 r->y = a->y - b->y;
293 r->z = a->z - b->z;
294 }
295
296 static inline void
vec_sub_from(struct vector * a,struct vector * b)297 vec_sub_from(struct vector *a, struct vector *b)
298 {
299 a->x -= b->x;
300 a->y -= b->y;
301 a->z -= b->z;
302 }
303
304 static inline float
vec_dot_product(struct vector * a,struct vector * b)305 vec_dot_product(struct vector *a, struct vector *b)
306 {
307 return a->x*b->x + a->y*b->y + a->z*b->z;
308 }
309
310 static inline float
vec_length_squared(struct vector * a)311 vec_length_squared(struct vector *a)
312 {
313 return vec_dot_product(a, a);
314 }
315
316 static inline void
vec_cross_product(struct vector * r,struct vector * a,struct vector * b)317 vec_cross_product(struct vector *r, struct vector *a, struct vector *b)
318 {
319 r->x = a->y*b->z - a->z*b->y;
320 r->y = a->z*b->x - a->x*b->z;
321 r->z = a->x*b->y - a->y*b->x;
322 }
323
324 static inline void
vec_scalar_mul(struct vector * a,float s)325 vec_scalar_mul(struct vector *a, float s)
326 {
327 a->x *= s;
328 a->y *= s;
329 a->z *= s;
330 }
331
332 static inline void
vec_scalar_mul_copy(struct vector * r,struct vector * a,float s)333 vec_scalar_mul_copy(struct vector *r, struct vector *a, float s)
334 {
335 r->x = a->x*s;
336 r->y = a->y*s;
337 r->z = a->z*s;
338 }
339
340 static float
vec_length(struct vector * a)341 vec_length(struct vector *a)
342 {
343 return sqrt(vec_length_squared(a));
344 }
345
346 static void
vec_normalize(struct vector * a)347 vec_normalize(struct vector *a)
348 {
349 float l;
350
351 l = vec_length(a);
352
353 if (l == 0.f)
354 a->x = 1.f, a->y = 0.f, a->z = 0.f;
355 else
356 vec_scalar_mul(a, 1.f/l);
357 }
358
359
360 /*
361 * m a t r i x
362 */
363
364 static inline void
mat_copy(struct matrix * r,struct matrix * m)365 mat_copy(struct matrix *r, struct matrix *m)
366 {
367 memcpy(r, m, sizeof *r);
368 }
369
370 static const struct matrix identity = {
371 1.f, 0.f, 0.f, 0.f,
372 0.f, 1.f, 0.f, 0.f,
373 0.f, 0.f, 1.f, 0.f
374 };
375
376 static void
mat_make_identity(struct matrix * m)377 mat_make_identity(struct matrix *m)
378 {
379 memcpy(m, &identity, sizeof *m);
380 }
381
382 static void
mat_make_rotation_around_x(struct matrix * m,float ang)383 mat_make_rotation_around_x(struct matrix *m, float ang)
384 {
385 float c, s;
386
387 c = cos(ang);
388 s = sin(ang);
389
390 mat_make_identity(m);
391
392 m->m22 = c; m->m23 = -s;
393 m->m32 = s; m->m33 = c;
394 }
395
396 static void
mat_make_rotation_around_y(struct matrix * m,float ang)397 mat_make_rotation_around_y(struct matrix *m, float ang)
398 {
399 float c, s;
400
401 c = cos(ang);
402 s = sin(ang);
403
404 mat_make_identity(m);
405
406 m->m11 = c; m->m13 = -s;
407 m->m31 = s; m->m33 = c;
408 }
409
410 #if 0
411 static void
412 mat_make_rotation_around_z(struct matrix *m, float ang)
413 {
414 float c, s;
415
416 c = cos(ang);
417 s = sin(ang);
418
419 mat_make_identity(m);
420
421 m->m11 = c; m->m12 = -s;
422 m->m21 = s; m->m22 = c;
423 }
424 #endif
425
426 static void
mat_make_translation(struct matrix * m,float x,float y,float z)427 mat_make_translation(struct matrix *m, float x, float y, float z)
428 {
429 mat_make_identity(m);
430
431 m->m14 = x;
432 m->m24 = y;
433 m->m34 = z;
434 }
435
436 static void
mat_mul_copy(struct matrix * r,struct matrix * a,struct matrix * b)437 mat_mul_copy(struct matrix *r, struct matrix *a, struct matrix *b)
438 {
439 float l11, l12, l13, l14;
440 float l21, l22, l23, l24;
441 float l31, l32, l33, l34;
442
443 l11 = a->m11*b->m11 + a->m12*b->m21 + a->m13*b->m31;
444 l12 = a->m11*b->m12 + a->m12*b->m22 + a->m13*b->m32;
445 l13 = a->m11*b->m13 + a->m12*b->m23 + a->m13*b->m33;
446 l14 = a->m11*b->m14 + a->m12*b->m24 + a->m13*b->m34 + a->m14;
447
448 l21 = a->m21*b->m11 + a->m22*b->m21 + a->m23*b->m31;
449 l22 = a->m21*b->m12 + a->m22*b->m22 + a->m23*b->m32;
450 l23 = a->m21*b->m13 + a->m22*b->m23 + a->m23*b->m33;
451 l24 = a->m21*b->m14 + a->m22*b->m24 + a->m23*b->m34 + a->m24;
452
453 l31 = a->m31*b->m11 + a->m32*b->m21 + a->m33*b->m31;
454 l32 = a->m31*b->m12 + a->m32*b->m22 + a->m33*b->m32;
455 l33 = a->m31*b->m13 + a->m32*b->m23 + a->m33*b->m33;
456 l34 = a->m31*b->m14 + a->m32*b->m24 + a->m33*b->m34 + a->m34;
457
458 r->m11 = l11; r->m12 = l12; r->m13 = l13; r->m14 = l14;
459 r->m21 = l21; r->m22 = l22; r->m23 = l23; r->m24 = l24;
460 r->m31 = l31; r->m32 = l32; r->m33 = l33; r->m34 = l34;
461 }
462
463 #if 0
464 static void
465 mat_mul(struct matrix *a, struct matrix *b)
466 {
467 mat_mul_copy(a, a, b);
468 }
469 #endif
470
471 static void
mat_transform_copy(struct vector * r,struct matrix * m,struct vector * v)472 mat_transform_copy(struct vector *r, struct matrix *m,
473 struct vector *v)
474 {
475 float x, y, z;
476
477 x = m->m11*v->x + m->m12*v->y + m->m13*v->z + m->m14;
478 y = m->m21*v->x + m->m22*v->y + m->m23*v->z + m->m24;
479 z = m->m31*v->x + m->m32*v->y + m->m33*v->z + m->m34;
480
481 r->x = x;
482 r->y = y;
483 r->z = z;
484 }
485
486 static inline void
mat_rotate_copy(struct vector * r,struct matrix * m,struct vector * v)487 mat_rotate_copy(struct vector *r, struct matrix *m, struct vector *v)
488 {
489 float x, y, z;
490
491 x = m->m11*v->x + m->m12*v->y + m->m13*v->z;
492 y = m->m21*v->x + m->m22*v->y + m->m23*v->z;
493 z = m->m31*v->x + m->m32*v->y + m->m33*v->z;
494
495 r->x = x;
496 r->y = y;
497 r->z = z;
498 }
499
500 static inline void
mat_rotate(struct vector * v,struct matrix * m)501 mat_rotate(struct vector *v, struct matrix *m)
502 {
503 mat_rotate_copy(v, m, v);
504 }
505
506
507 /*
508 * t r i a n g l e
509 */
510
511 struct edge {
512 struct pvertex *v0, *v1;
513 int dx, dy;
514 int du, dv;
515 int sy;
516 long sx;
517 long dxdy;
518 int lines;
519 int adjy;
520 };
521
522 static inline void
init_edge(fzort_ctx * ctx,struct edge * edge,struct pvertex * v0,struct pvertex * v1)523 init_edge(fzort_ctx *ctx, struct edge *edge,
524 struct pvertex *v0, struct pvertex *v1)
525 {
526 float y_max;
527
528 edge->v0 = v0;
529 edge->v1 = v1;
530 edge->dx = v1->x_scr - v0->x_scr;
531 edge->dy = v1->y_scr - v0->y_scr;
532 edge->du = v1->u_txt - v0->u_txt;
533 edge->dv = v1->v_txt - v0->v_txt;
534
535 edge->sy = v0->y_scr;
536 if (edge->sy < ctx->clip.y_min) {
537 edge->adjy = ctx->clip.y_min - edge->sy;
538 edge->sy = ctx->clip.y_min;
539 } else {
540 edge->adjy = 0;
541 }
542
543 y_max = v1->y_scr;
544 if (y_max > ctx->clip.y_max)
545 y_max = ctx->clip.y_max;
546
547 if (y_max <= edge->sy) {
548 edge->lines = edge->dxdy = edge->sx = 0;
549 } else {
550 edge->lines = (int) (y_max - edge->sy);
551 edge->dxdy = fp_div(edge->dx, edge->dy);
552 edge->sx = INT_TO_FP(v0->x_scr) + edge->adjy*edge->dxdy;
553 }
554 }
555
556 #define CONCAT(a, b) a ## b
557
558 #define NAME fill_triangle_1bpp_lsb_to_msb
559 #define PIXEL_TYPE unsigned char
560 #define LSB_TO_MSB
561 #define MONOCHROME
562 #include "fz_filler.h"
563
564 #define NAME fill_triangle_1bpp_msb_to_lsb
565 #define PIXEL_TYPE unsigned char
566 #define MONOCHROME
567 #include "fz_filler.h"
568
569 #define NAME fill_triangle_8bpp
570 #define PIXEL_TYPE unsigned char
571 #include "fz_filler.h"
572
573 #define NAME fill_triangle_16bpp
574 #define PIXEL_TYPE unsigned short
575 #include "fz_filler.h"
576
577 #define NAME fill_triangle_32bpp
578 #define PIXEL_TYPE unsigned int
579 #include "fz_filler.h"
580
581 /*
582 * r e n d e r
583 */
584
585 static void
radix_sort(struct render_order * out,struct render_order * in,int rshift,int n)586 radix_sort(struct render_order *out, struct render_order *in, int rshift,
587 int n)
588 {
589 static int count[256], index[256];
590 int i, b;
591
592 memset(count, 0, sizeof count);
593
594 for (i = 0; i < n; i++) {
595 b = (in[i].zi >> rshift) & 0xff;
596 count[b]++;
597 }
598
599 index[0] = 0;
600
601 for (i = 1; i < 256; i++)
602 index[i] = index[i - 1] + count[i - 1];
603
604 for (i = 0; i < n; i++) {
605 b = (in[i].zi >> rshift) & 0xff;
606 out[index[b]] = in[i];
607 index[b]++;
608 }
609 }
610
611 static void
render_process_mesh(fzort_ctx * ctx,struct matrix * m)612 render_process_mesh(fzort_ctx *ctx, struct matrix *m)
613 {
614 struct polygon *pin, *pend;
615 struct vertex *v, *vend;
616 struct pvertex *pv;
617 int i, j, npoly, x_scr_min, x_scr_max, y_scr_min, y_scr_max;
618
619 /* vertices */
620
621 ctx->cur_box.x_min = ctx->cur_box.y_min =
622 ctx->cur_box.x_max = ctx->cur_box.y_max = 0;
623
624 x_scr_min = ctx->clip.x_max + 1;
625 x_scr_max = ctx->clip.x_min - 1;
626 y_scr_min = ctx->clip.y_max + 1;
627 y_scr_max = ctx->clip.y_min - 1;
628
629 vend = ctx->mesh->vtx + ctx->mesh->nvtx;
630 pv = ctx->pvtx;
631
632 for (v = ctx->mesh->vtx; v != vend; v++) {
633 struct vector normal;
634 float w;
635
636 mat_transform_copy(&pv->p, m, &v->p);
637 mat_rotate_copy(&normal, m, &v->normal);
638 vec_normalize(&normal);
639
640 pv->u_txt = FLOAT_TO_FP((TEXTURE_SIZE/2) +
641 (TEXTURE_SIZE/2)*normal.y + 0.5);
642 pv->v_txt = FLOAT_TO_FP((TEXTURE_SIZE/2) +
643 (TEXTURE_SIZE/2)*normal.x + 0.5);
644
645 w = ctx->lx/pv->p.z;
646 pv->x_scr = (int) (ctx->cx + w*pv->p.x + 0.5);
647 pv->y_scr = (int) (ctx->cy + w*pv->p.y + 0.5);
648
649 if (pv->x_scr < x_scr_min)
650 x_scr_min = pv->x_scr;
651
652 if (pv->x_scr > x_scr_max)
653 x_scr_max = pv->x_scr;
654
655 if (pv->y_scr < y_scr_min)
656 y_scr_min = pv->y_scr;
657
658 if (pv->y_scr > y_scr_max)
659 y_scr_max = pv->y_scr;
660
661 pv++;
662 }
663
664 if (x_scr_min > ctx->clip.x_max)
665 return;
666
667 ctx->cur_box.x_min =
668 x_scr_min < ctx->clip.x_min ? ctx->clip.x_min : x_scr_min;
669
670 if (x_scr_max < ctx->clip.x_min)
671 return;
672
673 ctx->cur_box.x_max =
674 x_scr_max > ctx->clip.x_max ? ctx->clip.x_max : x_scr_max;
675
676 if (y_scr_min > ctx->clip.y_max)
677 return;
678
679 ctx->cur_box.y_min =
680 y_scr_min < ctx->clip.y_min ? ctx->clip.y_min : y_scr_min;
681
682 if (y_scr_max < ctx->clip.y_min)
683 return;
684
685 ctx->cur_box.y_max =
686 y_scr_max > ctx->clip.y_max ? ctx->clip.y_max : y_scr_max;
687
688 /* polygons */
689
690 npoly = 0;
691 pend = ctx->mesh->poly + ctx->mesh->npoly;
692
693 for (pin = ctx->mesh->poly; pin != pend; pin++) {
694 int nclip_x_min, nclip_x_max, nclip_y_min, nclip_y_max;
695 int *idx, *iend;
696
697 nclip_x_min = nclip_x_max = nclip_y_min = nclip_y_max = 0;
698
699 iend = &pin->vtx_index[pin->nvtx];
700
701 for (idx = &pin->vtx_index[0]; idx != iend; idx++) {
702 pv = &ctx->pvtx[*idx];
703
704 nclip_x_min += (pv->x_scr < ctx->clip.x_min);
705 nclip_x_max += (pv->x_scr > ctx->clip.x_max);
706 nclip_y_min += (pv->x_scr < ctx->clip.y_min);
707 nclip_y_max += (pv->y_scr > ctx->clip.y_max);
708 }
709
710 if (nclip_x_min != pin->nvtx && nclip_x_max != pin->nvtx &&
711 nclip_y_min != pin->nvtx && nclip_y_max != pin->nvtx) {
712 struct pvertex *p0, *p1, *p2, *p3;
713 int ok;
714
715 p0 = &ctx->pvtx[pin->vtx_index[0]];
716 p1 = &ctx->pvtx[pin->vtx_index[1]];
717 p2 = &ctx->pvtx[pin->vtx_index[2]];
718
719 ok = (p2->x_scr - p0->x_scr)*(p1->y_scr - p0->y_scr) -
720 (p1->x_scr - p0->x_scr)*(p2->y_scr - p0->y_scr) >= 0;
721
722 if (pin->nvtx == 4) {
723 p3 = &ctx->pvtx[pin->vtx_index[3]];
724
725 ok |= (p3->x_scr - p0->x_scr)*(p2->y_scr - p0->y_scr) -
726 (p2->x_scr - p0->x_scr)*(p3->y_scr - p0->y_scr) >= 0;
727 }
728
729 if (ok) {
730 ctx->order_in[npoly].poly = pin;
731 ctx->order_in[npoly].z = p0->p.z;
732 npoly++;
733 }
734 }
735 }
736
737 /* draw */
738
739 if (npoly) {
740 float z_min, z_max, z_scale, z;
741 struct polygon *poly;
742
743 z_min = z_max = 0.f;
744
745 for (i = 0; i < npoly; i++) {
746 z = ctx->order_in[i].z;
747
748 if (i == 0 || z < z_min)
749 z_min = z;
750
751 if (i == 0 || z > z_max)
752 z_max = z;
753 }
754
755 z_scale = 255.f/(z_max - z_min);
756
757 for (i = 0; i < npoly; i++)
758 ctx->order_in[i].zi = (unsigned int) (z_scale*(ctx->order_in[i].z - z_min));
759
760 radix_sort(ctx->order_out, ctx->order_in, 0, npoly);
761
762 for (i = npoly - 1; i >= 0; i--) {
763 poly = ctx->order_out[i].poly;
764
765 for (j = 1; j < poly->nvtx - 1; j++) {
766 ctx->fill_triangle_fn(ctx,
767 &ctx->pvtx[poly->vtx_index[0]],
768 &ctx->pvtx[poly->vtx_index[j]],
769 &ctx->pvtx[poly->vtx_index[j + 1]]);
770 }
771 }
772 }
773 }
774
775 /*
776 * m e s h
777 */
778
779 static void
mesh_free(struct mesh * m)780 mesh_free(struct mesh *m)
781 {
782 if (m->vtx != NULL)
783 free(m->vtx);
784
785 if (m->poly != NULL)
786 free(m->poly);
787
788 free(m);
789 }
790
791 static inline float
radius_offset(float phi,float theta,float phase,float amp)792 radius_offset(float phi, float theta, float phase, float amp)
793 {
794 return (amp + 4.*amp*sin(3.*phase + theta))*sin(phase + 5.*phi) +
795 (amp + 4.*amp*sin(2.*phase + 2.*phi))*sin(phase + 3.*theta);
796 }
797
798 static inline void
calc_coord(struct vector * v,float radius,float phi,float theta,float phase,float amp)799 calc_coord(struct vector *v, float radius, float phi, float theta,
800 float phase, float amp)
801 {
802 float mr, r;
803
804 /* coordinates */
805 r = radius + radius_offset(phi, theta, phase, amp);
806 v->z = -r*cos(phi);
807 mr = r*sin(phi);
808 v->y = -mr*sin(theta);
809 v->x = -mr*cos(theta);
810 }
811
812 static void
calc_mesh_vertices(struct mesh * mesh,int density,float radius,float phase,float amp)813 calc_mesh_vertices(struct mesh *mesh, int density, float radius,
814 float phase, float amp)
815 {
816 struct vertex *vtx;
817 double phi, theta, dphi, dtheta;
818 int u, v, a, b, c;
819 struct vector v0, v1;
820 float mr, r;
821 float cos_theta, sin_theta, cos_phi, sin_phi;
822 float cos_3theta, sin_3theta;
823 float sin_phase, cos_phase;
824 /*float sin_2phase, cos_2phase;*/
825 float sin_3phase, cos_3phase;
826 float cos_dphi, sin_dphi, cos_dtheta, sin_dtheta, st, ct;
827 float offs;
828 float k0, k1;
829
830 vtx = mesh->vtx;
831
832 /* vertices */
833
834 calc_coord(&vtx->p, radius, 0., M_PI, phase, amp);
835
836 vtx++;
837
838 sin_phase = sin(phase);
839 cos_phase = cos(phase);
840
841 /*sin_2phase = 2.*sin_phase*cos_phase;
842 cos_2phase = 1. - 2.*sin_phase*sin_phase;*/
843
844 sin_3phase = 3.*sin_phase - 4.*sin_phase*sin_phase*sin_phase;
845 cos_3phase = 4.*cos_phase*cos_phase*cos_phase - 3.*cos_phase;
846
847 dtheta = 2.*M_PI/density;
848 dphi = M_PI/(density + 1);
849
850 sin_dphi = sin(dphi);
851 cos_dphi = cos(dphi);
852
853 sin_dtheta = sin(dtheta);
854 cos_dtheta = cos(dtheta);
855
856 cos_phi = cos_dphi;
857 sin_phi = sin_dphi;
858
859 for (phi = dphi, u = 0; u < density; u++, phi += dphi) {
860 /* XXX: work these out */
861 k0 = sin(phase + 5.*phi);
862 k1 = amp + 4.*amp*sin(2.*phase + 2.*phi);
863
864 cos_theta = 1.;
865 sin_theta = 0.;
866
867 for (theta = 0., v = 0; v < density; v++, theta += dtheta) {
868 sin_3theta = 3*sin_theta -
869 4.*sin_theta*sin_theta*sin_theta;
870 cos_3theta = 4*cos_theta*cos_theta*cos_theta -
871 3.*cos_theta;
872
873 /*
874 (amp + 4.*amp*sin(3.*phase + theta))*
875 sin(phase + 5.*phi) +
876 (amp + 4.*amp*sin(2.*phase + 2.*phi))*
877 sin(phase + 3.*theta);
878 */
879
880 offs = (amp + 4.*amp*
881 (sin_3phase*cos_theta + sin_theta*cos_3phase))*k0 +
882 k1*(sin_phase*cos_3theta + cos_phase*sin_3theta);
883
884 r = radius + offs;
885
886 vtx->p.z = -r*cos_phi;
887 mr = r*sin_phi;
888 vtx->p.y = -mr*sin_theta;
889 vtx->p.x = -mr*cos_theta;
890 vtx++;
891
892 st = sin_theta*cos_dtheta + cos_theta*sin_dtheta;
893 ct = cos_theta*cos_dtheta - sin_theta*sin_dtheta;
894
895 sin_theta = st;
896 cos_theta = ct;
897 }
898
899 st = sin_phi*cos_dphi + cos_phi*sin_dphi;
900 ct = cos_phi*cos_dphi - sin_phi*sin_dphi;
901
902 sin_phi = st;
903 cos_phi = ct;
904 }
905
906 calc_coord(&vtx->p, radius, M_PI, M_PI, phase, amp);
907
908 /* normals */
909
910 vec_set(&mesh->vtx[0].normal, 0., 0., -1.);
911 vec_set(&mesh->vtx[1 + density*density].normal, 0., 0., 1.);
912
913 for (u = 0; u < density; u++) {
914 for (v = 0; v < density; v++) {
915 a = u*density + v + 1;
916 b = u*density + (v + 1)%density + 1;
917 c = (u + 1)*density + 1;
918 if (u < density - 1)
919 c += v;
920
921 vec_sub(&v0, &mesh->vtx[b].p, &mesh->vtx[a].p);
922 vec_sub(&v1, &mesh->vtx[c].p, &mesh->vtx[a].p);
923 vec_cross_product(&mesh->vtx[a].normal, &v0, &v1);
924 }
925 }
926 }
927
928 static void
set_triangle(struct polygon * poly,int a,int b,int c)929 set_triangle(struct polygon *poly, int a, int b, int c)
930 {
931 poly->nvtx = 3;
932 poly->vtx_index[0] = a;
933 poly->vtx_index[1] = b;
934 poly->vtx_index[2] = c;
935 }
936
937 static void
set_quad(struct polygon * poly,int a,int b,int c,int d)938 set_quad(struct polygon *poly, int a, int b, int c, int d)
939 {
940 poly->nvtx = 4;
941 poly->vtx_index[0] = a;
942 poly->vtx_index[1] = b;
943 poly->vtx_index[2] = c;
944 poly->vtx_index[3] = d;
945 }
946
947 static struct mesh *
make_sphere(int density)948 make_sphere(int density)
949 {
950 int u, v, a, b, c, d;
951 struct polygon *poly;
952 struct mesh *mesh;
953
954 if ((mesh = (struct mesh *) malloc(sizeof *mesh)) == NULL) {
955 return NULL;
956 }
957
958 mesh->npoly = mesh->nvtx = 0;
959
960 /* vertices */
961
962 mesh->nvtx = 2 + density*density;
963 mesh->vtx = (struct vertex *) malloc(mesh->nvtx * sizeof *mesh->vtx);
964
965 /* polygons */
966
967 mesh->npoly = (density + 1)*density;
968 poly = mesh->poly = (struct polygon *) malloc(mesh->npoly * sizeof *mesh->poly);
969
970 for (u = 0; u < density; u++) {
971 for (v = 0; v < density; v++) {
972 a = u*density + v + 1;
973 b = u*density + (v + 1)%density + 1;
974
975 if (u == 0) {
976 set_triangle(poly++, a, 0, b);
977 } else {
978 c = (u - 1)*density + v + 1;
979 d = (u - 1)*density + (v + 1)%density + 1;
980
981 set_quad(poly++, a, c, d, b);
982 }
983 }
984 }
985
986 for (v = 0; v < density; v++) {
987 a = density*density + 1;
988 d = (density - 1)*density + ((v + 1) % density) + 1;
989 c = (density - 1)*density + v + 1;
990
991 set_triangle(poly++, a, c, d);
992 }
993
994 return mesh;
995 }
996
997 /*
998 * t e x t u r e g e n e r a t i o n
999 */
1000
1001 static int
getpix(unsigned char * dest,int x,int y)1002 getpix(unsigned char *dest, int x, int y)
1003 {
1004 return dest[(y&(TEXTURE_SIZE-1))*TEXTURE_SIZE + (x&(TEXTURE_SIZE - 1))];
1005 }
1006
1007 static void
putpix(unsigned char * dest,int x,int y,int v)1008 putpix(unsigned char *dest, int x, int y, int v)
1009 {
1010 dest[(y&(TEXTURE_SIZE-1))*TEXTURE_SIZE + (x&(TEXTURE_SIZE-1))] = v;
1011 }
1012
1013 static int
randnum(int range)1014 randnum(int range)
1015 {
1016 return LRAND() % (2*(range + 1)) - range;
1017 }
1018
1019 static int
plasmaavg(unsigned char * dest,int x1,int y1,int x2,int y2)1020 plasmaavg(unsigned char *dest, int x1, int y1, int x2, int y2)
1021 {
1022 int average, distance;
1023
1024 average = (getpix(dest, x1, y1) + getpix(dest, x2, y2)) / 2;
1025 distance = abs(x1 - x2) + abs(y1 - y2);
1026
1027 if (distance > 2)
1028 distance -= 2;
1029
1030 return average + randnum(distance);
1031 }
1032
1033 static void
rplasma(unsigned char * dest,int left,int top,int right,int bottom)1034 rplasma(unsigned char *dest, int left, int top, int right, int bottom)
1035 {
1036 int x, y;
1037
1038 if (abs(top - bottom) < 2 && abs(right - left) < 2)
1039 return;
1040
1041 x = left;
1042 y = (top + bottom) / 2;
1043 if (!getpix(dest, x, y))
1044 putpix(dest, x, y, plasmaavg(dest, left, top, left, bottom));
1045
1046 x = right;
1047 if (!getpix(dest, x, y))
1048 putpix(dest, x, y, plasmaavg(dest, right, top, right, bottom));
1049
1050 x = (left + right) / 2;
1051 y = top;
1052 if (!getpix(dest, x, y))
1053 putpix(dest, x, y, plasmaavg(dest, left, top, right, top));
1054
1055 y = bottom;
1056 if (!getpix(dest, x, y))
1057 putpix(dest, x, y, plasmaavg(dest, left, bottom, right, bottom));
1058
1059 y = (top + bottom) / 2;
1060 if (!getpix(dest, x, y))
1061 putpix(dest, x, y, (plasmaavg(dest, x, top, x, bottom) +
1062 plasmaavg(dest, left, y, right, y)) / 2 + randnum(right - left));
1063
1064 rplasma(dest, left, top, x, y);
1065 rplasma(dest, x, top, right, y);
1066 rplasma(dest, x, y, right, bottom);
1067 rplasma(dest, left, y, x, bottom);
1068 }
1069
1070 static void
flare(unsigned char * dest)1071 flare(unsigned char *dest)
1072 {
1073 int i, j, r;
1074 float a;
1075 unsigned s;
1076
1077 struct vector n, l;
1078
1079 vec_set(&l, -.4, .4, 1.);
1080 vec_normalize(&l);
1081
1082 for (i = 0; i < TEXTURE_SIZE; i++) {
1083 for (j = 0; j < TEXTURE_SIZE; j++) {
1084 n.x = j - TEXTURE_SIZE/2;
1085 n.y = i - TEXTURE_SIZE/2;
1086 n.z = -TEXTURE_SIZE/2;
1087
1088 vec_normalize(&n);
1089
1090 a = vec_dot_product(&n, &l);
1091 a *= a; a *= a;
1092 a *= a; a *= a;
1093 a *= a; a *= a;
1094
1095 r = (int) (a*255);
1096 s = (dest[i*TEXTURE_SIZE + j]>>1) + r;
1097 s = s > 255 ? 255 : s;
1098 dest[i*TEXTURE_SIZE + j] = s;
1099 }
1100 }
1101 }
1102
1103 static void *
init_texture(int * palette,int depth)1104 init_texture(int *palette, int depth)
1105 {
1106 int i, j;
1107 unsigned int v, pixel_size;
1108 void *texture;
1109
1110 switch (depth) {
1111 case 1: case 8: pixel_size = sizeof(unsigned char); break;
1112 case 16: pixel_size = sizeof(unsigned short); break;
1113 case 24: case 32: pixel_size = sizeof(unsigned int); break;
1114 default: return NULL; /* ugh */
1115 }
1116
1117 if ((texture = malloc(TEXTURE_SIZE*TEXTURE_SIZE*pixel_size)) == NULL) {
1118 return NULL;
1119 }
1120
1121 if (!texture_initialized) {
1122 memset(texture8, 0, sizeof texture8);
1123 rplasma(texture8, 0, 0, TEXTURE_SIZE, TEXTURE_SIZE);
1124 flare(texture8);
1125 texture_initialized = True;
1126 }
1127
1128 switch (depth) {
1129 case 1:
1130 memcpy(texture, texture8, TEXTURE_SIZE*TEXTURE_SIZE);
1131 break;
1132
1133 case 8:
1134 for (i = 0; i < TEXTURE_SIZE; i++) {
1135 for (j = 0; j < TEXTURE_SIZE; j++) {
1136 v = texture8[i*TEXTURE_SIZE + j];
1137 ((unsigned char *)texture)[i*TEXTURE_SIZE + j] = palette[v];
1138 }
1139 }
1140 break;
1141
1142 case 16:
1143 for (i = 0; i < TEXTURE_SIZE; i++) {
1144 for (j = 0; j < TEXTURE_SIZE; j++) {
1145 v = texture8[i*TEXTURE_SIZE + j];
1146 ((unsigned short *)texture)[i*TEXTURE_SIZE + j]
1147 = palette[v];
1148 }
1149 }
1150 break;
1151
1152 case 24:
1153 case 32:
1154 for (i = 0; i < TEXTURE_SIZE; i++) {
1155 for (j = 0; j < TEXTURE_SIZE; j++) {
1156 v = texture8[i*TEXTURE_SIZE + j];
1157 ((unsigned int *)texture)[i*TEXTURE_SIZE + j] = palette[v];
1158 }
1159 }
1160 break;
1161 }
1162
1163 return texture;
1164 }
1165
1166
1167 /*
1168 * x i m a g e
1169 */
1170
1171 #if 0
1172 static int caught_x_error;
1173
1174 static int
1175 x_error_handler(Display *display, XErrorEvent *error)
1176 {
1177 caught_x_error = 1;
1178
1179 return 0;
1180 }
1181 #endif
1182
1183 static int
make_image(ModeInfo * mi,struct fzort_ctx * fz)1184 make_image(ModeInfo *mi, struct fzort_ctx *fz)
1185 {
1186 int img_width, img_height;
1187 int depth, format;
1188
1189 img_width = MIN(MI_WIDTH(mi), MI_HEIGHT(mi));
1190
1191 if (img_width > MAX_WIDTH)
1192 img_width = MAX_WIDTH;
1193
1194 img_height = img_width;
1195
1196 if (MI_DEPTH(mi) == 1 || MI_NPIXELS(mi) > 2) {
1197 depth = MI_DEPTH(mi);
1198 format = ZPixmap;
1199 } else {
1200 depth = 1;
1201 format = XYBitmap;
1202 }
1203
1204 fz->image = create_xshm_image (MI_DISPLAY(mi), MI_VISUAL(mi),
1205 depth, format, &fz->shm_info, img_width, img_height);
1206
1207 if (fz->image == NULL)
1208 return -1;
1209
1210 return 0;
1211 }
1212
1213 static void
free_an_image(ModeInfo * mi,struct fzort_ctx * fz)1214 free_an_image(ModeInfo *mi, struct fzort_ctx *fz)
1215 {
1216 destroy_xshm_image (MI_DISPLAY(mi), fz->image, &fz->shm_info);
1217 fz->image = NULL;
1218 }
1219
1220
1221 /*
1222 * f z o r t
1223 */
1224
1225 static void
free_fzort_screen(ModeInfo * mi,fzort_ctx * fz)1226 free_fzort_screen(ModeInfo *mi, fzort_ctx *fz)
1227 {
1228 if (fz == NULL) {
1229 return;
1230 }
1231 if (fz->initialized) {
1232 free(fz->pvtx);
1233 free(fz->order_in);
1234 free(fz->order_out);
1235 free(fz->texture);
1236 mesh_free(fz->mesh);
1237 free_an_image(mi, fz);
1238 fz->initialized = False;
1239 }
1240 fz = NULL;
1241 }
1242
1243 static void
init_color_map(ModeInfo * mi,fzort_ctx * fz,float r,float g,float b,float kd,float ks,float n)1244 init_color_map(ModeInfo *mi, fzort_ctx *fz, float r, float g, float b,
1245 float kd, float ks, float n)
1246 {
1247 float red, green, blue, ang;
1248 unsigned ib, ig, ir;
1249 float ka, kb;
1250 int i;
1251 XColor xc;
1252
1253 for (i = 0; i < 256; i++) {
1254 ang = (255 - i)*(M_PI/2.)/256.0;
1255
1256 ka = kd * cos(ang);
1257 kb = ks * pow(cos(ang), n);
1258
1259 red = r*ka + kb;
1260 green = g*ka + kb;
1261 blue = b*ka + kb;
1262
1263 ib = (unsigned int) ((blue > 1.0) ? 255 : 255*blue);
1264 ig = (unsigned int) ((green > 1.0) ? 255 : 255*green);
1265 ir = (unsigned int) ((red > 1.0) ? 255 : 255*red);
1266
1267 xc.red = ir<<8;
1268 xc.green = ig<<8;
1269 xc.blue = ib<<8;
1270 xc.flags = DoRed|DoGreen|DoBlue;
1271
1272 XAllocColor(MI_DISPLAY(mi), MI_COLORMAP(mi), &xc);
1273
1274 fz->palette[i] = xc.pixel;
1275 }
1276 }
1277
1278 static void
init_fzort_ctx(ModeInfo * mi,fzort_ctx * fz)1279 init_fzort_ctx(ModeInfo *mi, fzort_ctx *fz)
1280 {
1281 struct timeval tv;
1282
1283 if (fz->initialized) {
1284 free_fzort_screen(mi, fz);
1285 }
1286
1287 /* 0. create image for double-buffering */
1288
1289 if (make_image(mi, fz) < 0) {
1290 goto failed_0;
1291 }
1292
1293 fz->clip.x_min = 0;
1294 fz->clip.y_min = 0;
1295 fz->clip.x_max = fz->image->width - 1;
1296 fz->clip.y_max = fz->image->height - 1;
1297
1298 fz->raster.width = fz->image->width;
1299 fz->raster.height = fz->image->height;
1300 fz->raster.pitch = fz->image->bytes_per_line;
1301 fz->raster.bits = fz->image->data;
1302 fz->raster.bpp = fz->image->bits_per_pixel;
1303
1304 fz->lx = fz->raster.width;
1305 fz->ly = fz->raster.height;
1306 fz->cx = fz->raster.width/2;
1307 fz->cy = fz->raster.height/2;
1308
1309 switch (fz->raster.bpp) {
1310 case 1:
1311 /* check if the leftmost pixel is represented by the least
1312 * significant bit or vice-versa */
1313 fz->image->data[0] = 0;
1314 XPutPixel(fz->image, 0, 0, 1);
1315 if (fz->image->data[0] == 1)
1316 fz->fill_triangle_fn = fill_triangle_1bpp_lsb_to_msb;
1317 else
1318 fz->fill_triangle_fn = fill_triangle_1bpp_msb_to_lsb;
1319 break;
1320 case 8: fz->fill_triangle_fn = fill_triangle_8bpp; break;
1321 case 16: fz->fill_triangle_fn = fill_triangle_16bpp; break;
1322 case 24: case 32:
1323 fz->fill_triangle_fn = fill_triangle_32bpp; break;
1324 }
1325
1326 /* 1. create mesh */
1327
1328 if ((fz->mesh = make_sphere(MESH_DENSITY)) == NULL) {
1329 goto failed_1;
1330 }
1331
1332 /* 2. initialize palette */
1333
1334 if (fz->image->depth >= 8) {
1335 init_color_map(mi, fz, .2, .2, 1., .9, .5, 4.);
1336 }
1337
1338 /* 3. create texture */
1339
1340 if ((fz->texture = init_texture(fz->palette, fz->image->bits_per_pixel))
1341 == NULL) {
1342 goto failed_2;
1343 }
1344
1345 /* 4. allocate memory for vertices and polygons */
1346
1347 if ((fz->pvtx = (struct pvertex *) malloc(fz->mesh->nvtx * sizeof *fz->pvtx)) == NULL) {
1348 goto failed_3;
1349 }
1350
1351 if ((fz->order_in = (struct render_order *) malloc(fz->mesh->npoly * sizeof *fz->order_in))
1352 == NULL) {
1353 goto failed_4;
1354 }
1355
1356 if ((fz->order_out = (struct render_order *) malloc(fz->mesh->npoly * sizeof *fz->order_out))
1357 == NULL) {
1358 goto failed_5;
1359 }
1360
1361 gettimeofday(&tv, NULL);
1362 fz->start_ticks = tv.tv_sec*1000 + tv.tv_usec/1000;
1363
1364 fz->prev_box.x_min = 0;
1365 fz->prev_box.x_max = fz->clip.x_max;
1366 fz->prev_box.y_min = 0;
1367 fz->prev_box.y_max = fz->clip.y_max;
1368
1369 fz->initialized = True;
1370
1371 MI_CLEARWINDOW(mi);
1372
1373 return;
1374
1375 failed_5:
1376 free(fz->order_in);
1377 failed_4:
1378 free(fz->pvtx);
1379 failed_3:
1380 free(fz->texture);
1381 failed_2:
1382 mesh_free(fz->mesh);
1383 failed_1:
1384 free_an_image(mi, fz);
1385 failed_0:
1386 return;
1387 }
1388
1389 static void
render(fzort_ctx * fz,long ticks)1390 render(fzort_ctx *fz, long ticks)
1391 {
1392 struct matrix t, v;
1393 float a, b/* ,c*/;
1394 struct matrix rmatrix, ry, rx;
1395
1396 a = (float)ticks/2000.;
1397
1398 calc_mesh_vertices(fz->mesh, MESH_DENSITY, 120.,
1399 /* 4.*a, 12. + 5.*sin(2.*a)); */
1400 4.*a, 7. + 7.*sin(2.*a));
1401 /* 0., 0.); */
1402
1403 b = 1.5*a;
1404 /*c = 2.2*a;*/
1405
1406 mat_make_rotation_around_y(&ry, 1.5*a);
1407 mat_make_rotation_around_x(&rx, 2.2*a);
1408 mat_mul_copy(&rmatrix, &ry, &rx);
1409 mat_make_translation(&t, 220.*sin(b), 220.*cos(a),
1410 900. + 80.*cos(b)*sin(a));
1411 mat_mul_copy(&v, &t, &rmatrix);
1412 render_process_mesh(fz, &v);
1413 }
1414
1415 /*
1416 * P u b l i c i n t e r f a c e
1417 */
1418
1419 ENTRYPOINT void
init_fzort(ModeInfo * mi)1420 init_fzort(ModeInfo *mi)
1421 {
1422 fzort_ctx *fz;
1423
1424 MI_INIT(mi, fzorts);
1425 fz = &fzorts[MI_SCREEN(mi)];
1426 init_fzort_ctx(mi, fz);
1427 }
1428
1429 ENTRYPOINT void
draw_fzort(ModeInfo * mi)1430 draw_fzort(ModeInfo *mi)
1431 {
1432 fzort_ctx *fz;
1433 int x0, y0, src_x_min, src_y_min, src_x_max, src_y_max;
1434 int lines, bytes_per_pixel, bytes_per_block;
1435 char *ptr;
1436 long cur_ticks;
1437 struct timeval tv;
1438
1439 if (fzorts == NULL)
1440 return;
1441
1442 fz = &fzorts[MI_SCREEN(mi)];
1443 #if 0
1444 printf("Dies after here on Solaris/gcc\n");
1445 if (!fz->initialized)
1446 return;
1447 printf("Dies before here on Solaris/gcc\n");
1448 #else
1449 if (!fz->initialized)
1450 return;
1451 #endif
1452
1453 /* clear what was used by previous iteration */
1454
1455 if (fz->image->bits_per_pixel < 8) {
1456 /* monochrome pixmaps use so little memory that it's probably cheaper
1457 * to do a single memset */
1458 memset(fz->image->data, 0, fz->image->height*fz->image->bytes_per_line);
1459 } else {
1460 bytes_per_pixel = fz->image->bits_per_pixel/8;
1461 lines = fz->prev_box.y_max - fz->prev_box.y_min + 1;
1462 ptr = fz->image->data +
1463 fz->prev_box.y_min*fz->image->bytes_per_line +
1464 fz->prev_box.x_min*bytes_per_pixel;
1465 bytes_per_block= (fz->prev_box.x_max - fz->prev_box.x_min + 1)*
1466 bytes_per_pixel;
1467
1468 while (lines--) {
1469 memset(ptr, 0, bytes_per_block);
1470 ptr += fz->image->bytes_per_line;
1471 }
1472 }
1473
1474 gettimeofday(&tv, NULL);
1475 cur_ticks = tv.tv_sec*1000 + tv.tv_usec/1000;
1476
1477 /* render */
1478
1479 render(fz, cur_ticks - fz->start_ticks);
1480
1481 /* display image */
1482
1483 x0 = (MI_WIDTH(mi) - fz->image->width)/2;
1484 y0 = (MI_HEIGHT(mi) - fz->image->height)/2;
1485
1486 if (fz->image->width <= 200) {
1487 src_x_min = src_y_min = 0;
1488 src_x_max = fz->image->width - 1;
1489 src_y_max = fz->image->height - 1;
1490 } else {
1491 src_x_min = MIN(fz->prev_box.x_min, fz->cur_box.x_min);
1492 src_y_min = MIN(fz->prev_box.y_min, fz->cur_box.y_min);
1493
1494 src_x_max = MAX(fz->prev_box.x_max, fz->cur_box.x_max);
1495 src_y_max = MAX(fz->prev_box.y_max, fz->cur_box.y_max);
1496 }
1497
1498 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
1499 XSetBackground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
1500
1501 put_xshm_image(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
1502 fz->image,
1503 src_x_min, src_y_min, x0 + src_x_min, y0 + src_y_min,
1504 src_x_max - src_x_min + 1, src_y_max - src_y_min + 1,
1505 &fz->shm_info
1506 #ifndef STANDALONE
1507 , True
1508 #endif
1509 );
1510 fz->prev_box = fz->cur_box;
1511 }
1512
1513 ENTRYPOINT void
release_fzort(ModeInfo * mi)1514 release_fzort(ModeInfo *mi)
1515 {
1516 int i;
1517
1518 if (fzorts != NULL) {
1519 for (i = 0; i < MI_NUM_SCREENS(mi); i++) {
1520 free_fzort_screen(mi, &fzorts[i]);
1521 }
1522 }
1523
1524 free(fzorts);
1525
1526 fzorts = (fzort_ctx *) NULL;
1527 }
1528
1529 #ifndef STANDALONE
1530 ENTRYPOINT void
refresh_fzort(ModeInfo * mi)1531 refresh_fzort(ModeInfo *mi)
1532 {
1533 MI_CLEARWINDOW(mi);
1534 }
1535 #endif
1536
1537 XSCREENSAVER_MODULE ("Fzort", fzort)
1538
1539 #endif /* MODE_fzort */
1540