123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569 |
- /*
- ===========================================================================
- Copyright (C) 1997-2006 Id Software, Inc.
- This file is part of Quake 2 Tools source code.
- Quake 2 Tools source code is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
- Quake 2 Tools source code is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Quake 2 Tools source code; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ===========================================================================
- */
- #include <assert.h>
- #include "qe3.h"
- #define MAX_POINTS_ON_WINDING 64
- face_t *Face_Alloc( void );
- void Face_Free( face_t *f );
- winding_t *NewWinding (int points);
- void FreeWinding (winding_t *w);
- winding_t *Winding_Clone( winding_t *w );
- winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon);
- void PrintWinding (winding_t *w)
- {
- int i;
- printf ("-------------\n");
- for (i=0 ; i<w->numpoints ; i++)
- printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
- , w->points[i][1], w->points[i][2]);
- }
- void PrintPlane (plane_t *p)
- {
- printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1],
- p->normal[2], p->dist);
- }
- void PrintVector (vec3_t v)
- {
- printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]);
- }
- face_t *Face_Clone (face_t *f)
- {
- face_t *n;
- n = Face_Alloc();
- n->texdef = f->texdef;
- memcpy (n->planepts, f->planepts, sizeof(n->planepts));
- // all other fields are derived, and will be set by Brush_Build
- return n;
- }
- //============================================================================
- #define BOGUS_RANGE 18000
- /*
- ==================
- NewWinding
- ==================
- */
- winding_t *NewWinding (int points)
- {
- winding_t *w;
- int size;
- if (points > MAX_POINTS_ON_WINDING)
- Error ("NewWinding: %i points", points);
- size = (int)((winding_t *)0)->points[points];
- w = malloc (size);
- memset (w, 0, size);
- w->maxpoints = points;
- return w;
- }
- void FreeWinding (winding_t *w)
- {
- free (w);
- }
- /*
- ==================
- Winding_Clone
- ==================
- */
- winding_t *Winding_Clone(winding_t *w)
- {
- int size;
- winding_t *c;
- size = (int)((winding_t *)0)->points[w->numpoints];
- c = qmalloc (size);
- memcpy (c, w, size);
- return c;
- }
- /*
- ==================
- ClipWinding
- Clips the winding to the plane, returning the new winding on the positive side
- Frees the input winding.
- If keepon is true, an exactly on-plane winding will be saved, otherwise
- it will be clipped away.
- ==================
- */
- winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon)
- {
- vec_t dists[MAX_POINTS_ON_WINDING];
- int sides[MAX_POINTS_ON_WINDING];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t 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 (keepon && !counts[0] && !counts[1])
- return in;
- if (!counts[0])
- {
- FreeWinding (in);
- return NULL;
- }
- if (!counts[1])
- return in;
- maxpts = in->numpoints+4; // can't use counts[0]+2 because
- // of fp grouping errors
- neww = NewWinding (maxpts);
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- continue;
- }
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
- // generate a split point
- p2 = in->points[(i+1)%in->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;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
- if (neww->numpoints > maxpts)
- Error ("ClipWinding: points exceeded estimate");
- // free the original winding
- FreeWinding (in);
- return neww;
- }
- /*
- =============================================================================
- TEXTURE COORDINATES
- =============================================================================
- */
- /*
- ==================
- textureAxisFromPlane
- ==================
- */
- vec3_t baseaxis[18] =
- {
- {0,0,1}, {1,0,0}, {0,-1,0}, // floor
- {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
- {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
- {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
- {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
- {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
- };
- void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t 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);
- }
- float lightaxis[3] = {0.6, 0.8, 1.0};
- /*
- ================
- SetShadeForPlane
- Light different planes differently to
- improve recognition
- ================
- */
- float SetShadeForPlane (plane_t *p)
- {
- int i;
- float f;
- // axial plane
- for (i=0 ; i<3 ; i++)
- if (fabs(p->normal[i]) > 0.9)
- {
- f = lightaxis[i];
- return f;
- }
- // between two axial planes
- for (i=0 ; i<3 ; i++)
- if (fabs(p->normal[i]) < 0.1)
- {
- f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
- return f;
- }
- // other
- f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
- return f;
- }
- vec3_t vecs[2];
- float shift[2];
- /*
- ================
- BeginTexturingFace
- ================
- */
- void BeginTexturingFace (brush_t *b, face_t *f, qtexture_t *q)
- {
- vec3_t pvecs[2];
- int sv, tv;
- float ang, sinv, cosv;
- float ns, nt;
- int i,j;
- float shade;
- // get natural texture axis
- TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
- // set shading for face
- shade = SetShadeForPlane (&f->plane);
- if (camera.draw_mode == cd_texture && !b->owner->eclass->fixedsize)
- {
- f->d_color[0] =
- f->d_color[1] =
- f->d_color[2] = shade;
- }
- else
- {
- f->d_color[0] = shade*q->color[0];
- f->d_color[1] = shade*q->color[1];
- f->d_color[2] = shade*q->color[2];
- }
- if (camera.draw_mode != cd_texture)
- return;
- if (!f->texdef.scale[0])
- f->texdef.scale[0] = 1;
- if (!f->texdef.scale[1])
- f->texdef.scale[1] = 1;
- // rotate axis
- if (f->texdef.rotate == 0)
- { sinv = 0 ; cosv = 1; }
- else if (f->texdef.rotate == 90)
- { sinv = 1 ; cosv = 0; }
- else if (f->texdef.rotate == 180)
- { sinv = 0 ; cosv = -1; }
- else if (f->texdef.rotate == 270)
- { sinv = -1 ; cosv = 0; }
- else
- {
- ang = f->texdef.rotate / 180 * Q_PI;
- sinv = sin(ang);
- cosv = cos(ang);
- }
- if (pvecs[0][0])
- sv = 0;
- else if (pvecs[0][1])
- sv = 1;
- else
- sv = 2;
- if (pvecs[1][0])
- tv = 0;
- else if (pvecs[1][1])
- tv = 1;
- else
- tv = 2;
- for (i=0 ; i<2 ; i++)
- {
- ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
- nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
- vecs[i][sv] = ns;
- vecs[i][tv] = nt;
- }
- for (i=0 ; i<2 ; i++)
- for (j=0 ; j<3 ; j++)
- vecs[i][j] = vecs[i][j] / f->texdef.scale[i];
- }
- void _EmitTextureCoordinates (vec3_t v, qtexture_t *q)
- {
- float s, t;
- s = DotProduct (v, vecs[0]);
- t = DotProduct (v, vecs[1]);
- s += shift[0];
- t += shift[1];
- s /= q->width;
- t /= q->height;
- glTexCoord2f (s, t);
- }
- void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
- {
- float s, t, ns, nt;
- float ang, sinv, cosv;
- vec3_t vecs[2];
- texdef_t *td;
- // get natural texture axis
- TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]);
- td = &f->texdef;
- ang = td->rotate / 180 * Q_PI;
- sinv = sin(ang);
- cosv = cos(ang);
- if (!td->scale[0])
- td->scale[0] = 1;
- if (!td->scale[1])
- td->scale[1] = 1;
- s = DotProduct(xyzst, vecs[0]);
- t = DotProduct(xyzst, vecs[1]);
- ns = cosv * s - sinv * t;
- nt = sinv * s + cosv * t;
- s = ns/td->scale[0] + td->shift[0];
- t = nt/td->scale[1] + td->shift[1];
- // gl scales everything from 0 to 1
- s /= q->width;
- t /= q->height;
- xyzst[3] = s;
- xyzst[4] = t;
- }
- //==========================================================================
- /*
- =================
- BasePolyForPlane
- =================
- */
- winding_t *BasePolyForPlane (plane_t *p)
- {
- int i, x;
- vec_t max, v;
- vec3_t org, vright, vup;
- winding_t *w;
- // 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 ("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);
- 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]);
- w->numpoints = 4;
- return w;
- }
- void Brush_MakeFacePlanes (brush_t *b)
- {
- face_t *f;
- int j;
- vec3_t t1, t2, t3;
- for (f=b->brush_faces ; f ; f=f->next)
- {
- // convert to a vector / dist plane
- 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))
- printf ("WARNING: brush plane with no normal\n");
- VectorNormalize (f->plane.normal);
- f->plane.dist = DotProduct (t3, f->plane.normal);
- }
- }
- void DrawBrushEntityName (brush_t *b)
- {
- char *name;
- float a, s, c;
- vec3_t mid;
- int i;
- if (!b->owner)
- return; // during contruction
- if (b->owner == world_entity)
- return;
- if (b != b->owner->brushes.onext)
- return; // not key brush
- // draw the angle pointer
- a = FloatForKey (b->owner, "angle");
- if (a)
- {
- s = sin (a/180*Q_PI);
- c = cos (a/180*Q_PI);
- for (i=0 ; i<3 ; i++)
- mid[i] = (b->mins[i] + b->maxs[i])*0.5;
- glBegin (GL_LINE_STRIP);
- glVertex3fv (mid);
- mid[0] += c*8;
- mid[1] += s*8;
- glVertex3fv (mid);
- mid[0] -= c*4;
- mid[1] -= s*4;
- mid[0] -= s*4;
- mid[1] += c*4;
- glVertex3fv (mid);
- mid[0] += c*4;
- mid[1] += s*4;
- mid[0] += s*4;
- mid[1] -= c*4;
- glVertex3fv (mid);
- mid[0] -= c*4;
- mid[1] -= s*4;
- mid[0] += s*4;
- mid[1] -= c*4;
- glVertex3fv (mid);
- glEnd ();
- }
- if (!g_qeglobals.d_savedinfo.show_names)
- return;
- name = ValueForKey (b->owner, "classname");
- glRasterPos2f (b->mins[0]+4, b->mins[1]+4);
- glCallLists (strlen(name), GL_UNSIGNED_BYTE, name);
- }
- /*
- =================
- MakeFaceWinding
- returns the visible polygon on a face
- =================
- */
- winding_t *MakeFaceWinding (brush_t *b, face_t *face)
- {
- winding_t *w;
- face_t *clip;
- plane_t plane;
- qboolean past;
- // get a poly that covers an effectively infinite area
- w = BasePolyForPlane (&face->plane);
- // chop the poly by all of the other faces
- past = false;
- for (clip = b->brush_faces ; clip && w ; clip=clip->next)
- {
- if (clip == face)
- {
- past = true;
- continue;
- }
- if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
- && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
- { // identical plane, use the later one
- if (past)
- {
- free (w);
- return NULL;
- }
- continue;
- }
- // flip the plane, because we want to keep the back side
- VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
- plane.dist = -clip->plane.dist;
- w = ClipWinding (w, &plane, false);
- if (!w)
- return w;
- }
- if (w->numpoints < 3)
- {
- free(w);
- w = NULL;
- }
- if (!w)
- printf ("unused plane\n");
- return w;
- }
- void Brush_SnapPlanepts (brush_t *b)
- {
- int i, j;
- face_t *f;
- for (f=b->brush_faces ; f; f=f->next)
- for (i=0 ; i<3 ; i++)
- for (j=0 ; j<3 ; j++)
- f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
- }
- /*
- ** Brush_Build
- **
- ** Builds a brush rendering data and also sets the min/max bounds
- */
- #define ZERO_EPSILON 0.001
- void Brush_Build( brush_t *b )
- {
- // int order;
- // face_t *face;
- // winding_t *w;
- char title[1024];
- if (modified != 1)
- {
- modified = true; // mark the map as changed
- sprintf (title, "%s *", currentmap);
- QE_ConvertDOSToUnixName( title, title );
- Sys_SetTitle (title);
- }
- /*
- ** build the windings and generate the bounding box
- */
- Brush_BuildWindings( b );
- /*
- ** move the points and edges if in select mode
- */
- if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
- SetupVertexSelection ();
- }
- /*
- =================
- Brush_Parse
- The brush is NOT linked to any list
- =================
- */
- brush_t *Brush_Parse (void)
- {
- brush_t *b;
- face_t *f;
- int i,j;
- g_qeglobals.d_parsed_brushes++;
- b = qmalloc(sizeof(brush_t));
- do
- {
- if (!GetToken (true))
- break;
- if (!strcmp (token, "}") )
- break;
- f = Face_Alloc();
- // add the brush to the end of the chain, so
- // loading and saving a map doesn't reverse the order
- f->next = NULL;
- if (!b->brush_faces)
- {
- b->brush_faces = f;
- }
- else
- {
- face_t *scan;
- for (scan=b->brush_faces ; scan->next ; scan=scan->next)
- ;
- scan->next = f;
- }
- // read the three point plane definition
- for (i=0 ; i<3 ; i++)
- {
- if (i != 0)
- GetToken (true);
- if (strcmp (token, "(") )
- Error ("parsing brush");
- for (j=0 ; j<3 ; j++)
- {
- GetToken (false);
- f->planepts[i][j] = atoi(token);
- }
- GetToken (false);
- if (strcmp (token, ")") )
- Error ("parsing brush");
- }
- // read the texturedef
- GetToken (false);
- strcpy(f->texdef.name, token);
- GetToken (false);
- f->texdef.shift[0] = atoi(token);
- GetToken (false);
- f->texdef.shift[1] = atoi(token);
- GetToken (false);
- f->texdef.rotate = atoi(token);
- GetToken (false);
- f->texdef.scale[0] = atof(token);
- GetToken (false);
- f->texdef.scale[1] = atof(token);
- // the flags and value field aren't necessarily present
- f->d_texture = Texture_ForName( f->texdef.name );
- f->texdef.flags = f->d_texture->flags;
- f->texdef.value = f->d_texture->value;
- f->texdef.contents = f->d_texture->contents;
- if (TokenAvailable ())
- {
- GetToken (false);
- f->texdef.contents = atoi(token);
- GetToken (false);
- f->texdef.flags = atoi(token);
- GetToken (false);
- f->texdef.value = atoi(token);
- }
- } while (1);
- return b;
- }
- /*
- =================
- Brush_Write
- =================
- */
- void Brush_Write (brush_t *b, FILE *f)
- {
- face_t *fa;
- char *pname;
- int i;
- fprintf (f, "{\n");
- for (fa=b->brush_faces ; fa ; fa=fa->next)
- {
- for (i=0 ; i<3 ; i++)
- fprintf (f, "( %i %i %i ) ", (int)fa->planepts[i][0]
- , (int)fa->planepts[i][1], (int)fa->planepts[i][2]);
- pname = fa->texdef.name;
- if (pname[0] == 0)
- pname = "unnamed";
- fprintf (f, "%s %i %i %i ", pname,
- (int)fa->texdef.shift[0], (int)fa->texdef.shift[1],
- (int)fa->texdef.rotate);
- if (fa->texdef.scale[0] == (int)fa->texdef.scale[0])
- fprintf (f, "%i ", (int)fa->texdef.scale[0]);
- else
- fprintf (f, "%f ", (float)fa->texdef.scale[0]);
- if (fa->texdef.scale[1] == (int)fa->texdef.scale[1])
- fprintf (f, "%i", (int)fa->texdef.scale[1]);
- else
- fprintf (f, "%f", (float)fa->texdef.scale[1]);
- // only output flags and value if not default
- if (fa->texdef.value != fa->d_texture->value
- || fa->texdef.flags != fa->d_texture->flags
- || fa->texdef.contents != fa->d_texture->contents)
- {
- fprintf (f, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value);
- }
- fprintf (f, "\n");
- }
- fprintf (f, "}\n");
- }
- /*
- =============
- Brush_Create
- Create non-textured blocks for entities
- The brush is NOT linked to any list
- =============
- */
- brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
- {
- int i, j;
- vec3_t pts[4][2];
- face_t *f;
- brush_t *b;
- for (i=0 ; i<3 ; i++)
- if (maxs[i] < mins[i])
- Error ("Brush_InitSolid: backwards");
- b = qmalloc (sizeof(brush_t));
- pts[0][0][0] = mins[0];
- pts[0][0][1] = mins[1];
- pts[1][0][0] = mins[0];
- pts[1][0][1] = maxs[1];
- pts[2][0][0] = maxs[0];
- pts[2][0][1] = maxs[1];
- pts[3][0][0] = maxs[0];
- pts[3][0][1] = mins[1];
- for (i=0 ; i<4 ; i++)
- {
- pts[i][0][2] = mins[2];
- pts[i][1][0] = pts[i][0][0];
- pts[i][1][1] = pts[i][0][1];
- pts[i][1][2] = maxs[2];
- }
- for (i=0 ; i<4 ; i++)
- {
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
- j = (i+1)%4;
- VectorCopy (pts[j][1], f->planepts[0]);
- VectorCopy (pts[i][1], f->planepts[1]);
- VectorCopy (pts[i][0], f->planepts[2]);
- }
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
- VectorCopy (pts[0][1], f->planepts[0]);
- VectorCopy (pts[1][1], f->planepts[1]);
- VectorCopy (pts[2][1], f->planepts[2]);
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
- VectorCopy (pts[2][0], f->planepts[0]);
- VectorCopy (pts[1][0], f->planepts[1]);
- VectorCopy (pts[0][0], f->planepts[2]);
- return b;
- }
- /*
- =============
- Brush_MakeSided
- Makes the current brushhave the given number of 2d sides
- =============
- */
- void Brush_MakeSided (int sides)
- {
- int i;
- vec3_t mins, maxs;
- brush_t *b;
- texdef_t *texdef;
- face_t *f;
- vec3_t mid;
- float width;
- float sv, cv;
- if (sides < 3)
- {
- Sys_Status ("Bad sides number", 0);
- return;
- }
- if (!QE_SingleBrush ())
- {
- Sys_Status ("Must have a single brush selected", 0 );
- return;
- }
- b = selected_brushes.next;
- VectorCopy (b->mins, mins);
- VectorCopy (b->maxs, maxs);
- texdef = &g_qeglobals.d_texturewin.texdef;
- Brush_Free (b);
- // find center of brush
- width = 8;
- for (i=0 ; i<2 ; i++)
- {
- mid[i] = (maxs[i] + mins[i])*0.5;
- if (maxs[i] - mins[i] > width)
- width = maxs[i] - mins[i];
- }
- width /= 2;
- b = qmalloc (sizeof(brush_t));
- // create top face
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
- f->planepts[2][0] = mins[0];f->planepts[2][1] = mins[1];f->planepts[2][2] = maxs[2];
- f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = maxs[2];
- f->planepts[0][0] = maxs[0];f->planepts[0][1] = maxs[1];f->planepts[0][2] = maxs[2];
- // create bottom face
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
- f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
- f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
- f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
- for (i=0 ; i<sides ; i++)
- {
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
- sv = sin (i*3.14159265*2/sides);
- cv = cos (i*3.14159265*2/sides);
- f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
- f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
- f->planepts[0][2] = mins[2];
- f->planepts[1][0] = f->planepts[0][0];
- f->planepts[1][1] = f->planepts[0][1];
- f->planepts[1][2] = maxs[2];
- f->planepts[2][0] = floor(f->planepts[0][0] - width*sv + 0.5);
- f->planepts[2][1] = floor(f->planepts[0][1] + width*cv + 0.5);
- f->planepts[2][2] = maxs[2];
- }
- Brush_AddToList (b, &selected_brushes);
- Entity_LinkBrush (world_entity, b);
- Brush_Build( b );
- Sys_UpdateWindows (W_ALL);
- }
- /*
- =============
- Brush_Free
- Frees the brush with all of its faces and display list.
- Unlinks the brush from whichever chain it is in.
- Decrements the owner entity's brushcount.
- Removes owner entity if this was the last brush
- unless owner is the world.
- =============
- */
- void Brush_Free (brush_t *b)
- {
- face_t *f, *next;
- // free faces
- for (f=b->brush_faces ; f ; f=next)
- {
- next = f->next;
- Face_Free( f );
- }
- /*
- for ( i = 0; i < b->d_numwindings; i++ )
- {
- if ( b->d_windings[i] )
- {
- FreeWinding( b->d_windings[i] );
- b->d_windings[i] = 0;
- }
- }
- */
- // unlink from active/selected list
- if (b->next)
- Brush_RemoveFromList (b);
- // unlink from entity list
- if (b->onext)
- Entity_UnlinkBrush (b);
- free (b);
- }
- /*
- ============
- Brush_Move
- ============
- */
- void Brush_Move (brush_t *b, vec3_t move)
- {
- int i;
- face_t *f;
- for (f=b->brush_faces ; f ; f=f->next)
- for (i=0 ; i<3 ; i++)
- VectorAdd (f->planepts[i], move, f->planepts[i]);
- Brush_Build( b );
- }
- /*
- ============
- Brush_Clone
- Does NOT add the new brush to any lists
- ============
- */
- brush_t *Brush_Clone (brush_t *b)
- {
- brush_t *n;
- face_t *f, *nf;
- n = qmalloc(sizeof(brush_t));
- n->owner = b->owner;
- for (f=b->brush_faces ; f ; f=f->next)
- {
- nf = Face_Clone( f );
- nf->next = n->brush_faces;
- n->brush_faces = nf;
- }
- return n;
- }
- /*
- ==============
- Brush_Ray
- Itersects a ray with a brush
- Returns the face hit and the distance along the ray the intersection occured at
- Returns NULL and 0 if not hit at all
- ==============
- */
- face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist)
- {
- face_t *f, *firstface;
- vec3_t p1, p2;
- float frac, d1, d2;
- int i;
- VectorCopy (origin, p1);
- for (i=0 ; i<3 ; i++)
- p2[i] = p1[i] + dir[i]*16384;
- for (f=b->brush_faces ; f ; f=f->next)
- {
- d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
- d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
- if (d1 >= 0 && d2 >= 0)
- {
- *dist = 0;
- return NULL; // ray is on front side of face
- }
- if (d1 <=0 && d2 <= 0)
- continue;
- // clip the ray to the plane
- frac = d1 / (d1 - d2);
- if (d1 > 0)
- {
- firstface = f;
- for (i=0 ; i<3 ; i++)
- p1[i] = p1[i] + frac *(p2[i] - p1[i]);
- }
- else
- {
- for (i=0 ; i<3 ; i++)
- p2[i] = p1[i] + frac *(p2[i] - p1[i]);
- }
- }
- // find distance p1 is along dir
- VectorSubtract (p1, origin, p1);
- d1 = DotProduct (p1, dir);
- *dist = d1;
- return firstface;
- }
- void Brush_AddToList (brush_t *b, brush_t *list)
- {
- if (b->next || b->prev)
- Error ("Brush_RemoveFromList: allready linked");
- b->next = list->next;
- list->next->prev = b;
- list->next = b;
- b->prev = list;
- }
- void Brush_RemoveFromList (brush_t *b)
- {
- if (!b->next || !b->prev)
- Error ("Brush_RemoveFromList: not linked");
- b->next->prev = b->prev;
- b->prev->next = b->next;
- b->next = b->prev = NULL;
- }
- void Brush_SetTexture (brush_t *b, texdef_t *texdef)
- {
- face_t *f;
- for (f=b->brush_faces ; f ; f=f->next)
- f->texdef = *texdef;
- Brush_Build( b );
- }
- qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
- {
- float d1, d2, fr;
- int i;
- float *v;
- d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
- d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
- if (d1 >= 0 && d2 >= 0)
- return false; // totally outside
- if (d1 <= 0 && d2 <= 0)
- return true; // totally inside
- fr = d1 / (d1 - d2);
- if (d1 > 0)
- v = p1;
- else
- v = p2;
- for (i=0 ; i<3 ; i++)
- v[i] = p1[i] + fr*(p2[i] - p1[i]);
- return true;
- }
- int AddPlanept (float *f)
- {
- int i;
- for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
- if (g_qeglobals.d_move_points[i] == f)
- return 0;
- g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
- return 1;
- }
- /*
- ==============
- Brush_SelectFaceForDragging
- Adds the faces planepts to move_points, and
- rotates and adds the planepts of adjacent face if shear is set
- ==============
- */
- void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
- {
- int i;
- face_t *f2;
- winding_t *w;
- float d;
- brush_t *b2;
- int c;
- if (b->owner->eclass->fixedsize)
- return;
- c = 0;
- for (i=0 ; i<3 ; i++)
- c += AddPlanept (f->planepts[i]);
- if (c == 0)
- return; // allready completely added
- // select all points on this plane in all brushes the selection
- for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
- {
- if (b2 == b)
- continue;
- for (f2=b2->brush_faces ; f2 ; f2=f2->next)
- {
- for (i=0 ; i<3 ; i++)
- if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
- -f->plane.dist) > ON_EPSILON)
- break;
- if (i==3)
- { // move this face as well
- Brush_SelectFaceForDragging (b2, f2, shear);
- break;
- }
- }
- }
- // if shearing, take all the planes adjacent to
- // selected faces and rotate their points so the
- // edge clipped by a selcted face has two of the points
- if (!shear)
- return;
- for (f2=b->brush_faces ; f2 ; f2=f2->next)
- {
- if (f2 == f)
- continue;
- w = MakeFaceWinding (b, f2);
- if (!w)
- continue;
- // any points on f will become new control points
- for (i=0 ; i<w->numpoints ; i++)
- {
- d = DotProduct (w->points[i], f->plane.normal)
- - f->plane.dist;
- if (d > -ON_EPSILON && d < ON_EPSILON)
- break;
- }
- //
- // if none of the points were on the plane,
- // leave it alone
- //
- if (i != w->numpoints)
- {
- if (i == 0)
- { // see if the first clockwise point was the
- // last point on the winding
- d = DotProduct (w->points[w->numpoints-1]
- , f->plane.normal) - f->plane.dist;
- if (d > -ON_EPSILON && d < ON_EPSILON)
- i = w->numpoints - 1;
- }
- AddPlanept (f2->planepts[0]);
- VectorCopy (w->points[i], f2->planepts[0]);
- if (++i == w->numpoints)
- i = 0;
- // see if the next point is also on the plane
- d = DotProduct (w->points[i]
- , f->plane.normal) - f->plane.dist;
- if (d > -ON_EPSILON && d < ON_EPSILON)
- AddPlanept (f2->planepts[1]);
- VectorCopy (w->points[i], f2->planepts[1]);
- if (++i == w->numpoints)
- i = 0;
- // the third point is never on the plane
- VectorCopy (w->points[i], f2->planepts[2]);
- }
- free(w);
- }
- }
- /*
- ==============
- Brush_SideSelect
- The mouse click did not hit the brush, so grab one or more side
- planes for dragging
- ==============
- */
- void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
- , qboolean shear)
- {
- face_t *f, *f2;
- vec3_t p1, p2;
- for (f=b->brush_faces ; f ; f=f->next)
- {
- VectorCopy (origin, p1);
- VectorMA (origin, 16384, dir, p2);
- for (f2=b->brush_faces ; f2 ; f2=f2->next)
- {
- if (f2 == f)
- continue;
- ClipLineToFace (p1, p2, f2);
- }
- if (f2)
- continue;
- if (VectorCompare (p1, origin))
- continue;
- if (ClipLineToFace (p1, p2, f))
- continue;
- Brush_SelectFaceForDragging (b, f, shear);
- }
- }
- void Brush_BuildWindings( brush_t *b )
- {
- winding_t *w;
- face_t *face;
- vec_t v;
- Brush_SnapPlanepts( b );
- // clear the mins/maxs bounds
- b->mins[0] = b->mins[1] = b->mins[2] = 99999;
- b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
- Brush_MakeFacePlanes (b);
- face = b->brush_faces;
- for ( ; face ; face=face->next)
- {
- int i, j;
- w = face->face_winding = MakeFaceWinding (b, face);
- face->d_texture = Texture_ForName( face->texdef.name );
- if (!w)
- {
- continue;
- }
- for (i=0 ; i<w->numpoints ; i++)
- {
- // add to bounding box
- for (j=0 ; j<3 ; j++)
- {
- v = w->points[i][j];
- if (v > b->maxs[j])
- b->maxs[j] = v;
- if (v < b->mins[j])
- b->mins[j] = v;
- }
- }
- // setup s and t vectors, and set color
- BeginTexturingFace( b, face, face->d_texture);
- for (i=0 ; i<w->numpoints ; i++)
- {
- EmitTextureCoordinates( w->points[i], face->d_texture, face);
- }
- }
- }
- /*
- ==================
- Brush_RemoveEmptyFaces
- Frees any overconstraining faces
- ==================
- */
- void Brush_RemoveEmptyFaces ( brush_t *b )
- {
- face_t *f, *next;
- f = b->brush_faces;
- b->brush_faces = NULL;
- for ( ; f ; f=next)
- {
- next = f->next;
- if (!f->face_winding)
- Face_Free (f);
- else
- {
- f->next = b->brush_faces;
- b->brush_faces = f;
- }
- }
- }
- void Brush_Draw( brush_t *b )
- {
- face_t *face;
- int i, order;
- qtexture_t *prev = 0;
- winding_t *w;
- if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
- glDisable (GL_TEXTURE_2D);
- // guarantee the texture will be set first
- prev = NULL;
- for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
- {
- w = face->face_winding;
- if (!w)
- continue; // freed face
- if ( face->d_texture != prev && camera.draw_mode == cd_texture)
- {
- // set the texture for this face
- prev = face->d_texture;
- glBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
- }
- glColor3fv( face->d_color );
- // draw the polygon
- glBegin(GL_POLYGON);
- for (i=0 ; i<w->numpoints ; i++)
- {
- if (camera.draw_mode == cd_texture)
- glTexCoord2fv( &w->points[i][3] );
- glVertex3fv(w->points[i]);
- }
- glEnd();
- }
- if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
- glEnable (GL_TEXTURE_2D);
- glBindTexture( GL_TEXTURE_2D, 0 );
- }
- void Face_Draw( face_t *f )
- {
- int i;
- if ( f->face_winding == 0 )
- return;
- glBegin( GL_POLYGON );
- for ( i = 0 ; i < f->face_winding->numpoints; i++)
- glVertex3fv( f->face_winding->points[i] );
- glEnd();
- }
- void Brush_DrawXY( brush_t *b )
- {
- face_t *face;
- int order;
- winding_t *w;
- int i;
- for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
- {
- // only draw up facing polygons
- if (face->plane.normal[2] <= 0)
- continue;
- w = face->face_winding;
- if (!w)
- continue;
- // draw the polygon
- glBegin(GL_LINE_LOOP);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3fv(w->points[i]);
- glEnd();
- }
- // optionally add a text label
- if ( g_qeglobals.d_savedinfo.show_names )
- DrawBrushEntityName (b);
- }
- face_t *Face_Alloc( void )
- {
- face_t *f = qmalloc( sizeof( *f ) );
- return f;
- }
- void Face_Free( face_t *f )
- {
- assert( f != 0 );
- if ( f->face_winding )
- free( f->face_winding ), f->face_winding = 0;
- free( f );
- }
|