fixed point drawing in 3dgfx and added new greets screen
authorJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 8 Feb 2018 07:16:00 +0000 (09:16 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 8 Feb 2018 07:16:00 +0000 (09:16 +0200)
GNUmakefile
Makefile
src/3dgfx.c
src/3dgfx.h
src/gfxutil.h
src/greets.c [new file with mode: 0644]
src/polyclip.c
src/polyfill.h
src/screen.c

index 348256c..de6b64a 100644 (file)
@@ -24,6 +24,11 @@ imago:
 mikmod:
        $(MAKE) -C libs/mikmod
 
 mikmod:
        $(MAKE) -C libs/mikmod
 
+.PHONY: cleanlibs
+cleanlibs:
+       $(MAKE) -C libs/imago -f Makefile.dj clean
+       $(MAKE) -C libs/oldmik -f Makefile.dj clean
+
 .PHONY: clean
 clean:
        rm -f $(obj) $(bin)
 .PHONY: clean
 clean:
        rm -f $(obj) $(bin)
index 2f593c2..3a84c1a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 demoobj = main.obj demo.obj screen.obj cfgopt.obj music.obj gfxutil.obj &
 3dgfx.obj polyfill.obj polyclip.obj metasurf.obj dynarr.obj
 scrobj = tunnel.obj fract.obj grise.obj polytest.obj plasma.obj bump.obj &
 demoobj = main.obj demo.obj screen.obj cfgopt.obj music.obj gfxutil.obj &
 3dgfx.obj polyfill.obj polyclip.obj metasurf.obj dynarr.obj
 scrobj = tunnel.obj fract.obj grise.obj polytest.obj plasma.obj bump.obj &
-thunder.obj metaball.obj
+thunder.obj metaball.obj greets.obj
 sysobj = gfx.obj vbe.obj watdpmi.obj timer.obj keyb.obj mouse.obj sball.obj &
 logger.obj tinyfps.obj
 obj = $(baseobj) $(demoobj) $(sysobj) $(scrobj)
 sysobj = gfx.obj vbe.obj watdpmi.obj timer.obj keyb.obj mouse.obj sball.obj &
 logger.obj tinyfps.obj
 obj = $(baseobj) $(demoobj) $(sysobj) $(scrobj)
index a90da7a..0b3505b 100644 (file)
@@ -4,9 +4,11 @@
 #include <math.h>
 #include <assert.h>
 #include "3dgfx.h"
 #include <math.h>
 #include <assert.h>
 #include "3dgfx.h"
+#include "gfxutil.h"
 #include "polyfill.h"
 #include "polyclip.h"
 #include "inttypes.h"
 #include "polyfill.h"
 #include "polyclip.h"
 #include "inttypes.h"
+#include "demo.h"
 #include "util.h"
 
 #define STACK_SIZE     8
 #include "util.h"
 
 #define STACK_SIZE     8
@@ -451,6 +453,7 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
                        pv[i].r = v[i].r;
                        pv[i].g = v[i].g;
                        pv[i].b = v[i].b;
                        pv[i].r = v[i].r;
                        pv[i].g = v[i].g;
                        pv[i].b = v[i].b;
+                       pv[i].a = v[i].a;
                }
 
                /* backface culling */
                }
 
                /* backface culling */
@@ -467,7 +470,29 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
                        }
                }
 
                        }
                }
 
-               polyfill(st->fill_mode, pv, vnum);
+               switch(vnum) {
+               case 1:
+                       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);
+                               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);
+                               *dest = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b);
+                       }
+                       break;
+
+               case 2:
+                       /* TODO: draw line */
+                       break;
+
+               default:
+                       polyfill(st->fill_mode, pv, vnum);
+               }
        }
 }
 
        }
 }
 
