Skip to content

Instantly share code, notes, and snippets.

@dln
Created June 2, 2014 20:50
Show Gist options
  • Save dln/a19c2b9365ba816a5675 to your computer and use it in GitHub Desktop.
Save dln/a19c2b9365ba816a5675 to your computer and use it in GitHub Desktop.
Hack for xscreensaver I did a long time ago.
/* A screen saver hack to display the CodeFactory logotype
* in a jiggling fashion with a lil bit o bounce... *grin*
*
* Daniel Lundin <daniel@codefactory.se>
*
* Copyright 2001 Seven relatively short dudes and a pale chick
*
* This software is released under Disgruntled Catholic License v6.66
* Redistribution prohibited without authorization from the pope.
* Under special circumstances under which should such authorization
* request be denied or otherwise unable to achieve, redistribution may be
* authorized by the reader herself.
*
*/
#include <math.h>
#include "screenhack.h"
#define ABS(a) (((a)<0) ? -(a) : (a))
#define MIN(x,y) ((x)>(y)?(y):(x))
#define MAX(x,y) ((x)<(y)?(y):(x))
#define INT_MAX 2147483647
#define ROLL_ROT_SPEED 0.01
#define PITCH_ROT_SPEED 0.02
#define YAW_ROT_SPEED 0.01
char *progclass = "CFLogo";
char *defaults [] = {
"*ncolors: 256", /* number of colours used */
"*delay: 10",
0
};
XrmOptionDescRec options [] = {
{ "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
{ "-delay", ".delay", XrmoptionSepArg, 0 },
{ 0, 0, 0, 0 }
};
typedef struct {
double x,y,z; /* Coords */
double rx,ry,rz; /* Rotated float */
int px,py,pz; /* Projected coords */
} cfpoint;
typedef struct {
cfpoint *src; /* Source cfpoint */
cfpoint *dst; /* Destination cfpoint */
} cfline;
typedef struct {
int minx, miny; /* Upper left corner */
int maxx,maxy; /* Lower right corner */
} cfcliprect;
typedef struct {
cfpoint *points; /* Points */
cfline *lines; /* Lines */
uint numpts; /* Number of points */
uint numlines; /* Number of lines */
cfpoint pos; /* Object position in 3D space */
cfpoint dir; /* Delta movement */
cfpoint min; /* Bounding box corner */
cfpoint max; /* Other bounding box corner */
float roll,pitch,yaw; /* Rotation along all axes */
float roll_delta, /* Rotational speed */
pitch_delta,
yaw_delta;
cfcliprect clip; /* Box for XCopyArea blitting */
cfcliprect prev_clip; /* Last clip box (for clearing) */
} cfobject;
/* A simple cube */
static cfpoint obj[] = {
{-140, 140, -40, 0,0,0,0,0},
{-140, -140, -40, 0,0,0,0,0},
{-70, -140, -40, 0,0,0,0,0},
{-70, 30, -40, 0,0,0,0,0},
{ 0, -20, -40, 0,0,0,0,0},
{ 0, 30, -40, 0,0,0,0,0},
{ 70, -20, -40, 0,0,0,0,0},
{ 70, 30, -40, 0,0,0,0,0},
{ 140, -20, -40, 0,0,0,0,0},
{ 140, 140, -40, 0,0,0,0,0}, /* 9 */
{-140, 140, 40, 0,0,0,0,0},
{-140, -140, 40, 0,0,0,0,0},
{-70, -140, 40, 0,0,0,0,0},
{-70, 30, 40, 0,0,0,0,0},
{ 0, -20, 40, 0,0,0,0,0},
{ 0, 30, 40, 0,0,0,0,0},
{ 70, -20, 40, 0,0,0,0,0},
{ 70, 30, 40, 0,0,0,0,0},
{ 140, -20, 40, 0,0,0,0,0},
{ 140, 140, 40, 0,0,0,0,0} /* 9 */
};
/* Lines for the cube */
static cfline obj_lines[] = {
{&obj[0], &obj[1]},
{&obj[1], &obj[2]},
{&obj[2], &obj[3]},
{&obj[3], &obj[4]},
{&obj[4], &obj[5]},
{&obj[5], &obj[6]},
{&obj[6], &obj[7]},
{&obj[7], &obj[8]},
{&obj[8], &obj[9]},
{&obj[9], &obj[0]},
{&obj[10], &obj[11]},
{&obj[11], &obj[12]},
{&obj[12], &obj[13]},
{&obj[13], &obj[14]},
{&obj[14], &obj[15]},
{&obj[15], &obj[16]},
{&obj[16], &obj[17]},
{&obj[17], &obj[18]},
{&obj[18], &obj[19]},
{&obj[19], &obj[10]},
{&obj[10], &obj[0]},
{&obj[11], &obj[1]},
{&obj[12], &obj[2]},
{&obj[13], &obj[3]},
{&obj[14], &obj[4]},
{&obj[15], &obj[5]},
{&obj[16], &obj[6]},
{&obj[17], &obj[7]},
{&obj[18], &obj[8]},
{&obj[19], &obj[9]}
};
/* Logo object to toy around with */
static cfobject logo_object = {
obj,
obj_lines,
sizeof (obj) / sizeof (cfpoint),
sizeof (obj_lines) / sizeof (cfline),
{300, 200, 0}, /* Position */
{3.53, 2.35, 4}, /* Direction */
{15,15,-450}, {640,400,10}, /* Bounding box */
0, 0, 0, /* Rotation along all axes */
ROLL_ROT_SPEED, PITCH_ROT_SPEED, YAW_ROT_SPEED,
{INT_MAX,INT_MAX,0,0},
{INT_MAX,INT_MAX,0,0}
};
/* delay (usec) between iterations */
int delay=1;
uint numcolors;
Colormap cmap;
XColor* pal;
GC* gcs;
/* Rotate object and project it in 2D in rotatedPoints. */
void rotate_obj (cfobject *obj) {
float sinY, cosY, cosX, sinX, cosZ, sinZ;
float tmpY;
float distance;
cfpoint *point;
ulong i;
obj->roll += obj->roll_delta;
if (obj->roll > M_PI * 2)
obj->roll = obj->roll - M_PI * 2;
obj->pitch += obj->pitch_delta;
if (obj->pitch > M_PI * 2)
obj->pitch = obj->pitch - M_PI * 2;
obj->yaw += obj->yaw_delta;
if (obj->yaw > M_PI * 2)
obj->yaw = obj->yaw - M_PI * 2;
cosY = cos (obj->pitch);
sinY = sin (obj->pitch);
cosX = cos (obj->roll);
sinX = sin (obj->roll);
cosZ = cos (obj->yaw);
sinZ = sin (obj->yaw);
/* Move the object */
if (obj->pos.x > obj->max.x)
obj->dir.x = - ABS (obj->dir.x);
if (obj->pos.x < obj->min.x)
obj->dir.x = ABS (obj->dir.x);
if (obj->pos.y < obj->min.y )
obj->dir.y = ABS (obj->dir.y);
if (obj->pos.y > obj->max.y)
obj->dir.y = - ABS (obj->dir.y);
else
obj->dir.y += 0.9;
if (obj->pos.z > obj->max.z)
obj->dir.z = - ABS (obj->dir.z);
if (obj->pos.z < obj->min.z)
obj->dir.z = ABS (obj->dir.z);
obj->pos.x = obj->pos.x + obj->dir.x;
obj->pos.y = obj->pos.y + obj->dir.y;
obj->pos.z = obj->pos.z + obj->dir.z;
/* Store previous clipping area */
memcpy ( &(obj->prev_clip), &(obj->clip), sizeof (cfcliprect));
/* Reset clipping area */
obj->clip.maxx = 0;
obj->clip.minx = INT_MAX;
obj->clip.maxy = 0;
obj->clip.miny = INT_MAX;
for ( i = 0; i<obj->numpts; i++) {
point = &(obj->points[i]);
/* Rotate around Z axis */
point->rx = point->x*cosZ - point->y*sinZ;
point->ry = point->x*sinZ + point->y*cosZ;
/* Rotate around Y axis */
point->rz = point->rx*sinY + point->z*cosY;
point->rx = point->rx*cosY - point->z*sinY;
/* Rotate around X axis */
tmpY=point->ry; /* Store rotated Y coordinate */
point->ry = point->rz*sinX + tmpY*cosX;
point->rz = point->rz*cosX - tmpY*sinX;
/* Slimy-effect */
point->rx=point->rx * (1 - 0.04 * (ABS (obj->dir.y) / 12)
* cos ((1 - ABS (obj->dir.y) / 5) * M_PI * 2
- point->ry / 25));
point->ry=point->ry * (1 - 0.05 * (ABS (obj->dir.y) / 12)
* cos ((1 - ABS (obj->dir.y) / 5) * M_PI * 2
- point->ry / 25));
point->rz=point->rz * (1 - 0.02 * (ABS (obj->dir.y) / 12)
* cos ((1 - ABS (obj->dir.y) / 5) * M_PI * 2
- point->ry / 25));
/* Add (fake) perspective projection */
point->pz = point->rz + obj->pos.z;
distance = 250/(250-(float)(point->pz));
point->px = distance * point->rx + obj->pos.x;
point->py = distance * point->ry + obj->pos.y;
/* Adjust clip rect if point is outside */
if (point->px > obj->clip.maxx)
obj->clip.maxx = point->px;
if (point->py > obj->clip.maxy)
obj->clip.maxy = point->py;
if (point->px < obj->clip.minx)
obj->clip.minx = point->px;
if (point->py < obj->clip.miny)
obj->clip.miny = point->py;
}
}
#ifdef DEBUG
static float maxz,minz = 0;
#endif
/* Draw object. */
void draw_obj (cfobject *obj, Display *dpy, Drawable d) {
uint i,j;
cfline *line;
for (i=0; i<obj->numlines; i++)
{
line = &obj->lines[i];
j = numcolors * ((line->src->rz + 202)/410);
#ifdef DEBUG
if (minz > line->src->rz)
minz = line->src->rz;
if (maxz < line->src->rz)
maxz = line->src->rz;
#endif
if (j >= numcolors )
j = numcolors - 1;
if (j < 0 )
j = 0;
XDrawLine (dpy, d, gcs[j],
line->src->px, line->src->py,
line->dst->px, line->dst->py);
}
#ifdef DEBUG
printf ("%f,%f\n", minz, maxz);
#endif
}
cfobject *
split_object_lines (cfobject *src)
{
uint i,j,k;
cfobject *nobj;
nobj = malloc (sizeof (cfobject));
if (nobj != NULL)
{
/* Start with a copy of SRC */
memcpy (nobj, src, sizeof (cfobject));
if (nobj != NULL)
{
/* Calculate number of lines and points in subvidied object */
nobj->numlines = src->numlines * 2;
/* totalpts = totallines * ((1 << divs) - 1) + src->numpts; */
/* Be pessimistic and let the optimize_object clean up later */
nobj->numpts = nobj->numlines * 2;
nobj->points = malloc (sizeof (cfpoint) * nobj->numpts);
nobj->lines = malloc (sizeof (cfline) * nobj->numpts);
j = k = 0;
for (i=0; i<src->numlines; i++)
{
memcpy (&(nobj->points[j]), src->lines[i].src,
sizeof (cfpoint));
j++;
memcpy (&(nobj->points[j]), src->lines[i].dst,
sizeof (cfpoint));
j++;
nobj->points[j].x = (nobj->points[j-1].x
+ nobj->points[j-2].x) / 2;
nobj->points[j].y = (nobj->points[j-1].y
+ nobj->points[j-2].y) / 2;
nobj->points[j].z = (nobj->points[j-1].z
+ nobj->points[j-2].z) / 2;
j++;
nobj->lines[k].src = &(nobj->points[j-3]);
nobj->lines[k].dst = &(nobj->points[j-1]);
k++;
nobj->lines[k].src = &(nobj->points[j-2]);
nobj->lines[k].dst = &(nobj->points[j-1]);
k++;
}
}
}
return nobj;
}
cfobject *
subdivide_object (cfobject *src, uint divs)
{
uint i;
cfobject *result;
cfobject *tmp;
result = src;
for (i=0; i<divs; i++)
{
tmp = result;
result = split_object_lines (tmp);
if (tmp != src)
free (tmp);
}
return result;
}
void
screenhack (Display *dpy, Window window)
{
XGCValues gcv;
int delay = get_integer_resource ("delay", "Integer");
int i;
GC erase_gc = 0;
XWindowAttributes xgwa;
Pixmap b=0;
cfobject *theobject;
cfcliprect clipping;
theobject = subdivide_object (&logo_object, 5);
if ( theobject != NULL )
{
XGetWindowAttributes (dpy, window, &xgwa);
b = XCreatePixmap (dpy, window, xgwa.width,
xgwa.height, xgwa.depth);
gcv.foreground = get_pixel_resource ("background", "Background",
dpy, xgwa.colormap);
erase_gc = XCreateGC (dpy, b, GCForeground, &gcv);
/* Mix us some colors */
cmap = xgwa.colormap;
numcolors = get_integer_resource("ncolors", "Integer");
if(numcolors < 2)
numcolors = 2;
pal = calloc(numcolors, sizeof(XColor));
make_color_ramp(dpy, cmap,
200, 1, 0,
200, 0, 1,
pal, &(numcolors),
False, True, False);
gcs = calloc(numcolors, sizeof(GC));
gcv.line_width = 1;
for(i = 0; i < numcolors; i++) {
gcv.foreground =pal[i].pixel;
gcs[i] = XCreateGC(dpy, b, GCForeground|GCLineWidth, &gcv);
}
theobject->min.x = 15;
theobject->min.y = 15;
theobject->min.z = -350;
theobject->max.x = xgwa.width-15;
theobject->max.y = xgwa.height-15;
theobject->max.z = 30;
theobject->pos.x = xgwa.width/2;
theobject->pos.y = xgwa.height - 400;
theobject->pos.z = 0;
while (1)
{
XFillRectangle (dpy, b, erase_gc, 0, 0, xgwa.width, xgwa.height);
rotate_obj (theobject);
draw_obj (theobject, dpy, b);
clipping.minx = MIN(theobject->clip.minx,
theobject->prev_clip.minx) - 4 ;
clipping.miny = MIN(theobject->clip.miny,
theobject->prev_clip.miny) - 4;
clipping.maxx = MAX(theobject->clip.maxx,
theobject->prev_clip.maxx) + 4;
clipping.maxy = MAX(theobject->clip.maxy,
theobject->prev_clip.maxy) + 4;
XCopyArea (dpy, b, window, erase_gc,
clipping.minx,
clipping.miny,
clipping.maxx - clipping.minx,
clipping.maxy - clipping.miny,
clipping.minx,
clipping.miny);
XSync (dpy, False);
screenhack_handle_events (dpy);
if (delay)
usleep (delay);
}
free (theobject);
free (pal);
free (gcs);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment