po0o+@andrew.cmu.edu (Paul Andrew Olbrich) (04/03/91)
Try this!
-------
/*
glsperm.c
Drew Olbrich, February 1991
Compile with:
cc -O sperm.c -o sperm -lgl_s -lm
*/
#include <stdio.h>
#include <math.h>
#include "gl.h"
#include "device.h"
typedef double POINT[2];
typedef double VECTOR[2];
#define VEC_DOT(x, y) (x[0]*y[0] + x[1]*y[1])
#define VEC_LEN(x) (sqrt(x[0]*x[0] + x[1]*x[1]))
#define VEC_SET(x, a, b) x[0] = a, x[1] = b
#define VEC_COPY(y, x) y[0] = x[0], y[1] = x[1]
#define VEC_NEG(x) x[0] = -x[0], x[1] = -x[1]
#define VEC_ADD(z, x, y) z[0] = x[0] + y[0], z[1] = x[1] + y[1]
#define VEC_SUB(z, x, y) z[0] = x[0] - y[0], z[1] = x[1] - y[1]
#define VEC_MULT(x, a) x[0] *= a, x[1] *= a
#define VEC_DIV(x, a) x[0] /= a, x[1] /= a
#define VEC_ADDS(z, x, a, y) z[0] = x[0] + (a)*y[0], z[1] = x[1] + (a)*y[1]
#define VEC_NORM(x) { double l = VEC_LEN(x); VEC_DIV(x, l); }
#define COUNT 200
#define WIN_X 1280
#define WIN_Y 1024
typedef struct {
POINT x;
VECTOR v;
double sine, cosine;
double vel;
} SPERM;
SPERM sperm[COUNT];
double rad_scale = 3.5;
int index = 0;
double frand()
{
return (rand() % 16384)/16384.0;
}
init_display()
{
ginit();
prefsize(WIN_X, WIN_Y);
prefposition(0, WIN_X - 1, 0, WIN_Y - 1);
foreground();
winopen("sperm");
doublebuffer();
linewidth(3);
gconfig();
}
init_sperm()
{
int i;
double angle;
for (i = 0; i < COUNT; i++)
{
sperm[i].x[0] = frand()*WIN_X;
sperm[i].x[1] = frand()*WIN_Y;
VEC_SET(sperm[i].v, 0.0, 0.0);
angle = frand()*10.0 + 5.0;
sperm[i].sine = sin(angle*M_PI/180.0);
sperm[i].cosine = cos(angle*M_PI/180.0);
sperm[i].vel = frand()*4.0 + 4.0;
}
}
dynamics()
{
int i;
VECTOR w, old_w;
POINT p;
double r, dot, temp;
int org_x, org_y;
VECTOR origin, mouse;
int x1, y1, x2, y2;
VECTOR target;
getorigin(&org_x, &org_y);
VEC_SET(origin, (double) org_x, (double) org_y);
mouse[0] = getvaluator(MOUSEX);
mouse[1] = getvaluator(MOUSEY);
VEC_SUB(mouse, mouse, origin);
for (i = 0; i < COUNT; i++)
{
x1 = (int) sperm[i].x[0];
y1 = (int) sperm[i].x[1];
VEC_COPY(target, mouse);
VEC_SUB(w, sperm[i].x, target);
VEC_NORM(w);
VEC_COPY(old_w, w);
w[0] = old_w[0]*sperm[i].cosine - old_w[1]*sperm[i].sine;
w[1] = old_w[1]*sperm[i].cosine + old_w[0]*sperm[i].sine;
VEC_ADDS(p, target, rad_scale*(160.0 - sperm[i].vel*20.0), w);
VEC_SUB(w, p, sperm[i].x);
VEC_NORM(w);
VEC_ADDS(sperm[i].v, sperm[i].v, 1.0, w);
VEC_NORM(sperm[i].v);
VEC_MULT(sperm[i].v, sperm[i].vel);
VEC_ADD(sperm[i].x, sperm[i].x, sperm[i].v);
x2 = (int) sperm[i].x[0];
y2 = (int) sperm[i].x[1];
color(BLACK);
move2i(x1, y1);
draw2i(x2, y2);
}
}
main_loop()
{
while (!getbutton(RIGHTMOUSE))
{
color(WHITE);
clear();
dynamics();
swapbuffers();
}
}
main()
{
init_display();
init_sperm();
main_loop();
gexit();
}po0o+@andrew.cmu.edu (Paul Andrew Olbrich) (04/03/91)
Try this!
---------
/*
xsperm.c
Drew Olbrich, Febrary 1991
Compile with:
cc -o xsperm xsperm.c -lm -lX11
Note -- This code originally served as a demonstration
of how to do animation under X. The "guts" of the program
which draws the sperm are consequently located in one huge
chunk in the update_display() routine, and can be easily
cut out.
-----
This program demonstrates using X windows to poll mouse events
(movement and button clicks) and draw moving images on the
screen in real time.
To prevent flicker, new frames are created off-screen in a
frame buffer and then copied to the window.
The main functions are:
init_display() - initializes the X display
close_display() - close the display when we're done
update_display() - draw the next frame and display it
event_loop() - handle mouse events
The upper left corner of the window is coordinate (0, 0).
This demo will probably only work on a monochrome display.
Try clicking the buttons! (The right button kills the
program.)
*/
#include <stdio.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
typedef double POINT[2];
typedef double VECTOR[2];
#define VEC_DOT(x, y) (x[0]*y[0] + x[1]*y[1])
#define VEC_LEN(x) (sqrt(x[0]*x[0] + x[1]*x[1]))
#define VEC_SET(x, a, b) x[0] = a, x[1] = b
#define VEC_COPY(y, x) y[0] = x[0], y[1] = x[1]
#define VEC_NEG(x) x[0] = -x[0], x[1] = -x[1]
#define VEC_ADD(z, x, y) z[0] = x[0] + y[0], z[1] = x[1] + y[1]
#define VEC_SUB(z, x, y) z[0] = x[0] - y[0], z[1] = x[1] - y[1]
#define VEC_MULT(x, a) x[0] *= a, x[1] *= a
#define VEC_DIV(x, a) x[0] /= a, x[1] /= a
#define VEC_ADDS(z, x, a, y) z[0] = x[0] + (a)*y[0], z[1] = x[1] + (a)*y[1]
#define VEC_NORM(x) { double l = VEC_LEN(x); VEC_DIV(x, l); }
#define WIN_TITLE "xsperm"/* title to put on the window */
#define SCR_WIDTH 640 /* the size of my window */
#define SCR_HEIGHT 480
Display *dpy; /* a reference to my display */
Window win; /* a reference to my window */
GC gc_normal; /* used for drawing black on white */
GC gc_inverse; /* used for drawing white on black */
Pixmap buffer; /* the frame buffer */
POINT mouse; /* current mouse coordinates */
int pressed[3] = { 0, 0, 0 }; /* which buttons are currently being pressed */
#define BUTTON_LEFT 0 /* button definitions */
#define BUTTON_CENTER 1
#define BUTTON_RIGHT 2
/*
error() - generic error message handler
*/
error(message)
char *message;
{
fprintf(stderr, "xloop: %s\n", message);
exit(-1);
}
/*
init_display() - initialize the X display
*/
init_display()
{
int scn; /* a reference to the screen */
XSetWindowAttributes attr; /* storage for window attributes */
XGCValues gcvalues; /* storage for "graphics context" */
XSizeHints hints; /* storage for "window hints" */
dpy = XOpenDisplay(NULL); /* connect with the X window system */
if (dpy == NULL)
error("Could not open display.");
/* create the window */
scn = DefaultScreen(dpy);
win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
100, 100, SCR_WIDTH, SCR_HEIGHT,
1, BlackPixel(dpy, scn), WhitePixel(dpy, scn));
/* set up "window hints" so that we won't be allowed to
resize the window while it's running */
hints.flags = PSize | PMinSize | PMaxSize;
hints.width = hints.min_width = hints.max_width = SCR_WIDTH;
hints.height = hints.min_height = hints.max_height = SCR_HEIGHT;
XSetStandardProperties(dpy, win, WIN_TITLE, WIN_TITLE, None,
NULL, 0, &hints);
/* tell X which events we'd like to be aware of */
attr.event_mask = PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
XChangeWindowAttributes(dpy, win, CWEventMask, &attr);
/* draw the new window on the screen */
XMapWindow(dpy, win);
/* set up a "graphics context" for drawing black on white */
gcvalues.foreground = BlackPixel(dpy, scn);
gcvalues.background = WhitePixel(dpy, scn);
gc_normal = XCreateGC(dpy, win, GCForeground | GCBackground, &gcvalues);
/* set up a "graphics context" for drawing white on black */
gcvalues.foreground = WhitePixel(dpy, scn);
gcvalues.background = BlackPixel(dpy, scn);
gc_inverse = XCreateGC(dpy, win, GCForeground | GCBackground, &gcvalues);
/* create the frame buffer */
buffer = XCreatePixmap(dpy, win, SCR_WIDTH, SCR_HEIGHT,
DefaultDepth(dpy, scn));
if (buffer == NULL)
error("Can't create frame buffer.");
}
/*
close_display() - tell the X server that we're done
*/
close_display()
{
XFreePixmap(dpy, buffer); /* free the memory we used first */
XDestroyWindow(dpy, win); /* get rid of the window */
XCloseDisplay(dpy);
}
/*
dummy_predicate() - dummy event predicate
This function is used by 'XCheckIfEvent()' below to determine
which events we want to handle. However, we always want to
handle every event, so we will always return 1 (true).
*/
int dummy_predicate(display, event, arg)
Display *display;
XEvent *event;
char *arg;
{
return 1;
}
/*
update_display() - draw the next frame
The idea here is to clear the frame buffer, draw lines on it,
and then copy it to the screen.
If instead, we just cleared the screen and drew the lines there,
we'd get a lot of flicker. That would look pretty bad.
*/
update_display()
{
/* clear the frame buffer by drawing a white rectangle */
XFillRectangle(dpy, buffer, gc_inverse, 0, 0, SCR_WIDTH, SCR_HEIGHT);
/* draw stuff in the frame buffer */
/***********************************************************
This is just an icky hacked up example routine for
the sake of demonstration. You will want to delete
everything from here down to the next big comment.
However, note the use of 'XDrawLine()' down near
the bottom.
***********************************************************/
{
#define COUNT 300
int i, dx, dy;
static int init = 0;
static POINT x[COUNT];
static VECTOR v[COUNT];
static double sine[COUNT];
static double cosine[COUNT];
static double vel[COUNT];
int x1, y1, x2, y2;
static double rad = 1.0;
static double dir = 1.0;
if (!init)
{
init = 1;
for (i = 0; i < COUNT; i++)
{
double angle;
x[i][0] = (double) (random() % SCR_WIDTH);
x[i][1] = (double) (random() % SCR_HEIGHT);
v[i][0] = (double) (random() % 2000)/1000.0 - 1.0;
v[i][1] = (double) (random() % 2000)/1000.0 - 1.0;
angle = (random() % 1000)/1000.0*10.0 + 5.0;
sine[i] = sin(angle*M_PI/180.0);
cosine[i] = cos(angle*M_PI/180.0);
vel[i] = (random() % 1000)/1000.0*4.0 + 4.0;
VEC_NORM(v[i]);
}
}
if (pressed[BUTTON_LEFT])
{
rad = rad == 1.0 ? 3.0 : 1.0;
pressed[BUTTON_LEFT] = 0;
}
if (pressed[BUTTON_CENTER])
{
VECTOR y;
dir *= -1.0;
pressed[BUTTON_CENTER] = 0;
for (i = 0; i < COUNT; i++)
{
VEC_COPY(y, v[i]);
if (dir == -1.0)
{
v[i][0] = y[1];
v[i][1] = -y[0];
}
else
{
v[i][0] = -y[1];
v[i][1] = y[0];
}
}
}
for (i = 0; i < COUNT; i++)
{
x1 = (int) x[i][0]; /* old location */
y1 = (int) x[i][1];
{
VECTOR w, y;
POINT p;
double r, dot;
double temp;
VEC_SUB(w, x[i], mouse);
VEC_NORM(w);
VEC_COPY(y, w);
w[0] = y[0]*cosine[i] - dir*y[1]*sine[i];
w[1] = y[1]*cosine[i] + dir*y[0]*sine[i];
VEC_ADDS(p, mouse, rad*(160.0 - vel[i]*20.0), w);
VEC_SUB(w, p, x[i]);
r = VEC_LEN(w);
VEC_DIV(w, r);
VEC_ADDS(v[i], v[i], 1.0, w);
}
VEC_NORM(v[i]);
VEC_MULT(v[i], vel[i]);
VEC_ADD(x[i], x[i], v[i]);
x2 = (int) x[i][0]; /* new location */
y2 = (int) x[i][1];
XDrawLine(dpy, buffer, gc_normal, x1, y1, x2, y2);
}
}
/***********************************************************
End of icky example routine!
***********************************************************/
/* copy the finished frame buffer to the window */
XCopyArea(dpy, buffer, win, gc_normal, 0, 0, SCR_WIDTH, SCR_HEIGHT, 0, 0);
}
/*
event_loop() - handle mouse events
*/
event_loop()
{
int done = 0;
XEvent event;
while (!done)
{
update_display(); /* draw the next frame */
XSync(dpy, False); /* keep everything synchronized */
/* handle all events waiting in the event queue */
while (XCheckIfEvent(dpy, &event, dummy_predicate, ""))
switch (event.type) {
case MotionNotify : /* the mouse moved */
mouse[0] = event.xmotion.x;
mouse[1] = event.xmotion.y;
break;
case ButtonPress : /* a button was pressed down */
pressed[event.xbutton.button - 1] = 1;
break;
case ButtonRelease : /* a button was released */
pressed[event.xbutton.button - 1] = 0;
break;
}
if (pressed[BUTTON_RIGHT]) /* stop if the right button is pressed */
done = 1;
}
}
/*
main()
*/
main()
{
init_display();
event_loop();
close_display();
}will@rins.ryukoku.ac.jp (will) (04/03/91)
Compiled and ran with no prob. on my sparc, sun4, and mips computers. w/color. will.....