index 8708e21..8d05b8a 100644 (file)
@@ -7,7 +7,7 @@ struct g3d_vertex {
        float x, y, z, w;
        float nx, ny, nz;
        float u, v;
        float x, y, z, w;
        float nx, ny, nz;
        float u, v;
-       unsigned char r, g, b;
+       unsigned char r, g, b, a;
 };
 
 enum {
 };
 
 enum {
@@ -19,14 +19,15 @@ enum {
 
 /* g3d_enable/g3d_disable bits */
 enum {
 
 /* g3d_enable/g3d_disable bits */
 enum {
-       G3D_CULL_FACE = 1,
-       G3D_DEPTH_TEST = 2,     /* XXX not implemented */
-       G3D_LIGHTING = 4,
-       G3D_LIGHT0 = 8,
-       G3D_LIGHT1 = 16,
-       G3D_LIGHT2 = 32,
-       G3D_LIGHT3 = 64,
-       G3D_TEXTURE = 128,
+       G3D_CULL_FACE   = 0x0001,
+       G3D_DEPTH_TEST  = 0x0002,       /* XXX not implemented */
+       G3D_LIGHTING    = 0x0004,
+       G3D_LIGHT0              = 0x0008,
+       G3D_LIGHT1              = 0x0010,
+       G3D_LIGHT2              = 0x0020,
+       G3D_LIGHT3              = 0x0040,
+       G3D_TEXTURE             = 0x0080,
+       G3D_BLEND               = 0x0100,
 
        G3D_ALL = 0x7fffffff
 };
 
        G3D_ALL = 0x7fffffff
 };
index 07883ef..603c11d 100644 (file)
@@ -4,9 +4,9 @@
 #define PACK_RGB16(r, g, b) \
        (((((r) >> 3) & 0x1f) << 11) | ((((g) >> 2) & 0x3f) << 5) | (((b) >> 3) & 0x1f))
 
 #define PACK_RGB16(r, g, b) \
        (((((r) >> 3) & 0x1f) << 11) | ((((g) >> 2) & 0x3f) << 5) | (((b) >> 3) & 0x1f))
 
-#define UNPACK_R16(c)  (((c) >> 8) & 0x7c)
+#define UNPACK_R16(c)  (((c) >> 8) & 0xf8)
 #define UNPACK_G16(c)  (((c) >> 3) & 0xfc)
 #define UNPACK_G16(c)  (((c) >> 3) & 0xfc)
-#define UNPACK_B16(c)  (((c) << 3) & 0x7c)
+#define UNPACK_B16(c)  (((c) << 3) & 0xf8)
 
 #define PACK_RGB32(r, g, b) \
        ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff))
 
 #define PACK_RGB32(r, g, b) \
        ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff))
