// tjunc.c #include "bsp5.h" typedef struct wvert_s { vec_t t; struct wvert_s *prev, *next; } wvert_t; typedef struct wedge_s { struct wedge_s *next; vec3_t dir; vec3_t origin; wvert_t head; } wedge_t; int numwedges, numwverts; int tjuncs; int tjuncfaces; #define maxwverts 0x20000 #define maxwedges 0x10000 wvert_t wverts[maxwverts]; wedge_t wedges[maxwedges]; void printface (face_t *f) { int i; for (i=0 ; inumpoints ; i++) printf ("(%5.2f, %5.2f, %5.2f)\n", f->pts[i][0], f->pts[i][1], f->pts[i][2]); } //============================================================================ #define num_hash 1024 wedge_t *wedge_hash[num_hash]; static vec3_t hash_min, hash_scale; static void inithash (vec3_t mins, vec3_t maxs) { vec3_t size; vec_t volume; vec_t scale; int newsize[2]; vectorcopy (mins, hash_min); vectorsubtract (maxs, mins, size); memset (wedge_hash, 0, sizeof(wedge_hash)); volume = size[0]*size[1]; scale = sqrt(volume / num_hash); newsize[0] = size[0] / scale; newsize[1] = size[1] / scale; hash_scale[0] = newsize[0] / size[0]; hash_scale[1] = newsize[1] / size[1]; hash_scale[2] = newsize[1]; } static unsigned hashvec (vec3_t vec) { unsigned h; h = hash_scale[0] * (vec[0] - hash_min[0]) * hash_scale[2] + hash_scale[1] * (vec[1] - hash_min[1]); if ( h >= num_hash) return num_hash - 1; return h; } //============================================================================ void canonicalvector (vec3_t vec) { vectornormalize (vec); if (vec[0] > equal_epsilon) return; else if (vec[0] < -equal_epsilon) { vectorsubtract (vec3_origin, vec, vec); return; } else vec[0] = 0; if (vec[1] > equal_epsilon) return; else if (vec[1] < -equal_epsilon) { vectorsubtract (vec3_origin, vec, vec); return; } else vec[1] = 0; if (vec[2] > equal_epsilon) return; else if (vec[2] < -equal_epsilon) { vectorsubtract (vec3_origin, vec, vec); return; } else vec[2] = 0; error ("canonicalvector: degenerate"); } wedge_t *findedge (vec3_t p1, vec3_t p2, vec_t *t1, vec_t *t2) { vec3_t origin; vec3_t dir; wedge_t *w; vec_t temp; int h; vectorsubtract (p2, p1, dir); canonicalvector (dir); *t1 = dotproduct (p1, dir); *t2 = dotproduct (p2, dir); vectorma (p1, -*t1, dir, origin); if (*t1 > *t2) { temp = *t1; *t1 = *t2; *t2 = temp; } h = hashvec (origin); for (w = wedge_hash[h] ; w ; w=w->next) { temp = w->origin[0] - origin[0]; if (temp < -equal_epsilon || temp > equal_epsilon) continue; temp = w->origin[1] - origin[1]; if (temp < -equal_epsilon || temp > equal_epsilon) continue; temp = w->origin[2] - origin[2]; if (temp < -equal_epsilon || temp > equal_epsilon) continue; temp = w->dir[0] - dir[0]; if (temp < -equal_epsilon || temp > equal_epsilon) continue; temp = w->dir[1] - dir[1]; if (temp < -equal_epsilon || temp > equal_epsilon) continue; temp = w->dir[2] - dir[2]; if (temp < -equal_epsilon || temp > equal_epsilon) continue; return w; } if (numwedges == maxwedges) error ("findedge: numwedges == maxwedges"); w = &wedges[numwedges]; numwedges++; w->next = wedge_hash[h]; wedge_hash[h] = w; vectorcopy (origin, w->origin); vectorcopy (dir, w->dir); w->head.next = w->head.prev = &w->head; w->head.t = 99999; return w; } /* =============== addvert =============== */ #define t_epsilon 0.01 void addvert (wedge_t *w, vec_t t) { wvert_t *v, *newv; v = w->head.next; do { if (fabs(v->t - t) < t_epsilon) return; if (v->t > t) break; v = v->next; } while (1); // insert a new wvert before v if (numwverts == maxwverts) error ("addvert: numwverts == maxwverts"); newv = &wverts[numwverts]; numwverts++; newv->t = t; newv->next = v; newv->prev = v->prev; v->prev->next = newv; v->prev = newv; } /* =============== addedge =============== */ void addedge (vec3_t p1, vec3_t p2) { wedge_t *w; vec_t t1, t2; w = findedge(p1, p2, &t1, &t2); addvert (w, t1); addvert (w, t2); } /* =============== addfaceedges =============== */ void addfaceedges (face_t *f) { int i, j; for (i=0 ; i < f->numpoints ; i++) { j = (i+1)%f->numpoints; addedge (f->pts[i], f->pts[j]); } } //============================================================================ // a specially allocated face that can hold hundreds of edges if needed byte superfacebuf[8192]; face_t *superface = (face_t *)superfacebuf; void fixfaceedges (face_t *f); face_t *newlist; void splitfacefortjunc (face_t *f, face_t *original) { int i; face_t *new, *chain; vec3_t dir, test; vec_t v; int firstcorner, lastcorner; chain = null; do { if (f->numpoints <= maxpoints) { // the face is now small enough without more cutting // so copy it back to the original *original = *f; original->original = chain; original->next = newlist; newlist = original; return; } tjuncfaces++; restart: // find the last corner vectorsubtract (f->pts[f->numpoints-1], f->pts[0], dir); vectornormalize (dir); for (lastcorner=f->numpoints-1 ; lastcorner > 0 ; lastcorner--) { vectorsubtract (f->pts[lastcorner-1], f->pts[lastcorner], test); vectornormalize (test); v = dotproduct (test, dir); if (v < 0.9999 || v > 1.00001) { break; } } // find the first corner vectorsubtract (f->pts[1], f->pts[0], dir); vectornormalize (dir); for (firstcorner=1 ; firstcorner < f->numpoints-1 ; firstcorner++) { vectorsubtract (f->pts[firstcorner+1], f->pts[firstcorner], test); vectornormalize (test); v = dotproduct (test, dir); if (v < 0.9999 || v > 1.00001) { break; } } if (firstcorner+2 >= maxpoints) { // rotate the point winding vectorcopy (f->pts[0], test); for (i=1 ; inumpoints ; i++) { vectorcopy (f->pts[i], f->pts[i-1]); } vectorcopy (test, f->pts[f->numpoints-1]); goto restart; } // cut off as big a piece as possible, less than maxpoints, and not // past lastcorner new = newfacefromface (f); if (f->original) error ("splitfacefortjunc: f->original"); new->original = chain; chain = new; new->next = newlist; newlist = new; if (f->numpoints - firstcorner <= maxpoints) new->numpoints = firstcorner+2; else if (lastcorner+2 < maxpoints && f->numpoints - lastcorner <= maxpoints) new->numpoints = lastcorner+2; else new->numpoints = maxpoints; for (i=0 ; inumpoints ; i++) { vectorcopy (f->pts[i], new->pts[i]); } for (i=new->numpoints-1 ; inumpoints ; i++) { vectorcopy (f->pts[i], f->pts[i-(new->numpoints-2)]); } f->numpoints -= (new->numpoints-2); } while (1); } /* =============== fixfaceedges =============== */ void fixfaceedges (face_t *f) { int i, j, k; wedge_t *w; wvert_t *v; vec_t t1, t2; *superface = *f; restart: for (i=0 ; i < superface->numpoints ; i++) { j = (i+1)%superface->numpoints; w = findedge (superface->pts[i], superface->pts[j], &t1, &t2); for (v=w->head.next ; v->t < t1 + t_epsilon ; v = v->next) { } if (v->t < t2-t_epsilon) { tjuncs++; // insert a new vertex here for (k = superface->numpoints ; k> j ; k--) { vectorcopy (superface->pts[k-1], superface->pts[k]); } vectorma (w->origin, v->t, w->dir, superface->pts[j]); superface->numpoints++; goto restart; } } if (superface->numpoints <= maxpoints) { *f = *superface; f->next = newlist; newlist = f; return; } // the face needs to be split into multiple faces because of too many edges splitfacefortjunc (superface, f); } //============================================================================ void tjunc_find_r (node_t *node) { face_t *f; if (node->planenum == planenum_leaf) return; for (f=node->faces ; f ; f=f->next) addfaceedges (f); tjunc_find_r (node->children[0]); tjunc_find_r (node->children[1]); } void tjunc_fix_r (node_t *node) { face_t *f, *next; if (node->planenum == planenum_leaf) return; newlist = null; for (f=node->faces ; f ; f=next) { next = f->next; fixfaceedges (f); } node->faces = newlist; tjunc_fix_r (node->children[0]); tjunc_fix_r (node->children[1]); } /* =========== tjunc =========== */ void tjunc (node_t *headnode) { vec3_t maxs, mins; int i; qprintf ("---- tjunc ----\n"); if (notjunc) return; // // identify all points on common edges // // origin points won't allways be inside the map, so extend the hash area for (i=0 ; i<3 ; i++) { if ( fabs(brushset->maxs[i]) > fabs(brushset->mins[i]) ) maxs[i] = fabs(brushset->maxs[i]); else maxs[i] = fabs(brushset->mins[i]); } vectorsubtract (vec3_origin, maxs, mins); inithash (mins, maxs); numwedges = numwverts = 0; tjunc_find_r (headnode); qprintf ("%i world edges %i edge points\n", numwedges, numwverts); // // add extra vertexes on edges where needed // tjuncs = tjuncfaces = 0; tjunc_fix_r (headnode); qprintf ("%i edges added by tjunctions\n", tjuncs); qprintf ("%i faces added by tjunctions\n", tjuncfaces); }