378 lines
10 KiB
C
378 lines
10 KiB
C
|
/* -*- Mode: C; tab-width: 4 -*- */
|
||
|
/* triangle --- create a triangle-mountain */
|
||
|
|
||
|
#if !defined( lint ) && !defined( SABER )
|
||
|
static const char sccsid[] = "@(#)triangle.c 5.00 2000/11/01 xlockmore";
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*-
|
||
|
* Copyright (c) 1995 by Tobias Gloth
|
||
|
*
|
||
|
* Permission to use, copy, modify, and distribute this software and its
|
||
|
* documentation for any purpose and without fee is hereby granted,
|
||
|
* provided that the above copyright notice appear in all copies and that
|
||
|
* both that copyright notice and this permission notice appear in
|
||
|
* supporting documentation.
|
||
|
*
|
||
|
* This file is provided AS IS with no warranties of any kind. The author
|
||
|
* shall have no liability with respect to the infringement of copyrights,
|
||
|
* trade secrets or any patents by this file or any part thereof. In no
|
||
|
* event will the author be liable for any lost revenue or profits or
|
||
|
* other special, indirect and consequential damages.
|
||
|
*
|
||
|
* Revision History:
|
||
|
* 01-Nov-2000: Allocation checks
|
||
|
* 22-Dec-1997: Removed MI_PAUSE since it does not work on multiscreens.
|
||
|
* 10-May-1997: Compatible with xscreensaver
|
||
|
* 10-Mar-1996: re-arranged and re-formatted the code for appearance and
|
||
|
* to make common subroutines. Simplified.
|
||
|
* Ron Hitchens <ron@idiom.com>
|
||
|
* 07-Mar-1996: Removed internal delay code, set MI_PAUSE(mi) for inter-scene
|
||
|
* delays. No other delays are needed here.
|
||
|
* Made pause time sensitive to value of cycles (in 10ths of a
|
||
|
* second). Removed (hopefully) all references to globals.
|
||
|
* Ron Hitchens <ron@idiom.com>
|
||
|
* 27-Feb-1996: Undid the changes listed below. Added ModeInfo argument.
|
||
|
* Implemented delay between scenes using the MI_PAUSE(mi)
|
||
|
* scheme. Ron Hitchens <ron@idiom.com>
|
||
|
* 27-Dec-1995: Ron Hitchens <ron@idiom.com>
|
||
|
* Modified logic of draw_triangle() to provide a delay
|
||
|
* (sensitive to the value of cycles) between each iteration.
|
||
|
* Because this mode is so compute intensive, when the new
|
||
|
* event loop adjusted the delay to compensate, this mode had
|
||
|
* almost no delay time left. This change pauses between each
|
||
|
* new landscape, but could still be done better (it is not
|
||
|
* sensitive to input events while drawing, for example).
|
||
|
* 03-Nov-1995: Many changes (hopefully some good ones) by David Bagley
|
||
|
* 01-Oct-1995: Written by Tobias Gloth
|
||
|
*/
|
||
|
|
||
|
#ifdef STANDALONE
|
||
|
#define MODE_triangle
|
||
|
#define PROGCLASS "Triangle"
|
||
|
#define HACK_INIT init_triangle
|
||
|
#define HACK_DRAW draw_triangle
|
||
|
#define triangle_opts xlockmore_opts
|
||
|
#define DEFAULTS "*delay: 10000 \n" \
|
||
|
"*ncolors: 128 \n " \
|
||
|
"*wireframe: False \n" \
|
||
|
"*fullrandom: False \n"
|
||
|
#define SMOOTH_COLORS
|
||
|
#if 0
|
||
|
#define UNIFORM_COLORS /* To get blue water uncomment, but ... */
|
||
|
#endif
|
||
|
#include "xlockmore.h" /* in xscreensaver distribution */
|
||
|
#else /* STANDALONE */
|
||
|
#include "xlock.h" /* in xlockmore distribution */
|
||
|
#endif /* STANDALONE */
|
||
|
|
||
|
#ifdef MODE_triangle
|
||
|
|
||
|
ModeSpecOpt triangle_opts =
|
||
|
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
|
||
|
|
||
|
#ifdef USE_MODULES
|
||
|
ModStruct triangle_description =
|
||
|
{"triangle", "init_triangle", "draw_triangle", "release_triangle",
|
||
|
"refresh_triangle", "init_triangle", (char *) NULL, &triangle_opts,
|
||
|
10000, 1, 1, 1, 64, 1.0, "",
|
||
|
"Shows a triangle mountain range", 0, NULL};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#define MAX_STEPS 8
|
||
|
#define MAX_SIZE (1<<MAX_STEPS)
|
||
|
#define MAX_LEVELS 1000
|
||
|
|
||
|
#define DELTA 0.4
|
||
|
#define LEFT -0.25
|
||
|
#define RIGHT 1.25
|
||
|
#define TOP 0.3
|
||
|
#define BOTTOM 1.0
|
||
|
#define BLUE (45 * MI_NPIXELS(mi) / 64) /* Just the right shade of blue */
|
||
|
|
||
|
#define BACKFACE_REMOVAL
|
||
|
|
||
|
#define DISPLACE(h,d) ((h)/2+LRAND()/(MAXRAND/(2*(d)+1))-d)
|
||
|
|
||
|
typedef struct {
|
||
|
int width;
|
||
|
int height;
|
||
|
int size;
|
||
|
int steps;
|
||
|
int stage;
|
||
|
int busyLoop;
|
||
|
int fast;
|
||
|
int i;
|
||
|
int j;
|
||
|
int d;
|
||
|
short level[MAX_LEVELS];
|
||
|
int xpos[2 * MAX_SIZE + 1];
|
||
|
int ypos[MAX_SIZE + 1];
|
||
|
short H[(MAX_SIZE + 1) * (MAX_SIZE + 2) / 2];
|
||
|
short *h[MAX_SIZE + 1];
|
||
|
short delta[MAX_STEPS];
|
||
|
Bool wireframe;
|
||
|
Bool joke;
|
||
|
} trianglestruct;
|
||
|
|
||
|
static trianglestruct *triangles = (trianglestruct *) NULL;
|
||
|
|
||
|
static
|
||
|
void
|
||
|
draw_atriangle(ModeInfo * mi, XPoint * p, int y_0, int y_1, int y_2, double dinv)
|
||
|
{
|
||
|
Display *display = MI_DISPLAY(mi);
|
||
|
Window window = MI_WINDOW(mi);
|
||
|
GC gc = MI_GC(mi);
|
||
|
trianglestruct *tp = &triangles[MI_SCREEN(mi)];
|
||
|
|
||
|
if (MI_NPIXELS(mi) > 2) { /* color */
|
||
|
int dmax, dmin;
|
||
|
long color;
|
||
|
|
||
|
dmin = MIN(y_0, y_1);
|
||
|
dmin = MIN(dmin, y_2);
|
||
|
dmax = MAX(y_0, y_1);
|
||
|
dmax = MAX(dmax, y_2);
|
||
|
|
||
|
if (dmax == 0) {
|
||
|
color = BLUE;
|
||
|
} else {
|
||
|
color = MI_NPIXELS(mi) -
|
||
|
(int) ((double) MI_NPIXELS(mi) / M_PI_2 * atan(dinv * (dmax - dmin)));
|
||
|
}
|
||
|
|
||
|
XSetForeground(display, gc, MI_PIXEL(mi, color % MI_NPIXELS(mi)));
|
||
|
if (tp->joke) {
|
||
|
if ((Bool) (LRAND() & 1)) {
|
||
|
XDrawLines(display, window, gc, p, 4, CoordModeOrigin);
|
||
|
} else {
|
||
|
XFillPolygon(display, window, gc, p, 3, Convex, CoordModeOrigin);
|
||
|
}
|
||
|
} else if (tp->wireframe) {
|
||
|
XDrawLines(display, window, gc, p, 4, CoordModeOrigin);
|
||
|
} else {
|
||
|
/* dieing on my Sun here with gcc -g -O2, flakey */
|
||
|
XFillPolygon(display, window, gc, p, 3, Convex, CoordModeOrigin);
|
||
|
}
|
||
|
} else {
|
||
|
/* mono */
|
||
|
#ifdef BACKFACE_REMOVAL
|
||
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
||
|
XFillPolygon(display, window, gc, p, 3, Convex, CoordModeOrigin);
|
||
|
#endif
|
||
|
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
|
||
|
XDrawLines(display, window, gc, p, 4, CoordModeOrigin);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static
|
||
|
void
|
||
|
calc_points1(trianglestruct * tp, int d, int *y0_p, int *y1_p, int *y2_p, XPoint * p)
|
||
|
{
|
||
|
*y0_p = tp->level[MAX(tp->h[tp->i][tp->j], 0)];
|
||
|
*y1_p = tp->level[MAX(tp->h[tp->i + d][tp->j], 0)];
|
||
|
*y2_p = tp->level[MAX(tp->h[tp->i][tp->j + d], 0)];
|
||
|
|
||
|
p[0].x = tp->xpos[2 * tp->i + tp->j];
|
||
|
p[1].x = tp->xpos[2 * (tp->i + d) + tp->j];
|
||
|
p[2].x = tp->xpos[2 * tp->i + (tp->j + d)];
|
||
|
|
||
|
p[0].y = tp->ypos[tp->j] - *y0_p;
|
||
|
p[1].y = tp->ypos[tp->j] - *y1_p;
|
||
|
p[2].y = tp->ypos[tp->j + d] - *y2_p;
|
||
|
|
||
|
p[3] = p[0];
|
||
|
}
|
||
|
|
||
|
static
|
||
|
void
|
||
|
calc_points2(trianglestruct * tp, int d, int *y0_p, int *y1_p, int *y2_p, XPoint * p)
|
||
|
{
|
||
|
*y0_p = tp->level[MAX(tp->h[tp->i + d][tp->j], 0)];
|
||
|
*y1_p = tp->level[MAX(tp->h[tp->i + d][tp->j + d], 0)];
|
||
|
*y2_p = tp->level[MAX(tp->h[tp->i][tp->j + d], 0)];
|
||
|
|
||
|
p[0].x = tp->xpos[2 * (tp->i + d) + tp->j];
|
||
|
p[1].x = tp->xpos[2 * (tp->i + d) + (tp->j + d)];
|
||
|
p[2].x = tp->xpos[2 * tp->i + (tp->j + d)];
|
||
|
|
||
|
p[0].y = tp->ypos[tp->j] - *y0_p;
|
||
|
p[1].y = tp->ypos[tp->j + d] - *y1_p;
|
||
|
p[2].y = tp->ypos[tp->j + d] - *y2_p;
|
||
|
|
||
|
p[3]= p[0];
|
||
|
}
|
||
|
|
||
|
|
||
|
static
|
||
|
void
|
||
|
draw_mesh(ModeInfo * mi, trianglestruct * tp, int d, int count)
|
||
|
{
|
||
|
XPoint p[4];
|
||
|
int first = 1;
|
||
|
int y_0, y_1, y_2;
|
||
|
double dinv = 0.2 / d;
|
||
|
|
||
|
if ((tp->j == 0) && (tp->i == 0)) {
|
||
|
MI_CLEARWINDOWCOLORMAPFAST(mi, MI_GC(mi), MI_BLACK_PIXEL(mi));
|
||
|
}
|
||
|
for (; (tp->j < tp->size) && (count > 0); tp->j += ((count) ? d : 0)) {
|
||
|
for (tp->i = (first) ? tp->i : 0, first = 0;
|
||
|
(tp->i < MAX_SIZE - tp->j) && (count > 0);
|
||
|
tp->i += d, count--) {
|
||
|
if (tp->i + tp->j < tp->size) {
|
||
|
calc_points1(tp, d, &y_0, &y_1, &y_2, p);
|
||
|
draw_atriangle(mi, p, y_0, y_1, y_2, dinv);
|
||
|
}
|
||
|
if (tp->i + tp->j + d < tp->size) {
|
||
|
calc_points2(tp, d, &y_0, &y_1, &y_2, p);
|
||
|
draw_atriangle(mi, p, y_0, y_1, y_2, dinv);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (tp->j == tp->size) {
|
||
|
tp->busyLoop = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
init_triangle(ModeInfo * mi)
|
||
|
{
|
||
|
short *tmp;
|
||
|
int i, dim, one;
|
||
|
trianglestruct *tp;
|
||
|
|
||
|
if (triangles == NULL) {
|
||
|
if ((triangles = (trianglestruct *) calloc(MI_NUM_SCREENS(mi),
|
||
|
sizeof (trianglestruct))) == NULL)
|
||
|
return;
|
||
|
}
|
||
|
tp = &triangles[MI_SCREEN(mi)];
|
||
|
|
||
|
tp->width = MI_WIDTH(mi);
|
||
|
tp->height = MI_HEIGHT(mi);
|
||
|
tp->busyLoop = -1;
|
||
|
tp->fast = 2;
|
||
|
if (MI_IS_FULLRANDOM(mi)) {
|
||
|
tp->joke = (Bool) (NRAND(10) == 0);
|
||
|
tp->wireframe = (Bool) (LRAND() & 1);
|
||
|
} else
|
||
|
tp->wireframe = MI_IS_WIREFRAME(mi);
|
||
|
|
||
|
MI_CLEARWINDOW(mi);
|
||
|
|
||
|
tp->steps = MAX_STEPS;
|
||
|
do {
|
||
|
tp->size = 1 << --tp->steps;
|
||
|
} while (tp->size * 5 > tp->width);
|
||
|
tmp = tp->H;
|
||
|
for (i = 0; i < tp->size + 1; i++) {
|
||
|
tp->h[i] = tmp;
|
||
|
tmp += (tp->size) + 1 - i;
|
||
|
}
|
||
|
|
||
|
tp->stage = -1;
|
||
|
dim = MIN(tp->width, tp->height);
|
||
|
|
||
|
for (i = 0; i < 2 * tp->size + 1; i++) {
|
||
|
tp->xpos[i] = (short) ((((double) i)
|
||
|
/ ((double) (2 * tp->size)) * (RIGHT - LEFT) + LEFT)
|
||
|
* dim) + (tp->width - dim) / 2;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < (tp->size + 1); i++) {
|
||
|
tp->ypos[i] = (short) ((((double) i)
|
||
|
/ ((double) tp->size) * (BOTTOM - TOP) + TOP) * dim)
|
||
|
+ (tp->height - dim) / 2;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < tp->steps; i++) {
|
||
|
tp->delta[i] = ((short) (DELTA * dim)) >> i;
|
||
|
}
|
||
|
|
||
|
one = tp->delta[0];
|
||
|
|
||
|
if (one > 0)
|
||
|
for (i = 0; i < MAX_LEVELS; i++) {
|
||
|
tp->level[i] = (i * i) / one;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
draw_triangle(ModeInfo * mi)
|
||
|
{
|
||
|
int d, d2, i, j, delta;
|
||
|
trianglestruct *tp;
|
||
|
|
||
|
if (triangles == NULL)
|
||
|
return;
|
||
|
tp = &triangles[MI_SCREEN(mi)];
|
||
|
|
||
|
MI_IS_DRAWN(mi) = True;
|
||
|
if (tp->busyLoop > 0) {
|
||
|
if (tp->busyLoop >= 100)
|
||
|
tp->busyLoop = -1;
|
||
|
else
|
||
|
tp->busyLoop++;
|
||
|
return;
|
||
|
}
|
||
|
if (!tp->busyLoop) {
|
||
|
draw_mesh(mi, tp, tp->d / 2, MAX_SIZE / tp->d);
|
||
|
return;
|
||
|
}
|
||
|
if (tp->delta[0] > 0) {
|
||
|
if (!(++tp->stage)) {
|
||
|
tp->h[0][0] = (short int) MAX(0, DISPLACE(0, tp->delta[0]));
|
||
|
tp->h[tp->size][0] = (short int) MAX(0, DISPLACE(0, tp->delta[0]));
|
||
|
tp->h[0][tp->size] = (short int) MAX(0, DISPLACE(0, tp->delta[0]));
|
||
|
} else {
|
||
|
d = 2 << (tp->steps - tp->stage);
|
||
|
d2 = d / 2;
|
||
|
delta = tp->delta[tp->stage - 1];
|
||
|
|
||
|
for (i = 0; i < tp->size; i += d) {
|
||
|
for (j = 0; j < (tp->size - i); j += d) {
|
||
|
tp->h[i + d2][j] = (short int) DISPLACE(tp->h[i][j] +
|
||
|
tp->h[i + d][j], delta);
|
||
|
tp->h[i][j + d2] = (short int) DISPLACE(tp->h[i][j] +
|
||
|
tp->h[i][j + d], delta);
|
||
|
tp->h[i + d2][j + d2] = (short int) DISPLACE(tp->h[i + d][j] +
|
||
|
tp->h[i][j + d], delta);
|
||
|
}
|
||
|
|
||
|
tp->busyLoop = 0;
|
||
|
tp->i = 0;
|
||
|
tp->j = 0;
|
||
|
tp->d = d;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (tp->stage == tp->steps) {
|
||
|
#ifdef STANDALONE
|
||
|
erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
|
||
|
#endif
|
||
|
init_triangle(mi);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
release_triangle(ModeInfo * mi)
|
||
|
{
|
||
|
if (triangles != NULL) {
|
||
|
free(triangles);
|
||
|
triangles = (trianglestruct *) NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
refresh_triangle(ModeInfo * mi)
|
||
|
{
|
||
|
MI_CLEARWINDOW(mi);
|
||
|
}
|
||
|
|
||
|
#endif /* MODE_triangle */
|