/*
* Ported to Plan 9 from XScreensaver by mirtchov@cpsc.ucalgary.ca, 10/03
*
* modified with extra glendas: 11/03
*/
/* plan9-related stuff */
#include "plan9.h"
Image *glenda;
Image *mask;
ulong frames = 0;
vlong tbegin, tend;
#define POINT_COUNT 16
#define LINE_COUNT 32
#define ANGLE_SCALE 0.001
struct line_info
{
char li_ip;
char li_iq;
char li_color;
char li_pad;
};
struct point_state
{
short old_x, old_y;
short new_x, new_y;
};
struct hyper_state
{
char hs_stop;
char hs_icon;
char hs_resize;
char hs_redraw;
float hs_two_observer_z;
float hs_offset_x;
float hs_offset_y;
float hs_unit_scale;
int hs_delay;
double hs_cos_xy, hs_sin_xy;
double hs_cos_xz, hs_sin_xz;
double hs_cos_yz, hs_sin_yz;
double hs_cos_xw, hs_sin_xw;
double hs_cos_yw, hs_sin_yw;
double hs_cos_zw, hs_sin_zw;
double hs_ref_ax, hs_ref_ay, hs_ref_az, hs_ref_aw;
double hs_ref_bx, hs_ref_by, hs_ref_bz, hs_ref_bw;
double hs_ref_cx, hs_ref_cy, hs_ref_cz, hs_ref_cw;
double hs_ref_dx, hs_ref_dy, hs_ref_dz, hs_ref_dw;
struct point_state hs_points[POINT_COUNT];
};
static const struct line_info line_table[LINE_COUNT];
static void init (struct hyper_state *hs);
static void hyper (struct hyper_state *hs);
static void check_events (struct hyper_state *hs);
static void set_sizes (struct hyper_state *hs, int width, int height);
static struct hyper_state hyper_state;
void
screenhack (void)
{
struct hyper_state *hs;
hs = &hyper_state;
init (hs);
hyper (hs);
}
static void
init (struct hyper_state *hs)
{
int delay, width, height;
float observer_z;
observer_z = frand()*5.0;
if (observer_z < 1.125)
observer_z = 1.125;
hs->hs_two_observer_z = 2.0 * observer_z;
width = Dx(screen->r);
height = Dy(screen->r);
set_sizes (hs, width, height);
delay = 10;
hs->hs_delay = delay;
hs->hs_ref_ax = 1.0, hs->hs_ref_ay = 0.0, hs->hs_ref_az = 0.0, hs->hs_ref_aw = 0.0;
hs->hs_ref_bx = 0.0, hs->hs_ref_by = 1.0, hs->hs_ref_bz = 0.0, hs->hs_ref_bw = 0.0;
hs->hs_ref_cx = 0.0, hs->hs_ref_cy = 0.0, hs->hs_ref_cz = 1.0, hs->hs_ref_cw = 0.0;
hs->hs_ref_dx = 0.0, hs->hs_ref_dy = 0.0, hs->hs_ref_dz = 0.0, hs->hs_ref_dw = 1.0;
{
double xy;
double xz;
double yz;
double xw;
double yw;
double zw;
double cos_xy, sin_xy;
double cos_xz, sin_xz;
double cos_yz, sin_yz;
double cos_xw, sin_xw;
double cos_yw, sin_yw;
double cos_zw, sin_zw;
/* xy = 3 * ANGLE_SCALE;
xz = 5 * ANGLE_SCALE;
yz = 0 * ANGLE_SCALE;
xw = 0 * ANGLE_SCALE;
yw = 10 * ANGLE_SCALE;
zw = 0 * ANGLE_SCALE;
*/
xy = (nrand(3)+2) * ANGLE_SCALE;
xz = (nrand(7)+2) * ANGLE_SCALE;
yz = nrand(3) * ANGLE_SCALE;
xw = nrand(5) * ANGLE_SCALE;
yw = (nrand(10)+5) * ANGLE_SCALE;
zw = nrand(3) * ANGLE_SCALE;
cos_xy = cos (xy), sin_xy = sin (xy);
hs->hs_cos_xy = cos_xy, hs->hs_sin_xy = sin_xy;
cos_xz = cos (xz), sin_xz = sin (xz);
hs->hs_cos_xz = cos_xz, hs->hs_sin_xz = sin_xz;
cos_yz = cos (yz), sin_yz = sin (yz);
hs->hs_cos_yz = cos_yz, hs->hs_sin_yz = sin_yz;
cos_xw = cos (xw), sin_xw = sin (xw);
hs->hs_cos_xw = cos_xw, hs->hs_sin_xw = sin_xw;
cos_yw = cos (yw), sin_yw = sin (yw);
hs->hs_cos_yw = cos_yw, hs->hs_sin_yw = sin_yw;
cos_zw = cos (zw), sin_zw = sin (zw);
hs->hs_cos_zw = cos_zw, hs->hs_sin_zw = sin_zw;
}
}
static void
hyper (struct hyper_state *hs)
{
int roted;
roted = 0;
tbegin = nsec();
for (;;)
{
int icon;
int resize;
char moved[POINT_COUNT];
int redraw = 0;
int stop;
int delay;
check_events (hs);
icon = hs->hs_icon;
resize = hs->hs_resize;
if (icon || !(roted | resize))
goto skip1;
{
float observer_z;
float unit_scale;
float offset_x;
float offset_y;
double az, bz, cz, dz;
double sum_z;
double ax, bx, cx, dx;
double sum_x;
double ay, by, cy, dy;
double sum_y;
struct point_state *ps;
int old_x;
int old_y;
double mul;
double xf;
double yf;
int new_x;
int new_y;
int mov;
#define compute(as,bs,cs,ds,i) \
az = hs->hs_ref_az; bz = hs->hs_ref_bz; cz = hs->hs_ref_cz; dz = hs->hs_ref_dz; \
ax = hs->hs_ref_ax; bx = hs->hs_ref_bx; cx = hs->hs_ref_cx; dx = hs->hs_ref_dx; \
ay = hs->hs_ref_ay; by = hs->hs_ref_by; cy = hs->hs_ref_cy; dy = hs->hs_ref_dy; \
sum_z = as az bs bz cs cz ds dz; \
observer_z = hs->hs_two_observer_z; \
unit_scale = hs->hs_unit_scale; \
sum_x = as ax bs bx cs cx ds dx; \
sum_y = as ay bs by cs cy ds dy; \
ps = &hs->hs_points[i]; \
mul = unit_scale / (observer_z - sum_z); \
offset_x = hs->hs_offset_x; \
offset_y = hs->hs_offset_y; \
old_x = ps->new_x; \
old_y = ps->new_y; \
xf = sum_x * mul + offset_x; \
yf = sum_y * mul + offset_y; \
new_x = (int)(xf+0.5); \
new_y = (int)(yf+0.5); \
ps->old_x = old_x; \
ps->old_y = old_y; \
ps->new_x = new_x; \
ps->new_y = new_y; \
mov = old_x != new_x || old_y != new_y; \
moved[i] = mov;
compute (-, -, -, -, 0);
compute (-, -, -, +, 1);
compute (-, -, +, -, 2);
compute (-, -, +, +, 3);
compute (-, +, -, -, 4);
compute (-, +, -, +, 5);
compute (-, +, +, -, 6);
compute (-, +, +, +, 7);
compute (+, -, -, -, 8);
compute (+, -, -, +, 9);
compute (+, -, +, -, 10);
compute (+, -, +, +, 11);
compute (+, +, -, -, 12);
compute (+, +, -, +, 13);
compute (+, +, +, -, 14);
compute (+, +, +, +, 15);
}
skip1:
icon = hs->hs_icon;
if (icon || !(roted | redraw))
goto skip2;
{
int i, p_x, p_y;
for (i = 0; i < POINT_COUNT; i++) {
p_x = hs->hs_points[i].old_x;
p_y = hs->hs_points[i].old_y;
if(p_x == 0 && p_y == 0)
continue;
draw(screen,
rectaddpt(Rect(p_x-24, p_y-24, p_x+24, p_y+24), screen->r.min),
colors[i], mask, ZP);
p_x = hs->hs_points[i].new_x;
p_y = hs->hs_points[i].new_y;
draw(screen,
rectaddpt(Rect(p_x-24, p_y-24, p_x+24, p_y+24), screen->r.min),
glenda, mask, ZP);
}
flushimage(display, 1);
}
skip2:
stop = hs->hs_stop;
roted = 0;
if (stop)
goto skip3;
roted = 1;
{
double cos_a;
double sin_a;
double old_u;
double old_v;
double new_u;
double new_v;
/* If you get error messages about the following forms, and you think you're
using an ANSI C conforming compiler, then you're mistaken. Possibly you're
mixing an ANSI compiler with a non-ANSI preprocessor, or vice versa.
Regardless, your system is broken; it's not a bug in this program.
*/
#define rotate(name,dim0,dim1) \
old_u = hs->hs_ref_/**/name/**/dim0; \
old_v = hs->hs_ref_/**/name/**/dim1; \
new_u = old_u * cos_a + old_v * sin_a; \
new_v = old_v * cos_a - old_u * sin_a; \
hs->hs_ref_/**/name/**/dim0 = new_u; \
hs->hs_ref_/**/name/**/dim1 = new_v;
#define rotates(dim0,dim1) \
if (hs->hs_sin_/**/dim0/**/dim1 != 0) { \
cos_a = hs->hs_cos_/**/dim0/**/dim1; \
sin_a = hs->hs_sin_/**/dim0/**/dim1; \
rotate(a,dim0,dim1); \
rotate(b,dim0,dim1); \
rotate(c,dim0,dim1); \
rotate(d,dim0,dim1); \
}
rotates (x,y);
rotates (x,z);
rotates (y,z);
rotates (x,w);
rotates (y,w);
rotates (z,w);
}
skip3:
/* stop = hs->hs_stop; */
delay = hs->hs_delay;
if (stop && delay < 10)
delay = 10;
frames++;
if (delay > 0)
sleep (delay);
}
}
static void
check_events (struct hyper_state *hs)
{
hs->hs_resize = 0;
hs->hs_redraw = 0;
if(ecanmouse()) {
m = emouse();
if(m.buttons&4)
if(emenuhit(3, &m, &menu) == 0) {
tend = nsec();
print("fps: %uf\n", frames/((tend - tbegin)/1000000000.0));
exits(0);
}
if(m.buttons&1)
hs->hs_stop = hs->hs_stop ? 0 : 1;
if(m.buttons&2)
draw(screen, screen->r, display->black, nil, ZP);
}
}
static void
set_sizes (struct hyper_state *hs, int width, int height)
{
double observer_z;
int min_dim;
double var;
double offset_x;
double offset_y;
double unit_scale;
observer_z = 0.5 * hs->hs_two_observer_z;
min_dim = width < height ? width : height;
var = sqrt(observer_z * observer_z - 1.0);
offset_x = 0.5 * (double)(width - 1);
offset_y = 0.5 * (double)(height - 1);
unit_scale = 0.4 * min_dim * var;
hs->hs_offset_x = (float)offset_x;
hs->hs_offset_y = (float)offset_y;
hs->hs_unit_scale = (float)unit_scale;
}
/* data */
static const struct line_info line_table[LINE_COUNT] =
{
{ 0, 1, 0, },
{ 0, 2, 0, },
{ 1, 3, 0, },
{ 2, 3, 0, },
{ 4, 5, 1, },
{ 4, 6, 1, },
{ 5, 7, 1, },
{ 6, 7, 1, },
{ 0, 4, 4, },
{ 0, 8, 4, },
{ 4, 12, 4, },
{ 8, 12, 4, },
{ 1, 5, 5, },
{ 1, 9, 5, },
{ 5, 13, 5, },
{ 9, 13, 5, },
{ 2, 6, 6, },
{ 2, 10, 6, },
{ 6, 14, 6, },
{ 10, 14, 6, },
{ 3, 7, 7, },
{ 3, 11, 7, },
{ 7, 15, 7, },
{ 11, 15, 7, },
{ 8, 9, 2, },
{ 8, 10, 2, },
{ 9, 11, 2, },
{ 10, 11, 2, },
{ 12, 13, 3, },
{ 12, 14, 3, },
{ 13, 15, 3, },
{ 14, 15, 3, },
};
void
eresized(int new)
{
if(new && getwindow(display, Refnone) < 0) {
sysfatal("can't reattach to window");
}
set_sizes (&hyper_state, Dx(screen->r), Dy(screen->r));
hyper_state.hs_resize = 1;
draw(screen, screen->r, display->black, nil, ZP);
}
void
main(int argc, char **argv)
{
int i, fd;
USED(argc, argv);
srand(time(0)*getpid());
if(initdraw(nil, nil, "glenda") < 0)
sysfatal("initdraw failed: %r");
for(i = 0; i < POINT_COUNT; i++) {
colors[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1,
cmap2rgba(nrand(128)+64));
}
einit(Emouse);
// eresized(0);
fd = open("/lib/face/48x48x4/g/glenda.1", OREAD);
if(fd < 0)
sysfatal("cannot open /lib/face/48x48x4/g/glenda.1: %r");
glenda = readimage(display, fd, 0);
if(glenda == nil)
sysfatal("cannot load glenda's image: %r");
close(fd);
mask = allocimage(display, Rect(0, 0, 48, 48), glenda->chan, 1, DCyan);
if(mask == nil)
sysfatal("cannot allocate mask: %r");
draw(mask, mask->r, display->white, nil, ZP);
gendraw(mask, mask->r, display->black, ZP, glenda, glenda->r.min);
freeimage(glenda);
glenda = display->white;
draw(screen, screen->r, display->black, nil, ZP);
screenhack();
}
|