brush.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1997-2006 Id Software, Inc.
  4. This file is part of Quake 2 Tools source code.
  5. Quake 2 Tools source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake 2 Tools source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Quake 2 Tools source code; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include <assert.h>
  19. #include "qe3.h"
  20. #define MAX_POINTS_ON_WINDING 64
  21. face_t *Face_Alloc( void );
  22. void Face_Free( face_t *f );
  23. winding_t *NewWinding (int points);
  24. void FreeWinding (winding_t *w);
  25. winding_t *Winding_Clone( winding_t *w );
  26. winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon);
  27. void PrintWinding (winding_t *w)
  28. {
  29. int i;
  30. printf ("-------------\n");
  31. for (i=0 ; i<w->numpoints ; i++)
  32. printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
  33. , w->points[i][1], w->points[i][2]);
  34. }
  35. void PrintPlane (plane_t *p)
  36. {
  37. printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1],
  38. p->normal[2], p->dist);
  39. }
  40. void PrintVector (vec3_t v)
  41. {
  42. printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]);
  43. }
  44. face_t *Face_Clone (face_t *f)
  45. {
  46. face_t *n;
  47. n = Face_Alloc();
  48. n->texdef = f->texdef;
  49. memcpy (n->planepts, f->planepts, sizeof(n->planepts));
  50. // all other fields are derived, and will be set by Brush_Build
  51. return n;
  52. }
  53. //============================================================================
  54. #define BOGUS_RANGE 18000
  55. /*
  56. ==================
  57. NewWinding
  58. ==================
  59. */
  60. winding_t *NewWinding (int points)
  61. {
  62. winding_t *w;
  63. int size;
  64. if (points > MAX_POINTS_ON_WINDING)
  65. Error ("NewWinding: %i points", points);
  66. size = (int)((winding_t *)0)->points[points];
  67. w = malloc (size);
  68. memset (w, 0, size);
  69. w->maxpoints = points;
  70. return w;
  71. }
  72. void FreeWinding (winding_t *w)
  73. {
  74. free (w);
  75. }
  76. /*
  77. ==================
  78. Winding_Clone
  79. ==================
  80. */
  81. winding_t *Winding_Clone(winding_t *w)
  82. {
  83. int size;
  84. winding_t *c;
  85. size = (int)((winding_t *)0)->points[w->numpoints];
  86. c = qmalloc (size);
  87. memcpy (c, w, size);
  88. return c;
  89. }
  90. /*
  91. ==================
  92. ClipWinding
  93. Clips the winding to the plane, returning the new winding on the positive side
  94. Frees the input winding.
  95. If keepon is true, an exactly on-plane winding will be saved, otherwise
  96. it will be clipped away.
  97. ==================
  98. */
  99. winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon)
  100. {
  101. vec_t dists[MAX_POINTS_ON_WINDING];
  102. int sides[MAX_POINTS_ON_WINDING];
  103. int counts[3];
  104. vec_t dot;
  105. int i, j;
  106. vec_t *p1, *p2;
  107. vec3_t mid;
  108. winding_t *neww;
  109. int maxpts;
  110. counts[0] = counts[1] = counts[2] = 0;
  111. // determine sides for each point
  112. for (i=0 ; i<in->numpoints ; i++)
  113. {
  114. dot = DotProduct (in->points[i], split->normal);
  115. dot -= split->dist;
  116. dists[i] = dot;
  117. if (dot > ON_EPSILON)
  118. sides[i] = SIDE_FRONT;
  119. else if (dot < -ON_EPSILON)
  120. sides[i] = SIDE_BACK;
  121. else
  122. {
  123. sides[i] = SIDE_ON;
  124. }
  125. counts[sides[i]]++;
  126. }
  127. sides[i] = sides[0];
  128. dists[i] = dists[0];
  129. if (keepon && !counts[0] && !counts[1])
  130. return in;
  131. if (!counts[0])
  132. {
  133. FreeWinding (in);
  134. return NULL;
  135. }
  136. if (!counts[1])
  137. return in;
  138. maxpts = in->numpoints+4; // can't use counts[0]+2 because
  139. // of fp grouping errors
  140. neww = NewWinding (maxpts);
  141. for (i=0 ; i<in->numpoints ; i++)
  142. {
  143. p1 = in->points[i];
  144. if (sides[i] == SIDE_ON)
  145. {
  146. VectorCopy (p1, neww->points[neww->numpoints]);
  147. neww->numpoints++;
  148. continue;
  149. }
  150. if (sides[i] == SIDE_FRONT)
  151. {
  152. VectorCopy (p1, neww->points[neww->numpoints]);
  153. neww->numpoints++;
  154. }
  155. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  156. continue;
  157. // generate a split point
  158. p2 = in->points[(i+1)%in->numpoints];
  159. dot = dists[i] / (dists[i]-dists[i+1]);
  160. for (j=0 ; j<3 ; j++)
  161. { // avoid round off error when possible
  162. if (split->normal[j] == 1)
  163. mid[j] = split->dist;
  164. else if (split->normal[j] == -1)
  165. mid[j] = -split->dist;
  166. else
  167. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  168. }
  169. VectorCopy (mid, neww->points[neww->numpoints]);
  170. neww->numpoints++;
  171. }
  172. if (neww->numpoints > maxpts)
  173. Error ("ClipWinding: points exceeded estimate");
  174. // free the original winding
  175. FreeWinding (in);
  176. return neww;
  177. }
  178. /*
  179. =============================================================================
  180. TEXTURE COORDINATES
  181. =============================================================================
  182. */
  183. /*
  184. ==================
  185. textureAxisFromPlane
  186. ==================
  187. */
  188. vec3_t baseaxis[18] =
  189. {
  190. {0,0,1}, {1,0,0}, {0,-1,0}, // floor
  191. {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
  192. {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
  193. {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
  194. {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
  195. {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
  196. };
  197. void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
  198. {
  199. int bestaxis;
  200. float dot,best;
  201. int i;
  202. best = 0;
  203. bestaxis = 0;
  204. for (i=0 ; i<6 ; i++)
  205. {
  206. dot = DotProduct (pln->normal, baseaxis[i*3]);
  207. if (dot > best)
  208. {
  209. best = dot;
  210. bestaxis = i;
  211. }
  212. }
  213. VectorCopy (baseaxis[bestaxis*3+1], xv);
  214. VectorCopy (baseaxis[bestaxis*3+2], yv);
  215. }
  216. float lightaxis[3] = {0.6, 0.8, 1.0};
  217. /*
  218. ================
  219. SetShadeForPlane
  220. Light different planes differently to
  221. improve recognition
  222. ================
  223. */
  224. float SetShadeForPlane (plane_t *p)
  225. {
  226. int i;
  227. float f;
  228. // axial plane
  229. for (i=0 ; i<3 ; i++)
  230. if (fabs(p->normal[i]) > 0.9)
  231. {
  232. f = lightaxis[i];
  233. return f;
  234. }
  235. // between two axial planes
  236. for (i=0 ; i<3 ; i++)
  237. if (fabs(p->normal[i]) < 0.1)
  238. {
  239. f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
  240. return f;
  241. }
  242. // other
  243. f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
  244. return f;
  245. }
  246. vec3_t vecs[2];
  247. float shift[2];
  248. /*
  249. ================
  250. BeginTexturingFace
  251. ================
  252. */
  253. void BeginTexturingFace (brush_t *b, face_t *f, qtexture_t *q)
  254. {
  255. vec3_t pvecs[2];
  256. int sv, tv;
  257. float ang, sinv, cosv;
  258. float ns, nt;
  259. int i,j;
  260. float shade;
  261. // get natural texture axis
  262. TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
  263. // set shading for face
  264. shade = SetShadeForPlane (&f->plane);
  265. if (camera.draw_mode == cd_texture && !b->owner->eclass->fixedsize)
  266. {
  267. f->d_color[0] =
  268. f->d_color[1] =
  269. f->d_color[2] = shade;
  270. }
  271. else
  272. {
  273. f->d_color[0] = shade*q->color[0];
  274. f->d_color[1] = shade*q->color[1];
  275. f->d_color[2] = shade*q->color[2];
  276. }
  277. if (camera.draw_mode != cd_texture)
  278. return;
  279. if (!f->texdef.scale[0])
  280. f->texdef.scale[0] = 1;
  281. if (!f->texdef.scale[1])
  282. f->texdef.scale[1] = 1;
  283. // rotate axis
  284. if (f->texdef.rotate == 0)
  285. { sinv = 0 ; cosv = 1; }
  286. else if (f->texdef.rotate == 90)
  287. { sinv = 1 ; cosv = 0; }
  288. else if (f->texdef.rotate == 180)
  289. { sinv = 0 ; cosv = -1; }
  290. else if (f->texdef.rotate == 270)
  291. { sinv = -1 ; cosv = 0; }
  292. else
  293. {
  294. ang = f->texdef.rotate / 180 * Q_PI;
  295. sinv = sin(ang);
  296. cosv = cos(ang);
  297. }
  298. if (pvecs[0][0])
  299. sv = 0;
  300. else if (pvecs[0][1])
  301. sv = 1;
  302. else
  303. sv = 2;
  304. if (pvecs[1][0])
  305. tv = 0;
  306. else if (pvecs[1][1])
  307. tv = 1;
  308. else
  309. tv = 2;
  310. for (i=0 ; i<2 ; i++)
  311. {
  312. ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
  313. nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
  314. vecs[i][sv] = ns;
  315. vecs[i][tv] = nt;
  316. }
  317. for (i=0 ; i<2 ; i++)
  318. for (j=0 ; j<3 ; j++)
  319. vecs[i][j] = vecs[i][j] / f->texdef.scale[i];
  320. }
  321. void _EmitTextureCoordinates (vec3_t v, qtexture_t *q)
  322. {
  323. float s, t;
  324. s = DotProduct (v, vecs[0]);
  325. t = DotProduct (v, vecs[1]);
  326. s += shift[0];
  327. t += shift[1];
  328. s /= q->width;
  329. t /= q->height;
  330. glTexCoord2f (s, t);
  331. }
  332. void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
  333. {
  334. float s, t, ns, nt;
  335. float ang, sinv, cosv;
  336. vec3_t vecs[2];
  337. texdef_t *td;
  338. // get natural texture axis
  339. TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]);
  340. td = &f->texdef;
  341. ang = td->rotate / 180 * Q_PI;
  342. sinv = sin(ang);
  343. cosv = cos(ang);
  344. if (!td->scale[0])
  345. td->scale[0] = 1;
  346. if (!td->scale[1])
  347. td->scale[1] = 1;
  348. s = DotProduct(xyzst, vecs[0]);
  349. t = DotProduct(xyzst, vecs[1]);
  350. ns = cosv * s - sinv * t;
  351. nt = sinv * s + cosv * t;
  352. s = ns/td->scale[0] + td->shift[0];
  353. t = nt/td->scale[1] + td->shift[1];
  354. // gl scales everything from 0 to 1
  355. s /= q->width;
  356. t /= q->height;
  357. xyzst[3] = s;
  358. xyzst[4] = t;
  359. }
  360. //==========================================================================
  361. /*
  362. =================
  363. BasePolyForPlane
  364. =================
  365. */
  366. winding_t *BasePolyForPlane (plane_t *p)
  367. {
  368. int i, x;
  369. vec_t max, v;
  370. vec3_t org, vright, vup;
  371. winding_t *w;
  372. // find the major axis
  373. max = -BOGUS_RANGE;
  374. x = -1;
  375. for (i=0 ; i<3; i++)
  376. {
  377. v = fabs(p->normal[i]);
  378. if (v > max)
  379. {
  380. x = i;
  381. max = v;
  382. }
  383. }
  384. if (x==-1)
  385. Error ("BasePolyForPlane: no axis found");
  386. VectorCopy (vec3_origin, vup);
  387. switch (x)
  388. {
  389. case 0:
  390. case 1:
  391. vup[2] = 1;
  392. break;
  393. case 2:
  394. vup[0] = 1;
  395. break;
  396. }
  397. v = DotProduct (vup, p->normal);
  398. VectorMA (vup, -v, p->normal, vup);
  399. VectorNormalize (vup);
  400. VectorScale (p->normal, p->dist, org);
  401. CrossProduct (vup, p->normal, vright);
  402. VectorScale (vup, 8192, vup);
  403. VectorScale (vright, 8192, vright);
  404. // project a really big axis aligned box onto the plane
  405. w = NewWinding (4);
  406. VectorSubtract (org, vright, w->points[0]);
  407. VectorAdd (w->points[0], vup, w->points[0]);
  408. VectorAdd (org, vright, w->points[1]);
  409. VectorAdd (w->points[1], vup, w->points[1]);
  410. VectorAdd (org, vright, w->points[2]);
  411. VectorSubtract (w->points[2], vup, w->points[2]);
  412. VectorSubtract (org, vright, w->points[3]);
  413. VectorSubtract (w->points[3], vup, w->points[3]);
  414. w->numpoints = 4;
  415. return w;
  416. }
  417. void Brush_MakeFacePlanes (brush_t *b)
  418. {
  419. face_t *f;
  420. int j;
  421. vec3_t t1, t2, t3;
  422. for (f=b->brush_faces ; f ; f=f->next)
  423. {
  424. // convert to a vector / dist plane
  425. for (j=0 ; j<3 ; j++)
  426. {
  427. t1[j] = f->planepts[0][j] - f->planepts[1][j];
  428. t2[j] = f->planepts[2][j] - f->planepts[1][j];
  429. t3[j] = f->planepts[1][j];
  430. }
  431. CrossProduct(t1,t2, f->plane.normal);
  432. if (VectorCompare (f->plane.normal, vec3_origin))
  433. printf ("WARNING: brush plane with no normal\n");
  434. VectorNormalize (f->plane.normal);
  435. f->plane.dist = DotProduct (t3, f->plane.normal);
  436. }
  437. }
  438. void DrawBrushEntityName (brush_t *b)
  439. {
  440. char *name;
  441. float a, s, c;
  442. vec3_t mid;
  443. int i;
  444. if (!b->owner)
  445. return; // during contruction
  446. if (b->owner == world_entity)
  447. return;
  448. if (b != b->owner->brushes.onext)
  449. return; // not key brush
  450. // draw the angle pointer
  451. a = FloatForKey (b->owner, "angle");
  452. if (a)
  453. {
  454. s = sin (a/180*Q_PI);
  455. c = cos (a/180*Q_PI);
  456. for (i=0 ; i<3 ; i++)
  457. mid[i] = (b->mins[i] + b->maxs[i])*0.5;
  458. glBegin (GL_LINE_STRIP);
  459. glVertex3fv (mid);
  460. mid[0] += c*8;
  461. mid[1] += s*8;
  462. glVertex3fv (mid);
  463. mid[0] -= c*4;
  464. mid[1] -= s*4;
  465. mid[0] -= s*4;
  466. mid[1] += c*4;
  467. glVertex3fv (mid);
  468. mid[0] += c*4;
  469. mid[1] += s*4;
  470. mid[0] += s*4;
  471. mid[1] -= c*4;
  472. glVertex3fv (mid);
  473. mid[0] -= c*4;
  474. mid[1] -= s*4;
  475. mid[0] += s*4;
  476. mid[1] -= c*4;
  477. glVertex3fv (mid);
  478. glEnd ();
  479. }
  480. if (!g_qeglobals.d_savedinfo.show_names)
  481. return;
  482. name = ValueForKey (b->owner, "classname");
  483. glRasterPos2f (b->mins[0]+4, b->mins[1]+4);
  484. glCallLists (strlen(name), GL_UNSIGNED_BYTE, name);
  485. }
  486. /*
  487. =================
  488. MakeFaceWinding
  489. returns the visible polygon on a face
  490. =================
  491. */
  492. winding_t *MakeFaceWinding (brush_t *b, face_t *face)
  493. {
  494. winding_t *w;
  495. face_t *clip;
  496. plane_t plane;
  497. qboolean past;
  498. // get a poly that covers an effectively infinite area
  499. w = BasePolyForPlane (&face->plane);
  500. // chop the poly by all of the other faces
  501. past = false;
  502. for (clip = b->brush_faces ; clip && w ; clip=clip->next)
  503. {
  504. if (clip == face)
  505. {
  506. past = true;
  507. continue;
  508. }
  509. if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
  510. && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
  511. { // identical plane, use the later one
  512. if (past)
  513. {
  514. free (w);
  515. return NULL;
  516. }
  517. continue;
  518. }
  519. // flip the plane, because we want to keep the back side
  520. VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
  521. plane.dist = -clip->plane.dist;
  522. w = ClipWinding (w, &plane, false);
  523. if (!w)
  524. return w;
  525. }
  526. if (w->numpoints < 3)
  527. {
  528. free(w);
  529. w = NULL;
  530. }
  531. if (!w)
  532. printf ("unused plane\n");
  533. return w;
  534. }
  535. void Brush_SnapPlanepts (brush_t *b)
  536. {
  537. int i, j;
  538. face_t *f;
  539. for (f=b->brush_faces ; f; f=f->next)
  540. for (i=0 ; i<3 ; i++)
  541. for (j=0 ; j<3 ; j++)
  542. f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
  543. }
  544. /*
  545. ** Brush_Build
  546. **
  547. ** Builds a brush rendering data and also sets the min/max bounds
  548. */
  549. #define ZERO_EPSILON 0.001
  550. void Brush_Build( brush_t *b )
  551. {
  552. // int order;
  553. // face_t *face;
  554. // winding_t *w;
  555. char title[1024];
  556. if (modified != 1)
  557. {
  558. modified = true; // mark the map as changed
  559. sprintf (title, "%s *", currentmap);
  560. QE_ConvertDOSToUnixName( title, title );
  561. Sys_SetTitle (title);
  562. }
  563. /*
  564. ** build the windings and generate the bounding box
  565. */
  566. Brush_BuildWindings( b );
  567. /*
  568. ** move the points and edges if in select mode
  569. */
  570. if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
  571. SetupVertexSelection ();
  572. }
  573. /*
  574. =================
  575. Brush_Parse
  576. The brush is NOT linked to any list
  577. =================
  578. */
  579. brush_t *Brush_Parse (void)
  580. {
  581. brush_t *b;
  582. face_t *f;
  583. int i,j;
  584. g_qeglobals.d_parsed_brushes++;
  585. b = qmalloc(sizeof(brush_t));
  586. do
  587. {
  588. if (!GetToken (true))
  589. break;
  590. if (!strcmp (token, "}") )
  591. break;
  592. f = Face_Alloc();
  593. // add the brush to the end of the chain, so
  594. // loading and saving a map doesn't reverse the order
  595. f->next = NULL;
  596. if (!b->brush_faces)
  597. {
  598. b->brush_faces = f;
  599. }
  600. else
  601. {
  602. face_t *scan;
  603. for (scan=b->brush_faces ; scan->next ; scan=scan->next)
  604. ;
  605. scan->next = f;
  606. }
  607. // read the three point plane definition
  608. for (i=0 ; i<3 ; i++)
  609. {
  610. if (i != 0)
  611. GetToken (true);
  612. if (strcmp (token, "(") )
  613. Error ("parsing brush");
  614. for (j=0 ; j<3 ; j++)
  615. {
  616. GetToken (false);
  617. f->planepts[i][j] = atoi(token);
  618. }
  619. GetToken (false);
  620. if (strcmp (token, ")") )
  621. Error ("parsing brush");
  622. }
  623. // read the texturedef
  624. GetToken (false);
  625. strcpy(f->texdef.name, token);
  626. GetToken (false);
  627. f->texdef.shift[0] = atoi(token);
  628. GetToken (false);
  629. f->texdef.shift[1] = atoi(token);
  630. GetToken (false);
  631. f->texdef.rotate = atoi(token);
  632. GetToken (false);
  633. f->texdef.scale[0] = atof(token);
  634. GetToken (false);
  635. f->texdef.scale[1] = atof(token);
  636. // the flags and value field aren't necessarily present
  637. f->d_texture = Texture_ForName( f->texdef.name );
  638. f->texdef.flags = f->d_texture->flags;
  639. f->texdef.value = f->d_texture->value;
  640. f->texdef.contents = f->d_texture->contents;
  641. if (TokenAvailable ())
  642. {
  643. GetToken (false);
  644. f->texdef.contents = atoi(token);
  645. GetToken (false);
  646. f->texdef.flags = atoi(token);
  647. GetToken (false);
  648. f->texdef.value = atoi(token);
  649. }
  650. } while (1);
  651. return b;
  652. }
  653. /*
  654. =================
  655. Brush_Write
  656. =================
  657. */
  658. void Brush_Write (brush_t *b, FILE *f)
  659. {
  660. face_t *fa;
  661. char *pname;
  662. int i;
  663. fprintf (f, "{\n");
  664. for (fa=b->brush_faces ; fa ; fa=fa->next)
  665. {
  666. for (i=0 ; i<3 ; i++)
  667. fprintf (f, "( %i %i %i ) ", (int)fa->planepts[i][0]
  668. , (int)fa->planepts[i][1], (int)fa->planepts[i][2]);
  669. pname = fa->texdef.name;
  670. if (pname[0] == 0)
  671. pname = "unnamed";
  672. fprintf (f, "%s %i %i %i ", pname,
  673. (int)fa->texdef.shift[0], (int)fa->texdef.shift[1],
  674. (int)fa->texdef.rotate);
  675. if (fa->texdef.scale[0] == (int)fa->texdef.scale[0])
  676. fprintf (f, "%i ", (int)fa->texdef.scale[0]);
  677. else
  678. fprintf (f, "%f ", (float)fa->texdef.scale[0]);
  679. if (fa->texdef.scale[1] == (int)fa->texdef.scale[1])
  680. fprintf (f, "%i", (int)fa->texdef.scale[1]);
  681. else
  682. fprintf (f, "%f", (float)fa->texdef.scale[1]);
  683. // only output flags and value if not default
  684. if (fa->texdef.value != fa->d_texture->value
  685. || fa->texdef.flags != fa->d_texture->flags
  686. || fa->texdef.contents != fa->d_texture->contents)
  687. {
  688. fprintf (f, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value);
  689. }
  690. fprintf (f, "\n");
  691. }
  692. fprintf (f, "}\n");
  693. }
  694. /*
  695. =============
  696. Brush_Create
  697. Create non-textured blocks for entities
  698. The brush is NOT linked to any list
  699. =============
  700. */
  701. brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
  702. {
  703. int i, j;
  704. vec3_t pts[4][2];
  705. face_t *f;
  706. brush_t *b;
  707. for (i=0 ; i<3 ; i++)
  708. if (maxs[i] < mins[i])
  709. Error ("Brush_InitSolid: backwards");
  710. b = qmalloc (sizeof(brush_t));
  711. pts[0][0][0] = mins[0];
  712. pts[0][0][1] = mins[1];
  713. pts[1][0][0] = mins[0];
  714. pts[1][0][1] = maxs[1];
  715. pts[2][0][0] = maxs[0];
  716. pts[2][0][1] = maxs[1];
  717. pts[3][0][0] = maxs[0];
  718. pts[3][0][1] = mins[1];
  719. for (i=0 ; i<4 ; i++)
  720. {
  721. pts[i][0][2] = mins[2];
  722. pts[i][1][0] = pts[i][0][0];
  723. pts[i][1][1] = pts[i][0][1];
  724. pts[i][1][2] = maxs[2];
  725. }
  726. for (i=0 ; i<4 ; i++)
  727. {
  728. f = Face_Alloc();
  729. f->texdef = *texdef;
  730. f->next = b->brush_faces;
  731. b->brush_faces = f;
  732. j = (i+1)%4;
  733. VectorCopy (pts[j][1], f->planepts[0]);
  734. VectorCopy (pts[i][1], f->planepts[1]);
  735. VectorCopy (pts[i][0], f->planepts[2]);
  736. }
  737. f = Face_Alloc();
  738. f->texdef = *texdef;
  739. f->next = b->brush_faces;
  740. b->brush_faces = f;
  741. VectorCopy (pts[0][1], f->planepts[0]);
  742. VectorCopy (pts[1][1], f->planepts[1]);
  743. VectorCopy (pts[2][1], f->planepts[2]);
  744. f = Face_Alloc();
  745. f->texdef = *texdef;
  746. f->next = b->brush_faces;
  747. b->brush_faces = f;
  748. VectorCopy (pts[2][0], f->planepts[0]);
  749. VectorCopy (pts[1][0], f->planepts[1]);
  750. VectorCopy (pts[0][0], f->planepts[2]);
  751. return b;
  752. }
  753. /*
  754. =============
  755. Brush_MakeSided
  756. Makes the current brushhave the given number of 2d sides
  757. =============
  758. */
  759. void Brush_MakeSided (int sides)
  760. {
  761. int i;
  762. vec3_t mins, maxs;
  763. brush_t *b;
  764. texdef_t *texdef;
  765. face_t *f;
  766. vec3_t mid;
  767. float width;
  768. float sv, cv;
  769. if (sides < 3)
  770. {
  771. Sys_Status ("Bad sides number", 0);
  772. return;
  773. }
  774. if (!QE_SingleBrush ())
  775. {
  776. Sys_Status ("Must have a single brush selected", 0 );
  777. return;
  778. }
  779. b = selected_brushes.next;
  780. VectorCopy (b->mins, mins);
  781. VectorCopy (b->maxs, maxs);
  782. texdef = &g_qeglobals.d_texturewin.texdef;
  783. Brush_Free (b);
  784. // find center of brush
  785. width = 8;
  786. for (i=0 ; i<2 ; i++)
  787. {
  788. mid[i] = (maxs[i] + mins[i])*0.5;
  789. if (maxs[i] - mins[i] > width)
  790. width = maxs[i] - mins[i];
  791. }
  792. width /= 2;
  793. b = qmalloc (sizeof(brush_t));
  794. // create top face
  795. f = Face_Alloc();
  796. f->texdef = *texdef;
  797. f->next = b->brush_faces;
  798. b->brush_faces = f;
  799. f->planepts[2][0] = mins[0];f->planepts[2][1] = mins[1];f->planepts[2][2] = maxs[2];
  800. f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = maxs[2];
  801. f->planepts[0][0] = maxs[0];f->planepts[0][1] = maxs[1];f->planepts[0][2] = maxs[2];
  802. // create bottom face
  803. f = Face_Alloc();
  804. f->texdef = *texdef;
  805. f->next = b->brush_faces;
  806. b->brush_faces = f;
  807. f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
  808. f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
  809. f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
  810. for (i=0 ; i<sides ; i++)
  811. {
  812. f = Face_Alloc();
  813. f->texdef = *texdef;
  814. f->next = b->brush_faces;
  815. b->brush_faces = f;
  816. sv = sin (i*3.14159265*2/sides);
  817. cv = cos (i*3.14159265*2/sides);
  818. f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
  819. f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
  820. f->planepts[0][2] = mins[2];
  821. f->planepts[1][0] = f->planepts[0][0];
  822. f->planepts[1][1] = f->planepts[0][1];
  823. f->planepts[1][2] = maxs[2];
  824. f->planepts[2][0] = floor(f->planepts[0][0] - width*sv + 0.5);
  825. f->planepts[2][1] = floor(f->planepts[0][1] + width*cv + 0.5);
  826. f->planepts[2][2] = maxs[2];
  827. }
  828. Brush_AddToList (b, &selected_brushes);
  829. Entity_LinkBrush (world_entity, b);
  830. Brush_Build( b );
  831. Sys_UpdateWindows (W_ALL);
  832. }
  833. /*
  834. =============
  835. Brush_Free
  836. Frees the brush with all of its faces and display list.
  837. Unlinks the brush from whichever chain it is in.
  838. Decrements the owner entity's brushcount.
  839. Removes owner entity if this was the last brush
  840. unless owner is the world.
  841. =============
  842. */
  843. void Brush_Free (brush_t *b)
  844. {
  845. face_t *f, *next;
  846. // free faces
  847. for (f=b->brush_faces ; f ; f=next)
  848. {
  849. next = f->next;
  850. Face_Free( f );
  851. }
  852. /*
  853. for ( i = 0; i < b->d_numwindings; i++ )
  854. {
  855. if ( b->d_windings[i] )
  856. {
  857. FreeWinding( b->d_windings[i] );
  858. b->d_windings[i] = 0;
  859. }
  860. }
  861. */
  862. // unlink from active/selected list
  863. if (b->next)
  864. Brush_RemoveFromList (b);
  865. // unlink from entity list
  866. if (b->onext)
  867. Entity_UnlinkBrush (b);
  868. free (b);
  869. }
  870. /*
  871. ============
  872. Brush_Move
  873. ============
  874. */
  875. void Brush_Move (brush_t *b, vec3_t move)
  876. {
  877. int i;
  878. face_t *f;
  879. for (f=b->brush_faces ; f ; f=f->next)
  880. for (i=0 ; i<3 ; i++)
  881. VectorAdd (f->planepts[i], move, f->planepts[i]);
  882. Brush_Build( b );
  883. }
  884. /*
  885. ============
  886. Brush_Clone
  887. Does NOT add the new brush to any lists
  888. ============
  889. */
  890. brush_t *Brush_Clone (brush_t *b)
  891. {
  892. brush_t *n;
  893. face_t *f, *nf;
  894. n = qmalloc(sizeof(brush_t));
  895. n->owner = b->owner;
  896. for (f=b->brush_faces ; f ; f=f->next)
  897. {
  898. nf = Face_Clone( f );
  899. nf->next = n->brush_faces;
  900. n->brush_faces = nf;
  901. }
  902. return n;
  903. }
  904. /*
  905. ==============
  906. Brush_Ray
  907. Itersects a ray with a brush
  908. Returns the face hit and the distance along the ray the intersection occured at
  909. Returns NULL and 0 if not hit at all
  910. ==============
  911. */
  912. face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist)
  913. {
  914. face_t *f, *firstface;
  915. vec3_t p1, p2;
  916. float frac, d1, d2;
  917. int i;
  918. VectorCopy (origin, p1);
  919. for (i=0 ; i<3 ; i++)
  920. p2[i] = p1[i] + dir[i]*16384;
  921. for (f=b->brush_faces ; f ; f=f->next)
  922. {
  923. d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
  924. d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
  925. if (d1 >= 0 && d2 >= 0)
  926. {
  927. *dist = 0;
  928. return NULL; // ray is on front side of face
  929. }
  930. if (d1 <=0 && d2 <= 0)
  931. continue;
  932. // clip the ray to the plane
  933. frac = d1 / (d1 - d2);
  934. if (d1 > 0)
  935. {
  936. firstface = f;
  937. for (i=0 ; i<3 ; i++)
  938. p1[i] = p1[i] + frac *(p2[i] - p1[i]);
  939. }
  940. else
  941. {
  942. for (i=0 ; i<3 ; i++)
  943. p2[i] = p1[i] + frac *(p2[i] - p1[i]);
  944. }
  945. }
  946. // find distance p1 is along dir
  947. VectorSubtract (p1, origin, p1);
  948. d1 = DotProduct (p1, dir);
  949. *dist = d1;
  950. return firstface;
  951. }
  952. void Brush_AddToList (brush_t *b, brush_t *list)
  953. {
  954. if (b->next || b->prev)
  955. Error ("Brush_RemoveFromList: allready linked");
  956. b->next = list->next;
  957. list->next->prev = b;
  958. list->next = b;
  959. b->prev = list;
  960. }
  961. void Brush_RemoveFromList (brush_t *b)
  962. {
  963. if (!b->next || !b->prev)
  964. Error ("Brush_RemoveFromList: not linked");
  965. b->next->prev = b->prev;
  966. b->prev->next = b->next;
  967. b->next = b->prev = NULL;
  968. }
  969. void Brush_SetTexture (brush_t *b, texdef_t *texdef)
  970. {
  971. face_t *f;
  972. for (f=b->brush_faces ; f ; f=f->next)
  973. f->texdef = *texdef;
  974. Brush_Build( b );
  975. }
  976. qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
  977. {
  978. float d1, d2, fr;
  979. int i;
  980. float *v;
  981. d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
  982. d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
  983. if (d1 >= 0 && d2 >= 0)
  984. return false; // totally outside
  985. if (d1 <= 0 && d2 <= 0)
  986. return true; // totally inside
  987. fr = d1 / (d1 - d2);
  988. if (d1 > 0)
  989. v = p1;
  990. else
  991. v = p2;
  992. for (i=0 ; i<3 ; i++)
  993. v[i] = p1[i] + fr*(p2[i] - p1[i]);
  994. return true;
  995. }
  996. int AddPlanept (float *f)
  997. {
  998. int i;
  999. for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
  1000. if (g_qeglobals.d_move_points[i] == f)
  1001. return 0;
  1002. g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
  1003. return 1;
  1004. }
  1005. /*
  1006. ==============
  1007. Brush_SelectFaceForDragging
  1008. Adds the faces planepts to move_points, and
  1009. rotates and adds the planepts of adjacent face if shear is set
  1010. ==============
  1011. */
  1012. void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
  1013. {
  1014. int i;
  1015. face_t *f2;
  1016. winding_t *w;
  1017. float d;
  1018. brush_t *b2;
  1019. int c;
  1020. if (b->owner->eclass->fixedsize)
  1021. return;
  1022. c = 0;
  1023. for (i=0 ; i<3 ; i++)
  1024. c += AddPlanept (f->planepts[i]);
  1025. if (c == 0)
  1026. return; // allready completely added
  1027. // select all points on this plane in all brushes the selection
  1028. for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
  1029. {
  1030. if (b2 == b)
  1031. continue;
  1032. for (f2=b2->brush_faces ; f2 ; f2=f2->next)
  1033. {
  1034. for (i=0 ; i<3 ; i++)
  1035. if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
  1036. -f->plane.dist) > ON_EPSILON)
  1037. break;
  1038. if (i==3)
  1039. { // move this face as well
  1040. Brush_SelectFaceForDragging (b2, f2, shear);
  1041. break;
  1042. }
  1043. }
  1044. }
  1045. // if shearing, take all the planes adjacent to
  1046. // selected faces and rotate their points so the
  1047. // edge clipped by a selcted face has two of the points
  1048. if (!shear)
  1049. return;
  1050. for (f2=b->brush_faces ; f2 ; f2=f2->next)
  1051. {
  1052. if (f2 == f)
  1053. continue;
  1054. w = MakeFaceWinding (b, f2);
  1055. if (!w)
  1056. continue;
  1057. // any points on f will become new control points
  1058. for (i=0 ; i<w->numpoints ; i++)
  1059. {
  1060. d = DotProduct (w->points[i], f->plane.normal)
  1061. - f->plane.dist;
  1062. if (d > -ON_EPSILON && d < ON_EPSILON)
  1063. break;
  1064. }
  1065. //
  1066. // if none of the points were on the plane,
  1067. // leave it alone
  1068. //
  1069. if (i != w->numpoints)
  1070. {
  1071. if (i == 0)
  1072. { // see if the first clockwise point was the
  1073. // last point on the winding
  1074. d = DotProduct (w->points[w->numpoints-1]
  1075. , f->plane.normal) - f->plane.dist;
  1076. if (d > -ON_EPSILON && d < ON_EPSILON)
  1077. i = w->numpoints - 1;
  1078. }
  1079. AddPlanept (f2->planepts[0]);
  1080. VectorCopy (w->points[i], f2->planepts[0]);
  1081. if (++i == w->numpoints)
  1082. i = 0;
  1083. // see if the next point is also on the plane
  1084. d = DotProduct (w->points[i]
  1085. , f->plane.normal) - f->plane.dist;
  1086. if (d > -ON_EPSILON && d < ON_EPSILON)
  1087. AddPlanept (f2->planepts[1]);
  1088. VectorCopy (w->points[i], f2->planepts[1]);
  1089. if (++i == w->numpoints)
  1090. i = 0;
  1091. // the third point is never on the plane
  1092. VectorCopy (w->points[i], f2->planepts[2]);
  1093. }
  1094. free(w);
  1095. }
  1096. }
  1097. /*
  1098. ==============
  1099. Brush_SideSelect
  1100. The mouse click did not hit the brush, so grab one or more side
  1101. planes for dragging
  1102. ==============
  1103. */
  1104. void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
  1105. , qboolean shear)
  1106. {
  1107. face_t *f, *f2;
  1108. vec3_t p1, p2;
  1109. for (f=b->brush_faces ; f ; f=f->next)
  1110. {
  1111. VectorCopy (origin, p1);
  1112. VectorMA (origin, 16384, dir, p2);
  1113. for (f2=b->brush_faces ; f2 ; f2=f2->next)
  1114. {
  1115. if (f2 == f)
  1116. continue;
  1117. ClipLineToFace (p1, p2, f2);
  1118. }
  1119. if (f2)
  1120. continue;
  1121. if (VectorCompare (p1, origin))
  1122. continue;
  1123. if (ClipLineToFace (p1, p2, f))
  1124. continue;
  1125. Brush_SelectFaceForDragging (b, f, shear);
  1126. }
  1127. }
  1128. void Brush_BuildWindings( brush_t *b )
  1129. {
  1130. winding_t *w;
  1131. face_t *face;
  1132. vec_t v;
  1133. Brush_SnapPlanepts( b );
  1134. // clear the mins/maxs bounds
  1135. b->mins[0] = b->mins[1] = b->mins[2] = 99999;
  1136. b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
  1137. Brush_MakeFacePlanes (b);
  1138. face = b->brush_faces;
  1139. for ( ; face ; face=face->next)
  1140. {
  1141. int i, j;
  1142. w = face->face_winding = MakeFaceWinding (b, face);
  1143. face->d_texture = Texture_ForName( face->texdef.name );
  1144. if (!w)
  1145. {
  1146. continue;
  1147. }
  1148. for (i=0 ; i<w->numpoints ; i++)
  1149. {
  1150. // add to bounding box
  1151. for (j=0 ; j<3 ; j++)
  1152. {
  1153. v = w->points[i][j];
  1154. if (v > b->maxs[j])
  1155. b->maxs[j] = v;
  1156. if (v < b->mins[j])
  1157. b->mins[j] = v;
  1158. }
  1159. }
  1160. // setup s and t vectors, and set color
  1161. BeginTexturingFace( b, face, face->d_texture);
  1162. for (i=0 ; i<w->numpoints ; i++)
  1163. {
  1164. EmitTextureCoordinates( w->points[i], face->d_texture, face);
  1165. }
  1166. }
  1167. }
  1168. /*
  1169. ==================
  1170. Brush_RemoveEmptyFaces
  1171. Frees any overconstraining faces
  1172. ==================
  1173. */
  1174. void Brush_RemoveEmptyFaces ( brush_t *b )
  1175. {
  1176. face_t *f, *next;
  1177. f = b->brush_faces;
  1178. b->brush_faces = NULL;
  1179. for ( ; f ; f=next)
  1180. {
  1181. next = f->next;
  1182. if (!f->face_winding)
  1183. Face_Free (f);
  1184. else
  1185. {
  1186. f->next = b->brush_faces;
  1187. b->brush_faces = f;
  1188. }
  1189. }
  1190. }
  1191. void Brush_Draw( brush_t *b )
  1192. {
  1193. face_t *face;
  1194. int i, order;
  1195. qtexture_t *prev = 0;
  1196. winding_t *w;
  1197. if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
  1198. glDisable (GL_TEXTURE_2D);
  1199. // guarantee the texture will be set first
  1200. prev = NULL;
  1201. for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
  1202. {
  1203. w = face->face_winding;
  1204. if (!w)
  1205. continue; // freed face
  1206. if ( face->d_texture != prev && camera.draw_mode == cd_texture)
  1207. {
  1208. // set the texture for this face
  1209. prev = face->d_texture;
  1210. glBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
  1211. }
  1212. glColor3fv( face->d_color );
  1213. // draw the polygon
  1214. glBegin(GL_POLYGON);
  1215. for (i=0 ; i<w->numpoints ; i++)
  1216. {
  1217. if (camera.draw_mode == cd_texture)
  1218. glTexCoord2fv( &w->points[i][3] );
  1219. glVertex3fv(w->points[i]);
  1220. }
  1221. glEnd();
  1222. }
  1223. if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
  1224. glEnable (GL_TEXTURE_2D);
  1225. glBindTexture( GL_TEXTURE_2D, 0 );
  1226. }
  1227. void Face_Draw( face_t *f )
  1228. {
  1229. int i;
  1230. if ( f->face_winding == 0 )
  1231. return;
  1232. glBegin( GL_POLYGON );
  1233. for ( i = 0 ; i < f->face_winding->numpoints; i++)
  1234. glVertex3fv( f->face_winding->points[i] );
  1235. glEnd();
  1236. }
  1237. void Brush_DrawXY( brush_t *b )
  1238. {
  1239. face_t *face;
  1240. int order;
  1241. winding_t *w;
  1242. int i;
  1243. for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
  1244. {
  1245. // only draw up facing polygons
  1246. if (face->plane.normal[2] <= 0)
  1247. continue;
  1248. w = face->face_winding;
  1249. if (!w)
  1250. continue;
  1251. // draw the polygon
  1252. glBegin(GL_LINE_LOOP);
  1253. for (i=0 ; i<w->numpoints ; i++)
  1254. glVertex3fv(w->points[i]);
  1255. glEnd();
  1256. }
  1257. // optionally add a text label
  1258. if ( g_qeglobals.d_savedinfo.show_names )
  1259. DrawBrushEntityName (b);
  1260. }
  1261. face_t *Face_Alloc( void )
  1262. {
  1263. face_t *f = qmalloc( sizeof( *f ) );
  1264. return f;
  1265. }
  1266. void Face_Free( face_t *f )
  1267. {
  1268. assert( f != 0 );
  1269. if ( f->face_winding )
  1270. free( f->face_winding ), f->face_winding = 0;
  1271. free( f );
  1272. }