home *** CD-ROM | disk | FTP | other *** search
- /*-------------------------------------------------------------------------
- File : brush.c
- Author : John Carmack (id Software) and C. Newham.
- Version : 1.0
- Date : 96/08/29
-
- Description
- -----------
- Creates the brush windings. ie: works out the polygons from the
- planes specified in the MAP file, determines the vertices and
- calculates texture scaling.
-
- Comments
- --------
- freeWindings doesn't free memory as in the original.
- -------------------------------------------------------------------------*/
-
- #include <stdio.h>
- #include <math.h>
- #include "brush.h"
- #include "io.h"
-
-
- /*--------------------------------------
- TextureAxisFromPlane
- --------------------------------------*/
- float TextureAxisFromPlane(plane_t *pln, float *xv, float *yv)
- {
- int bestaxis;
- float dot,best;
- int i;
-
- best = 0;
- bestaxis = 0;
-
- for (i=0 ; i<6 ; i++)
- {
- dot = DotProduct (pln->normal, baseaxis[i*3]);
- if (dot > best)
- {
- best = dot;
- bestaxis = i;
- }
- }
-
- VectorCopy (baseaxis[bestaxis*3+1], xv);
- VectorCopy (baseaxis[bestaxis*3+2], yv);
-
- return lightaxis[bestaxis>>1];
- }
-
-
-
- /*--------------------------------------
- CheckFace
-
- Note: this will not catch 0 area polygons
- --------------------------------------*/
- void CheckFace (face_t *f)
- {
- int i, j;
- float *p1, *p2;
- float d, edgedist;
- vec3_t dir, edgenormal;
- winding_t *w;
-
- w = f->w;
- if (!w)
- Error (0, "CheckFace: no winding\n");
-
- if (w->numpoints < 3)
- Error (0,"CheckFace: points < 3\n");
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- p1 = w->points[i];
-
- for (j=0 ; j<3 ; j++)
- if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
- Error (0,"CheckFace: outside BOGUS_RANGE\n");
-
- j = i+1 == w->numpoints ? 0 : i+1;
-
- /* check the point is on the face plane */
- d = DotProduct (p1, f->plane.normal) - f->plane.dist;
-
- if (d < -ON_EPSILON || d > ON_EPSILON)
- Error (0,"CheckFace: point off plane\n");
-
- /* check the edge isn't degenerate */
- p2 = w->points[j];
- VectorSubtract (p2, p1, dir);
-
- if (VectorLength (dir) < ON_EPSILON)
- Error (0,"CheckFace: degenerate edge\n");
-
- CrossProduct (f->plane.normal, dir, edgenormal);
- VectorNormalize (edgenormal);
- edgedist = DotProduct (p1, edgenormal);
- edgedist += ON_EPSILON;
-
- /* all other points must be on front side */
- for (j=0 ; j<w->numpoints ; j++)
- {
- if (j == i)
- continue;
- d = DotProduct (w->points[j], edgenormal);
- if (d > edgedist)
- Error (0,"CheckFace: non-convex");
- }
- }
- }
-
-
-
- /*--------------------------------------
- NewWinding
- --------------------------------------*/
- winding_t *NewWinding (int points)
- {
- winding_t *w;
- int size;
-
- if (points > MAX_POINTS_ON_WINDING)
- Error (0,"NewWinding: too many points\n");
-
- size = (int)((winding_t *)0)->points[points];
- w = (winding_t *)malloc (size);
- memset (w, 0, size);
-
- return w;
- }
-
-
- /*--------------------------------------
- --------------------------------------*/
- void freeWindings()
- {
- int i;
-
- for (i=0 ; i<MAX_FACES ; i++)
- if (faces[i].w)
- {
- /*free (faces[i].w); MARK*/
- faces[i].w = NULL;
- }
- }
-
-
-
- /*--------------------------------------
- BasePolyForPlane
-
- There has GOT to be a better way of doing this...
- --------------------------------------*/
- winding_t *BasePolyForPlane (face_t *f)
- {
- int i, x;
- float max, v;
- vec3_t org, vright, vup;
- vec3_t xaxis, yaxis;
- winding_t *w;
- texturedef_t *td;
- plane_t *p;
- float ang, sinv, cosv;
- float s, t, ns, nt;
-
- p = &f->plane;
-
- /* find the major axis */
-
- max = -BOGUS_RANGE;
- x = -1;
- for (i=0 ; i<3; i++)
- {
- v = fabs(p->normal[i]);
- if (v > max)
- {
- x = i;
- max = v;
- }
- }
-
- if (x==-1)
- Error (0,"BasePolyForPlane: no axis found");
-
- VectorCopy (vec3_origin, vup);
- switch (x)
- {
- case 0:
- case 1:
- vup[2] = 1;
- break;
- case 2:
- vup[0] = 1;
- break;
- }
-
- v = DotProduct (vup, p->normal);
-
- VectorMA (vup, -v, p->normal, vup);
- VectorNormalize (vup);
-
- VectorScale (p->normal, p->dist, org);
-
- CrossProduct (vup, p->normal, vright);
-
- VectorScale (vup, 8192, vup);
- VectorScale (vright, 8192, vright);
-
- /* project a really big axis aligned box onto the plane */
- w = NewWinding (4);
- w->numpoints = 4;
-
- VectorSubtract (org, vright, w->points[0]);
- VectorAdd (w->points[0], vup, w->points[0]);
-
- VectorAdd (org, vright, w->points[1]);
- VectorAdd (w->points[1], vup, w->points[1]);
-
- VectorAdd (org, vright, w->points[2]);
- VectorSubtract (w->points[2], vup, w->points[2]);
-
- VectorSubtract (org, vright, w->points[3]);
- VectorSubtract (w->points[3], vup, w->points[3]);
-
-
- /* set texture values */
- f->light = TextureAxisFromPlane(&f->plane, xaxis, yaxis);
- td = &f->texture;
-
- /* rotate axis */
- ang = td->rotate / 180 * M_PI;
- sinv = sin(ang);
- cosv = cos(ang);
-
- if (!td->scale[0])
- td->scale[0] = 1;
-
- if (!td->scale[1])
- td->scale[1] = 1;
-
- for (i=0 ; i<4 ; i++)
- {
- s = DotProduct (w->points[i], xaxis);
- t = DotProduct (w->points[i], yaxis);
-
- ns = cosv * s - sinv * t;
- nt = sinv * s + cosv * t;
-
- w->points[i][3] = ns/td->scale[0] + td->shift[0];
- w->points[i][4] = nt/td->scale[1] + td->shift[1];
- }
-
-
- return w;
- }
-
-
-
-
- /*--------------------------------------
- ClipWinding
-
- Clips the winding to the plane, returning the new winding on the positive side
- Frees the input winding.
- --------------------------------------*/
- winding_t *ClipWinding (winding_t *in, plane_t *split)
- {
- float dists[MAX_POINTS_ON_WINDING];
- int sides[MAX_POINTS_ON_WINDING];
- int counts[3];
- float dot;
- int i, j;
- float *p1, *p2, *mid;
- winding_t *neww;
- int maxpts;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- /* determine sides for each point */
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > ON_EPSILON)
- sides[i] = SIDE_FRONT;
- else if (dot < -ON_EPSILON)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- if (!counts[0] && !counts[1])
- return in;
-
- if (!counts[0])
- {
- free (in);
- return NULL;
- }
-
- if (!counts[1])
- return in;
-
- maxpts = in->numpoints+4; /* can't use counts[0]+2 because */
- /* of fp groupin */
- neww = NewWinding (maxpts);
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
-
- mid = neww->points[neww->numpoints];
-
- if (sides[i] == SIDE_FRONT || sides[i] == SIDE_ON)
- {
- VectorCopy (p1, mid);
- mid[3] = p1[3];
- mid[4] = p1[4];
- neww->numpoints++;
- if (sides[i] == SIDE_ON)
- continue;
- mid = neww->points[neww->numpoints];
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- /* generate a split point */
- if (i == in->numpoints - 1)
- p2 = in->points[0];
- else
- p2 = p1 + 5;
-
- neww->numpoints++;
-
- dot = dists[i] / (dists[i]-dists[i+1]);
-
- for (j=0 ; j<3 ; j++)
- {
- /* avoid round off error when possible */
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
-
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- mid[3] = p1[3] + dot*(p2[3]-p1[3]);
- mid[4] = p1[4] + dot*(p2[4]-p1[4]);
- }
-
- if (neww->numpoints > maxpts)
- Error (0,"ClipWinding: points exceeded estimate");
-
- /* free the original winding */
- free (in);
-
- return neww;
- }
-
-
- /*--------------------------------------
- calcWindings
-
- recalc the faces and mins / maxs from the
- planes.
-
- If a face has a NULL winding, it is an
- overconstraining plane and can be removed.
- --------------------------------------*/
- void calcWindings()
- {
- int i,j, k;
- float v;
- face_t *f;
- winding_t *w;
- plane_t plane;
- vec3_t t1, t2, t3;
- int useplane[MAX_FACES];
-
- bmins[0] = bmins[1] = bmins[2] = 99999;
- bmaxs[0] = bmaxs[1] = bmaxs[2] = -99999;
- invalid = FALSE;
-
- freeWindings();
-
- for (i=0 ; i<MAX_FACES ; i++)
- {
- f = &faces[i];
-
- /* calc a plane from the points */
- for (j=0 ; j<3 ; j++)
- {
- t1[j] = f->planepts[0][j] - f->planepts[1][j];
- t2[j] = f->planepts[2][j] - f->planepts[1][j];
- t3[j] = f->planepts[1][j];
- }
-
- CrossProduct(t1,t2, f->plane.normal);
-
- if (VectorCompare (f->plane.normal, vec3_origin))
- {
- useplane[i] = FALSE;
- break;
- }
-
- VectorNormalize (f->plane.normal);
- f->plane.dist = DotProduct (t3, f->plane.normal);
-
- /* if the plane duplicates another plane, ignore it
- (assume it is a brush being edited that will be fixed) */
-
- useplane[i] = TRUE;
-
- for (j=0 ; j< i ; j++)
- {
- if ( f->plane.normal[0] == faces[j].plane.normal[0]
- && f->plane.normal[1] == faces[j].plane.normal[1]
- && f->plane.normal[2] == faces[j].plane.normal[2]
- && f->plane.dist == faces[j].plane.dist )
- {
- printf("Warning: duplicate plane detected!\n");
- useplane[i] = FALSE;
- break;
- }
- }
- }
-
- for (i=0 ; i<numfaces ; i++)
- {
- if (!useplane[i])
- continue; /* duplicate plane */
-
- f = &faces[i];
-
- w = BasePolyForPlane (f);
-
- for (j=0 ; j<numfaces && w ; j++)
- {
- if (j == i)
- continue;
-
- /* flip the plane, because we want to keep the back side */
-
- VectorSubtract (vec3_origin, faces[j].plane.normal, plane.normal);
- plane.dist = -faces[j].plane.dist;
-
- w = ClipWinding (w, &plane);
- }
-
- f->w = w;
-
- if (w)
- {
- CheckFace (f);
- for (j=0 ; j<w->numpoints ; j++)
- {
- for (k=0 ; k<3 ; k++)
- {
- v = w->points[j][k];
-
- if (fabs(v - rint(v)) < FP_EPSILON)
- v = w->points[j][k] = rint(v);
- if (v < bmins[k])
- bmins[k] = v;
- if (v > bmaxs[k])
- bmaxs[k] = v;
- }
- }
- }
- }
-
- if (bmins[0] == 99999)
- {
- invalid = TRUE;
- VectorCopy (vec3_origin, bmins);
- VectorCopy (vec3_origin, bmaxs);
-
- }
-
- }
-
-
-
- /*--------------------------------------
- Read a Brush
- --------------------------------------*/
- void ReadBrush (char *token, int *scriptline, char *dat, int *location)
- {
- face_t *f;
- int i,j;
-
- printf (">>read brush\n");
-
- f = faces;
- numfaces = 0;
-
- while (1)
- {
- if (!GetToken(TRUE, token, scriptline, dat, location))
- break;
- if (!strcmp (token, "}") )
- break;
-
- for (i=0 ; i<3 ; i++)
- {
- if (i != 0)
- /* get opening bracket of the vertex def */
- GetToken(TRUE, token, scriptline, dat, location);
- if (strcmp (token, "(") )
- Error (*scriptline, "parsing map file - missing (\n");
-
- for (j=0 ; j<3 ; j++)
- {
- /* get the 3 values that define a vertex */
- GetToken(FALSE, token, scriptline, dat, location);
- f->planepts[i][j] = atoi(token);
- }
-
- /* get the closing bracket of the vertex def */
- GetToken(FALSE, token, scriptline, dat, location);
- if (strcmp (token, ")") )
- Error (*scriptline, "parsing map file - missing )");
- }
-
- GetToken(FALSE, token, scriptline, dat, location);
- strcpy (f->texture.texture, token);
- GetToken(FALSE, token, scriptline, dat, location);
- f->texture.shift[0] = atof(token);
- GetToken(FALSE, token, scriptline, dat, location);
- f->texture.shift[1] = atof(token);
- GetToken(FALSE, token, scriptline, dat, location);
- f->texture.rotate = atof(token);
- GetToken(FALSE, token, scriptline, dat, location);
- f->texture.scale[0] = atof(token);
- GetToken(FALSE, token, scriptline, dat, location);
- f->texture.scale[1] = atof(token);
-
-
- f++;
- numfaces++;
- }
-
- calcWindings();
-
- }
-
-
-