diff --git a/src/greets.c b/src/greets.c
new file mode 100644 (file)
index 0000000..0876b60
--- /dev/null
@@ -0,0 +1,332 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "demo.h"
+#include "3dgfx.h"
+#include "screen.h"
+#include "cfgopt.h"
+#include "imago2.h"
+#include "util.h"
+
+#define PCOUNT         4000
+#define MAX_LIFE       6.0f
+#define PALPHA         1.0f
+#define ZBIAS          0.25
+#define DRAG           0.95
+#define FORCE          0.07
+#define FREQ           0.085
+static float wind[] = {-0.0, 0.0, 0.01};
+
+
+struct vec2 {
+       float x, y;
+};
+
+struct vec3 {
+       float x, y, z;
+};
+
+struct particle {
+       float x, y, z;
+       float vx, vy, vz;       /* velocity */
+       float r, g, b;
+       float life;
+};
+
+struct emitter {
+       struct particle *plist;
+       int pcount;
+};
+
+struct vfield {
+       struct vec2 pos, size;
+
+       int width, height;
+       int xshift;
+       struct vec2 *v;
+};
+
+
+static int init(void);
+static void destroy(void);
+static void start(long trans_time);
+static void draw(void);
+
+int init_emitter(struct emitter *em, int num, unsigned char *map, int xsz, int ysz);
+void update_particles(struct emitter *em, float dt);
+void draw_particles(struct emitter *em);
+
+int init_vfield_load(struct vfield *vf, const char *fname);
+void vfield_eval(struct vfield *vf, float x, float y, struct vec2 *dir);
+
+
+static struct screen scr = {
+       "greets",
+       init,
+       destroy,
+       start, 0,
+       draw
+};
+
+static struct emitter em;
+static struct vfield vfield;
+static struct g3d_vertex *varr;
+static long start_time;
+
+static float cam_theta, cam_phi = 25;
+static float cam_dist = 3;
+
+struct screen *greets_screen(void)
+{
+       return &scr;
+}
+
+
+static int init(void)
+{
+       int xsz, ysz;
+       unsigned char *pixels;
+
+       if(!(pixels = img_load_pixels("data/greets1.png", &xsz, &ysz, IMG_FMT_GREY8))) {
+               fprintf(stderr, "failed to load particle spawn map\n");
+               return -1;
+       }
+
+       init_emitter(&em, PCOUNT, pixels, xsz, ysz);
+       img_free_pixels(pixels);
+
+       if(!(varr = malloc(PCOUNT * sizeof *varr))) {
+               perror("failed to allocate particle vertex buffer\n");
+               return -1;
+       }
+
+       if(init_vfield_load(&vfield, "data/vfield1") == -1) {
+               return -1;
+       }
+
+       return 0;
+}
+
+static void destroy(void)
+{
+}
+
+static void start(long trans_time)
+{
+       g3d_matrix_mode(G3D_PROJECTION);
+       g3d_load_identity();
+       g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
+
+       start_time = time_msec;
+}
+
+static void update(void)
+{
+       static long prev_msec;
+       static int prev_mx, prev_my;
+       static unsigned int prev_bmask;
+
+       long msec = time_msec - start_time;
+       float dt = (msec - prev_msec) / 1000.0f;
+       prev_msec = msec;
+
+       if(mouse_bmask) {
+               if((mouse_bmask ^ prev_bmask) == 0) {
+                       int dx = mouse_x - prev_mx;
+                       int dy = mouse_y - prev_my;
+
+                       if(dx || dy) {
+                               if(mouse_bmask & 1) {
+                                       cam_theta += dx * 1.0;
+                                       cam_phi += dy * 1.0;
+
+                                       if(cam_phi < -90) cam_phi = -90;
+                                       if(cam_phi > 90) cam_phi = 90;
+                               }
+                               if(mouse_bmask & 4) {
+                                       cam_dist += dy * 0.5;
+
+                                       if(cam_dist < 0) cam_dist = 0;
+                               }
+                       }
+               }
+       }
+       prev_mx = mouse_x;
+       prev_my = mouse_y;
+       prev_bmask = mouse_bmask;
+
+       update_particles(&em, dt);
+}
+
+static void draw(void)
+{
+       update();
+
+       memset(fb_pixels, 0, fb_width * fb_height * 2);
+
+       g3d_matrix_mode(G3D_MODELVIEW);
+       g3d_load_identity();
+       g3d_translate(0, 0, -cam_dist);
+       if(opt.sball) {
+               g3d_mult_matrix(sball_matrix);
+       } else {
+               g3d_rotate(cam_phi, 1, 0, 0);
+               g3d_rotate(cam_theta, 0, 1, 0);
+       }
+
+       draw_particles(&em);
+
+       swap_buffers(fb_pixels);
+}
+
+
+
+int init_emitter(struct emitter *em, int num, unsigned char *map, int xsz, int ysz)
+{
+       int i, x, y;
+       float aspect = (float)xsz / (float)ysz;
+       struct particle *p;
+
+       if(!(em->plist = malloc(num * sizeof *em->plist))) {
+               return -1;
+       }
+       em->pcount = num;
+
+       p = em->plist;
+       for(i=0; i<num; i++) {
+               do {
+                       x = rand() % xsz;
+                       y = rand() % ysz;
+               } while(map[y * xsz + x] < 128);
+
+               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 = p->g = p->b = 0.9;
+               p->vx = p->vy = p->vz = 0.0f;
+               p->life = MAX_LIFE;
+               ++p;
+       }
+       return 0;
+}
+
+void update_particles(struct emitter *em, float dt)
+{
+       int i;
+       struct vec2 accel;
+       struct particle *p = em->plist;
+       struct g3d_vertex *v = varr;
+
+       for(i=0; i<em->pcount; i++) {
+               vfield_eval(&vfield, p->x, p->y, &accel);
+               p->x += p->vx * DRAG * dt;
+               p->y += p->vy * DRAG * dt;
+               p->z += p->vz * DRAG * dt;
+               p->vx += (wind[0] + accel.x * FORCE) * dt;
+               p->vy += (wind[1] + accel.y * FORCE) * dt;
+               p->vz += (wind[2] + p->z * ZBIAS) * dt;
+               p->life -= dt;
+               if(p->life < 0.0f) p->life = 0.0f;
+
+               v->x = p->x;
+               v->y = p->y;
+               v->z = p->z;
+               v->w = 1.0f;
+               v->r = v->g = v->b = 200;
+               v->a = cround64(p->life * 255.0 / MAX_LIFE);
+               ++v;
+
+               ++p;
+       }
+}
+
+void draw_particles(struct emitter *em)
+{
+       g3d_enable(G3D_BLEND);
+       g3d_draw(G3D_POINTS, varr, PCOUNT);
+       g3d_disable(G3D_BLEND);
+}
+
+
+int init_vfield_load(struct vfield *vf, const char *fname)
+{
+       FILE *fp;
+       int tmp;
+
+       if(!(fp = fopen(fname, "rb"))) {
+               fprintf(stderr, "failed to open vector field: %s\n", fname);
+               return -1;
+       }
+       if(fread(&vf->width, sizeof vf->width, 1, fp) < 1 ||
+                       fread(&vf->height, sizeof vf->height, 1, fp) < 1) {
+               fprintf(stderr, "init_vfield_load: unexpected end of file while reading header\n");
+               fclose(fp);
+               return -1;
+       }
+
+       /* assume xsz is pow2 otherwise fuck you */
+       tmp = vf->width - 1;
+       vf->xshift = 0;
+       while(tmp) {
+               ++vf->xshift;
+               tmp >>= 1;
+       }
+
+       if(!(vf->v = malloc(vf->width * vf->height * sizeof *vf->v))) {
+               fprintf(stderr, "failed to allocate %dx%d vector field\n", vf->width, vf->height);
+               fclose(fp);
+               return -1;
+       }
+       if(fread(vf->v, sizeof *vf->v, vf->width * vf->height, fp) < vf->width * vf->height) {
+               fprintf(stderr, "init_vfield_load: unexpected end of file while reading %dx%d vector field\n",
+                               vf->width, vf->height);
+               fclose(fp);
+               return -1;
+       }
+       fclose(fp);
+
+       vf->pos.x = vf->pos.y = 0;
+       vf->size.x = vf->size.y = 1;
+       return 0;
+}
+
+void vfield_eval(struct vfield *vf, float x, float y, struct vec2 *dir)
+{
+       int px, py;
+       float tx, ty;
+       struct vec2 *p1, *p2;
+       struct vec2 left, right;
+
+       x = ((x - vf->pos.x) / vf->size.x + 0.5f) * vf->width;
+       y = ((y - vf->pos.y) / vf->size.y + 0.5f) * vf->height;
+       x = floor(x);
+       y = floor(y);
+
+       if(x < 0) x = 0;
+       if(y < 0) y = 0;
+       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;
+       p2 = p1 + vf->width;
+
+       left.x = p1->x + (p2->x - p1->x) * ty;
+       left.y = p1->y + (p2->y - p1->y) * ty;
+       ++p1;
+       ++p2;
+       right.x = p1->x + (p2->x - p1->x) * ty;
+       right.y = p1->y + (p2->y - p1->y) * ty;
+
+       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;
+}
index f5ef9c7..d02f645 100644 (file)
@@ -14,6 +14,7 @@ static int clip_edge_frustum(struct g3d_vertex *poly, int *vnumptr,
                const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane);
 static float distance_signed(float *pos, const struct cplane *plane);
 static int intersect(const struct ray *ray, const struct cplane *plane, float *t);
                const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane);
 static float distance_signed(float *pos, const struct cplane *plane);
 static int intersect(const struct ray *ray, const struct cplane *plane, float *t);
