baseobj = main.obj
-demoobj = demo.obj screen.obj tunnel.obj
-sysobj = gfx.obj vbe.obj dpmi.obj timer.obj keyb.obj logger.obj
+demoobj = demo.obj screen.obj tunnel.obj fract.obj gfxutil.obj
+sysobj = gfx.obj vbe.obj dpmi.obj timer.obj keyb.obj mouse.obj logger.obj
obj = $(baseobj) $(demoobj) $(sysobj)
bin = demo.exe
int fb_bpp = 16;
void *fb_pixels;
unsigned long time_msec;
+int mouse_x, mouse_y;
+unsigned int mouse_bmask;
static unsigned long nframes;
+static const char *start_scr_name = "tunnel";
int demo_init(int argc, char **argv)
{
+ if(argv[1]) {
+ start_scr_name = argv[1];
+ }
+
if(scr_init() == -1) {
return -1;
}
- scr_change(scr_lookup("tunnel"), 4000);
+ if(scr_change(scr_lookup(start_scr_name), 4000) == -1) {
+ fprintf(stderr, "screen %s not found\n", start_scr_name);
+ return -1;
+ }
/* clear the framebuffer at least once */
memset(fb_pixels, 0, fb_width * fb_height * fb_bpp / CHAR_BIT);
extern int fb_width, fb_height, fb_bpp;
extern void *fb_pixels;
extern unsigned long time_msec;
+extern int mouse_x, mouse_y;
+extern unsigned int mouse_bmask;
int demo_init(int argc, char **argv);
void demo_cleanup(void);
#include <stdio.h>
+#include <limits.h>
#include "demo.h"
#include "keyb.h"
#include "timer.h"
int main(int argc, char **argv)
{
+ void *vmem;
+ long fbsize = fb_width * fb_height * fb_bpp / CHAR_BIT;
+
init_timer(100);
kb_init(32);
- if(!(fb_pixels = set_video_mode(fb_width, fb_height, fb_bpp))) {
+ if(!(fb_pixels = malloc(fbsize))) {
+ fprintf(stderr, "failed to allocate backbuffer\n");
+ return 1;
+ }
+
+ if(!(vmem = set_video_mode(fb_width, fb_height, fb_bpp))) {
return 1;
}
}
if(quit) goto break_evloop;
- /*wait_vsync();*/
+ mouse_bmask = read_mouse(&mouse_x, &mouse_y);
+
time_msec = get_msec();
demo_draw();
+
+ /*wait_vsync();*/
+ memcpy(vmem, fb_pixels, fbsize);
}
break_evloop:
--- /dev/null
+#include "mouse.h"
+
+typedef unsigned short uint16_t;
+
+#define INTR 0x33
+
+#define QUERY 0
+#define SHOW 1
+#define HIDE 2
+#define READ 3
+#define WRITE 4
+#define PIXRATE 0xf
+
+#define XLIM 7
+#define YLIM 8
+
+int have_mouse(void)
+{
+ uint16_t res = 0;
+ _asm {
+ mov eax, QUERY
+ int INTR
+ mov res, ax
+ }
+ return res;
+}
+
+void show_mouse(int show)
+{
+ uint16_t cmd = show ? SHOW : HIDE;
+ _asm {
+ mov ax, cmd
+ int INTR
+ }
+}
+
+int read_mouse(int *xp, int *yp)
+{
+ uint16_t x, y, state;
+ _asm {
+ mov eax, READ
+ int INTR
+ mov state, bx
+ mov x, cx
+ mov y, dx
+ }
+
+ if(xp) *xp = x;
+ if(yp) *yp = y;
+ return state;
+}
+
+void set_mouse(int x, int y)
+{
+ _asm {
+ mov eax, WRITE
+ mov ecx, x
+ mov edx, y
+ int INTR
+ }
+}
+
+void set_mouse_limits(int xmin, int ymin, int xmax, int ymax)
+{
+ _asm {
+ mov eax, XLIM
+ mov ecx, xmin
+ mov edx, xmax
+ int INTR
+ mov eax, YLIM
+ mov ecx, ymin
+ mov edx, ymax
+ int INTR
+ }
+}
+
+void set_mouse_rate(int xrate, int yrate)
+{
+ _asm {
+ mov ax, PIXRATE
+ mov ecx, xrate
+ mov edx, yrate
+ int INTR
+ }
+}
+
+void set_mouse_mode(enum mouse_mode mode)
+{
+ if(mode == MOUSE_GFX) {
+ set_mouse_rate(1, 1);
+ } else {
+ set_mouse_rate(8, 16);
+ }
+}
--- /dev/null
+#ifndef MOUSE_H_
+#define MOUSE_H_
+
+enum {
+ MOUSE_LEFT = 1,
+ MOUSE_RIGHT = 2,
+ MOUSE_MIDDLE = 4
+};
+
+enum mouse_mode {
+ MOUSE_GFX,
+ MOUSE_TEXT
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int have_mouse(void);
+void show_mouse(int show);
+int read_mouse(int *xp, int *yp);
+void set_mouse(int x, int y);
+void set_mouse_limits(int xmin, int ymin, int xmax, int ymax);
+void set_mouse_rate(int xrate, int yrate);
+void set_mouse_mode(enum mouse_mode mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MOUSE_H_ */
--- /dev/null
+#include <string.h>
+#include <limits.h>
+#include "demo.h"
+#include "screen.h"
+#include "gfxutil.h"
+
+struct vec2x {
+ long x, y;
+};
+
+static int init(void);
+static void destroy(void);
+static void draw(void);
+static int julia(long x, long y, long cx, long cy, int max_iter);
+static int calc_walk(struct vec2x *path, long x, long y, int max_steps);
+
+static struct screen scr = {
+ "fract",
+ init,
+ destroy,
+ 0, 0,
+ draw
+};
+
+static long aspect_24x8 = (long)(1.3333333 * 256.0);
+static long xscale_24x8 = (long)(1.3333333 * 1.2 * 256.0);
+static long yscale_24x8 = (long)(1.2 * 256.0);
+static int cx, cy;
+static int max_iter = 50;
+
+#define WALK_SIZE 20
+
+struct screen *fract_screen(void)
+{
+ return &scr;
+}
+
+static int init(void)
+{
+ return 0;
+}
+
+static void destroy(void)
+{
+}
+
+#define PACK_RGB16(r, g, b) \
+ (((((r) >> 3) & 0x1f) << 11) | ((((g) >> 2) & 0x3f) << 5) | (((b) >> 3) & 0x1f))
+
+static void draw(void)
+{
+ int i, j, len, x, y;
+ unsigned short *pixels = fb_pixels;
+ struct vec2x walkpos[WALK_SIZE];
+
+ cx = mouse_x;
+ cy = mouse_y;
+
+ for(i=0; i<fb_height; i++) {
+ for(j=0; j<fb_width; j++) {
+ unsigned char pidx = julia(j, i, cx, cy, max_iter) & 0xff;
+ *pixels++ = (pidx >> 3) | ((pidx >> 2) << 5) | ((pidx >> 3) << 11);
+ }
+ }
+
+ pixels = fb_pixels;
+
+ if((len = calc_walk(walkpos, mouse_x, mouse_y, WALK_SIZE))) {
+ x = walkpos[0].x >> 16;
+ y = walkpos[0].y >> 16;
+
+ for(i=1; i<len; i++) {
+ int x0 = x;
+ int y0 = y;
+ int x1 = walkpos[i].x >> 16;
+ int y1 = walkpos[i].y >> 16;
+
+ if(clip_line(&x0, &y0, &x1, &y1, 0, 0, fb_width - 1, fb_height - 1)) {
+ draw_line(x0, y0, x1, y1, PACK_RGB16(32, 128, 255));
+ }
+ x = x1;
+ y = y1;
+ }
+ }
+
+ pixels[mouse_y * fb_width + mouse_x] = 0xffe;
+}
+
+static long normalize_coord(long x, long range)
+{
+ /* 2 * x / range - 1*/
+ return (x << 17) / range - 65536;
+}
+
+static long device_coord(long x, long range)
+{
+ /* (x + 1) / 2 * (range - 1) */
+ return ((x + 65536) >> 1) * (range - 1);
+}
+
+static int julia(long x, long y, long cx, long cy, int max_iter)
+{
+ int i;
+
+ /* convert to fixed point roughly [-1, 1] */
+ x = (normalize_coord(x, fb_width) >> 8) * xscale_24x8;
+ y = (normalize_coord(y, fb_height) >> 8) * yscale_24x8;
+ cx = (normalize_coord(cx, fb_width) >> 8) * xscale_24x8;
+ cy = (normalize_coord(cy, fb_height) >> 8) * yscale_24x8;
+
+ for(i=0; i<max_iter; i++) {
+ /* z_n = z_{n-1}**2 + c */
+ long px = x >> 8;
+ long py = y >> 8;
+
+ if(px * px + py * py > (4 << 16)) {
+ break;
+ }
+ x = px * px - py * py + cx;
+ y = (px * py << 1) + cy;
+ }
+
+ return i < max_iter ? (256 * i / max_iter) : 0;
+}
+
+static int calc_walk(struct vec2x *path, long x, long y, int max_steps)
+{
+ int i;
+ long cx, cy;
+
+ /* convert to fixed point roughly [-1, 1] */
+ x = cx = (normalize_coord(x, fb_width) >> 8) * xscale_24x8;
+ y = cy = (normalize_coord(y, fb_height) >> 8) * yscale_24x8;
+
+ for(i=0; i<max_steps; i++) {
+ /* z_n = z_{n-1}**2 + c */
+ long px = x >> 8;
+ long py = y >> 8;
+
+ path[i].x = device_coord((x << 8) / xscale_24x8, fb_width);
+ path[i].y = device_coord((y << 8) / yscale_24x8, fb_height);
+
+ if(px * px + py * py > (4 << 16)) {
+ break;
+ }
+ x = px * px - py * py + cx;
+ y = (px * py << 1) + cy;
+ }
+
+ return i;
+}
--- /dev/null
+#include "gfxutil.h"
+#include "demo.h"
+
+enum {
+ IN = 0,
+ LEFT = 1,
+ RIGHT = 2,
+ TOP = 4,
+ BOTTOM = 8
+};
+
+static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax)
+{
+ int code = 0;
+
+ if(x < xmin) {
+ code |= LEFT;
+ } else if(x > xmax) {
+ code |= RIGHT;
+ }
+ if(y < ymin) {
+ code |= TOP;
+ } else if(y > ymax) {
+ code |= BOTTOM;
+ }
+ return code;
+}
+
+#define FIXMUL(a, b) (((a) * (b)) >> 8)
+#define FIXDIV(a, b) (((a) << 8) / (b))
+
+#define LERP(a, b, t) ((a) + FIXMUL((b) - (a), (t)))
+
+int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax)
+{
+ int oc_out;
+
+ int oc0 = outcode(*x0, *y0, xmin, ymin, xmax, ymax);
+ int oc1 = outcode(*x1, *y1, xmin, ymin, xmax, ymax);
+
+ long fx0, fy0, fx1, fy1, fxmin, fymin, fxmax, fymax;
+
+ if(!(oc0 | oc1)) return 1; /* both points are inside */
+
+ fx0 = *x0 << 8;
+ fy0 = *y0 << 8;
+ fx1 = *x1 << 8;
+ fy1 = *y1 << 8;
+ fxmin = xmin << 8;
+ fymin = ymin << 8;
+ fxmax = xmax << 8;
+ fymax = ymax << 8;
+
+ for(;;) {
+ long x, y, t;
+
+ if(oc0 & oc1) return 0; /* both have points with the same outbit, not visible */
+ if(!(oc0 | oc1)) break; /* both points are inside */
+
+ oc_out = oc0 ? oc0 : oc1;
+
+ if(oc_out & TOP) {
+ t = FIXDIV(fymin - fy0, fy1 - fy0);
+ x = LERP(fx0, fx1, t);
+ y = fymin;
+ } else if(oc_out & BOTTOM) {
+ t = FIXDIV(fymax - fy0, fy1 - fy0);
+ x = LERP(fx0, fx1, t);
+ y = fymax;
+ } else if(oc_out & LEFT) {
+ t = FIXDIV(fxmin - fx0, fx1 - fx0);
+ x = fxmin;
+ y = LERP(fy0, fy1, t);
+ } else if(oc_out & RIGHT) {
+ t = FIXDIV(fxmax - fx0, fx1 - fx0);
+ x = fxmax;
+ y = LERP(fy0, fy1, t);
+ }
+
+ if(oc_out == oc0) {
+ fx0 = x;
+ fy0 = y;
+ oc0 = outcode(fx0 >> 8, fy0 >> 8, xmin, ymin, xmax, ymax);
+ } else {
+ fx1 = x;
+ fy1 = y;
+ oc1 = outcode(fx1 >> 8, fy1 >> 8, xmin, ymin, xmax, ymax);
+ }
+ }
+
+ *x0 = fx0 >> 8;
+ *y0 = fy0 >> 8;
+ *x1 = fx1 >> 8;
+ *y1 = fy1 >> 8;
+ return 1;
+}
+
+void draw_line(int x0, int y0, int x1, int y1, unsigned short color)
+{
+ int i, dx, dy, x_inc, y_inc, error;
+ unsigned short *fb = fb_pixels;
+
+ fb += y0 * fb_width + x0;
+
+ dx = x1 - x0;
+ dy = y1 - y0;
+
+ if(dx >= 0) {
+ x_inc = 1;
+ } else {
+ x_inc = -1;
+ dx = -dx;
+ }
+ if(dy >= 0) {
+ y_inc = fb_width;
+ } else {
+ y_inc = -fb_width;
+ dy = -dy;
+ }
+
+ if(dx > dy) {
+ error = dy * 2 - dx;
+ for(i=0; i<=dx; i++) {
+ *fb = color;
+ if(error >= 0) {
+ error -= dx * 2;
+ fb += y_inc;
+ }
+ error += dy * 2;
+ fb += x_inc;
+ }
+ } else {
+ error = dx * 2 - dy;
+ for(i=0; i<=dy; i++) {
+ *fb = color;
+ if(error >= 0) {
+ error -= dy * 2;
+ fb += x_inc;
+ }
+ error += dx * 2;
+ fb += y_inc;
+ }
+ }
+}
--- /dev/null
+#ifndef GFXUTIL_H_
+#define GFXUTIL_H_
+
+int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax);
+void draw_line(int x0, int y0, int x1, int y1, unsigned short color);
+
+#endif /* GFXUTIL_H_ */
#include "demo.h"
struct screen *tunnel_screen(void);
+struct screen *fract_screen(void);
-#define NUM_SCR 1
+#define NUM_SCR 32
static struct screen *scr[NUM_SCR];
static struct screen *cur, *prev, *next;
int scr_init(void)
{
- int i;
+ int i, idx = 0;
- if(!(scr[0] = tunnel_screen())) {
+ if(!(scr[idx++] = tunnel_screen())) {
+ return -1;
+ }
+ if(!(scr[idx++] = fract_screen())) {
return -1;
}
for(i=0; i<NUM_SCR; i++) {
- if(scr[i]->init() == -1) {
+ if(scr[i] && scr[i]->init() == -1) {
return -1;
}
}
{
int i;
for(i=0; i<NUM_SCR; i++) {
+ if(!scr[i]) break;
scr[i]->shutdown();
}
}
if(prev) { /* we're in the middle of a transition */
long interval = time_msec - trans_start;
if(interval >= trans_dur) {
- next->start(trans_dur);
+ if(next->start) {
+ next->start(trans_dur);
+ }
prev = 0;
cur = next;
next = 0;
{
int i;
for(i=0; i<NUM_SCR; i++) {
+ if(!scr[i]) break;
if(strcmp(scr[i]->name, name) == 0) {
return scr[i];
}
}
if(cur) {
- cur->stop(trans_dur);
+ if(cur->stop) {
+ cur->stop(trans_dur);
+ }
prev = cur;
next = s;
} else {
- s->start(trans_dur);
+ if(s->start) {
+ s->start(trans_dur);
+ }
cur = s;
prev = 0;
demo_keyboard(ev->key.keysym.sym, ev->key.state == SDL_PRESSED ? 1 : 0);
break;
+ case SDL_MOUSEMOTION:
+ mouse_x = ev->motion.x / fbscale;
+ mouse_y = ev->motion.y / fbscale;
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ mouse_bmask |= 1 << ev->button.button;
+ if(0) {
+ case SDL_MOUSEBUTTONUP:
+ mouse_bmask &= ~(1 << ev->button.button);
+ }
+ mouse_x = ev->button.x / fbscale;
+ mouse_y = ev->button.y / fbscale;
+ break;
+
default:
break;
}