From 9b942b99fe10222bee50c47bfc809de268d331ec Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Thu, 8 Feb 2018 09:16:00 +0200 Subject: [PATCH] fixed point drawing in 3dgfx and added new greets screen --- GNUmakefile | 5 + Makefile | 2 +- src/3dgfx.c | 27 ++++- src/3dgfx.h | 19 ++-- src/gfxutil.h | 4 +- src/greets.c | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/polyclip.c | 6 + src/polyfill.h | 2 +- src/screen.c | 4 + 9 files changed, 387 insertions(+), 14 deletions(-) create mode 100644 src/greets.c diff --git a/GNUmakefile b/GNUmakefile index 348256c..de6b64a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -24,6 +24,11 @@ imago: 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) diff --git a/Makefile b/Makefile index 2f593c2..3a84c1a 100644 --- 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 & -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) diff --git a/src/3dgfx.c b/src/3dgfx.c index a90da7a..0b3505b 100644 --- a/src/3dgfx.c +++ b/src/3dgfx.c @@ -4,9 +4,11 @@ #include #include #include "3dgfx.h" +#include "gfxutil.h" #include "polyfill.h" #include "polyclip.h" #include "inttypes.h" +#include "demo.h" #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].a = v[i].a; } /* 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); + } } } diff --git a/src/3dgfx.h b/src/3dgfx.h index 8708e21..8d05b8a 100644 --- a/src/3dgfx.h +++ b/src/3dgfx.h @@ -7,7 +7,7 @@ struct g3d_vertex { float x, y, z, w; float nx, ny, nz; float u, v; - unsigned char r, g, b; + unsigned char r, g, b, a; }; enum { @@ -19,14 +19,15 @@ 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 }; diff --git a/src/gfxutil.h b/src/gfxutil.h index 07883ef..603c11d 100644 --- a/src/gfxutil.h +++ b/src/gfxutil.h @@ -4,9 +4,9 @@ #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_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)) diff --git a/src/greets.c b/src/greets.c new file mode 100644 index 0000000..0876b60 --- /dev/null +++ b/src/greets.c @@ -0,0 +1,332 @@ +#include +#include +#include +#include +#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; ix = (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; ipcount; 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; +} diff --git a/src/polyclip.c b/src/polyclip.c index f5ef9c7..d02f645 100644 --- a/src/polyclip.c +++ b/src/polyclip.c @@ -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); +static int inside_frustum_plane(const struct g3d_vertex *v, int fplane); 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; + if(vnum == 1) { + /* special case: point clipping */ + return inside_frustum_plane(vin, fplane) ? 1 : -1; + } + for(i=0; i