+
+static void draw_level_rec(struct bvhnode *bn)
+{
+ int i, j;
+ struct triangle *tri;
+ struct material *curmtl;
+ float color[4] = {0, 0, 0, 1};
+
+ if(bn->faces) {
+ tri = bn->faces;
+ curmtl = tri->mtl;
+
+ glBegin(GL_TRIANGLES);
+ for(i=0; i<bn->num_faces; i++) {
+ if(tri->mtl != curmtl) {
+ glEnd();
+ color[0] = tri->mtl->color.x;
+ color[1] = tri->mtl->color.y;
+ color[2] = tri->mtl->color.z;
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
+ curmtl = tri->mtl;
+ glBegin(GL_TRIANGLES);
+ }
+
+ for(j=0; j<3; j++) {
+ glNormal3fv(&tri->v[j].norm.x);
+ glTexCoord2fv(&tri->v[j].tex.x);
+ glVertex3fv(&tri->v[j].pos.x);
+ }
+ tri++;
+ }
+ glEnd();
+ }
+
+ bn = bn->sub;
+ while(bn) {
+ draw_level_rec(bn);
+ bn = bn->next;
+ }
+}
+
+void draw_level(struct level *lvl)
+{
+ draw_level_rec(lvl->st_root);
+ draw_level_rec(lvl->dyn_root);
+}
+
+static struct material *add_material(struct level *lvl, struct material *mtl)
+{
+ int i, newsz;
+ struct material *tmp;
+
+ for(i=0; i<lvl->num_mtls; i++) {
+ if(memcmp(lvl->mtls + i, mtl, sizeof *mtl) == 0) {
+ return lvl->mtls + i;
+ }
+ }
+
+ if(lvl->num_mtls >= lvl->max_mtls) {
+ newsz = lvl->max_mtls ? lvl->max_mtls * 2 : 16;
+ if(!(tmp = realloc(lvl->mtls, newsz * sizeof *lvl->mtls))) {
+ fprintf(stderr, "add_material: failed to resize materials array to %d\n", newsz);
+ return 0;
+ }
+ lvl->mtls = tmp;
+ lvl->max_mtls = newsz;
+ }
+ lvl->mtls[lvl->num_mtls] = *mtl;
+
+ return lvl->mtls + lvl->num_mtls++;
+}
+
+static int append_polygons(struct bvhnode *bnode, struct triangle *faces, int num_faces, struct material *mtl)
+{
+ int i, j, newsz;
+ struct triangle *tri;
+
+ newsz = bnode->num_faces + num_faces;
+ if(!(tri = realloc(bnode->faces, newsz * sizeof *bnode->faces))) {
+ fprintf(stderr, "append_polygons: failed to resize faces array to %d\n", newsz);
+ return -1;
+ }
+ bnode->faces = tri;
+ tri += bnode->num_faces;
+ bnode->num_faces = newsz;
+
+ for(i=0; i<num_faces; i++) {
+ *tri = *faces++;
+ tri->mtl = mtl;
+
+ for(j=0; j<3; j++) {
+ cgm_vec3 *p = &tri->v[j].pos;
+ if(p->x < bnode->aabb.vmin.x) bnode->aabb.vmin.x = p->x;
+ if(p->x > bnode->aabb.vmax.x) bnode->aabb.vmax.x = p->x;
+ if(p->y < bnode->aabb.vmin.y) bnode->aabb.vmin.y = p->y;
+ if(p->y > bnode->aabb.vmax.y) bnode->aabb.vmax.y = p->y;
+ if(p->z < bnode->aabb.vmin.z) bnode->aabb.vmin.z = p->z;
+ if(p->z > bnode->aabb.vmax.z) bnode->aabb.vmax.z = p->z;
+ }
+ tri++;
+ }
+ return 0;
+}