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