- added blur in gfxutil
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 10 Feb 2018 12:04:24 +0000 (14:04 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 10 Feb 2018 12:04:24 +0000 (14:04 +0200)
- fixed 3dgfx to use the framebuffer set by g3d_framebuffer
- trying a variant of the greets effect with a frame by frame blur

src/3dgfx.c
src/dos/timer.h [deleted file]
src/gfxutil.c
src/gfxutil.h
src/greets.c
src/sdl/main.c
src/sdl/timer.c [new file with mode: 0644]
src/timer.h [new file with mode: 0644]

index 0b3505b..c32e6c2 100644 (file)
@@ -44,7 +44,7 @@ struct g3d_state {
        struct material mtl;
 
        int width, height;
-       void *pixels;
+       uint16_t *pixels;
 
        int vport[4];
 };
@@ -475,13 +475,13 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
                        if(st->opt & G3D_BLEND) {
                                int r, g, b;
                                int inv_alpha = 255 - pv[0].a;
-                               uint16_t *dest = fb_pixels + (pv[0].y >> 8) * fb_width + (pv[0].x >> 8);
+                               uint16_t *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
                                r = ((int)pv[0].r * pv[0].a + UNPACK_R16(*dest) * inv_alpha) >> 8;
                                g = ((int)pv[0].g * pv[0].a + UNPACK_G16(*dest) * inv_alpha) >> 8;
                                b = ((int)pv[0].b * pv[0].a + UNPACK_B16(*dest) * inv_alpha) >> 8;
                                *dest++ = PACK_RGB16(r, g, b);
                        } else {
-                               uint16_t *dest = fb_pixels + (pv[0].y >> 8) * fb_width + (pv[0].x >> 8);
+                               uint16_t *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
                                *dest = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b);
                        }
                        break;
diff --git a/src/dos/timer.h b/src/dos/timer.h
deleted file mode 100644 (file)
index 5f232b1..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-colcycle - color cycling image viewer
-Copyright (C) 2016  John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef TIMER_H_
-#define TIMER_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* expects the required timer resolution in hertz
- * if res_hz is 0, the current resolution is retained
- */
-void init_timer(int res_hz);
-
-void reset_timer(void);
-unsigned long get_msec(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* TIMER_H_ */
index 811915e..cb51780 100644 (file)
@@ -144,45 +144,60 @@ void draw_line(int x0, int y0, int x1, int y1, unsigned short color)
 }
 
 
+#define BLUR(w, h, pstep, sstep) \
+       for(i=0; i<h; i++) { \
+               int sum = sptr[0] * (rad + 1); \
+               int count = (rad * 2 + 1) << 8; \
+               int midsize = w - rad * 2; \
+               int lastpix = sptr[pstep * (w - 1)]; \
+               /* add up the contributions for the -1 pixel */ \
+               for(j=0; j<rad; j++) { \
+                       sum += sptr[pstep * j]; \
+               } \
+               /* first part adding sptr[rad] and subtracting sptr[0] */ \
+               for(j=0; j<rad + 1; j++) { \
+                       sum += (int)sptr[pstep * rad] - (int)sptr[0]; \
+                       sptr += pstep; \
+                       *dptr = scale * sum / count; \
+                       dptr += pstep; \
+               } \
+               /* middle part adding sptr[rad] and subtracting sptr[-(rad+1)] */ \
+               for(j=0; j<midsize - 1; j++) { \
+                       sum += (int)sptr[pstep * rad] - (int)sptr[-(rad + 1) * pstep]; \
+                       sptr += pstep; \
+                       *dptr = scale * sum / count; \
+                       dptr += pstep; \
+               } \
+               /* last part adding lastpix and subtracting sptr[-(rad+1)] */ \
+               for(j=0; j<rad; j++) { \
+                       sum += lastpix - (int)sptr[-(rad + 1) * pstep]; \
+                       sptr += pstep; \
+                       *dptr = scale * sum / count; \
+                       dptr += pstep; \
+               } \
+               sptr += sstep; \
+               dptr += sstep; \
+       }
+
 /* TODO bound blur rad to image size to avoid inner loop conditionals */
 /* TODO make version with pow2 (rad*2+1) to avoid div with count everywhere */
