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)
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__)
+#include <malloc.h>
+#else
+#include <alloca.h>
+#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; i<dynarr_size(bsp->soup); 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; i<nfaces; i++) {
+ for(j=0; j<m->prim; 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<num_polys; i++) {
+ struct cplane *plane = &polyarr[i].plane;
+ int num_splits = 0;
+
+#pragma omp parallel for reduction(+:num_splits)
+ for(j=0; j<num_polys; j++) {
+ if(i == j) continue;
+
+ if(check_clip_poly(polyarr[j].verts, polyarr[j].vcount, plane) == 0) {
+ num_splits++;
+ }
+ }
+
+ if(num_splits < best_splits) {
+ best_splits = num_splits;
+ best = i;
+ }
+ }
+
+ //printf("choose_poly(..., %d) -> %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<num_polys; i++) {
+ if(i == pidx) continue;
+
+ vnum = polyarr[i].vcount;
+
+ if(vnum * 2 > 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; i<dynarr_size(front_polys); i++) {
+ free(front_polys[i].verts);
+ }
+ dynarr_free(front_polys);
+
+ for(i=0; i<dynarr_size(back_polys); i++) {
+ free(back_polys[i].verts);
+ }
+ dynarr_free(back_polys);
+
+ return 0;
+}
+
+#undef DRAW_NGONS
+
+#ifndef DRAW_NGONS
+static void debug_draw_poly(struct g3d_vertex *varr, int vcount)
+{
+ int i, nfaces = vcount - 2;
+ int vbuf_size = nfaces * 3;
+ struct g3d_vertex *vbuf = alloca(vbuf_size * sizeof *vbuf);
+ struct g3d_vertex *vptr = varr + 1;
+
+ for(i=0; i<nfaces; i++) {
+ vbuf[i * 3] = varr[0];
+ vbuf[i * 3 + 1] = *vptr++;
+ vbuf[i * 3 + 2] = *vptr;
+ }
+
+ g3d_draw_indexed(G3D_TRIANGLES, vbuf, vbuf_size, 0, 0);
+}
+#endif
+
+static void draw_bsp_tree(struct bspnode *n, const vec3_t *vdir)
+{
+ float dot;
+ struct bsppoly *p;
+
+ if(!n) return;
+
+ p = &n->poly;
+
+ 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 */
+}
--- /dev/null
+#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_ */
#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};
return 1;
}
- if(opt.sball && sball_init() == 0) {
- use_sball = 1;
- }
-
reset_timer();
while(!quit) {
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();
#ifndef NOKEYB
kb_shutdown();
#endif
- if(use_sball) {
- sball_shutdown();
- }
return 0;
}
}
}
}
-
-
-#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;
-}
--- /dev/null
+; 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
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dos.h>
-#include <conio.h>
-
-#ifdef __WATCOMC__
-#include <i86.h>
-#endif
-
-#ifdef __DJGPP__
-#include <stdint.h>
-#include <dpmi.h>
-#include <go32.h>
-#include <pc.h>
-#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;
-}
#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)
{
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);
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;
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)
static void draw(void)
{
int i;
+ static float vdir[3];
float t = (float)time_msec / 16.0f;
update();
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<sizeof mesh_car / sizeof mesh_car[0]; i++) {
if(mesh_car[i].varr) {
g3d_set_texture(tex_car[i].width, tex_car[i].height, tex_car[i].pixels);
- zsort_mesh(&mesh_car[i]);
- draw_mesh(&mesh_car[i]);
+ if(use_bsp) {
+ draw_bsp(&bsp_car[i], vdir[0], vdir[1], vdir[2]);
+ } else {
+ zsort_mesh(&mesh_car[i]);
+ draw_mesh(&mesh_car[i]);
+ }
}
}
swap_buffers(fb_pixels);
}
+
+static void keypress(int key)
+{
+ switch(key) {
+ case 'b':
+ use_bsp = !use_bsp;
+ printf("drawing with %s\n", use_bsp ? "BSP tree" : "z-sorting");
+ break;
+ }
+}
static int clip_edge(struct g3d_vertex *poly, int *vnumptr,
const struct g3d_vertex *v0, const struct g3d_vertex *v1,
const struct cplane *plane);
+static int check_clip_edge(const struct g3d_vertex *v0,
+ const struct g3d_vertex *v1, const struct cplane *plane);
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);
return edges_clipped > 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; i++) {
+ nextidx = i + 1;
+ if(nextidx >= 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)
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)
{
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);
}
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);