+static int inside_frustum_plane(const struct g3d_vertex *v, int fplane);
 
 
 int clip_poly(struct g3d_vertex *vout, int *voutnum,
 
 
 int clip_poly(struct g3d_vertex *vout, int *voutnum,
@@ -47,6 +48,11 @@ int clip_frustum(struct g3d_vertex *vout, int *voutnum,
        int edges_clipped = 0;
        int out_vnum = 0;
 
        int edges_clipped = 0;
        int out_vnum = 0;
 
+       if(vnum == 1) {
+               /* special case: point clipping */
+               return inside_frustum_plane(vin, fplane) ? 1 : -1;
+       }
+
        for(i=0; i<vnum; i++) {
                int res = clip_edge_frustum(vout, &out_vnum, vin + i, vin + (i + 1) % vnum, fplane);
                if(res == 0) {
        for(i=0; i<vnum; i++) {
                int res = clip_edge_frustum(vout, &out_vnum, vin + i, vin + (i + 1) % vnum, fplane);
                if(res == 0) {
index 2a6b42d..b52b5de 100644 (file)
@@ -15,7 +15,7 @@ enum {
 struct pvertex {
        int32_t x, y; /* 24.8 fixed point */
        int32_t u, v; /* 16.16 fixed point */
 struct pvertex {
        int32_t x, y; /* 24.8 fixed point */
        int32_t u, v; /* 16.16 fixed point */
-       int32_t r, g, b;  /* int 0-255 */
+       int32_t r, g, b, a;  /* int 0-255 */
 };
 
 struct pimage {
 };
 
 struct pimage {
index 2b551f4..fb89206 100644 (file)
@@ -13,6 +13,7 @@ struct screen *plasma_screen(void);
 struct screen *bump_screen(void);
 struct screen *thunder_screen(void);
 struct screen *metaballs_screen(void);
 struct screen *bump_screen(void);
 struct screen *thunder_screen(void);
 struct screen *metaballs_screen(void);
+struct screen *greets_screen(void);
 
 #define NUM_SCR 32
 static struct screen *scr[NUM_SCR];
 
 #define NUM_SCR 32
 static struct screen *scr[NUM_SCR];
@@ -49,6 +50,9 @@ int scr_init(void)
        if(!(scr[idx++] = metaballs_screen())) {
                return -1;
        }
        if(!(scr[idx++] = metaballs_screen())) {
                return -1;
        }
+       if(!(scr[idx++] = greets_screen())) {
+               return -1;
+       }
        num_screens = idx;
 
        assert(num_screens <= NUM_SCR);
        num_screens = idx;
 
        assert(num_screens <= NUM_SCR);