-void blur_grey_horiz(uint16_t *dest, uint16_t *src, int xsz, int ysz, int rad)
+void blur_grey_horiz(uint16_t *dest, uint16_t *src, int xsz, int ysz, int rad, int scale)
 {
        int i, j;
+       unsigned char *dptr = (unsigned char*)dest;
+       unsigned char *sptr = (unsigned char*)src;
 
-       for(i=0; i<ysz; i++) {
-               int sum = src[0] * (rad + 1);
-               int count = rad * 2 + 1;
-               uint16_t lastpix = src[xsz - 1];
-
-               /* add up the contributions for the -1 pixel */
-               for(j=0; j<rad; j++) {
-                       sum += src[j];
-               }
-
-               /* first part adding src[rad] and subtracting src[0] */
-               for(j=0; j<rad; j++) {
-                       sum += src[rad] - src[0];
-                       ++src;
-                       *dest++ = sum / count;
-               }
-
-               /* middle part adding src[rad] and subtracting src[-(rad+1)] */
-               for(j=0; j<xsz - rad; j++) {
-                       sum += src[rad] - src[-(rad + 1)];
-                       ++src;
-                       *dest++ = sum / count;
-               }
-
-               /* last part adding lastpix and subtracting src[-(rad+1)] */
-               for(j=0; j<rad; j++) {
-                       sum += lastpix - src[-(rad + 1)];
-                       ++src;
-                       *dest++ = sum / count;
-               }
-       }
+       BLUR(xsz, ysz, 2, 0);
 }
 
-void blur_grey_vert(uint16_t *dest, uint16_t *src, int xsz, int ysz, int radius)
+
+void blur_grey_vert(uint16_t *dest, uint16_t *src, int xsz, int ysz, int rad, int scale)
 {
+       int i, j;
+       unsigned char *dptr = (unsigned char*)dest;
+       unsigned char *sptr = (unsigned char*)src;
+       int pixel_step = xsz * 2;
+       int scanline_step = 2 - ysz * pixel_step;
+
+       BLUR(ysz, xsz, pixel_step, scanline_step);
 }
index cf64487..15f8b66 100644 (file)
@@ -4,9 +4,7 @@
 #include "inttypes.h"
 
 #define PACK_RGB16(r, g, b) \
-       (((((uint16_t)(r) >> 3) & 0x1f) << 11) | \
-        ((((uint16_t)(g) >> 2) & 0x3f) << 5) | \
-        (((uint16_t)(b) >> 3) & 0x1f))
+       (((r) << 8) & 0xf800) | (((g) << 3) & 0x7e0) | (((b) >> 3) & 0x1f)
 
 #define UNPACK_R16(c)  (((c) >> 8) & 0xf8)
 #define UNPACK_G16(c)  (((c) >> 3) & 0xfc)
@@ -18,7 +16,8 @@
 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);
 
-void blur_grey_horiz(uint16_t *dest, uint16_t *src, int xsz, int ysz, int radius);
-void blur_grey_vert(uint16_t *dest, uint16_t *src, int xsz, int ysz, int radius);
+/* scale in 24.8 fixed point */
+void blur_grey_horiz(uint16_t *dest, uint16_t *src, int xsz, int ysz, int radius, int scale);
+void blur_grey_vert(uint16_t *dest, uint16_t *src, int xsz, int ysz, int radius, int scale);
 
 #endif /* GFXUTIL_H_ */
index 9fa14df..0ad90a1 100644 (file)
@@ -2,15 +2,31 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <assert.h>
 #include "demo.h"
 #include "3dgfx.h"
 #include "screen.h"
 #include "cfgopt.h"
 #include "imago2.h"
 #include "util.h"
+#include "gfxutil.h"
+#include "timer.h"
+
+#ifdef MSDOS
+#include "dos/gfx.h"   /* for wait_vsync assembly macro */
+#else
+void wait_vsync(void);
+#endif
+
+/* if defined, use bilinear interpolation for dispersion field vectors */
+#define BILERP_FIELD
+/* if defined randomize field vectors by RAND_FIELD_MAX */
+#define RANDOMIZE_FIELD
+
+#define RAND_FIELD_MAX 0.7
 
 #define PCOUNT         4000
-#define MAX_LIFE       6.0f
+#define MAX_LIFE       7.0f
 #define PALPHA         1.0f
 #define ZBIAS          0.25
 #define DRAG           0.95
