From: John Tsiombikas Date: Sat, 25 Aug 2018 10:21:37 +0000 (+0300) Subject: BSP tree test X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosrtxon;a=commitdiff_plain;h=ac1dd983cb211904ca6c74ca28ceb5e83aa09527 BSP tree test --- diff --git a/GNUmakefile b/GNUmakefile index 6251a07..1961fe3 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -6,8 +6,8 @@ bin = demo inc = -I/usr/local/include -Isrc -Isrc/sdl -Ilibs/imago/src -Ilibs/mikmod/include warn = -pedantic -Wall -Wno-unused-variable -Wno-unused-function -CFLAGS = $(warn) -g $(inc) `sdl-config --cflags` -LDFLAGS = -Llibs/imago -Llibs/mikmod -limago -lmikmod `sdl-config --libs` -lm +CFLAGS = $(warn) -g -O3 $(inc) `sdl-config --cflags` -fopenmp +LDFLAGS = -Llibs/imago -Llibs/mikmod -limago -lmikmod `sdl-config --libs` -lm -lgomp $(bin): $(obj) imago mikmod $(CC) -o $@ $(obj) $(LDFLAGS) diff --git a/src/bsptree.c b/src/bsptree.c new file mode 100644 index 0000000..7783e25 --- /dev/null +++ b/src/bsptree.c @@ -0,0 +1,482 @@ +#include +#include +#include +#include +#include +#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__) +#include +#else +#include +#endif +#include "bsptree.h" +#include "dynarr.h" +#include "inttypes.h" +#include "polyclip.h" +#include "vmath.h" +#include "util.h" + +struct bspfile_header { + char magic[4]; + uint32_t num_nodes; +}; + +static int count_nodes(struct bspnode *n); +static void free_tree(struct bspnode *n); + +static int init_poly(struct bsppoly *poly, struct g3d_vertex *v, int vnum); +static int init_poly_noplane(struct bsppoly *poly, struct g3d_vertex *v, int vnum); + +static struct bspnode *build_tree(struct bsppoly *polyarr, int num_polys); + +static void draw_bsp_tree(struct bspnode *n, const vec3_t *vdir); + +static void save_bsp_tree(struct bspnode *n, FILE *fp); +static struct bspnode *load_bsp_tree(FILE *fp); + +int init_bsp(struct bsptree *bsp) +{ + bsp->root = 0; + bsp->soup = 0; + return 0; +} + +void destroy_bsp(struct bsptree *bsp) +{ + int i; + + free_tree(bsp->root); + + if(bsp->soup) { + for(i=0; isoup); i++) { + free(bsp->soup[i].verts); + } + dynarr_free(bsp->soup); + } +} + +int save_bsp(struct bsptree *bsp, const char *fname) +{ + FILE *fp; + struct bspfile_header hdr; + + if(!(fp = fopen(fname, "wb"))) { + fprintf(stderr, "save_bsp: failed to open %s for writing\n", fname); + return -1; + } + + memcpy(hdr.magic, "MBSP", 4); + hdr.num_nodes = count_nodes(bsp->root); + fwrite(&hdr, sizeof hdr, 1, fp); + + save_bsp_tree(bsp->root, fp); + + fclose(fp); + return 0; +} + +int load_bsp(struct bsptree *bsp, const char *fname) +{ + FILE *fp; + struct bspfile_header hdr; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "load_bsp: failed to open %s\n", fname); + return -1; + } + + if(fread(&hdr, sizeof hdr, 1, fp) < 1) { + fprintf(stderr, "load_bsp: %s: failed to read header\n", fname); + fclose(fp); + return -1; + } + if(memcmp(hdr.magic, "MBSP", 4) != 0) { + fprintf(stderr, "load_bsp: %s: invalid magic\n", fname); + fclose(fp); + return -1; + } + bsp->root = load_bsp_tree(fp); + + fclose(fp); + return 0; +} + +int bsp_add_poly(struct bsptree *bsp, struct g3d_vertex *v, int vnum) +{ + struct bsppoly poly, *tmp; + + if(!bsp->soup && !(bsp->soup = dynarr_alloc(0, sizeof *bsp->soup))) { + fprintf(stderr, "bsp_add_poly: failed to create polygon soup dynamic array\n"); + return -1; + } + + if(init_poly(&poly, v, vnum) == -1) { + return -1; + } + + if(!(tmp = dynarr_push(bsp->soup, &poly))) { + fprintf(stderr, "bsp_add_poly: failed to reallocate polygon soup\n"); + free(poly.verts); + return -1; + } + bsp->soup = tmp; + + return 0; +} + +int bsp_add_mesh(struct bsptree *bsp, struct g3d_mesh *m) +{ + int i, j, nfaces; + struct g3d_vertex v[4]; + struct g3d_vertex *vptr = m->varr; + uint16_t *iptr = m->iarr; + + nfaces = m->iarr ? m->icount / m->prim : m->vcount / m->prim; + + for(i=0; iprim; j++) { + if(m->iarr) { + v[j] = m->varr[*iptr++]; + } else { + v[j] = *vptr++; + } + } + if(bsp_add_poly(bsp, v, m->prim) == -1) { + return -1; + } + } + return 0; +} + +int bsp_build(struct bsptree *bsp) +{ + assert(bsp->soup); + assert(!dynarr_empty(bsp->soup)); + + free_tree(bsp->root); + + printf("building BSP tree with %d source polygons ...\n", dynarr_size(bsp->soup)); + if(!(bsp->root = build_tree(bsp->soup, dynarr_size(bsp->soup)))) { + fprintf(stderr, "bsp_build failed\n"); + return -1; + } + printf("done. created a tree with %d nodes\n", count_nodes(bsp->root)); + + /* build_tree has called dynarr_free on bsp->soup */ + bsp->soup = 0; + + return 0; +} + +void draw_bsp(struct bsptree *bsp, float view_x, float view_y, float view_z) +{ + vec3_t vdir; + + assert(bsp->root); + + vdir.x = view_x; + vdir.y = view_y; + vdir.z = view_z; + draw_bsp_tree(bsp->root, &vdir); +} + +static int count_nodes(struct bspnode *n) +{ + if(!n) return 0; + return count_nodes(n->front) + count_nodes(n->back) + 1; +} + +static void free_tree(struct bspnode *n) +{ + if(n) { + free_tree(n->front); + free_tree(n->back); + free(n->poly.verts); + free(n); + } +} + + +static int init_poly(struct bsppoly *poly, struct g3d_vertex *v, int vnum) +{ + vec3_t va, vb, norm; + + if(init_poly_noplane(poly, v, vnum) == -1) { + return -1; + } + + va.x = v[1].x - v[0].x; + va.y = v[1].y - v[0].y; + va.z = v[1].z - v[0].z; + vb.x = v[2].x - v[0].x; + vb.y = v[2].y - v[0].y; + vb.z = v[2].z - v[0].z; + norm = v3_cross(va, vb); + v3_normalize(&norm); + + poly->plane.x = v[0].x; + poly->plane.y = v[0].y; + poly->plane.z = v[0].z; + poly->plane.nx = norm.x; + poly->plane.ny = norm.y; + poly->plane.nz = norm.z; + return 0; +} + +static int init_poly_noplane(struct bsppoly *poly, struct g3d_vertex *v, int vnum) +{ + if(!(poly->verts = malloc(vnum * sizeof *poly->verts))) { + fprintf(stderr, "failed to allocate BSP polygon\n"); + return -1; + } + poly->vcount = vnum; + memcpy(poly->verts, v, vnum * sizeof *poly->verts); + return 0; +} + +static int choose_poly(struct bsppoly *polyarr, int num_polys) +{ + int i, j, best, best_splits; + + if(num_polys <= 1) { + return 0; + } + + best = -1; + best_splits = INT_MAX; + + for(i=0; i %d splits\n", num_polys, best_splits); + + return best; +} + +static struct bspnode *build_tree(struct bsppoly *polyarr, int num_polys) +{ + int i, pidx, vnum; + struct bsppoly *sp, *tmp; + struct bsppoly *front_polys, *back_polys; + struct bspnode *node; + + struct bspnode *nres; + int clipres, clipres_neg, clipped_vnum, clipped_neg_vnum, max_clipped_vnum = 0; + struct g3d_vertex *v, *clipped = 0, *clipped_neg = 0; + struct cplane negplane; + + if((pidx = choose_poly(polyarr, num_polys)) == -1) { + return 0; + } + sp = polyarr + pidx; + + negplane.x = sp->plane.x; + negplane.y = sp->plane.y; + negplane.z = sp->plane.z; + negplane.nx = -sp->plane.nx; + negplane.ny = -sp->plane.ny; + negplane.nz = -sp->plane.nz; + + if(!(front_polys = dynarr_alloc(0, sizeof *front_polys)) || + !(back_polys = dynarr_alloc(0, sizeof *back_polys))) { + fprintf(stderr, "build_tree: failed to allocate front/back polygon arrays\n"); + dynarr_free(front_polys); + return 0; + } + + for(i=0; i max_clipped_vnum) { + /* resize clipped polygon buffers if necessary */ + max_clipped_vnum = vnum * 2; + if(!(v = realloc(clipped, max_clipped_vnum * sizeof *clipped))) { + fprintf(stderr, "build_tree: failed to reallocate clipped polygon buffer\n"); + goto fail; + } + clipped = v; + if(!(v = realloc(clipped_neg, max_clipped_vnum * sizeof *clipped))) { + fprintf(stderr, "build_tree: failed to reallocate clipped polygon buffer\n"); + goto fail; + } + clipped_neg = v; + } + + v = polyarr[i].verts; + + clipres = clip_poly(clipped, &clipped_vnum, v, vnum, &sp->plane); + clipres_neg = clip_poly(clipped_neg, &clipped_neg_vnum, v, vnum, &negplane); + + /* detect edge cases where due to floating point imprecision, clipping + * by the positive plane clips the polygon, but clipping by the negative + * plane doesn't. If that happens, consider the polygon completely on + * the side indicated by -clipres_neg + */ + if(clipres == 0 && clipres_neg != 0) { + clipres = -clipres_neg; + } + + if(clipres > 0) { + /* polygon completely in the positive subspace */ + if(!(tmp = dynarr_push(front_polys, polyarr + i))) { + fprintf(stderr, "build_tree: failed to reallocate polygon array\n"); + goto fail; + } + front_polys = tmp; + + } else if(clipres < 0) { + /* polygon completely in the negative subspace */ + if(!(tmp = dynarr_push(back_polys, polyarr + i))) { + fprintf(stderr, "build_tree: failed to reallocate polygon array\n"); + goto fail; + } + back_polys = tmp; + + } else { + /* polygon is straddling the plane */ + struct bsppoly poly; + poly.plane = polyarr[i].plane; + + if(init_poly_noplane(&poly, clipped, clipped_vnum) == -1) { + goto fail; + } + if(!(tmp = dynarr_push(front_polys, &poly))) { + fprintf(stderr, "build_tree: failed to reallocate polygon array\n"); + free(poly.verts); + goto fail; + } + front_polys = tmp; + + if(init_poly_noplane(&poly, clipped_neg, clipped_neg_vnum) == -1) { + goto fail; + } + if(!(tmp = dynarr_push(back_polys, &poly))) { + fprintf(stderr, "build_tree: failed to reallocate polygon array\n"); + free(poly.verts); + goto fail; + } + back_polys = tmp; + + /* we allocated new sub-polygons, so we need to free the original vertex array */ + free(polyarr[i].verts); + } + } + + if(!(node = malloc(sizeof *node))) { + fprintf(stderr, "build_tree: failed to allocate new BSP node\n"); + goto fail; + } + node->poly = *sp; + node->front = node->back = 0; + + if(dynarr_size(front_polys)) { + if(!(node->front = build_tree(front_polys, dynarr_size(front_polys)))) { + goto fail; + } + } + if(dynarr_size(back_polys)) { + if(!(node->back = build_tree(back_polys, dynarr_size(back_polys)))) { + goto fail; + } + } + + free(clipped); + free(clipped_neg); + + /* we no longer need the original polygon array */ + dynarr_free(polyarr); + + return node; + +fail: + free(clipped); + free(clipped_neg); + + for(i=0; ipoly; + + dot = vdir->x * p->plane.nx + vdir->y * p->plane.ny + vdir->z * p->plane.nz; + if(dot >= 0.0f) { + draw_bsp_tree(n->front, vdir); +#ifdef DRAW_NGONS + g3d_draw_indexed(p->vcount, p->verts, p->vcount, 0, 0); +#else + debug_draw_poly(p->verts, p->vcount); +#endif + draw_bsp_tree(n->back, vdir); + } else { + draw_bsp_tree(n->back, vdir); +#ifdef DRAW_NGONS + g3d_draw_indexed(p->vcount, p->verts, p->vcount, 0, 0); +#else + debug_draw_poly(p->verts, p->vcount); +#endif + draw_bsp_tree(n->front, vdir); + } +} + +static void save_bsp_tree(struct bspnode *n, FILE *fp) +{ + /* TODO */ +} + +static struct bspnode *load_bsp_tree(FILE *fp) +{ + return 0; /* TODO */ +} diff --git a/src/bsptree.h b/src/bsptree.h new file mode 100644 index 0000000..2839ab0 --- /dev/null +++ b/src/bsptree.h @@ -0,0 +1,37 @@ +#ifndef BSPMESH_H_ +#define BSPMESH_H_ + +#include "mesh.h" +#include "vmath.h" +#include "polyclip.h" + +struct bsppoly { + struct cplane plane; + int vcount; + struct g3d_vertex *verts; +}; + +struct bspnode { + struct bsppoly poly; + struct bspnode *front, *back; +}; + +struct bsptree { + struct bspnode *root; + struct bsppoly *soup; /* dynarr: see dynarr.h */ +}; + +int init_bsp(struct bsptree *bsp); +void destroy_bsp(struct bsptree *bsp); + +int save_bsp(struct bsptree *bsp, const char *fname); +int load_bsp(struct bsptree *bsp, const char *fname); + +int bsp_add_poly(struct bsptree *bsp, struct g3d_vertex *v, int vnum); +int bsp_add_mesh(struct bsptree *bsp, struct g3d_mesh *m); + +int bsp_build(struct bsptree *bsp); + +void draw_bsp(struct bsptree *bsp, float view_x, float view_y, float view_z); + +#endif /* BSPMESH_H_ */ diff --git a/src/dos/main.c b/src/dos/main.c index 018ed51..0b3747e 100644 --- a/src/dos/main.c +++ b/src/dos/main.c @@ -10,21 +10,16 @@ #include "timer.h" #include "gfx.h" #include "vmath.h" -#include "sball.h" #include "cfgopt.h" #include "logger.h" #include "tinyfps.h" #undef NOKEYB -static int handle_sball_event(sball_event *ev); -static void recalc_sball_matrix(float *xform); - static int quit; static int use_mouse; static long fbsize; -static int use_sball; static vec3_t pos = {0, 0, 0}; static quat_t rot = {0, 0, 0, 1}; @@ -61,10 +56,6 @@ int main(int argc, char **argv) return 1; } - if(opt.sball && sball_init() == 0) { - use_sball = 1; - } - reset_timer(); while(!quit) { @@ -83,14 +74,6 @@ int main(int argc, char **argv) if(use_mouse) { mouse_bmask = read_mouse(&mouse_x, &mouse_y); } - if(use_sball && sball_pending()) { - sball_event ev; - printf("got sball event\n"); - while(sball_getevent(&ev)) { - handle_sball_event(&ev); - } - recalc_sball_matrix(sball_matrix); - } time_msec = get_msec(); demo_draw(); @@ -102,9 +85,6 @@ break_evloop: #ifndef NOKEYB kb_shutdown(); #endif - if(use_sball) { - sball_shutdown(); - } return 0; } @@ -130,50 +110,3 @@ void swap_buffers(void *pixels) } } } - - -#define TX(ev) ((ev)->motion.motion[0]) -#define TY(ev) ((ev)->motion.motion[1]) -#define TZ(ev) ((ev)->motion.motion[2]) -#define RX(ev) ((ev)->motion.motion[3]) -#define RY(ev) ((ev)->motion.motion[4]) -#define RZ(ev) ((ev)->motion.motion[5]) - -static int handle_sball_event(sball_event *ev) -{ - switch(ev->type) { - case SBALL_EV_MOTION: - if(RX(ev) | RY(ev) | RZ(ev)) { - float rx = (float)RX(ev); - float ry = (float)RY(ev); - float rz = (float)RZ(ev); - float axis_len = sqrt(rx * rx + ry * ry + rz * rz); - if(axis_len > 0.0) { - rot = quat_rotate(rot, axis_len * 0.001, -rx / axis_len, - -ry / axis_len, -rz / axis_len); - } - } - - pos.x += TX(ev) * 0.001; - pos.y += TY(ev) * 0.001; - pos.z += TZ(ev) * 0.001; - break; - - case SBALL_EV_BUTTON: - if(ev->button.pressed) { - pos = v3_cons(0, 0, 0); - rot = quat_cons(1, 0, 0, 0); - } - break; - } - - return 0; -} - -void recalc_sball_matrix(float *xform) -{ - quat_to_mat(xform, rot); - xform[12] = pos.x; - xform[13] = pos.y; - xform[14] = pos.z; -} diff --git a/src/dos/mouse.asm b/src/dos/mouse.asm new file mode 100644 index 0000000..c82e7fd --- /dev/null +++ b/src/dos/mouse.asm @@ -0,0 +1,193 @@ +; vi:set filetype=nasm: +; foo_ are watcom functions, _foo are djgpp functions + +QUERY equ 0 +SHOW equ 1 +HIDE equ 2 +READ equ 3 +WRITE equ 4 +PIXRATE equ 15 +XLIM equ 7 +YLIM equ 8 + +PUSHA_EAX_OFFS equ 28 +PUSHA_ECX_OFFS equ 20 +PUSHA_EDX_OFFS equ 16 + + section .text + bits 32 + +; int have_mouse(void) + global have_mouse_ + global _have_mouse +have_mouse_: +_have_mouse: + pusha + mov ax, QUERY + int 0x33 + and eax, 0xffff + mov [esp + PUSHA_EAX_OFFS], eax + popa + ret + +; void show_mouse(int show) + global show_mouse_ +show_mouse_: + pusha + test ax, ax + mov ax, HIDE + jz .skip + mov ax, SHOW +.skip: int 0x33 + popa + ret + + global _show_mouse +_show_mouse: + push ebp + mov ebp, esp + push ebx + push esi + push edi + mov ax, [ebp + 8] + test ax, ax + mov ax, HIDE + jz .skip + mov ax, SHOW +.skip: int 0x33 + pop edi + pop esi + pop ebx + pop ebp + ret + +; int read_mouse(int *xp, int *yp) + global read_mouse_ +read_mouse_: + pusha + mov esi, eax ; xp + mov edi, edx ; yp + mov ax, READ + int 0x33 + xor eax, eax + and ecx, 0xffff + and edx, 0xffff + mov ax, bx + mov [esp + PUSHA_EAX_OFFS], eax + mov [esi], ecx + mov [edi], edx + popa + ret + + global _read_mouse +_read_mouse: + push ebp + mov ebp, esp + push ebx + push esi + push edi + mov ax, READ + int 0x33 + xor eax, eax + mov ax, bx + and ecx, 0xffff + mov ebx, [ebp + 8] + mov [ebx], ecx + and edx, 0xffff + mov ebx, [ebp + 12] + mov [ebx], edx + pop edi + pop esi + pop ebx + pop ebp + ret + +; void set_mouse(int x, int y) + global set_mouse_ +set_mouse_: + pusha + mov cx, ax + mov ax, WRITE + int 0x33 + popa + ret + + global _set_mouse +_set_mouse: + push ebp + mov ebp, esp + push ebx + push esi + push edi + mov ax, WRITE + mov cx, [ebp + 8] + mov dx, [ebp + 12] + int 0x33 + pop edi + pop esi + pop ebx + pop ebp + ret + +; void set_mouse_limits(int xmin, int ymin, int xmax, int ymax) + global set_mouse_limits_ +set_mouse_limits_: + pusha + mov cx, ax + mov dx, bx + mov ax, XLIM + int 0x33 + mov ax, YLIM + mov cx, [esp + PUSHA_EDX_OFFS] + mov dx, [esp + PUSHA_ECX_OFFS] + int 0x33 + popa + ret + + global _set_mouse_limits +_set_mouse_limits: + push ebp + mov ebp, esp + push ebx + push esi + push edi + mov ax, XLIM + mov cx, [ebp + 8] + mov dx, [ebp + 16] + int 0x33 + mov ax, YLIM + mov cx, [ebp + 12] + mov dx, [ebp + 20] + int 0x33 + pop edi + pop esi + pop ebx + pop ebp + ret + +; void set_mouse_rate(int xrate, int yrate) + global set_mouse_rate_ +set_mouse_rate_: + pusha + mov cx, ax + mov ax, PIXRATE + int 0x33 + popa + ret + + global _set_mouse_rate +_set_mouse_rate: + push ebp + mov ebp, esp + push ebx + push esi + push edi + mov ax, PIXRATE + mov cx, [esp + 4] + mov dx, [esp + 8] + int 0x33 + pop edi + pop esi + pop ebx + pop ebp + ret diff --git a/src/dos/sball.c b/src/dos/sball.c deleted file mode 100644 index 9b9238a..0000000 --- a/src/dos/sball.c +++ /dev/null @@ -1,448 +0,0 @@ -#include -#include -#include -#include -#include - -#ifdef __WATCOMC__ -#include -#endif - -#ifdef __DJGPP__ -#include -#include -#include -#include -#endif - -#include "sball.h" - -struct motion { - int x, y, z; - int rx, ry, rz; -}; - -#define UART1_BASE 0x3f8 -#define UART2_BASE 0x2f8 -#define UART1_IRQ 4 -#define UART2_IRQ 3 - -#define UART_DATA 0 -#define UART_INTR 1 -#define UART_DIVLO 0 -#define UART_DIVHI 1 -#define UART_FIFO 2 -#define UART_IID 2 -#define UART_LCTL 3 -#define UART_MCTL 4 -#define UART_LSTAT 5 -#define UART_MSTAT 6 - -/* interrupt enable register bits */ -#define INTR_RECV 1 -#define INTR_SEND 2 -#define INTR_LSTAT 4 -#define INTR_DELTA 8 - -/* fifo control register bits */ -#define FIFO_ENABLE 0x01 -#define FIFO_RECV_CLEAR 0x02 -#define FIFO_SEND_CLEAR 0x04 -#define FIFO_DMA 0x08 -#define FIFO_TRIG_4 0x40 -#define FIFO_TRIG_8 0x80 -#define FIFO_TRIG_14 0xc0 - -/* interrupt id register bits */ -#define IID_PENDING 0x01 -#define IID_ID0 0x02 -#define IID_ID1 0x04 -#define IID_ID2 0x08 -#define IID_FIFO_EN 0xc0 - -#define IID_SOURCE 0xe - -#define IID_DELTA 0 -#define IID_SEND 0x2 -#define IID_RECV 0x4 -#define IID_FIFO 0xc -#define IID_STATUS 0x6 - -/* line control register bits */ -#define LCTL_BITS_8 0x03 -#define LCTL_STOP_2 0x04 -#define LCTL_DLAB 0x80 -#define LCTL_8N1 LCTL_BITS_8 -#define LCTL_8N2 (LCTL_BITS_8 | LCTL_STOP_2) - -/* modem control register bits */ -#define MCTL_DTR 0x01 -#define MCTL_RTS 0x02 -#define MCTL_OUT1 0x04 -#define MCTL_OUT2 0x08 -#define MCTL_LOOP 0x10 - -/* line status register bits */ -#define LST_DRDY 0x01 -#define LST_ERR_OVER 0x02 -#define LST_ERR_PARITY 0x04 -#define LST_ERR_FRAME 0x08 -#define LST_ERR_BRK 0x10 -#define LST_TREG_EMPTY 0x20 -#define LST_TIDLE 0x40 -#define LST_ERROR 0x80 - -/* modem status register bits */ -#define MST_DELTA_CTS 0x01 -#define MST_DELTA_DSR 0x02 -#define MST_TERI 0x04 -#define MST_DELTA_DCD 0x08 -#define MST_CTS 0x10 -#define MST_DSR 0x20 -#define MST_RING 0x40 -#define MST_DCD 0x80 - -/* interrupt controller stuff */ -#define PIC1_CMD_PORT 0x20 -#define PIC1_DATA_PORT 0x21 -#define PIC2_CMD_PORT 0xa0 -#define PIC2_DATA_PORT 0xa1 -#define OCW2_EOI 0x20 - -struct packet { - int id; - char data[80]; -}; - -static int init_smouse(void); -static void read_motion(int *m, const char *s); -static void read_keystate(unsigned int *stptr, const char *s); -static void procpkt(struct packet *p); -static void enqueue_event(sball_event *ev); - -#define COM_FMT_8N1 LCTL_8N1 -#define COM_FMT_8N2 LCTL_8N2 -static void com_setup(int port, int baud, unsigned int fmt); -static void com_close(void); - -static void com_putc(char c); -static void com_puts(const char *s); -static int com_getc(void); -static char *com_gets(char *buf, int sz); - -static int com_have_recv(void); -static int com_can_send(void); - -#ifdef __WATCOMC__ -#define INTERRUPT __interrupt __far -static void (INTERRUPT *prev_recv_intr)(void); -#endif - -#ifdef __DJGPP__ -#define INTERRUPT - -static _go32_dpmi_seginfo intr, prev_intr; - -#define outp(port, val) outportb(port, val) -#define inp(port) inportb(port) -#endif - -static void INTERRUPT recv_intr(void); - -static int uart_base, uart_intr_num; - -static struct packet pktbuf[16]; -static int pktbuf_ridx, pktbuf_widx; -#define BNEXT(x) (((x) + 1) & 0xf) -#define BEMPTY(b) (b##_ridx == b##_widx) - -static sball_event evbuf[16]; -static int evbuf_ridx, evbuf_widx; - - -int sball_init(void) -{ - com_setup(0, 9600, COM_FMT_8N2); - init_smouse(); - return 0; -} - -void sball_shutdown(void) -{ - com_close(); -} - -int sball_getdev(void) -{ - return 0; -} - -int sball_pending(void) -{ - _disable(); - while(!BEMPTY(pktbuf)) { - procpkt(pktbuf + pktbuf_ridx); - pktbuf_ridx = BNEXT(pktbuf_ridx); - } - _enable(); - return !BEMPTY(evbuf); -} - -int sball_getevent(sball_event *ev) -{ - _disable(); - while(!BEMPTY(pktbuf)) { - procpkt(pktbuf + pktbuf_ridx); - pktbuf_ridx = BNEXT(pktbuf_ridx); - } - _enable(); - - if(BEMPTY(evbuf)) { - return 0; - } - *ev = evbuf[evbuf_ridx]; - evbuf_ridx = BNEXT(evbuf_ridx); - return 1; -} - -static int init_smouse(void) -{ - /* try repeatedly zeroing the device until we get a response */ - do { - delay(500); - com_puts("z\r"); - } while(BEMPTY(pktbuf)); - - /* then ask for id string and request motion updates */ - com_puts("vQ\r"); - com_puts("m3\r"); - return 0; -} - -static void procpkt(struct packet *p) -{ - static unsigned int bnstate; - int i; - unsigned int st, delta, prev; - sball_event *ev; - - switch(p->id) { - case 'd': - ev = evbuf + evbuf_widx; - read_motion(ev->motion.motion, p->data); - ev->type = SBALL_EV_MOTION; - enqueue_event(ev); - break; - - case 'k': - read_keystate(&st, p->data); - - delta = st ^ bnstate; - prev = bnstate; - bnstate = st; - - for(i=0; i<32; i++) { - if(delta & 1) { - ev = evbuf + evbuf_widx; - ev->type = SBALL_EV_BUTTON; - ev->button.id = i; - ev->button.pressed = st & 1; - ev->button.state = prev ^ (1 << i); - enqueue_event(ev); - } - st >>= 1; - delta >>= 1; - } - break; - - case 'v': - printf("Device: %s\n", p->data); - break; - /* - default: - printf("DBG %c -> %s\n", (char)p->id, p->data); - */ - } -} - -static void enqueue_event(sball_event *ev) -{ - if(ev != evbuf + evbuf_widx) { - evbuf[evbuf_widx] = *ev; - } - - evbuf_widx = BNEXT(evbuf_widx); - if(evbuf_widx == evbuf_ridx) { - fprintf(stderr, "enqueue_event: overflow, dropping oldest\n"); - evbuf_ridx = BNEXT(evbuf_ridx); - } -} - -static void com_setup(int port, int baud, unsigned int fmt) -{ - unsigned char ctl; - unsigned short div = 115200 / baud; - static int base[] = {UART1_BASE, UART2_BASE}; - static int irq[] = {UART1_IRQ, UART2_IRQ}; - - uart_base = base[port]; - uart_intr_num = irq[port] | 8; - - _disable(); -#ifdef __WATCOMC__ - prev_recv_intr = _dos_getvect(uart_intr_num); - _dos_setvect(uart_intr_num, recv_intr); -#endif -#ifdef __DJGPP__ - _go32_dpmi_get_protected_mode_interrupt_vector(uart_intr_num, &prev_intr); - intr.pm_offset = (intptr_t)recv_intr; - intr.pm_selector = _go32_my_cs(); - _go32_dpmi_allocate_iret_wrapper(&intr); - _go32_dpmi_set_protected_mode_interrupt_vector(uart_intr_num, &intr); -#endif - /* unmask the appropriate interrupt */ - outp(PIC1_DATA_PORT, inp(PIC1_DATA_PORT) & ~(1 << irq[port])); - - outp(uart_base + UART_LCTL, LCTL_DLAB); - outp(uart_base + UART_DIVLO, div & 0xff); - outp(uart_base + UART_DIVHI, (div >> 8) & 0xff); - outp(uart_base + UART_LCTL, fmt); /* fmt should be LCTL_8N1, LCTL_8N2 etc */ - outp(uart_base + UART_FIFO, FIFO_ENABLE | FIFO_SEND_CLEAR | FIFO_RECV_CLEAR); - outp(uart_base + UART_MCTL, MCTL_DTR | MCTL_RTS | MCTL_OUT2); - outp(uart_base + UART_INTR, INTR_RECV); - - _enable(); -} - -static void com_close(void) -{ - _disable(); - outp(uart_base + UART_INTR, 0); - outp(uart_base + UART_MCTL, 0); -#ifdef __WATCOMC__ - _dos_setvect(uart_intr_num, prev_recv_intr); -#endif -#ifdef __DJGPP__ - _go32_dpmi_set_protected_mode_interrupt_vector(uart_intr_num, &prev_intr); - _go32_dpmi_free_iret_wrapper(&intr); -#endif - _enable(); -} - -static void com_putc(char c) -{ - while(!com_can_send()); - while((inp(uart_base + UART_MSTAT) & MST_CTS) == 0); - outp(uart_base + UART_DATA, c); -} - -static void com_puts(const char *s) -{ - while(*s) { - com_putc(*s++); - } -} - -static int com_getc(void) -{ - int have; - while(!(have = com_have_recv())); - return inp(uart_base + UART_DATA); -} - -static char *com_gets(char *buf, int sz) -{ - int c; - char *ptr = buf; - - while(sz-- > 1 && (c = com_getc()) != -1) { - if(c == '\r') { - *ptr++ = '\n'; - break; - } - *ptr++ = c; - } - if(c == -1) { - return 0; - } - *ptr = 0; - return buf; -} - -static int com_have_recv(void) -{ - unsigned short stat = inp(uart_base + UART_LSTAT); - if(stat & LST_ERROR) { - fprintf(stderr, "receive error\n"); - abort(); - } - return stat & LST_DRDY; -} - -static int com_can_send(void) -{ - return inp(uart_base + UART_LSTAT) & LST_TREG_EMPTY; -} - -static void INTERRUPT recv_intr() -{ - static char buf[128]; - static char *bptr = buf; - struct packet *pkt; - int idreg, c, datasz; - - while(((idreg = inp(uart_base + UART_IID)) & IID_PENDING) == 0) { - while(com_have_recv()) { - if((c = inp(uart_base + UART_DATA)) == '\r') { - *bptr = 0; - datasz = bptr - buf; - bptr = buf; - - pkt = pktbuf + pktbuf_widx; - pktbuf_widx = BNEXT(pktbuf_widx); - - if(pktbuf_widx == pktbuf_ridx) { - /* we overflowed, drop the oldest packet */ - pktbuf_ridx = BNEXT(pktbuf_ridx); - } - - if(datasz > sizeof pkt->data) { - datasz = sizeof pkt->data; /* truncate */ - } - pkt->id = buf[0]; - memcpy(pkt->data, buf + 1, datasz); - - } else if(bptr - buf < sizeof buf - 1) { - *bptr++ = c; - } - } - } - - outp(PIC1_CMD_PORT, OCW2_EOI); -} - -static void read_motion(int *m, const char *s) -{ - int i; - - for(i=0; i<6; i++) { - long val = ((((long)s[0] & 0xf) << 12) | - (((long)s[1] & 0xf) << 8) | - (((long)s[2] & 0xf) << 4) | - ((long)s[3] & 0xf)) - 32768; - s += 4; - *m++ = (int)val; - } -} - -static void read_keystate(unsigned int *stptr, const char *s) -{ - int i, bit = 0; - unsigned int st = 0; - - for(i=0; i<3; i++) { - st |= ((unsigned int)*s++ & 0xf) << bit; - bit += 4; - } - *stptr = st; -} diff --git a/src/parts/rtxonoff.c b/src/parts/rtxonoff.c index 4c5f35e..0f44854 100644 --- a/src/parts/rtxonoff.c +++ b/src/parts/rtxonoff.c @@ -9,27 +9,33 @@ #include "imago2.h" #include "gfxutil.h" #include "mesh.h" +#include "bsptree.h" static int init(void); static void destroy(void); static void start(long trans_time); static void draw(void); +static void keypress(int key); static struct screen scr = { "rtxonoff", init, destroy, start, 0, - draw + draw, + keypress }; static float cam_theta = -29, cam_phi = 35; -static float cam_dist = 6; +static float cam_dist = 10; + +static int use_bsp = 1; static const char *car_fname[2] = {"data/ldiablo.obj", 0}; static const char *cartex_fname[2] = {"data/ldiablo.png", 0}; static struct g3d_mesh mesh_car[2]; static struct pimage tex_car[2]; +static struct bsptree bsp_car[2]; struct screen *rtxonoff_screen(void) { @@ -45,6 +51,7 @@ static int init(void) if(!(tex_car[i].pixels = img_load_pixels(cartex_fname[i], &tex_car[i].width, &tex_car[i].height, IMG_FMT_RGB24))) { fprintf(stderr, "failed to load car texture: %s\n", cartex_fname[i]); + return -1; } convimg_rgb24_rgb16(tex_car[i].pixels, (unsigned char*)tex_car[i].pixels, tex_car[i].width, tex_car[i].height); @@ -53,6 +60,13 @@ static int init(void) if(load_mesh(&mesh_car[i], car_fname[i]) == -1) { return -1; } + + init_bsp(&bsp_car[i]); + if(bsp_add_mesh(&bsp_car[i], &mesh_car[i]) == -1) { + fprintf(stderr, "failed to construct BSP tree %d\n", i); + return -1; + } + bsp_build(&bsp_car[i]); } } return 0; @@ -60,6 +74,13 @@ static int init(void) static void destroy(void) { + int i; + + for(i=0; i<2; i++) { + free(mesh_car[i].varr); + free(mesh_car[i].iarr); + destroy_bsp(&bsp_car[i]); + } } static void start(long trans_time) @@ -81,6 +102,7 @@ static void update(void) static void draw(void) { int i; + static float vdir[3]; float t = (float)time_msec / 16.0f; update(); @@ -93,16 +115,38 @@ static void draw(void) g3d_rotate(cam_phi, 1, 0, 0); g3d_rotate(cam_theta, 0, 1, 0); + if(use_bsp) { + const float *mat = g3d_get_matrix(G3D_MODELVIEW, 0); + /* transform (0, 0, -1) with transpose(mat3x3) */ + vdir[0] = -mat[2]; + vdir[1] = -mat[6]; + vdir[2] = -mat[10]; + } + g3d_polygon_mode(G3D_TEX_GOURAUD); for(i=0; i 0 ? 0 : 1; } +int check_clip_poly(const struct g3d_vertex *v, int vnum, struct cplane *plane) +{ + int i, nextidx, res; + int edges_clipped = 0; + + for(i=0; i= vnum) nextidx = 0; + res = check_clip_edge(v + i, v + nextidx, plane); + if(res == 0) { + ++edges_clipped; + } + } + return edges_clipped ? 0 : res; +} int clip_frustum(struct g3d_vertex *vout, int *voutnum, const struct g3d_vertex *vin, int vnum, int fplane) @@ -163,6 +180,27 @@ static int clip_edge(struct g3d_vertex *poly, int *vnumptr, return 0; } +/* same as above, but only checks for clipping and classifies the edge */ +static int check_clip_edge(const struct g3d_vertex *v0, + const struct g3d_vertex *v1, const struct cplane *plane) +{ + float pos0[3], pos1[3]; + float d0, d1; + + pos0[0] = v0->x; pos0[1] = v0->y; pos0[2] = v0->z; + pos1[0] = v1->x; pos1[1] = v1->y; pos1[2] = v1->z; + + d0 = distance_signed(pos0, plane); + d1 = distance_signed(pos1, plane); + + if(d0 > 0.0f && d1 > 0.0f) { + return 1; + } + if(d0 < 0.0f && d1 < 0.0f) { + return -1; + } + return 0; +} static float distance_signed(float *pos, const struct cplane *plane) { diff --git a/src/polyclip.h b/src/polyclip.h index 0b460cf..adee29d 100644 --- a/src/polyclip.h +++ b/src/polyclip.h @@ -25,6 +25,12 @@ enum { int clip_poly(struct g3d_vertex *vout, int *voutnum, const struct g3d_vertex *vin, int vnum, struct cplane *plane); +/* only checks if the polygon would be clipped by the plane, and classifies it + * as inside/outside/straddling, without actually producing a clipped polygon. + * return values are the same as clip_poly. + */ +int check_clip_poly(const struct g3d_vertex *v, int vnum, struct cplane *plane); + /* Special-case frustum clipper (might be slightly faster) */ int clip_frustum(struct g3d_vertex *vout, int *voutnum, const struct g3d_vertex *vin, int vnum, int fplane); diff --git a/src/sdl/main.c b/src/sdl/main.c index 3165e31..2bb2d47 100644 --- a/src/sdl/main.c +++ b/src/sdl/main.c @@ -38,7 +38,7 @@ int main(int argc, char **argv) } vmem_front = vmem_back = fb_pixels; - SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE); if(!(fbsurf = SDL_SetVideoMode(xsz, ysz, fb_bpp, sdl_flags))) { fprintf(stderr, "failed to set video mode %dx%d %dbpp\n", fb_width, fb_height, fb_bpp); free(fb_pixels);