From 757e7697c9a4434df6f3fdf3234de504bb4636bc Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 29 Aug 2016 05:14:35 +0300 Subject: [PATCH] fractal effect is cooking --- Makefile | 4 +- src/demo.c | 12 ++++- src/demo.h | 2 + src/dos/main.c | 17 ++++++- src/dos/mouse.c | 94 ++++++++++++++++++++++++++++++++++ src/dos/mouse.h | 31 ++++++++++++ src/fract.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/gfxutil.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/gfxutil.h | 7 +++ src/screen.c | 26 +++++++--- src/sdl/main.c | 15 ++++++ 11 files changed, 491 insertions(+), 12 deletions(-) create mode 100644 src/dos/mouse.c create mode 100644 src/dos/mouse.h create mode 100644 src/fract.c create mode 100644 src/gfxutil.c create mode 100644 src/gfxutil.h diff --git a/Makefile b/Makefile index 1044346..75dba8d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ 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 diff --git a/src/demo.c b/src/demo.c index fe0c2c4..98f8001 100644 --- a/src/demo.c +++ b/src/demo.c @@ -11,15 +11,25 @@ int fb_height = 240; 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; + } return 0; } diff --git a/src/demo.h b/src/demo.h index a022275..530e3de 100644 --- a/src/demo.h +++ b/src/demo.h @@ -4,6 +4,8 @@ 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); diff --git a/src/dos/main.c b/src/dos/main.c index ac2ccd2..442f343 100644 --- a/src/dos/main.c +++ b/src/dos/main.c @@ -1,4 +1,5 @@ #include +#include #include "demo.h" #include "keyb.h" #include "timer.h" @@ -8,10 +9,18 @@ static int quit; 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; } @@ -28,9 +37,13 @@ int main(int argc, char **argv) } 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: diff --git a/src/dos/mouse.c b/src/dos/mouse.c new file mode 100644 index 0000000..e2779c9 --- /dev/null +++ b/src/dos/mouse.c @@ -0,0 +1,94 @@ +#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); + } +} diff --git a/src/dos/mouse.h b/src/dos/mouse.h new file mode 100644 index 0000000..7dd17b8 --- /dev/null +++ b/src/dos/mouse.h @@ -0,0 +1,31 @@ +#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_ */ diff --git a/src/fract.c b/src/fract.c new file mode 100644 index 0000000..0245b72 --- /dev/null +++ b/src/fract.c @@ -0,0 +1,151 @@ +#include +#include +#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> 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> 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> 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> 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; +} diff --git a/src/gfxutil.c b/src/gfxutil.c new file mode 100644 index 0000000..0257f79 --- /dev/null +++ b/src/gfxutil.c @@ -0,0 +1,144 @@ +#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; + } + } +} diff --git a/src/gfxutil.h b/src/gfxutil.h new file mode 100644 index 0000000..8de5607 --- /dev/null +++ b/src/gfxutil.h @@ -0,0 +1,7 @@ +#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_ */ diff --git a/src/screen.c b/src/screen.c index a0faa4b..a949fc4 100644 --- a/src/screen.c +++ b/src/screen.c @@ -5,8 +5,9 @@ #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; @@ -14,14 +15,17 @@ static long trans_start, trans_dur; 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; iinit() == -1) { + if(scr[i] && scr[i]->init() == -1) { return -1; } } @@ -32,6 +36,7 @@ void scr_shutdown(void) { int i; for(i=0; ishutdown(); } } @@ -41,7 +46,9 @@ void scr_update(void) 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; @@ -58,6 +65,7 @@ struct screen *scr_lookup(const char *name) { int i; for(i=0; iname, name) == 0) { return scr[i]; } @@ -78,12 +86,16 @@ int scr_change(struct screen *s, long trans_time) } 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; diff --git a/src/sdl/main.c b/src/sdl/main.c index 0abb3e3..b3ff905 100644 --- a/src/sdl/main.c +++ b/src/sdl/main.c @@ -110,6 +110,21 @@ static void handle_event(SDL_Event *ev) 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; } -- 1.7.10.4