@@ -74,6 +90,16 @@ static struct vfield vfield;
 static struct g3d_vertex *varr;
 static long start_time;
 
+static uint16_t *cur_smokebuf, *prev_smokebuf;
+static int smokebuf_size;
+#define smokebuf_start (cur_smokebuf < prev_smokebuf ? cur_smokebuf : prev_smokebuf)
+#define swap_smoke_buffers() \
+       do { \
+               uint16_t *tmp = cur_smokebuf; \
+               cur_smokebuf = prev_smokebuf; \
+               prev_smokebuf = tmp; \
+       } while(0)
+
 static float cam_theta, cam_phi = 25;
 static float cam_dist = 3;
 
@@ -105,11 +131,21 @@ static int init(void)
                return -1;
        }
 
+       smokebuf_size = fb_width * fb_height * sizeof *cur_smokebuf;
+       if(!(cur_smokebuf = malloc(smokebuf_size * 2))) {
+               perror("failed to allocate smoke framebuffer");
+               return -1;
+       }
+       prev_smokebuf = cur_smokebuf + fb_width * fb_height;
+
        return 0;
 }
 
 static void destroy(void)
 {
+       free(varr);
+       free(vfield.v);
+       free(smokebuf_start);
 }
 
 static void start(long trans_time)
@@ -118,6 +154,8 @@ static void start(long trans_time)
        g3d_load_identity();
        g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
 
+       memset(smokebuf_start, 0, smokebuf_size * 2);
+
        start_time = time_msec;
 }
 
@@ -161,9 +199,12 @@ static void update(void)
 
 static void draw(void)
 {
-       update();
+       int i, j;
+       uint16_t *dest, *src;
+       unsigned long msec;
+       static unsigned long last_swap;
 
-       memset(fb_pixels, 0, fb_width * fb_height * 2);
+       update();
 
        g3d_matrix_mode(G3D_MODELVIEW);
        g3d_load_identity();
@@ -175,9 +216,35 @@ static void draw(void)
                g3d_rotate(cam_theta, 0, 1, 0);
        }
 
+       memcpy(cur_smokebuf, prev_smokebuf, smokebuf_size);
+
+       g3d_framebuffer(fb_width, fb_height, cur_smokebuf);
        draw_particles(&em);
+       g3d_framebuffer(fb_width, fb_height, fb_pixels);
+
+       dest = fb_pixels;
+       src = cur_smokebuf;
+       for(i=0; i<fb_height; i++) {
+               for(j=0; j<fb_width; j++) {
+                       unsigned int alpha = *src++;
+                       *dest++ = PACK_RGB16(alpha, alpha, alpha);
+               }
+       }
+
+#define BLUR_RAD       5
+       blur_grey_horiz(prev_smokebuf, cur_smokebuf, fb_width, fb_height, BLUR_RAD, 240);
+       blur_grey_vert(cur_smokebuf, prev_smokebuf, fb_width, fb_height, BLUR_RAD, 240);
+       swap_smoke_buffers();
 
+       msec = get_msec();
+       if(msec - last_swap < 16) {
+               wait_vsync();
+       }
+       if(!opt.vsync) {
+               wait_vsync();
+       }
        swap_buffers(fb_pixels);
+       last_swap = get_msec();
 }
 
 
