fractal effect is cooking
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 29 Aug 2016 02:14:35 +0000 (05:14 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 29 Aug 2016 02:14:35 +0000 (05:14 +0300)
Makefile
src/demo.c
src/demo.h
src/dos/main.c
src/dos/mouse.c [new file with mode: 0644]
src/dos/mouse.h [new file with mode: 0644]
src/fract.c [new file with mode: 0644]
src/gfxutil.c [new file with mode: 0644]
src/gfxutil.h [new file with mode: 0644]
src/screen.c
src/sdl/main.c

index 1044346..75dba8d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 baseobj = main.obj
 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
 
 obj = $(baseobj) $(demoobj) $(sysobj)
 bin = demo.exe
 
index fe0c2c4..98f8001 100644 (file)
@@ -11,15 +11,25 @@ int fb_height = 240;
 int fb_bpp = 16;
 void *fb_pixels;
 unsigned long time_msec;
 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 unsigned long nframes;
+static const char *start_scr_name = "tunnel";
 
 int demo_init(int argc, char **argv)
 {
 
 int demo_init(int argc, char **argv)
 {
+       if(argv[1]) {
+               start_scr_name = argv[1];
+       }
+
        if(scr_init() == -1) {
                return -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;
 }
 
        return 0;
 }
index a022275..530e3de 100644 (file)
@@ -4,6 +4,8 @@
 extern int fb_width, fb_height, fb_bpp;
 extern void *fb_pixels;
 extern unsigned long time_msec;
 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);
 
 int demo_init(int argc, char **argv);
 void demo_cleanup(void);
index ac2ccd2..442f343 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdio.h>
 #include <stdio.h>
+#include <limits.h>
 #include "demo.h"
 #include "keyb.h"
 #include "timer.h"
 #include "demo.h"
 #include "keyb.h"
 #include "timer.h"
@@ -8,10 +9,18 @@ static int quit;
 
 int main(int argc, char **argv)
 {
 
 int main(int argc, char **argv)
 {
+       void *vmem;
+       long fbsize = fb_width * fb_height * fb_bpp / CHAR_BIT;
+
        init_timer(100);
        kb_init(32);
 
        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;
        }
 
                return 1;
        }
 
@@ -28,9 +37,13 @@ int main(int argc, char **argv)
                }
                if(quit) goto break_evloop;
 
                }
                if(quit) goto break_evloop;
 
-               /*wait_vsync();*/
+               mouse_bmask = read_mouse(&mouse_x, &mouse_y);
+
                time_msec = get_msec();
                demo_draw();
                time_msec = get_msec();
                demo_draw();
+
+               /*wait_vsync();*/
+               memcpy(vmem, fb_pixels, fbsize);
        }
 
 break_evloop:
        }
 
 break_evloop:
diff --git a/src/dos/mouse.c b/src/dos/mouse.c
new file mode 100644 (file)
index 0000000..e2779c9
--- /dev/null
@@ -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 (file)
index 0000000..7dd17b8
--- /dev/null
@@ -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 (file)
index 0000000..0245b72
--- /dev/null
@@ -0,0 +1,151 @@
+#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;
+}
diff --git a/src/gfxutil.c b/src/gfxutil.c
new file mode 100644 (file)
index 0000000..0257f79
--- /dev/null
@@ -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 (file)
index 0000000..8de5607
--- /dev/null
@@ -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_ */
index a0faa4b..a949fc4 100644 (file)
@@ -5,8 +5,9 @@
 #include "demo.h"
 
 struct screen *tunnel_screen(void);
 #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;
 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 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++) {
                return -1;
        }
 
        for(i=0; i<NUM_SCR; i++) {
-               if(scr[i]->init() == -1) {
+               if(scr[i] && scr[i]->init() == -1) {
                        return -1;
                }
        }
                        return -1;
                }
        }
@@ -32,6 +36,7 @@ void scr_shutdown(void)
 {
        int i;
        for(i=0; i<NUM_SCR; i++) {
 {
        int i;
        for(i=0; i<NUM_SCR; i++) {
+               if(!scr[i]) break;
                scr[i]->shutdown();
        }
 }
                scr[i]->shutdown();
        }
 }
@@ -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) {
        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;
                        prev = 0;
                        cur = next;
                        next = 0;
@@ -58,6 +65,7 @@ struct screen *scr_lookup(const char *name)
 {
        int i;
        for(i=0; i<NUM_SCR; i++) {
 {
        int i;
        for(i=0; i<NUM_SCR; i++) {
+               if(!scr[i]) break;
                if(strcmp(scr[i]->name, name) == 0) {
                        return scr[i];
                }
                if(strcmp(scr[i]->name, name) == 0) {
                        return scr[i];
                }
@@ -78,12 +86,16 @@ int scr_change(struct screen *s, long trans_time)
        }
 
        if(cur) {
        }
 
        if(cur) {
-               cur->stop(trans_dur);
+               if(cur->stop) {
+                       cur->stop(trans_dur);
+               }
 
                prev = cur;
                next = s;
        } else {
 
                prev = cur;
                next = s;
        } else {
-               s->start(trans_dur);
+               if(s->start) {
+                       s->start(trans_dur);
+               }
 
                cur = s;
                prev = 0;
 
                cur = s;
                prev = 0;
index 0abb3e3..b3ff905 100644 (file)
@@ -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;
 
                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;
        }
        default:
                break;
        }