5 #if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__)
17 struct bspfile_header {
22 static int count_nodes(struct bspnode *n);
23 static void free_tree(struct bspnode *n);
25 static struct bspnode *new_node(struct g3d_vertex *v, int vnum);
26 static struct bspnode *add_poly_tree(struct bspnode *n, struct g3d_vertex *v, int vnum);
27 static void draw_bsp_tree(struct bspnode *n, const vec3_t *vdir);
29 static void save_bsp_tree(struct bspnode *n, FILE *fp);
30 static struct bspnode *load_bsp_tree(FILE *fp);
32 int init_bsp(struct bsptree *bsp)
38 void destroy_bsp(struct bsptree *bsp)
43 int save_bsp(struct bsptree *bsp, const char *fname)
46 struct bspfile_header hdr;
48 if(!(fp = fopen(fname, "wb"))) {
49 fprintf(stderr, "save_bsp: failed to open %s for writing\n", fname);
53 memcpy(hdr.magic, "MBSP", 4);
54 hdr.num_nodes = count_nodes(bsp->root);
55 fwrite(&hdr, sizeof hdr, 1, fp);
57 save_bsp_tree(bsp->root, fp);
63 int load_bsp(struct bsptree *bsp, const char *fname)
66 struct bspfile_header hdr;
68 if(!(fp = fopen(fname, "rb"))) {
69 fprintf(stderr, "load_bsp: failed to open %s\n", fname);
73 if(fread(&hdr, sizeof hdr, 1, fp) < 1) {
74 fprintf(stderr, "load_bsp: %s: failed to read header\n", fname);
78 if(memcmp(hdr.magic, "MBSP", 4) != 0) {
79 fprintf(stderr, "load_bsp: %s: invalid magic\n", fname);
83 bsp->root = load_bsp_tree(fp);
89 int bsp_add_poly(struct bsptree *bsp, struct g3d_vertex *v, int vnum)
94 if(!(n = add_poly_tree(bsp->root, v, vnum))) {
95 fprintf(stderr, "bsp_add_poly: failed to add polygon\n");
102 int bsp_add_mesh(struct bsptree *bsp, struct g3d_mesh *m)
105 struct g3d_vertex v[4];
106 struct g3d_vertex *vptr = m->varr;
107 uint16_t *iptr = m->iarr;
109 nfaces = m->iarr ? m->icount / m->prim : m->vcount / m->prim;
111 for(i=0; i<nfaces; i++) {
112 for(j=0; j<m->prim; j++) {
114 v[j] = m->varr[*iptr++];
119 if(bsp_add_poly(bsp, v, m->prim) == -1) {
126 void draw_bsp(struct bsptree *bsp, float view_x, float view_y, float view_z)
132 draw_bsp_tree(bsp->root, &vdir);
135 static int count_nodes(struct bspnode *n)
138 return count_nodes(n->front) + count_nodes(n->back) + 1;
141 static void free_tree(struct bspnode *n)
151 static struct bspnode *new_node(struct g3d_vertex *v, int vnum)
156 if(!(n = malloc(sizeof *n)) || !(n->verts = malloc(vnum * sizeof *n->verts))) {
157 fprintf(stderr, "failed to allocate BSP tree node\n");
161 va.x = v[1].x - v[0].x;
162 va.y = v[1].y - v[0].y;
163 va.z = v[1].z - v[0].z;
164 vb.x = v[2].x - v[0].x;
165 vb.y = v[2].y - v[0].y;
166 vb.z = v[2].z - v[0].z;
167 norm = v3_cross(va, vb);
173 n->plane.nx = norm.x;
174 n->plane.ny = norm.y;
175 n->plane.nz = norm.z;
178 memcpy(n->verts, v, vnum * sizeof *n->verts);
180 n->front = n->back = 0;
184 static struct bspnode *add_poly_tree(struct bspnode *n, struct g3d_vertex *v, int vnum)
186 struct bspnode *nres;
187 int clipres, clipres_neg, clipped_vnum, clipped_neg_vnum;
188 struct g3d_vertex *clipped, *clipped_neg;
189 struct cplane negplane;
194 return new_node(v, vnum);
197 negplane.x = n->plane.x;
198 negplane.y = n->plane.y;
199 negplane.z = n->plane.z;
200 negplane.nx = -n->plane.nx;
201 negplane.ny = -n->plane.ny;
202 negplane.nz = -n->plane.nz;
204 clipped = alloca((vnum * 2) * sizeof *clipped);
205 clipped_neg = alloca((vnum * 2) * sizeof *clipped_neg);
207 clipres = clip_poly(clipped, &clipped_vnum, v, vnum, &n->plane);
208 clipres_neg = clip_poly(clipped_neg, &clipped_neg_vnum, v, vnum, &negplane);
210 /* detect edge cases where due to floating point imprecision, clipping
211 * by the positive plane clips the polygon, but clipping by the negative
212 * plane doesn't. If that happens, consider the polygon completely on
213 * the side indicated by -clipres_neg
215 if(clipres == 0 && clipres_neg != 0) {
216 clipres = -clipres_neg;
220 /* polygon completely in the positive subspace */
221 if(!(nres = add_poly_tree(n->front, v, vnum))) {
226 } else if(clipres < 0) {
227 /* polygon completely in the negative subspace */
228 if(!(nres = add_poly_tree(n->back, v, vnum))) {
234 /* polygon is straddling the plane */
235 if(!(nres = add_poly_tree(n->front, clipped, clipped_vnum))) {
240 if(!(nres = add_poly_tree(n->back, clipped_neg, clipped_neg_vnum))) {
251 static void debug_draw_poly(struct g3d_vertex *varr, int vcount)
253 int i, nfaces = vcount - 2;
254 int vbuf_size = nfaces * 3;
255 struct g3d_vertex *vbuf = alloca(vbuf_size * sizeof *vbuf);
256 struct g3d_vertex *vptr = varr + 1;
258 for(i=0; i<nfaces; i++) {
259 vbuf[i * 3] = varr[0];
260 vbuf[i * 3 + 1] = *vptr++;
261 vbuf[i * 3 + 2] = *vptr;
264 g3d_draw_indexed(G3D_TRIANGLES, vbuf, vbuf_size, 0, 0);
268 static void draw_bsp_tree(struct bspnode *n, const vec3_t *vdir)
274 dot = vdir->x * n->plane.nx + vdir->y * n->plane.ny + vdir->z * n->plane.nz;
276 draw_bsp_tree(n->front, vdir);
278 g3d_draw_indexed(n->vcount, n->verts, n->vcount, 0, 0);
280 debug_draw_poly(n->verts, n->vcount);
282 draw_bsp_tree(n->back, vdir);
284 draw_bsp_tree(n->back, vdir);
286 g3d_draw_indexed(n->vcount, n->verts, n->vcount, 0, 0);
288 debug_draw_poly(n->verts, n->vcount);
290 draw_bsp_tree(n->front, vdir);
294 static void save_bsp_tree(struct bspnode *n, FILE *fp)
299 static struct bspnode *load_bsp_tree(FILE *fp)