@@ -203,9 +270,7 @@ int init_emitter(struct emitter *em, int num, unsigned char *map, int xsz, int y
                p->x = (float)x / (float)xsz - 0.5;
                p->y = -(float)y / (float)xsz + 0.5 / aspect;
                p->z = ((float)i / (float)num * 2.0 - 1.0) * 0.005;
-               p->r = 0;
-               p->g = 0x1f;
-               p->b = 255;
+               p->r = p->g = p->b = 255;
                p->vx = p->vy = p->vz = 0.0f;
                p->life = MAX_LIFE;
                ++p;
@@ -235,10 +300,10 @@ void update_particles(struct emitter *em, float dt)
                v->y = p->y;
                v->z = p->z;
                v->w = 1.0f;
-               v->r = p->r;
-               v->g = p->g;
-               v->b = p->b;
                v->a = cround64(p->life * 255.0 / MAX_LIFE);
+               v->r = 0;
+               v->g = (v->a & 0xe0) >> 3;
+               v->b = (v->a & 0x1f) << 3;
                ++v;
 
                ++p;
@@ -247,9 +312,7 @@ void update_particles(struct emitter *em, float dt)
 
 void draw_particles(struct emitter *em)
 {
-       g3d_enable(G3D_BLEND);
        g3d_draw(G3D_POINTS, varr, PCOUNT);
-       g3d_disable(G3D_BLEND);
 }
 
 
@@ -312,15 +375,16 @@ void vfield_eval(struct vfield *vf, float x, float y, struct vec2 *dir)
        if(x > vf->width - 2) x = vf->width - 2;
        if(y > vf->height - 2) y = vf->height - 2;
 
-       tx = fmod(x, 1.0f);
-       ty = fmod(y, 1.0f);
-
        px = (int)x;
        py = (int)y;
 
        p1 = vf->v + (py << vf->xshift) + px;
+#ifdef BILERP_FIELD
        p2 = p1 + vf->width;
 
+       tx = fmod(x, 1.0f);
+       ty = fmod(y, 1.0f);
+
        left.x = p1->x + (p2->x - p1->x) * ty;
        left.y = p1->y + (p2->y - p1->y) * ty;
        ++p1;
@@ -330,7 +394,13 @@ void vfield_eval(struct vfield *vf, float x, float y, struct vec2 *dir)
 
        dir->x = left.x + (right.x - left.x) * tx;
        dir->y = left.y + (right.y - left.y) * ty;
-
-       dir->x += ((float)rand() / RAND_MAX - 0.5) * 0.7;
-       dir->y += ((float)rand() / RAND_MAX - 0.5) * 0.7;
+#else
+       dir->x = p1->x;
+       dir->y = p1->y;
+#endif
+
+#ifdef RANDOMIZE_FIELD
+       dir->x += ((float)rand() / RAND_MAX - 0.5) * RAND_FIELD_MAX;
+       dir->y += ((float)rand() / RAND_MAX - 0.5) * RAND_FIELD_MAX;
+#endif
 }
index 09645aa..c00bf7d 100644 (file)
@@ -4,12 +4,13 @@
 #include <SDL/SDL.h>
 #include "demo.h"
 #include "tinyfps.h"
+#include "timer.h"
+#include "cfgopt.h"
 
 static void handle_event(SDL_Event *ev);
 static void toggle_fullscreen(void);
 
 static int quit;
-static long start_time;
 static SDL_Surface *fbsurf;
 
 static int fbscale = 2;
@@ -52,7 +53,7 @@ int main(int argc, char **argv)
                SDL_Quit();
                return 1;
        }
-       start_time = SDL_GetTicks();
+       reset_timer();
 
        while(!quit) {
                SDL_Event ev;
@@ -61,7 +62,7 @@ int main(int argc, char **argv)
                        if(quit) goto break_evloop;
                }
 
-               time_msec = SDL_GetTicks() - start_time;
+               time_msec = get_msec();
                demo_draw();
                drawFps(fb_pixels);
 
@@ -103,9 +104,19 @@ void demo_quit(void)
        quit = 1;
 }
 
+void wait_vsync(void)
+{
+       unsigned long start = SDL_GetTicks();
+       unsigned long until = (start | 0xf) + 1;
+       while(SDL_GetTicks() <= until);
+}
+
 void swap_buffers(void *pixels)
 {
        /* do nothing, all pointers point to the same buffer */
+       if(opt.vsync) {
+               wait_vsync();
+       }
 }
 
 static void handle_event(SDL_Event *ev)
diff --git a/src/sdl/timer.c b/src/sdl/timer.c
new file mode 100644 (file)
index 0000000..2193ddd
--- /dev/null
@@ -0,0 +1,18 @@
+#include <SDL/SDL.h>
+#include "timer.h"
+
+static unsigned long start_time;
+
+void init_timer(int res_hz)
+{
+}
+
+void reset_timer(void)
+{
+       start_time = SDL_GetTicks();
+}
+
+unsigned long get_msec(void)
+{
+       return SDL_GetTicks() - start_time;
+}
diff --git a/src/timer.h b/src/timer.h
new file mode 100644 (file)
index 0000000..1fa83c3
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef TIMER_H_
+#define TIMER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* expects the required timer resolution in hertz
+ * if res_hz is 0, the current resolution is retained
+ */
+void init_timer(int res_hz);
+
+void reset_timer(void);
+unsigned long get_msec(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TIMER_H_ */