doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
EditorBrush.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "qe3.h"
33 #include <GL/glu.h>
34 
35 #include "../../renderer/tr_local.h"
36 #include "../../renderer/model_local.h" // for idRenderModelMD5
37 
38 void Brush_UpdateLightPoints(brush_t *b, const idVec3 &offset);
39 void Brush_DrawCurve( brush_t *b, bool bSelected, bool cam );
40 
41 // globals
42 int g_nBrushId = 0;
43 bool g_bShowLightVolumes = false;
44 bool g_bShowLightTextures = false;
45 
46 void GLCircle(float x, float y, float z, float r);
47 
48 const int POINTS_PER_KNOT = 50;
49 
50 /*
51 ================
52 DrawRenderModel
53 ================
54 */
55 void DrawRenderModel( idRenderModel *model, idVec3 &origin, idMat3 &axis, bool cameraView ) {
56  for ( int i = 0; i < model->NumSurfaces(); i++ ) {
57  const modelSurface_t *surf = model->Surface( i );
58  const idMaterial *material = surf->shader;
59 
60  int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
61 
62  if ( cameraView && (nDrawMode == cd_texture || nDrawMode == cd_light) ) {
63  material->GetEditorImage()->Bind();
64  }
65 
66  qglBegin( GL_TRIANGLES );
67 
68  const srfTriangles_t *tri = surf->geometry;
69  for ( int j = 0; j < tri->numIndexes; j += 3 ) {
70  for ( int k = 0; k < 3; k++ ) {
71  int index = tri->indexes[j + k];
72  idVec3 v;
73 
74  v = tri->verts[index].xyz * axis + origin;
75  qglTexCoord2f( tri->verts[index].st.x, tri->verts[index].st.y );
76  qglVertex3fv( v.ToFloatPtr() );
77  }
78  }
79 
80  qglEnd();
81  }
82 }
83 
84 /*
85 ================
86 SnapVectorToGrid
87 ================
88 */
90  v.x = floor(v.x / g_qeglobals.d_gridsize + 0.5f) * g_qeglobals.d_gridsize;
91  v.y = floor(v.y / g_qeglobals.d_gridsize + 0.5f) * g_qeglobals.d_gridsize;
92  v.z = floor(v.z / g_qeglobals.d_gridsize + 0.5f) * g_qeglobals.d_gridsize;
93 }
94 
95 /*
96 ================
97 Brush_Name
98 ================
99 */
100 const char *Brush_Name( brush_t *b ) {
101  static char cBuff[1024];
102 
103  b->numberId = g_nBrushId++;
104  if (g_qeglobals.m_bBrushPrimitMode) {
105  sprintf(cBuff, "Brush %i", b->numberId);
106  Brush_SetEpair(b, "Name", cBuff);
107  }
108 
109  return cBuff;
110 }
111 
112 /*
113 ================
114 Brush_Alloc
115 ================
116 */
117 brush_t *Brush_Alloc( void ) {
118  brush_t *b = new brush_t;
119  b->prev = b->next = NULL;
120  b->oprev = b->onext = NULL;
121  b->owner = NULL;
122  b->mins.Zero();
123  b->maxs.Zero();
124 
125  b->lightCenter.Zero();
126  b->lightRight.Zero();
127  b->lightTarget.Zero();
128  b->lightUp.Zero();
129  b->lightRadius.Zero();
130  b->lightOffset.Zero();
131  b->lightColor.Zero();
132  b->lightStart.Zero();
133  b->lightEnd.Zero();
134  b->pointLight = false;
135  b->startEnd = false;
136  b->lightTexture = 0;
137  b->trackLightOrigin = false;
138 
139  b->entityModel = false;
140  b->brush_faces = NULL;
141  b->hiddenBrush = false;
142  b->pPatch = NULL;
143  b->pUndoOwner = NULL;
144  b->undoId = 0;
145  b->redoId = 0;
146  b->ownerId = 0;
147  b->numberId = 0;
148  b->itemOwner = 0;
149  b->bModelFailed = false;
150  b->modelHandle = NULL;
151  b->forceVisibile = false;
152  b->forceWireFrame = false;
153  return b;
154 }
155 
156 /*
157 ================
158 TextureAxisFromPlane
159 ================
160 */
162  idVec3(0, 0, 1),
163  idVec3(1, 0, 0),
164  idVec3(0, -1, 0),
165 
166  // floor
167  idVec3(0, 0, -1),
168  idVec3(1, 0, 0),
169  idVec3(0, -1, 0),
170 
171  // ceiling
172  idVec3(1, 0, 0),
173  idVec3(0, 1, 0),
174  idVec3(0, 0, -1),
175 
176  // west wall
177  idVec3(-1, 0, 0),
178  idVec3(0, 1, 0),
179  idVec3(0, 0, -1),
180 
181  // east wall
182  idVec3(0, 1, 0),
183  idVec3(1, 0, 0),
184  idVec3(0, 0, -1),
185 
186  // south wall
187  idVec3(0, -1, 0),
188  idVec3(1, 0, 0),
189  idVec3(0, 0, -1) // north wall
190 };
191 
192 void TextureAxisFromPlane( const idPlane &pln, idVec3 &xv, idVec3 &yv) {
193  int bestaxis;
194  float dot, best;
195  int i;
196 
197  best = 0;
198  bestaxis = 0;
199 
200  for (i = 0; i < 6; i++) {
201  dot = DotProduct(pln, baseaxis[i * 3]);
202  if (dot > best) {
203  best = dot;
204  bestaxis = i;
205  }
206  }
207 
208  VectorCopy(baseaxis[bestaxis * 3 + 1], xv);
209  VectorCopy(baseaxis[bestaxis * 3 + 2], yv);
210 }
211 
212 /*
213 ================
214 ShadeForNormal
215 
216  Light different planes differently to improve recognition
217 ================
218 */
219 float lightaxis[3] = { 0.6f, 0.8f, 1.0f };
220 
221 float ShadeForNormal(idVec3 normal) {
222  int i;
223  float f;
224 
225  // axial plane
226  for (i = 0; i < 3; i++) {
227  if ( idMath::Fabs(normal[i]) > 0.9f ) {
228  f = lightaxis[i];
229  return f;
230  }
231  }
232 
233  // between two axial planes
234  for (i = 0; i < 3; i++) {
235  if ( idMath::Fabs(normal[i]) < 0.1f ) {
236  f = (lightaxis[(i + 1) % 3] + lightaxis[(i + 2) % 3]) / 2;
237  return f;
238  }
239  }
240 
241  // other
242  f = (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
243  return f;
244 }
245 
246 /*
247 ================
248 Face_Alloc
249 ================
250 */
251 face_t *Face_Alloc(void) {
252  brushprimit_texdef_t bp;
253 
254  face_t *f = (face_t *) Mem_ClearedAlloc(sizeof(*f));
255 
256  bp.coords[0][0] = 0.0f;
257  bp.coords[1][1] = 0.0f;
258  f->brushprimit_texdef = bp;
259  f->dirty = true;
260  return f;
261 }
262 
263 /*
264 ================
265 Face_Free
266 ================
267 */
268 void Face_Free(face_t *f) {
269  assert(f != 0);
270 
271  if (f->face_winding) {
272  delete f->face_winding;
273  }
274 
275  f->texdef.~texdef_t();
276 
277  Mem_Free(f);
278 }
279 
280 /*
281 ================
282 Face_Clone
283 ================
284 */
285 face_t *Face_Clone(face_t *f) {
286  face_t *n;
287 
288  n = Face_Alloc();
289  n->texdef = f->texdef;
290  n->brushprimit_texdef = f->brushprimit_texdef;
291 
292  memcpy(n->planepts, f->planepts, sizeof(n->planepts));
293  n->plane = f->plane;
294  n->originalPlane = f->originalPlane;
295  n->dirty = f->dirty;
296 
297  // all other fields are derived, and will be set by Brush_Build
298  return n;
299 }
300 
301 /*
302 ================
303 Face_FullClone
304 
305  Used by Undo.
306  Makes an exact copy of the face.
307 ================
308 */
309 face_t *Face_FullClone(face_t *f) {
310  face_t *n;
311 
312  n = Face_Alloc();
313  n->texdef = f->texdef;
314  n->brushprimit_texdef = f->brushprimit_texdef;
315  memcpy(n->planepts, f->planepts, sizeof(n->planepts));
316  n->plane = f->plane;
317  n->originalPlane = f->originalPlane;
318  n->dirty = f->dirty;
319  if (f->face_winding) {
320  n->face_winding = f->face_winding->Copy();
321  }
322  else {
323  n->face_winding = NULL;
324  }
325 
326  n->d_texture = Texture_ForName(n->texdef.name);
327  return n;
328 }
329 
330 /*
331 ================
332 Clamp
333 ================
334 */
335 void Clamp(float &f, int nClamp) {
336  float fFrac = f - static_cast<int>(f);
337  f = static_cast<int>(f) % nClamp;
338  f += fFrac;
339 }
340 
341 /*
342 ================
343 Face_MoveTexture
344 ================
345 */
346 void Face_MoveTexture(face_t *f, idVec3 delta) {
347  idVec3 vX, vY;
348 
349  /*
350  * #ifdef _DEBUG if (g_PrefsDlg.m_bBrushPrimitMode) common->Printf("Warning :
351  * Face_MoveTexture not done in brush primitive mode\n"); #endif
352  */
353  if (g_qeglobals.m_bBrushPrimitMode) {
355  }
356  else {
357  TextureAxisFromPlane( f->plane, vX, vY );
358 
359  idVec3 vDP, vShift;
360  vDP[0] = DotProduct(delta, vX);
361  vDP[1] = DotProduct(delta, vY);
362 
363  double fAngle = DEG2RAD( f->texdef.rotate );
364  double c = cos(fAngle);
365  double s = sin(fAngle);
366 
367  vShift[0] = vDP[0] * c - vDP[1] * s;
368  vShift[1] = vDP[0] * s + vDP[1] * c;
369 
370  if (!f->texdef.scale[0]) {
371  f->texdef.scale[0] = 1;
372  }
373 
374  if (!f->texdef.scale[1]) {
375  f->texdef.scale[1] = 1;
376  }
377 
378  f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];
379  f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];
380 
381  // clamp the shifts
382  Clamp(f->texdef.shift[0], f->d_texture->GetEditorImage()->uploadWidth);
383  Clamp(f->texdef.shift[1], f->d_texture->GetEditorImage()->uploadHeight);
384  }
385 }
386 
387 /*
388 ================
389 Face_SetColor
390 ================
391 */
392 void Face_SetColor(brush_t *b, face_t *f, float fCurveColor) {
393  float shade;
394  const idMaterial *q;
395 
396  q = f->d_texture;
397 
398  // set shading for face
399  shade = ShadeForNormal( f->plane.Normal() );
400  if (g_pParentWnd->GetCamera()->Camera().draw_mode == cd_texture && (b->owner && !b->owner->eclass->fixedsize)) {
401  // if (b->curveBrush) shade = fCurveColor;
402  f->d_color[0] = f->d_color[1] = f->d_color[2] = shade;
403  }
404  else if ( f && b && b->owner ) {
405  f->d_color[0] = shade * b->owner->eclass->color.x;
406  f->d_color[1] = shade * b->owner->eclass->color.y;
407  f->d_color[2] = shade * b->owner->eclass->color.z;
408  }
409 }
410 
411 /*
412 ================
413 Face_TextureVectors
414 
415  NOTE: this is never to get called while in brush primitives mode
416 ================
417 */
418 void Face_TextureVectors(face_t *f, float STfromXYZ[2][4]) {
419  idVec3 pvecs[2];
420  int sv, tv;
421  float ang, sinv, cosv;
422  float ns, nt;
423  int i, j;
424  const idMaterial *q;
425  texdef_t *td;
426 
427 #ifdef _DEBUG
428 
429  //
430  // ++timo when playing with patches, this sometimes get called and the Warning is
431  // displayed find some way out ..
432  //
433  if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert) {
434  common->Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");
435  }
436 #endif
437  td = &f->texdef;
438  q = f->d_texture;
439 
440  memset(STfromXYZ, 0, 8 * sizeof (float));
441 
442  if (!td->scale[0]) {
443  td->scale[0] = (g_PrefsDlg.m_bHiColorTextures) ? 2 : 1;
444  }
445 
446  if (!td->scale[1]) {
447  td->scale[1] = (g_PrefsDlg.m_bHiColorTextures) ? 2 : 1;
448  }
449 
450  // get natural texture axis
451  TextureAxisFromPlane( f->plane, pvecs[0], pvecs[1]);
452 
453  // rotate axis
454  if (td->rotate == 0) {
455  sinv = 0;
456  cosv = 1;
457  }
458  else if (td->rotate == 90) {
459  sinv = 1;
460  cosv = 0;
461  }
462  else if (td->rotate == 180) {
463  sinv = 0;
464  cosv = -1;
465  }
466  else if (td->rotate == 270) {
467  sinv = -1;
468  cosv = 0;
469  }
470  else {
471  ang = DEG2RAD( td->rotate );
472  sinv = sin(ang);
473  cosv = cos(ang);
474  }
475 
476  if (pvecs[0][0]) {
477  sv = 0;
478  }
479  else if (pvecs[0][1]) {
480  sv = 1;
481  }
482  else {
483  sv = 2;
484  }
485 
486  if (pvecs[1][0]) {
487  tv = 0;
488  }
489  else if (pvecs[1][1]) {
490  tv = 1;
491  }
492  else {
493  tv = 2;
494  }
495 
496  for (i = 0; i < 2; i++) {
497  ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
498  nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
499  STfromXYZ[i][sv] = ns;
500  STfromXYZ[i][tv] = nt;
501  }
502 
503  // scale
504  for (i = 0; i < 2; i++) {
505  for (j = 0; j < 3; j++) {
506  STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];
507  }
508  }
509 
510  // shift
511  STfromXYZ[0][3] = td->shift[0];
512  STfromXYZ[1][3] = td->shift[1];
513 
514  for (j = 0; j < 4; j++) {
515  STfromXYZ[0][j] /= q->GetEditorImage()->uploadWidth;
516  STfromXYZ[1][j] /= q->GetEditorImage()->uploadHeight;
517  }
518 }
519 
520 /*
521 ================
522 Face_MakePlane
523 ================
524 */
525 void Face_MakePlane(face_t *f) {
526  int j;
527  idVec3 t1, t2, t3;
528 
529  idPlane oldPlane = f->plane;
530 
531  // convert to a vector / dist plane
532  for (j = 0; j < 3; j++) {
533  t1[j] = f->planepts[0][j] - f->planepts[1][j];
534  t2[j] = f->planepts[2][j] - f->planepts[1][j];
535  t3[j] = f->planepts[1][j];
536  }
537 
538  f->plane = t1.Cross( t2 );
539  //if ( f->plane.Compare( vec3_origin ) ) {
540  // printf("WARNING: brush plane with no normal\n");
541  //}
542 
543  f->plane.Normalize(false);
544  f->plane[3] = - (t3 * f->plane.Normal());
545 
546  if ( !f->dirty && !f->plane.Compare( oldPlane, 0.01f ) ) {
547  f->dirty = true;
548  }
549 }
550 
551 /*
552 ================
553 EmitTextureCoordinates
554 ================
555 */
556 void EmitTextureCoordinates(idVec5 &xyzst, const idMaterial *q, face_t *f, bool force) {
557  float STfromXYZ[2][4];
558 
559  if (g_qeglobals.m_bBrushPrimitMode && !force) {
560  EmitBrushPrimitTextureCoordinates(f, f->face_winding);
561  }
562  else {
563  Face_TextureVectors(f, STfromXYZ);
564  xyzst[3] = DotProduct(xyzst, STfromXYZ[0]) + STfromXYZ[0][3];
565  xyzst[4] = DotProduct(xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
566  }
567 }
568 
569 /*
570 ================
571 Brush_MakeFacePlanes
572 ================
573 */
574 void Brush_MakeFacePlanes(brush_t *b) {
575  face_t *f;
576 
577  for (f = b->brush_faces; f; f = f->next) {
578  Face_MakePlane(f);
579  }
580 }
581 
582 /*
583 ================
584 DrawBrushEntityName
585 ================
586 */
587 void DrawBrushEntityName(brush_t *b) {
588  const char *name;
589 
590  // float a, s, c; vec3_t mid; int i;
591  if (!b->owner) {
592  return; // during contruction
593  }
594 
595  if (b->owner == world_entity) {
596  return;
597  }
598 
599  if (b != b->owner->brushes.onext) {
600  return; // not key brush
601  }
602 
603  if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES)) {
604  // draw the angle pointer
605  float a = FloatForKey(b->owner, "angle");
606  if (a) {
607  float s = sin( DEG2RAD( a ) );
608  float c = cos( DEG2RAD( a ) );
609 
610  idVec3 mid = (b->mins + b->maxs) / 2.0f;
611 
612  qglBegin(GL_LINE_STRIP);
613  qglVertex3fv(mid.ToFloatPtr());
614  mid[0] += c * 8;
615  mid[1] += s * 8;
616  mid[2] += s * 8;
617  qglVertex3fv(mid.ToFloatPtr());
618  mid[0] -= c * 4;
619  mid[1] -= s * 4;
620  mid[2] -= s * 4;
621  mid[0] -= s * 4;
622  mid[1] += c * 4;
623  mid[2] += c * 4;
624  qglVertex3fv(mid.ToFloatPtr());
625  mid[0] += c * 4;
626  mid[1] += s * 4;
627  mid[2] += s * 4;
628  mid[0] += s * 4;
629  mid[1] -= c * 4;
630  mid[2] -= c * 4;
631  qglVertex3fv(mid.ToFloatPtr());
632  mid[0] -= c * 4;
633  mid[1] -= s * 4;
634  mid[2] -= s * 4;
635  mid[0] += s * 4;
636  mid[1] -= c * 4;
637  mid[2] -= c * 4;
638  qglVertex3fv(mid.ToFloatPtr());
639  qglEnd();
640  }
641  }
642 
643  int viewType = g_pParentWnd->ActiveXY()->GetViewType();
644  float scale = g_pParentWnd->ActiveXY()->Scale();
645 
646  if (g_qeglobals.d_savedinfo.show_names && scale >= 1.0f) {
647  name = ValueForKey(b->owner, "name");
648  int nameLen = strlen(name);
649  if ( nameLen == 0 ) {
650  name = ValueForKey(b->owner, "classname");
651  nameLen = strlen(name);
652  }
653  if ( nameLen > 0 ) {
654  idVec3 origin = b->owner->origin;
655 
656  float halfWidth = ( (nameLen / 2) * (7.0f / scale) );
657  float halfHeight = 4.0f / scale;
658 
659  switch (viewType) {
660  case XY:
661  origin.x -= halfWidth;
662  origin.y += halfHeight;
663  break;
664  case XZ:
665  origin.x -= halfWidth;
666  origin.z += halfHeight;
667  break;
668  case YZ:
669  origin.y -= halfWidth;
670  origin.z += halfHeight;
671  break;
672  }
673  qglRasterPos3fv( origin.ToFloatPtr() );
674  qglCallLists(nameLen, GL_UNSIGNED_BYTE, name);
675  }
676  }
677 }
678 
679 /*
680 ================
681 Brush_MakeFaceWinding
682 
683  returns the visible winding
684 ================
685 */
686 idWinding *Brush_MakeFaceWinding(brush_t *b, face_t *face, bool keepOnPlaneWinding) {
687  idWinding *w;
688  face_t *clip;
689  idPlane plane;
690  bool past;
691 
692  // get a poly that covers an effectively infinite area
693  w = new idWinding( face->plane );
694 
695  // chop the poly by all of the other faces
696  past = false;
697  for (clip = b->brush_faces; clip && w; clip = clip->next) {
698  if (clip == face) {
699  past = true;
700  continue;
701  }
702 
703  if ( DotProduct(face->plane, clip->plane) > 0.999f &&
704  idMath::Fabs(face->plane[3] - clip->plane[3]) < 0.01f ) { // identical plane, use the later one
705  if (past) {
706  delete w;
707  common->Printf("Unable to create face winding on brush\n");
708  return NULL;
709  }
710  continue;
711  }
712 
713  // flip the plane, because we want to keep the back side
714  VectorSubtract(vec3_origin, clip->plane, plane );
715  plane[3] = -clip->plane[3];
716 
717  w = w->Clip( plane, ON_EPSILON, keepOnPlaneWinding );
718  if ( !w ) {
719  return w;
720  }
721  }
722 
723  if ( w->GetNumPoints() < 3) {
724  delete w;
725  w = NULL;
726  }
727 
728  if (!w) {
729  Sys_Status("Unable to create face winding on brush\n");
730  }
731  return w;
732 }
733 
734 /*
735 ================
736 Brush_Build
737 
738  Builds a brush rendering data and also sets the min/max bounds
739  TTimo added a bConvert flag to convert between old and new brush texture formats
740  TTimo brush grouping: update the group treeview if necessary
741 ================
742 */
743 void Brush_Build(brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool updateLights) {
744  bool bLocalConvert = false;
745 
746 #ifdef _DEBUG
747  if (!g_qeglobals.m_bBrushPrimitMode && bConvert) {
748  common->Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
749  }
750 #endif
751  //
752  // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need
753  // convert for this brush only
754  //
755  if (bConvert && !g_qeglobals.bNeedConvert) {
756  bLocalConvert = true;
757  g_qeglobals.bNeedConvert = true;
758  }
759 
760  /* build the windings and generate the bounding box */
761  Brush_BuildWindings(b, bSnap, EntityHasModel(b->owner) || b->pPatch, updateLights);
762 
763  /* move the points and edges if in select mode */
764  if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) {
765  SetupVertexSelection();
766  }
767 
768  if (bMarkMap) {
769  Sys_MarkMapModified();
771  }
772 
773  if (bLocalConvert) {
774  g_qeglobals.bNeedConvert = false;
775  }
776 }
777 
778 /*
779 ================
780 Brush_SplitBrushByFace
781 
782  The incoming brush is NOT freed. The incoming face is NOT left referenced.
783 ================
784 */
785 void Brush_SplitBrushByFace(brush_t *in, face_t *f, brush_t **front, brush_t **back) {
786  brush_t *b;
787  face_t *nf;
788  idVec3 temp;
789 
790  b = Brush_Clone(in);
791  nf = Face_Clone(f);
792 
793  nf->texdef = b->brush_faces->texdef;
794  nf->brushprimit_texdef = b->brush_faces->brushprimit_texdef;
795  nf->next = b->brush_faces;
796  b->brush_faces = nf;
797 
798  Brush_Build(b);
800  if (!b->brush_faces) { // completely clipped away
801  Brush_Free(b);
802  *back = NULL;
803  }
804  else {
805  Entity_LinkBrush(in->owner, b);
806  *back = b;
807  }
808 
809  b = Brush_Clone(in);
810  nf = Face_Clone(f);
811 
812  // swap the plane winding
813  VectorCopy(nf->planepts[0], temp);
814  VectorCopy(nf->planepts[1], nf->planepts[0]);
815  VectorCopy(temp, nf->planepts[1]);
816 
817  nf->texdef = b->brush_faces->texdef;
818  nf->brushprimit_texdef = b->brush_faces->brushprimit_texdef;
819  nf->next = b->brush_faces;
820  b->brush_faces = nf;
821 
822  Brush_Build(b);
824  if (!b->brush_faces) { // completely clipped away
825  Brush_Free(b);
826  *front = NULL;
827  }
828  else {
829  Entity_LinkBrush(in->owner, b);
830  *front = b;
831  }
832 }
833 
834 /*
835 ================
836 Brush_BestSplitFace
837 
838  returns the best face to split the brush with. return NULL if the brush is convex
839 ================
840 */
841 face_t *Brush_BestSplitFace(brush_t *b) {
842  face_t *face, *f, *bestface;
843  idWinding *front, *back;
844  int splits, tinywindings, value, bestvalue;
845 
846  bestvalue = 999999;
847  bestface = NULL;
848  for ( face = b->brush_faces; face; face = face->next ) {
849  splits = 0;
850  tinywindings = 0;
851  for ( f = b->brush_faces; f; f = f->next ) {
852  if ( f == face ) {
853  continue;
854  }
855 
856  f->face_winding->Split( face->plane, 0.1f, &front, &back );
857 
858  if ( !front ) {
859  delete back;
860  }
861  else if ( !back ) {
862  delete front;
863  }
864  else {
865  splits++;
866  if ( front->IsTiny() ) {
867  tinywindings++;
868  }
869 
870  if ( back->IsTiny() ) {
871  tinywindings++;
872  }
873  delete front;
874  delete back;
875  }
876  }
877 
878  if ( splits ) {
879  value = splits + 50 * tinywindings;
880  if ( value < bestvalue ) {
881  bestvalue = value;
882  bestface = face;
883  }
884  }
885  }
886 
887  return bestface;
888 }
889 
890 /*
891 ================
892 Brush_MakeConvexBrushes
893 
894  MrE FIXME: this doesn't work because the old Brush_SplitBrushByFace is used
895  Turns the brush into a minimal number of convex brushes.
896  If the input brush is convex then it will be returned. Otherwise the input
897  brush will be freed.
898  NOTE: the input brush should have windings for the faces.
899 ================
900 */
901 brush_t *Brush_MakeConvexBrushes(brush_t *b) {
902  brush_t *front, *back, *end;
903  face_t *face;
904 
905  b->next = NULL;
906  face = Brush_BestSplitFace(b);
907  if (!face) {
908  return b;
909  }
910 
911  Brush_SplitBrushByFace(b, face, &front, &back);
912 
913  // this should never happen
914  if (!front && !back) {
915  return b;
916  }
917 
918  Brush_Free(b);
919  if (!front) {
920  return Brush_MakeConvexBrushes(back);
921  }
922 
923  b = Brush_MakeConvexBrushes(front);
924  if (back) {
925  for (end = b; end->next; end = end->next);
926  end->next = Brush_MakeConvexBrushes(back);
927  }
928 
929  return b;
930 }
931 
932 /*
933 ================
934 Brush_Convex
935 
936  returns true if the brush is convex
937 ================
938 */
939 int Brush_Convex(brush_t *b) {
940  face_t *face1, *face2;
941 
942  for (face1 = b->brush_faces; face1; face1 = face1->next) {
943  if (!face1->face_winding) {
944  continue;
945  }
946 
947  for (face2 = b->brush_faces; face2; face2 = face2->next) {
948  if (face1 == face2) {
949  continue;
950  }
951 
952  if (!face2->face_winding) {
953  continue;
954  }
955 
956  if ( face1->face_winding->PlanesConcave( *face2->face_winding,
957  face1->plane.Normal(), face2->plane.Normal(), -face1->plane[3], -face2->plane[3] ) ) {
958  return false;
959  }
960  }
961  }
962 
963  return true;
964 }
965 
966 /*
967 ================
968 Brush_MoveVertexes
969 
970  The input brush must be convex.
971  The input brush must have face windings.
972  The output brush will be convex.
973  Returns true if the WHOLE vertex movement is performed.
974 ================
975 */
976 #define MAX_MOVE_FACES 64
977 #define TINY_EPSILON 0.0325f
978 
979 int Brush_MoveVertex(brush_t *b, const idVec3 &vertex, const idVec3 &delta, idVec3 &end, bool bSnap) {
980  face_t *f, *face, *newface, *lastface, *nextface;
981  face_t *movefaces[MAX_MOVE_FACES];
982  int movefacepoints[MAX_MOVE_FACES];
983  idWinding *w, tmpw(3);
984  idVec3 start, mid;
985  idPlane plane;
986  int i, j, k, nummovefaces, result, done;
987  float dot, front, back, frac, smallestfrac;
988 
989  result = true;
990  tmpw.SetNumPoints( 3 );
991  VectorCopy(vertex, start);
992  VectorAdd(vertex, delta, end);
993 
994  // snap or not?
995  //
996  if (bSnap) {
997  for (i = 0; i < 3; i++) {
998  end[i] = floor( end[i] / 0.125f + 0.5f ) * 0.125f;
999  }
1000  }
1001 
1002  VectorCopy(end, mid);
1003 
1004  // if the start and end are the same
1005  if ( start.Compare( end, TINY_EPSILON ) ) {
1006  return false;
1007  }
1008 
1009  // the end point may not be the same as another vertex
1010  for ( face = b->brush_faces; face; face = face->next ) {
1011  w = face->face_winding;
1012  if (!w) {
1013  continue;
1014  }
1015 
1016  for (i = 0; i < w->GetNumPoints(); i++) {
1017  if ( end.Compare( (*w)[i].ToVec3(), TINY_EPSILON ) ) {
1018  VectorCopy(vertex, end);
1019  return false;
1020  }
1021  }
1022  }
1023 
1024  done = false;
1025  while (!done) {
1026  //
1027  // chop off triangles from all brush faces that use the to be moved vertex store
1028  // pointers to these chopped off triangles in movefaces[]
1029  //
1030  nummovefaces = 0;
1031  for (face = b->brush_faces; face; face = face->next) {
1032  w = face->face_winding;
1033  if (!w) {
1034  continue;
1035  }
1036 
1037  for (i = 0; i < w->GetNumPoints(); i++) {
1038  if ( start.Compare( (*w)[i].ToVec3(), TINY_EPSILON ) ) {
1039  if (face->face_winding->GetNumPoints() <= 3) {
1040  movefacepoints[nummovefaces] = i;
1041  movefaces[nummovefaces++] = face;
1042  break;
1043  }
1044 
1045  dot = DotProduct(end, face->plane) + face->plane[3];
1046 
1047  // if the end point is in front of the face plane
1048  //if ( dot > 0.1f ) {
1049  if ( dot > TINY_EPSILON ) {
1050  // fanout triangle subdivision
1051  for (k = i; k < i + w->GetNumPoints() - 3; k++) {
1052  VectorCopy((*w)[i], tmpw[0]);
1053  VectorCopy((*w)[(k + 1) % w->GetNumPoints()], tmpw[1]);
1054  VectorCopy((*w)[(k + 2) % w->GetNumPoints()], tmpw[2]);
1055  newface = Face_Clone(face);
1056 
1057  // get the original
1058  for (f = face; f->original; f = f->original) {};
1059 
1060  newface->original = f;
1061 
1062  // store the new winding
1063  if (newface->face_winding) {
1064  delete newface->face_winding;
1065  }
1066 
1067  newface->face_winding = tmpw.Copy();
1068 
1069  // get the texture
1070  newface->d_texture = Texture_ForName(newface->texdef.name);
1071 
1072  // add the face to the brush
1073  newface->next = b->brush_faces;
1074  b->brush_faces = newface;
1075 
1076  // add this new triangle to the move faces
1077  movefacepoints[nummovefaces] = 0;
1078  movefaces[nummovefaces++] = newface;
1079  }
1080 
1081  // give the original face a new winding
1082  VectorCopy((*w)[(i - 2 + w->GetNumPoints()) % w->GetNumPoints()], tmpw[0]);
1083  VectorCopy((*w)[(i - 1 + w->GetNumPoints()) % w->GetNumPoints()], tmpw[1]);
1084  VectorCopy((*w)[i], tmpw[2]);
1085  delete face->face_winding;
1086  face->face_winding = tmpw.Copy();
1087 
1088  // add the original face to the move faces
1089  movefacepoints[nummovefaces] = 2;
1090  movefaces[nummovefaces++] = face;
1091  }
1092  else {
1093  // chop a triangle off the face
1094  VectorCopy((*w)[(i - 1 + w->GetNumPoints()) % w->GetNumPoints()], tmpw[0]);
1095  VectorCopy((*w)[i], tmpw[1]);
1096  VectorCopy((*w)[(i + 1) % w->GetNumPoints()], tmpw[2]);
1097 
1098  // remove the point from the face winding
1099  w->RemovePoint( i );
1100 
1101  // get texture crap right
1102  Face_SetColor(b, face, 1.0);
1103  for (j = 0; j < w->GetNumPoints(); j++) {
1104  EmitTextureCoordinates( (*w)[j], face->d_texture, face );
1105  }
1106 
1107  // make a triangle face
1108  newface = Face_Clone(face);
1109 
1110  // get the original
1111  for (f = face; f->original; f = f->original) {};
1112 
1113  newface->original = f;
1114 
1115  // store the new winding
1116  if (newface->face_winding) {
1117  delete newface->face_winding;
1118  }
1119 
1120  newface->face_winding = tmpw.Copy();
1121 
1122  // get the texture
1123  newface->d_texture = Texture_ForName(newface->texdef.name);
1124 
1125  // add the face to the brush
1126  newface->next = b->brush_faces;
1127  b->brush_faces = newface;
1128  movefacepoints[nummovefaces] = 1;
1129  movefaces[nummovefaces++] = newface;
1130  }
1131  break;
1132  }
1133  }
1134  }
1135 
1136  //
1137  // now movefaces contains pointers to triangle faces that contain the to be moved
1138  // vertex
1139  //
1140  done = true;
1141  VectorCopy(end, mid);
1142  smallestfrac = 1;
1143  for (face = b->brush_faces; face; face = face->next) {
1144  // check if there is a move face that has this face as the original
1145  for (i = 0; i < nummovefaces; i++) {
1146  if (movefaces[i]->original == face) {
1147  break;
1148  }
1149  }
1150 
1151  if (i >= nummovefaces) {
1152  continue;
1153  }
1154 
1155  // check if the original is not a move face itself
1156  for (j = 0; j < nummovefaces; j++) {
1157  if (face == movefaces[j]) {
1158  break;
1159  }
1160  }
1161 
1162  // if the original is not a move face itself
1163  if (j >= nummovefaces) {
1164  memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane));
1165  }
1166  else {
1167  k = movefacepoints[j];
1168  w = movefaces[j]->face_winding;
1169  VectorCopy((*w)[(k + 1) % w->GetNumPoints()], tmpw[0]);
1170  VectorCopy((*w)[(k + 2) % w->GetNumPoints()], tmpw[1]);
1171 
1172  k = movefacepoints[i];
1173  w = movefaces[i]->face_winding;
1174  VectorCopy((*w)[(k + 1) % w->GetNumPoints()], tmpw[2]);
1175 
1176  if ( !plane.FromPoints( tmpw[0].ToVec3(), tmpw[1].ToVec3(), tmpw[2].ToVec3(), false ) ) {
1177  VectorCopy((*w)[(k + 2) % w->GetNumPoints()], tmpw[2]);
1178  if ( !plane.FromPoints( tmpw[0].ToVec3(), tmpw[1].ToVec3(), tmpw[2].ToVec3() ), false ) {
1179  // this should never happen otherwise the face merge did
1180  // a crappy job a previous pass
1181  continue;
1182  }
1183  }
1184  plane[0] = -plane[0];
1185  plane[1] = -plane[1];
1186  plane[2] = -plane[2];
1187  plane[3] = -plane[3];
1188  }
1189 
1190  // now we've got the plane to check against
1191  front = DotProduct(start, plane) + plane[3];
1192  back = DotProduct(end, plane) + plane[3];
1193 
1194  // if the whole move is at one side of the plane
1195  if (front < TINY_EPSILON && back < TINY_EPSILON) {
1196  continue;
1197  }
1198 
1199  if (front > -TINY_EPSILON && back > -TINY_EPSILON) {
1200  continue;
1201  }
1202 
1203  // if there's no movement orthogonal to this plane at all
1204  if ( idMath::Fabs(front - back) < 0.001f ) {
1205  continue;
1206  }
1207 
1208  // ok first only move till the plane is hit
1209  frac = front / (front - back);
1210  if (frac < smallestfrac) {
1211  mid[0] = start[0] + (end[0] - start[0]) * frac;
1212  mid[1] = start[1] + (end[1] - start[1]) * frac;
1213  mid[2] = start[2] + (end[2] - start[2]) * frac;
1214  smallestfrac = frac;
1215  }
1216 
1217  done = false;
1218  }
1219 
1220  // move the vertex
1221  for (i = 0; i < nummovefaces; i++) {
1222  // move vertex to end position
1223  VectorCopy( mid, (*movefaces[i]->face_winding)[movefacepoints[i]] );
1224 
1225  // create new face plane
1226  for (j = 0; j < 3; j++) {
1227  VectorCopy( (*movefaces[i]->face_winding)[j], movefaces[i]->planepts[j] );
1228  }
1229 
1230  Face_MakePlane( movefaces[i] );
1231  if ( movefaces[i]->plane.Normal().Length() < TINY_EPSILON ) {
1232  result = false;
1233  }
1234  }
1235 
1236  // if the brush is no longer convex
1237  if (!result || !Brush_Convex(b)) {
1238  for (i = 0; i < nummovefaces; i++) {
1239  // move the vertex back to the initial position
1240  VectorCopy( start, (*movefaces[i]->face_winding)[movefacepoints[i]] );
1241 
1242  // create new face plane
1243  for (j = 0; j < 3; j++) {
1244  VectorCopy( (*movefaces[i]->face_winding)[j], movefaces[i]->planepts[j] );
1245  }
1246 
1247  Face_MakePlane(movefaces[i]);
1248  }
1249 
1250  result = false;
1251  VectorCopy(start, end);
1252  done = true;
1253  }
1254  else {
1255  VectorCopy(mid, start);
1256  }
1257 
1258  // get texture crap right
1259  for (i = 0; i < nummovefaces; i++) {
1260  Face_SetColor( b, movefaces[i], 1.0f );
1261  for (j = 0; j < movefaces[i]->face_winding->GetNumPoints(); j++) {
1262  EmitTextureCoordinates( (*movefaces[i]->face_winding)[j], movefaces[i]->d_texture, movefaces[i] );
1263  }
1264  }
1265 
1266  // now try to merge faces with their original faces
1267  lastface = NULL;
1268  for (face = b->brush_faces; face; face = nextface) {
1269  nextface = face->next;
1270  if (!face->original) {
1271  lastface = face;
1272  continue;
1273  }
1274 
1275  if ( !face->plane.Compare( face->original->plane, 0.0001f ) ) {
1276  lastface = face;
1277  continue;
1278  }
1279 
1280  w = face->face_winding->TryMerge( *face->original->face_winding, face->plane.Normal(), true );
1281  if (!w) {
1282  lastface = face;
1283  continue;
1284  }
1285 
1286  delete face->original->face_winding;
1287  face->original->face_winding = w;
1288 
1289  // get texture crap right
1290  Face_SetColor( b, face->original, 1.0f );
1291  for (j = 0; j < face->original->face_winding->GetNumPoints(); j++) {
1292  EmitTextureCoordinates( (*face->original->face_winding)[j], face->original->d_texture, face->original);
1293  }
1294 
1295  // remove the face that was merged with the original
1296  if (lastface) {
1297  lastface->next = face->next;
1298  }
1299  else {
1300  b->brush_faces = face->next;
1301  }
1302 
1303  Face_Free(face);
1304  }
1305  }
1306 
1307  return result;
1308 }
1309 
1310 /*
1311 ================
1312 Brush_InsertVertexBetween
1313 
1314  Adds a vertex to the brush windings between the given two points.
1315 ================
1316 */
1317 int Brush_InsertVertexBetween(brush_t *b, idVec3 p1, idVec3 p2) {
1318  face_t *face;
1319  idWinding *w, *neww;
1320  idVec3 point;
1321  int i, insert;
1322 
1323  if ( p1.Compare( p2, TINY_EPSILON ) ) {
1324  return false;
1325  }
1326 
1327  VectorAdd( p1, p2, point );
1328  VectorScale( point, 0.5f, point );
1329  insert = false;
1330 
1331  // the end point may not be the same as another vertex
1332  for (face = b->brush_faces; face; face = face->next) {
1333  w = face->face_winding;
1334  if (!w) {
1335  continue;
1336  }
1337 
1338  neww = NULL;
1339  for (i = 0; i < w->GetNumPoints(); i++) {
1340  if (! p1.Compare((*w)[i].ToVec3(), TINY_EPSILON)) {
1341  continue;
1342  }
1343 
1344  if ( p2.Compare( (*w)[(i + 1) % w->GetNumPoints()].ToVec3(), TINY_EPSILON ) ) {
1345  neww = new idWinding( *w );
1346  neww->InsertPoint( point, (i + 1) % w->GetNumPoints() );
1347  break;
1348  }
1349  else if ( p2.Compare( (*w)[(i - 1 + w->GetNumPoints()) % w->GetNumPoints()].ToVec3(), TINY_EPSILON ) ) {
1350  neww = new idWinding( *w );
1351  neww->InsertPoint( point, i );
1352  break;
1353  }
1354  }
1355 
1356  if (neww) {
1357  delete face->face_winding;
1358  face->face_winding = neww;
1359  insert = true;
1360  }
1361  }
1362 
1363  return insert;
1364 }
1365 
1366 /*
1367 ================
1368 Brush_ResetFaceOriginals
1369 
1370  reset points to original faces to NULL
1371 ================
1372 */
1373 void Brush_ResetFaceOriginals(brush_t *b) {
1374  face_t *face;
1375 
1376  for (face = b->brush_faces; face; face = face->next) {
1377  face->original = NULL;
1378  }
1379 }
1380 
1381 /*
1382 ================
1383 Brush_Parse
1384 
1385  The brush is NOT linked to any list
1386  FIXME: when using old brush primitives, the test loop for "Brush" and "patchDef2" "patchDef3"
1387  run before each face parsing. It works, but it's a performance hit
1388 ================
1389 */
1390 brush_t *Brush_Parse(idVec3 origin) {
1391  brush_t *b;
1392  face_t *f;
1393  int i, j;
1394  idVec3 useOrigin = origin;
1395 
1396  g_qeglobals.d_parsed_brushes++;
1397  b = Brush_Alloc();
1398  do {
1399  if (!GetToken(true)) {
1400  break;
1401  }
1402 
1403  if (!strcmp(token, "}")) {
1404  break;
1405  }
1406 
1407  // handle "Brush" primitive
1408  if ( idStr::Icmp(token, "brushDef") == 0 || idStr::Icmp(token, "brushDef2") == 0 || idStr::Icmp(token, "brushDef3") == 0 ) {
1409  // Timo parsing new brush format
1410  g_qeglobals.bPrimitBrushes = true;
1411 
1412  // check the map is not mixing the two kinds of brushes
1413  if (g_qeglobals.m_bBrushPrimitMode) {
1414  if (g_qeglobals.bOldBrushes) {
1415  common->Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n");
1416  }
1417  }
1418  else {
1419  // ++Timo write new brush primitive -> old conversion code for Q3->Q2 conversions ?
1420  common->Printf("Warning : conversion code from brush primitive not done ( Brush_Parse )\n");
1421  }
1422 
1423  bool newFormat = false;
1424  if ( idStr::Icmp(token, "brushDef2") == 0 ) {
1425  newFormat = true;
1426 
1427  // useOrigin.Zero();
1428  }
1429  else if ( idStr::Icmp(token, "brushDef3") == 0 ) {
1430  newFormat = true;
1431  }
1432 
1433 
1434  BrushPrimit_Parse(b, newFormat, useOrigin);
1435 
1436  if (newFormat) {
1437  //Brush_BuildWindings(b, true, true, false, false);
1438  }
1439 
1440  if (b == NULL) {
1441  Warning("parsing brush primitive");
1442  return NULL;
1443  }
1444  else {
1445  continue;
1446  }
1447  }
1448 
1449  if ( idStr::Icmp(token, "patchDef2") == 0 || idStr::Icmp(token, "patchDef3") == 0 ) {
1450  Brush_Free(b);
1451 
1452  // double string compare but will go away soon
1453  b = Patch_Parse( idStr::Icmp(token, "patchDef2") == 0 );
1454  if (b == NULL) {
1455  Warning("parsing patch/brush");
1456  return NULL;
1457  }
1458  else {
1459  continue;
1460  }
1461 
1462  // handle inline patch
1463  }
1464  else {
1465  // Timo parsing old brush format
1466  g_qeglobals.bOldBrushes = true;
1467  if (g_qeglobals.m_bBrushPrimitMode) {
1468  // check the map is not mixing the two kinds of brushes
1469  if (g_qeglobals.bPrimitBrushes) {
1470  common->Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n");
1471  }
1472 
1473  // set the "need" conversion flag
1474  g_qeglobals.bNeedConvert = true;
1475  }
1476 
1477  f = Face_Alloc();
1478 
1479  //
1480  // add the brush to the end of the chain, so loading and saving a map doesn't
1481  // reverse the order
1482  //
1483  f->next = NULL;
1484  if (!b->brush_faces) {
1485  b->brush_faces = f;
1486  }
1487  else {
1488  face_t *scan;
1489  for (scan = b->brush_faces; scan->next; scan = scan->next)
1490  ;
1491  scan->next = f;
1492  }
1493 
1494  // read the three point plane definition
1495  for (i = 0; i < 3; i++) {
1496  if (i != 0) {
1497  GetToken(true);
1498  }
1499 
1500  if (strcmp(token, "(")) {
1501  Warning("parsing brush");
1502  return NULL;
1503  }
1504 
1505  for (j = 0; j < 3; j++) {
1506  GetToken(false);
1507  f->planepts[i][j] = atof(token);
1508  }
1509 
1510  GetToken(false);
1511  if (strcmp(token, ")")) {
1512  Warning("parsing brush");
1513  return NULL;
1514  }
1515  }
1516  }
1517 
1518  // read the texturedef
1519  GetToken(false);
1520  f->texdef.SetName(token);
1521  if (token[0] == '(') {
1522  int i = 32;
1523  }
1524 
1525  GetToken(false);
1526  f->texdef.shift[0] = atoi(token);
1527  GetToken(false);
1528  f->texdef.shift[1] = atoi(token);
1529  GetToken(false);
1530  f->texdef.rotate = atoi(token);
1531  GetToken(false);
1532  f->texdef.scale[0] = atof(token);
1533  GetToken(false);
1534  f->texdef.scale[1] = atof(token);
1535 
1536  // the flags and value field aren't necessarily present
1537  f->d_texture = Texture_ForName(f->texdef.name);
1538 
1539  //
1540  // FIXME: idMaterial f->texdef.flags = f->d_texture->flags; f->texdef.value =
1541  // f->d_texture->value; f->texdef.contents = f->d_texture->contents;
1542  //
1543  if (TokenAvailable()) {
1544  GetToken(false);
1545  GetToken(false);
1546  GetToken(false);
1547  f->texdef.value = atoi(token);
1548  }
1549  } while (1);
1550 
1551  return b;
1552 }
1553 
1554 /*
1555 ================
1556 QERApp_MapPrintf_FILE
1557 
1558  callback for surface properties plugin must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h )
1559  carefully initialize !
1560 ================
1561 */
1562 FILE *g_File;
1563 
1564 void WINAPI QERApp_MapPrintf_FILE(char *text, ...) {
1565  va_list argptr;
1566  char buf[32768];
1567 
1568  va_start(argptr, text);
1569  vsprintf(buf, text, argptr);
1570  va_end(argptr);
1571 
1572  fprintf(g_File, buf);
1573 }
1574 
1575 /*
1576 ================
1577 Brush_SetEpair
1578 
1579  sets an epair for the given brush
1580 ================
1581 */
1582 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue) {
1583  if (g_qeglobals.m_bBrushPrimitMode) {
1584  if (b->pPatch) {
1585  Patch_SetEpair(b->pPatch, pKey, pValue);
1586  }
1587  else {
1588  b->epairs.Set(pKey, pValue);
1589  }
1590  }
1591  else {
1592  Sys_Status("Can only set key/values in Brush primitive mode\n");
1593  }
1594 }
1595 
1596 /*
1597 ================
1598 Brush_GetKeyValue
1599 ================
1600 */
1601 const char *Brush_GetKeyValue(brush_t *b, const char *pKey) {
1602  if (g_qeglobals.m_bBrushPrimitMode) {
1603  if (b->pPatch) {
1604  return Patch_GetKeyValue(b->pPatch, pKey);
1605  }
1606  else {
1607  return b->epairs.GetString(pKey);
1608  }
1609  }
1610  else {
1611  Sys_Status("Can only set brush/patch key/values in Brush primitive mode\n");
1612  }
1613 
1614  return "";
1615 }
1616 
1617 /*
1618 ================
1619 Brush_Write
1620 
1621  save all brushes as Brush primitive format
1622 ================
1623 */
1624 void Brush_Write(brush_t *b, FILE *f, const idVec3 &origin, bool newFormat) {
1625  face_t *fa;
1626  char *pname;
1627  int i;
1628 
1629  if (b->pPatch) {
1630  Patch_Write(b->pPatch, f);
1631  return;
1632  }
1633 
1634  if (g_qeglobals.m_bBrushPrimitMode) {
1635  // save brush primitive format
1636  if (newFormat) {
1637  WriteFileString(f, "{\nbrushDef3\n{\n");
1638  }
1639  else {
1640  WriteFileString(f, "{\nbrushDef\n{\n");
1641  }
1642 
1643  // brush epairs
1644  int count = b->epairs.GetNumKeyVals();
1645  for (int j = 0; j < count; j++) {
1646  WriteFileString(f, "\"%s\" \"%s\"\n", b->epairs.GetKeyVal(j)->GetKey().c_str(), b->epairs.GetKeyVal(j)->GetValue().c_str());
1647  }
1648 
1649  for (fa = b->brush_faces; fa; fa = fa->next) {
1650  // save planepts
1651  if (newFormat) {
1652  idPlane plane;
1653 
1654  if (fa->dirty) {
1655  fa->planepts[0] -= origin;
1656  fa->planepts[1] -= origin;
1657  fa->planepts[2] -= origin;
1658  plane.FromPoints( fa->planepts[0], fa->planepts[1], fa->planepts[2], false );
1659  fa->planepts[0] += origin;
1660  fa->planepts[1] += origin;
1661  fa->planepts[2] += origin;
1662  } else {
1663  plane = fa->originalPlane;
1664  }
1665 
1666  WriteFileString(f, " ( ");
1667  for (i = 0; i < 4; i++) {
1668  if (plane[i] == (int)plane[i]) {
1669  WriteFileString(f, "%i ", (int)plane[i]);
1670  }
1671  else {
1672  WriteFileString(f, "%f ", plane[i]);
1673  }
1674  }
1675 
1676  WriteFileString(f, ") ");
1677  }
1678  else {
1679  for (i = 0; i < 3; i++) {
1680  WriteFileString(f, "( ");
1681  for (int j = 0; j < 3; j++) {
1682  if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1683  WriteFileString(f, "%i ", static_cast<int>(fa->planepts[i][j]));
1684  }
1685  else {
1686  WriteFileString(f, "%f ", fa->planepts[i][j]);
1687  }
1688  }
1689 
1690  WriteFileString(f, ") ");
1691  }
1692  }
1693 
1694  // save texture coordinates
1695  WriteFileString(f, "( ( ");
1696  for (i = 0; i < 3; i++) {
1697  if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i])) {
1698  WriteFileString(f, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[0][i]));
1699  }
1700  else {
1701  WriteFileString(f, "%f ", fa->brushprimit_texdef.coords[0][i]);
1702  }
1703  }
1704 
1705  WriteFileString(f, ") ( ");
1706  for (i = 0; i < 3; i++) {
1707  if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i])) {
1708  WriteFileString(f, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[1][i]));
1709  }
1710  else {
1711  WriteFileString(f, "%f ", fa->brushprimit_texdef.coords[1][i]);
1712  }
1713  }
1714 
1715  WriteFileString(f, ") ) ");
1716 
1717  char *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "notexture";
1718  WriteFileString(f, "\"%s\" ", pName);
1719  WriteFileString(f, "%i %i %i\n", 0, 0, 0);
1720  }
1721 
1722  WriteFileString(f, "}\n}\n");
1723  }
1724  else {
1725  WriteFileString(f, "{\n");
1726  for (fa = b->brush_faces; fa; fa = fa->next) {
1727  for (i = 0; i < 3; i++) {
1728  WriteFileString(f, "( ");
1729  for (int j = 0; j < 3; j++) {
1730  if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1731  WriteFileString(f, "%i ", static_cast<int>(fa->planepts[i][j]));
1732  }
1733  else {
1734  WriteFileString(f, "%f ", fa->planepts[i][j]);
1735  }
1736  }
1737 
1738  WriteFileString(f, ") ");
1739  }
1740 
1741  pname = fa->texdef.name;
1742  if (pname[0] == 0) {
1743  pname = "unnamed";
1744  }
1745 
1747  (
1748  f,
1749  "%s %i %i %i ",
1750  pname,
1751  (int)fa->texdef.shift[0],
1752  (int)fa->texdef.shift[1],
1753  (int)fa->texdef.rotate
1754  );
1755 
1756  if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) {
1757  WriteFileString(f, "%i ", (int)fa->texdef.scale[0]);
1758  }
1759  else {
1760  WriteFileString(f, "%f ", (float)fa->texdef.scale[0]);
1761  }
1762 
1763  if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) {
1764  WriteFileString(f, "%i", (int)fa->texdef.scale[1]);
1765  }
1766  else {
1767  WriteFileString(f, "%f", (float)fa->texdef.scale[1]);
1768  }
1769 
1770  WriteFileString(f, " %i %i %i",0, 0, 0);
1771 
1772  WriteFileString(f, "\n");
1773  }
1774 
1775  WriteFileString(f, "}\n");
1776  }
1777 }
1778 
1779 /*
1780 ================
1781 QERApp_MapPrintf_MEMFILE
1782 
1783  callback for surface properties plugin must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h )
1784  carefully initialize !
1785 ================
1786 */
1787 CMemFile *g_pMemFile;
1788 
1789 void WINAPI QERApp_MapPrintf_MEMFILE(char *text, ...) {
1790  va_list argptr;
1791  char buf[32768];
1792 
1793  va_start(argptr, text);
1794  vsprintf(buf, text, argptr);
1795  va_end(argptr);
1796 
1798 }
1799 
1800 /*
1801 ================
1802 Brush_Write
1803 
1804  save all brushes as Brush primitive format to a CMemFile*
1805 ================
1806 */
1807 void Brush_Write(brush_t *b, CMemFile *pMemFile, const idVec3 &origin, bool newFormat) {
1808  face_t *fa;
1809  char *pname;
1810  int i;
1811 
1812  if (b->pPatch) {
1813  Patch_Write(b->pPatch, pMemFile);
1814  return;
1815  }
1816 
1817  if (g_qeglobals.m_bBrushPrimitMode) {
1818  // brush primitive format
1819  if (newFormat) {
1820  MemFile_fprintf(pMemFile, "{\nBrushDef2\n{\n");
1821  }
1822  else {
1823  MemFile_fprintf(pMemFile, "{\nBrushDef\n{\n");
1824  }
1825 
1826  // brush epairs
1827  // brush epairs
1828  int count = b->epairs.GetNumKeyVals();
1829  for (int j = 0; j < count; j++) {
1830  MemFile_fprintf(pMemFile, "\"%s\" \"%s\"\n", b->epairs.GetKeyVal(j)->GetKey().c_str(), b->epairs.GetKeyVal(j)->GetValue().c_str());
1831  }
1832 
1833  for (fa = b->brush_faces; fa; fa = fa->next) {
1834  if (newFormat) {
1835  // save planepts
1836  idPlane plane;
1837 
1838  if (fa->dirty) {
1839  fa->planepts[0] -= origin;
1840  fa->planepts[1] -= origin;
1841  fa->planepts[2] -= origin;
1842  plane.FromPoints( fa->planepts[0], fa->planepts[1], fa->planepts[2], false );
1843  fa->planepts[0] += origin;
1844  fa->planepts[1] += origin;
1845  fa->planepts[2] += origin;
1846  } else {
1847  plane = fa->originalPlane;
1848  }
1849 
1850  MemFile_fprintf(pMemFile, " ( ");
1851  for (i = 0; i < 4; i++) {
1852  if (plane[i] == (int)plane[i]) {
1853  MemFile_fprintf(pMemFile, "%i ", (int)plane[i]);
1854  }
1855  else {
1856  MemFile_fprintf(pMemFile, "%f ", plane[i]);
1857  }
1858  }
1859 
1860  MemFile_fprintf(pMemFile, ") ");
1861  }
1862  else {
1863  for (i = 0; i < 3; i++) {
1864  MemFile_fprintf(pMemFile, "( ");
1865  for (int j = 0; j < 3; j++) {
1866  if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1867  MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j]));
1868  }
1869  else {
1870  MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]);
1871  }
1872  }
1873 
1874  MemFile_fprintf(pMemFile, ") ");
1875  }
1876  }
1877 
1878  // save texture coordinates
1879  MemFile_fprintf(pMemFile, "( ( ");
1880  for (i = 0; i < 3; i++) {
1881  if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i])) {
1882  MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[0][i]));
1883  }
1884  else {
1885  MemFile_fprintf(pMemFile, "%f ", fa->brushprimit_texdef.coords[0][i]);
1886  }
1887  }
1888 
1889  MemFile_fprintf(pMemFile, ") ( ");
1890  for (i = 0; i < 3; i++) {
1891  if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i])) {
1892  MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[1][i]));
1893  }
1894  else {
1895  MemFile_fprintf(pMemFile, "%f ", fa->brushprimit_texdef.coords[1][i]);
1896  }
1897  }
1898 
1899  MemFile_fprintf(pMemFile, ") ) ");
1900 
1901  // save texture attribs
1902  char *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "unnamed";
1903  MemFile_fprintf(pMemFile, "\"%s\" ", pName);
1904  MemFile_fprintf(pMemFile, "%i %i %i\n", 0, 0, 0);
1905  }
1906 
1907  MemFile_fprintf(pMemFile, "}\n}\n");
1908  }
1909  else {
1910  // old brushes format also handle surface properties plugin
1911  MemFile_fprintf(pMemFile, "{\n");
1912  for (fa = b->brush_faces; fa; fa = fa->next) {
1913  for (i = 0; i < 3; i++) {
1914  MemFile_fprintf(pMemFile, "( ");
1915  for (int j = 0; j < 3; j++) {
1916  if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1917  MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j]));
1918  }
1919  else {
1920  MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]);
1921  }
1922  }
1923 
1924  MemFile_fprintf(pMemFile, ") ");
1925  }
1926 
1927  pname = fa->texdef.name;
1928  if (pname[0] == 0) {
1929  pname = "unnamed";
1930  }
1931 
1933  (
1934  pMemFile,
1935  "%s %i %i %i ",
1936  pname,
1937  (int)fa->texdef.shift[0],
1938  (int)fa->texdef.shift[1],
1939  (int)fa->texdef.rotate
1940  );
1941 
1942  if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) {
1943  MemFile_fprintf(pMemFile, "%i ", (int)fa->texdef.scale[0]);
1944  }
1945  else {
1946  MemFile_fprintf(pMemFile, "%f ", (float)fa->texdef.scale[0]);
1947  }
1948 
1949  if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) {
1950  MemFile_fprintf(pMemFile, "%i", (int)fa->texdef.scale[1]);
1951  }
1952  else {
1953  MemFile_fprintf(pMemFile, "%f", (float)fa->texdef.scale[1]);
1954  }
1955 
1956  MemFile_fprintf(pMemFile, " %i %i %i", 0, 0, 0);
1957 
1958  MemFile_fprintf(pMemFile, "\n");
1959  }
1960 
1961  MemFile_fprintf(pMemFile, "}\n");
1962  }
1963 }
1964 
1965 /*
1966 ================
1967 Brush_Create
1968 
1969  Create non-textured blocks for entities The brush is NOT linked to any list
1970 ================
1971 */
1972 brush_t *Brush_Create(idVec3 mins, idVec3 maxs, texdef_t *texdef) {
1973  int i, j;
1974  idVec3 pts[4][2];
1975  face_t *f;
1976  brush_t *b;
1977 
1978  //
1979  // brush primitive mode : convert texdef to brushprimit_texdef ? most of the time
1980  // texdef is empty
1981  //
1982  for (i = 0; i < 3; i++) {
1983  if (maxs[i] < mins[i]) {
1984  Error("Brush_InitSolid: backwards");
1985  }
1986  }
1987 
1988  b = Brush_Alloc();
1989 
1990  pts[0][0][0] = mins[0];
1991  pts[0][0][1] = mins[1];
1992 
1993  pts[1][0][0] = mins[0];
1994  pts[1][0][1] = maxs[1];
1995 
1996  pts[2][0][0] = maxs[0];
1997  pts[2][0][1] = maxs[1];
1998 
1999  pts[3][0][0] = maxs[0];
2000  pts[3][0][1] = mins[1];
2001 
2002  for (i = 0; i < 4; i++) {
2003  pts[i][0][2] = mins[2];
2004  pts[i][1][0] = pts[i][0][0];
2005  pts[i][1][1] = pts[i][0][1];
2006  pts[i][1][2] = maxs[2];
2007  }
2008 
2009  for (i = 0; i < 4; i++) {
2010  f = Face_Alloc();
2011  f->texdef = *texdef;
2012  f->next = b->brush_faces;
2013  b->brush_faces = f;
2014  j = (i + 1) % 4;
2015 
2016  VectorCopy(pts[j][1], f->planepts[0]);
2017  VectorCopy(pts[i][1], f->planepts[1]);
2018  VectorCopy(pts[i][0], f->planepts[2]);
2019  }
2020 
2021  f = Face_Alloc();
2022  f->texdef = *texdef;
2023  f->next = b->brush_faces;
2024  b->brush_faces = f;
2025 
2026  VectorCopy(pts[0][1], f->planepts[0]);
2027  VectorCopy(pts[1][1], f->planepts[1]);
2028  VectorCopy(pts[2][1], f->planepts[2]);
2029 
2030  f = Face_Alloc();
2031  f->texdef = *texdef;
2032  f->next = b->brush_faces;
2033  b->brush_faces = f;
2034 
2035  VectorCopy(pts[2][0], f->planepts[0]);
2036  VectorCopy(pts[1][0], f->planepts[1]);
2037  VectorCopy(pts[0][0], f->planepts[2]);
2038 
2039  return b;
2040 }
2041 
2042 /*
2043 =============
2044 Brush_Scale
2045 =============
2046 */
2047 void Brush_Scale(brush_t* b) {
2048  for ( face_t *f = b->brush_faces; f; f = f->next ) {
2049  for ( int i = 0; i < 3; i++ ) {
2050  VectorScale( f->planepts[i], g_qeglobals.d_gridsize, f->planepts[i] );
2051  }
2052  }
2053 }
2054 
2055 /*
2056 ================
2057 Brush_CreatePyramid
2058 
2059  Create non-textured pyramid for light entities The brush is NOT linked to any list
2060 ================
2061 */
2062 brush_t *Brush_CreatePyramid(idVec3 mins, idVec3 maxs, texdef_t *texdef) {
2063  // ++timo handle new brush primitive ? return here ??
2064  return Brush_Create(mins, maxs, texdef);
2065 
2066  int i;
2067  for (i = 0; i < 3; i++) {
2068  if (maxs[i] < mins[i]) {
2069  Error("Brush_InitSolid: backwards");
2070  }
2071  }
2072 
2073  brush_t *b = Brush_Alloc();
2074 
2075  idVec3 corners[4];
2076 
2077  float fMid = idMath::Rint(mins[2] + (idMath::Rint((maxs[2] - mins[2]) / 2)));
2078 
2079  corners[0][0] = mins[0];
2080  corners[0][1] = mins[1];
2081  corners[0][2] = fMid;
2082 
2083  corners[1][0] = mins[0];
2084  corners[1][1] = maxs[1];
2085  corners[1][2] = fMid;
2086 
2087  corners[2][0] = maxs[0];
2088  corners[2][1] = maxs[1];
2089  corners[2][2] = fMid;
2090 
2091  corners[3][0] = maxs[0];
2092  corners[3][1] = mins[1];
2093  corners[3][2] = fMid;
2094 
2095  idVec3 top, bottom;
2096 
2097  top[0] = idMath::Rint(mins[0] + ((maxs[0] - mins[0]) / 2));
2098  top[1] = idMath::Rint(mins[1] + ((maxs[1] - mins[1]) / 2));
2099  top[2] = idMath::Rint(maxs[2]);
2100 
2101  VectorCopy(top, bottom);
2102  bottom[2] = mins[2];
2103 
2104  // sides
2105  for (i = 0; i < 4; i++) {
2106  face_t *f = Face_Alloc();
2107  f->texdef = *texdef;
2108  f->next = b->brush_faces;
2109  b->brush_faces = f;
2110 
2111  int j = (i + 1) % 4;
2112 
2113  VectorCopy(top, f->planepts[0]);
2114  VectorCopy(corners[i], f->planepts[1]);
2115  VectorCopy(corners[j], f->planepts[2]);
2116 
2117  f = Face_Alloc();
2118  f->texdef = *texdef;
2119  f->next = b->brush_faces;
2120  b->brush_faces = f;
2121 
2122  VectorCopy(bottom, f->planepts[2]);
2123  VectorCopy(corners[i], f->planepts[1]);
2124  VectorCopy(corners[j], f->planepts[0]);
2125  }
2126 
2127  return b;
2128 }
2129 
2130 /*
2131 ================
2132 Brush_MakeSided
2133 
2134  Makes the current brush have the given number of 2d sides
2135 ================
2136 */
2137 void Brush_MakeSided(int sides) {
2138  int i, axis;
2139  idVec3 mins, maxs;
2140  brush_t *b;
2141  texdef_t *texdef;
2142  face_t *f;
2143  idVec3 mid;
2144  float width;
2145  float sv, cv;
2146 
2147  if (sides < 3) {
2148  Sys_Status("Bad sides number", 0);
2149  return;
2150  }
2151 
2152  if (sides >= MAX_POINTS_ON_WINDING - 4) {
2153  Sys_Status("too many sides.\n");
2154  return;
2155  }
2156 
2157  if (!QE_SingleBrush()) {
2158  Sys_Status("Must have a single brush selected", 0);
2159  return;
2160  }
2161 
2162  b = selected_brushes.next;
2163  VectorCopy(b->mins, mins);
2164  VectorCopy(b->maxs, maxs);
2165  texdef = &g_qeglobals.d_texturewin.texdef;
2166 
2167  Brush_Free(b);
2168 
2169  if (g_pParentWnd->ActiveXY()) {
2170  switch (g_pParentWnd->ActiveXY()->GetViewType())
2171  {
2172  case XY:
2173  axis = 2;
2174  break;
2175  case XZ:
2176  axis = 1;
2177  break;
2178  case YZ:
2179  axis = 0;
2180  break;
2181  }
2182  }
2183  else {
2184  axis = 2;
2185  }
2186 
2187  // find center of brush
2188  width = 8;
2189  for (i = 0; i < 3; i++) {
2190  mid[i] = (maxs[i] + mins[i]) * 0.5f;
2191  if (i == axis) {
2192  continue;
2193  }
2194 
2195  if ((maxs[i] - mins[i]) * 0.5f > width) {
2196  width = (maxs[i] - mins[i]) * 0.5f;
2197  }
2198  }
2199 
2200  b = Brush_Alloc();
2201 
2202  // create top face
2203  f = Face_Alloc();
2204  f->texdef = *texdef;
2205  f->next = b->brush_faces;
2206  b->brush_faces = f;
2207 
2208  f->planepts[2][(axis + 1) % 3] = mins[(axis + 1) % 3];
2209  f->planepts[2][(axis + 2) % 3] = mins[(axis + 2) % 3];
2210  f->planepts[2][axis] = maxs[axis];
2211  f->planepts[1][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2212  f->planepts[1][(axis + 2) % 3] = mins[(axis + 2) % 3];
2213  f->planepts[1][axis] = maxs[axis];
2214  f->planepts[0][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2215  f->planepts[0][(axis + 2) % 3] = maxs[(axis + 2) % 3];
2216  f->planepts[0][axis] = maxs[axis];
2217 
2218  // create bottom face
2219  f = Face_Alloc();
2220  f->texdef = *texdef;
2221  f->next = b->brush_faces;
2222  b->brush_faces = f;
2223 
2224  f->planepts[0][(axis + 1) % 3] = mins[(axis + 1) % 3];
2225  f->planepts[0][(axis + 2) % 3] = mins[(axis + 2) % 3];
2226  f->planepts[0][axis] = mins[axis];
2227  f->planepts[1][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2228  f->planepts[1][(axis + 2) % 3] = mins[(axis + 2) % 3];
2229  f->planepts[1][axis] = mins[axis];
2230  f->planepts[2][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2231  f->planepts[2][(axis + 2) % 3] = maxs[(axis + 2) % 3];
2232  f->planepts[2][axis] = mins[axis];
2233 
2234  for (i = 0; i < sides; i++) {
2235  f = Face_Alloc();
2236  f->texdef = *texdef;
2237  f->next = b->brush_faces;
2238  b->brush_faces = f;
2239 
2240  sv = sin(i * 3.14159265 * 2 / sides);
2241  cv = cos(i * 3.14159265 * 2 / sides);
2242 
2243  f->planepts[0][(axis + 1) % 3] = floor(mid[(axis + 1) % 3] + width * cv + 0.5f);
2244  f->planepts[0][(axis + 2) % 3] = floor(mid[(axis + 2) % 3] + width * sv + 0.5f);
2245  f->planepts[0][axis] = mins[axis];
2246 
2247  f->planepts[1][(axis + 1) % 3] = f->planepts[0][(axis + 1) % 3];
2248  f->planepts[1][(axis + 2) % 3] = f->planepts[0][(axis + 2) % 3];
2249  f->planepts[1][axis] = maxs[axis];
2250 
2251  f->planepts[2][(axis + 1) % 3] = floor(f->planepts[0][(axis + 1) % 3] - width * sv + 0.5f);
2252  f->planepts[2][(axis + 2) % 3] = floor(f->planepts[0][(axis + 2) % 3] + width * cv + 0.5f);
2253  f->planepts[2][axis] = maxs[axis];
2254  }
2255 
2257 
2259 
2260  Brush_Build(b);
2261 
2262  Sys_UpdateWindows(W_ALL);
2263 }
2264 
2265 /*
2266 ================
2267 Brush_Free
2268 
2269  Frees the brush with all of its faces and display list.
2270  Unlinks the brush from whichever chain it is in.
2271  Decrements the owner entity's brushcount.
2272  Removes owner entity if this was the last brush unless owner is the world.
2273  Removes from groups
2274 
2275  set bRemoveNode to false to avoid trying to delete the item in group view tree control
2276 ================
2277 */
2278 void Brush_Free(brush_t *b, bool bRemoveNode) {
2279  face_t *f, *next;
2280 
2281  // free the patch if it's there
2282  if ( b->pPatch ) {
2283  Patch_Delete(b->pPatch);
2284  }
2285 
2286  // free faces
2287  for ( f = b->brush_faces; f; f = next ) {
2288  next = f->next;
2289  Face_Free(f);
2290  }
2291 
2292  b->epairs.Clear();
2293 
2294  // unlink from active/selected list
2295  if ( b->next ) {
2297  }
2298 
2299  // unlink from entity list
2300  if ( b->onext ) {
2301  Entity_UnlinkBrush(b);
2302  }
2303 
2304  delete b;
2305 }
2306 
2307 /*
2308 ================
2309 Face_MemorySize
2310 
2311  returns the size in memory of the face
2312 ================
2313 */
2314 int Face_MemorySize(face_t *f) {
2315  int size = 0;
2316 
2317  if ( f->face_winding ) {
2318  size += sizeof( idWinding ) + f->face_winding->GetNumPoints() * sizeof( (f->face_winding)[0] );
2319  }
2320  size += sizeof( face_t );
2321  return size;
2322 }
2323 
2324 /*
2325 ================
2326 Brush_MemorySize
2327 
2328  returns the size in memory of the brush
2329 ================
2330 */
2331 int Brush_MemorySize( brush_t *b ) {
2332  face_t *f;
2333  int size = 0;
2334  if ( b->pPatch ) {
2335  size += Patch_MemorySize( b->pPatch );
2336  }
2337 
2338  for ( f = b->brush_faces; f; f = f->next ) {
2339  size += Face_MemorySize(f);
2340  }
2341 
2342  size += sizeof( brush_t ) + b->epairs.Size();
2343  return size;
2344 }
2345 
2346 /*
2347 ================
2348 Brush_Clone
2349 
2350  does not add the brush to any lists
2351 ================
2352 */
2353 brush_t *Brush_Clone(brush_t *b) {
2354  brush_t *n = NULL;
2355  face_t *f, *nf;
2356 
2357  if (b->pPatch) {
2358  patchMesh_t *p = Patch_Duplicate(b->pPatch);
2359  Brush_RemoveFromList(p->pSymbiot);
2360  Entity_UnlinkBrush(p->pSymbiot);
2361  n = p->pSymbiot;
2362  }
2363  else {
2364  n = Brush_Alloc();
2365  n->numberId = g_nBrushId++;
2366  n->owner = b->owner;
2367  n->lightColor = b->lightColor;
2368  n->lightEnd = b->lightEnd;
2369  n->lightOffset = b->lightOffset;
2370  n->lightRadius = b->lightRadius;
2371  n->lightRight = b->lightRight;
2372  n->lightStart = b->lightStart;
2373  n->lightTarget = b->lightTarget;
2374  n->lightCenter = b->lightCenter;
2375  n->lightTexture = b->lightTexture;
2376  n->lightUp = b->lightUp;
2377  n->modelHandle = b->modelHandle;
2378  n->pointLight = b->pointLight;
2379  for (f = b->brush_faces; f; f = f->next) {
2380  nf = Face_Clone(f);
2381  nf->next = n->brush_faces;
2382  n->brush_faces = nf;
2383  }
2384  }
2385 
2386  return n;
2387 }
2388 
2389 /*
2390 ================
2391 Brush_FullClone
2392 
2393  Used by Undo.
2394  Makes an exact copy of the brush.
2395  Does NOT add the new brush to any lists.
2396 ================
2397 */
2398 brush_t *Brush_FullClone(brush_t *b) {
2399  brush_t *n = NULL;
2400  face_t *f, *nf, *f2, *nf2;
2401  int j;
2402 
2403  if (b->pPatch) {
2404  patchMesh_t *p = Patch_Duplicate(b->pPatch);
2405  Brush_RemoveFromList(p->pSymbiot);
2406  Entity_UnlinkBrush(p->pSymbiot);
2407  n = p->pSymbiot;
2408  n->owner = b->owner;
2409  Brush_Build(n);
2410  }
2411  else {
2412  n = Brush_Alloc();
2413  n->numberId = g_nBrushId++;
2414  n->owner = b->owner;
2415  n->lightColor = b->lightColor;
2416  n->lightEnd = b->lightEnd;
2417  n->lightOffset = b->lightOffset;
2418  n->lightRadius = b->lightRadius;
2419  n->lightRight = b->lightRight;
2420  n->lightStart = b->lightStart;
2421  n->lightTarget = b->lightTarget;
2422  n->lightCenter = b->lightCenter;
2423  n->lightTexture = b->lightTexture;
2424  n->lightUp = b->lightUp;
2425  n->modelHandle = b->modelHandle;
2426  n->pointLight = b->pointLight;
2427  VectorCopy(b->mins, n->mins);
2428  VectorCopy(b->maxs, n->maxs);
2429  for (f = b->brush_faces; f; f = f->next) {
2430  if (f->original) {
2431  continue;
2432  }
2433 
2434  nf = Face_FullClone(f);
2435  nf->next = n->brush_faces;
2436  n->brush_faces = nf;
2437 
2438  // copy all faces that have the original set to this face
2439  for (f2 = b->brush_faces; f2; f2 = f2->next) {
2440  if (f2->original == f) {
2441  nf2 = Face_FullClone(f2);
2442  nf2->next = n->brush_faces;
2443  n->brush_faces = nf2;
2444 
2445  // set original
2446  nf2->original = nf;
2447  }
2448  }
2449  }
2450 
2451  for (nf = n->brush_faces; nf; nf = nf->next) {
2452  Face_SetColor( n, nf, 1.0f );
2453  if (nf->face_winding) {
2454  if (g_qeglobals.m_bBrushPrimitMode) {
2455  EmitBrushPrimitTextureCoordinates(nf, nf->face_winding);
2456  }
2457  else {
2458  for (j = 0; j < nf->face_winding->GetNumPoints(); j++) {
2459  EmitTextureCoordinates( (*nf->face_winding)[j], nf->d_texture, nf );
2460  }
2461  }
2462  }
2463  }
2464  }
2465 
2466  return n;
2467 }
2468 
2469 extern bool GetMatrixForKey(entity_t *ent, const char *key, idMat3 &mat);
2470 extern bool Patch_Intersect(patchMesh_t *pm, idVec3 origin, idVec3 direction , float &scale);
2471 extern bool RayIntersectsTri
2472  (
2473  const idVec3 &origin,
2474  const idVec3 &direction,
2475  const idVec3 &vert0,
2476  const idVec3 &vert1,
2477  const idVec3 &vert2,
2478  float &scale
2479  );
2480 
2481 
2482 /*
2483 ================
2484 RotateVector
2485 ================
2486 */
2487 void RotateVector(idVec3 &v, idVec3 origin, float a, float c, float s) {
2488  float x = v[0];
2489  float y = v[1];
2490  if (a) {
2491  float x2 = (((x - origin[0]) * c) - ((y - origin[1]) * s)) + origin[0];
2492  float y2 = (((x - origin[0]) * s) + ((y - origin[1]) * c)) + origin[1];
2493  x = x2;
2494  y = y2;
2495  }
2496  v[0] = x;
2497  v[1] = y;
2498 }
2499 /*
2500 ================
2501 Brush_ModelIntersect
2502 ================
2503 */
2504 
2505 bool Brush_ModelIntersect(brush_t *b, idVec3 origin, idVec3 dir,float &scale) {
2506  idRenderModel *model = b->modelHandle;
2507  idRenderModel *md5;
2508 
2509  if ( !model )
2510  model = b->owner->eclass->entityModel;
2511 
2512  scale = 0;
2513  if (model) {
2514  if ( model->IsDynamicModel() != DM_STATIC ) {
2515  if ( dynamic_cast<idRenderModelMD5 *>( model ) ) {
2516  // take care of animated models
2517  md5 = b->owner->eclass->entityModel;
2518 
2519  const char *classname = ValueForKey( b->owner, "classname" );
2520  if (stricmp(classname, "func_static") == 0) {
2521  classname = ValueForKey(b->owner, "animclass");
2522  }
2523  const char *anim = ValueForKey( b->owner, "anim" );
2524  int frame = IntForKey( b->owner, "frame" ) + 1;
2525  if ( frame < 1 ) {
2526  frame = 1;
2527  }
2528  if ( !anim || !anim[ 0 ] ) {
2529  anim = "idle";
2530  }
2531  model = gameEdit->ANIM_CreateMeshForAnim( md5, classname, anim, frame, false );
2532  if ( !model ) {
2533  model = renderModelManager->DefaultModel();
2534  }
2535  }
2536  }
2537 
2538  bool matrix = false;
2539  idMat3 mat;
2540  float a, s, c;
2541  if (GetMatrixForKey(b->owner, "rotation", mat)) {
2542  matrix = true;
2543  } else {
2544  a = FloatForKey(b->owner, "angle");
2545  if (a) {
2546  s = sin( DEG2RAD( a ) );
2547  c = cos( DEG2RAD( a ) );
2548  }
2549  else {
2550  s = c = 0;
2551  }
2552  }
2553 
2554  for (int i = 0; i < model->NumSurfaces() ; i++) {
2555  const modelSurface_t *surf = model->Surface( i );
2556  srfTriangles_t *tri = surf->geometry;
2557  for (int j = 0; j < tri->numIndexes; j += 3) {
2558  idVec3 v1, v2, v3;
2559  v1 = tri->verts[tri->indexes[j]].xyz;
2560  v2 = tri->verts[tri->indexes[j + 1]].xyz;
2561  v3 = tri->verts[tri->indexes[j + 2]].xyz;
2562 
2563  if (matrix) {
2564  v1 *= b->owner->rotation;
2565  v1 += b->owner->origin;
2566  v2 *= b->owner->rotation;
2567  v2 += b->owner->origin;
2568  v3 *= b->owner->rotation;
2569  v3 += b->owner->origin;
2570  } else {
2571  v1 += b->owner->origin;
2572  v2 += b->owner->origin;
2573  v3 += b->owner->origin;
2574  RotateVector(v1, b->owner->origin, a, c, s);
2575  RotateVector(v2, b->owner->origin, a, c, s);
2576  RotateVector(v3, b->owner->origin, a, c, s);
2577  }
2578 
2579  if (RayIntersectsTri(origin, dir, v1, v2, v3,scale)) {
2580  return true;
2581  }
2582  }
2583  }
2584  }
2585 
2586  return false;
2587 }
2588 
2589 face_t *Brush_Ray(idVec3 origin, idVec3 dir, brush_t *b, float *dist, bool testPrimitive) {
2590  face_t *f, *firstface = NULL;
2591  idVec3 p1, p2;
2592  float frac, d1, d2;
2593  int i;
2594  float scale = HUGE_DISTANCE * 2;
2595  VectorCopy(origin, p1);
2596  for (i = 0; i < 3; i++) {
2597  p2[i] = p1[i] + dir[i] * HUGE_DISTANCE * 2;
2598  }
2599 
2600  for (f = b->brush_faces; f; f = f->next) {
2601  d1 = DotProduct(p1, f->plane) + f->plane[3];
2602  d2 = DotProduct(p2, f->plane) + f->plane[3];
2603  if (d1 >= 0 && d2 >= 0) {
2604  *dist = 0;
2605  return NULL; // ray is on front side of face
2606  }
2607 
2608  if (d1 <= 0 && d2 <= 0) {
2609  continue;
2610  }
2611 
2612  // clip the ray to the plane
2613  frac = d1 / (d1 - d2);
2614  if (d1 > 0) {
2615  firstface = f;
2616  for (i = 0; i < 3; i++) {
2617  p1[i] = p1[i] + frac * (p2[i] - p1[i]);
2618  }
2619  }
2620  else {
2621  for (i = 0; i < 3; i++) {
2622  p2[i] = p1[i] + frac * (p2[i] - p1[i]);
2623  }
2624  }
2625  }
2626 
2627  // find distance p1 is along dir
2628  VectorSubtract(p1, origin, p1);
2629  d1 = DotProduct(p1, dir);
2630 
2631  if (testPrimitive && !g_PrefsDlg.m_selectByBoundingBrush) {
2632  if (b->pPatch) {
2633  if (!Patch_Intersect(b->pPatch, origin, dir, scale)) {
2634  *dist = 0;
2635  return NULL;
2636  }
2637  }
2638  else if ( b->modelHandle != NULL && dynamic_cast<idRenderModelPrt*>( b->modelHandle ) == NULL && dynamic_cast< idRenderModelLiquid*> ( b->modelHandle ) == NULL ) {
2639  if (!Brush_ModelIntersect(b, origin, dir, scale)) {
2640  *dist = 0;
2641  return NULL;
2642  }
2643  }
2644  }
2645 
2646  *dist = d1;
2647  return firstface;
2648 }
2649 
2650 /*
2651 ================
2652 Brush_Point
2653 ================
2654 */
2655 face_t *Brush_Point(idVec3 origin, brush_t *b) {
2656  face_t *f;
2657  float d1;
2658 
2659  for (f = b->brush_faces; f; f = f->next) {
2660  d1 = DotProduct(origin, f->plane) + f->plane[3];
2661  if (d1 > 0) {
2662  return NULL; // point is on front side of face
2663  }
2664  }
2665 
2666  return b->brush_faces;
2667 }
2668 
2669 /*
2670 ================
2671 Brush_AddToList
2672 ================
2673 */
2674 void Brush_AddToList(brush_t *b, brush_t *list) {
2675  if (b->next || b->prev) {
2676  Error("Brush_AddToList: allready linked");
2677  }
2678 
2679  if (list == &selected_brushes || list == &active_brushes) {
2680  if (b->pPatch && list == &selected_brushes) {
2681  Patch_Select(b->pPatch);
2682  }
2683  }
2684 
2685  b->list = list;
2686  b->next = list->next;
2687  list->next->prev = b;
2688  list->next = b;
2689  b->prev = list;
2690 
2691 }
2692 
2693 /*
2694 ================
2695 Brush_RemoveFromList
2696 ================
2697 */
2698 void Brush_RemoveFromList(brush_t *b) {
2699  if (!b->next || !b->prev) {
2700  Error("Brush_RemoveFromList: not linked");
2701  }
2702 
2703  if (b->pPatch) {
2704  Patch_Deselect(b->pPatch);
2705 
2706  // Patch_Deselect(b->nPatchID);
2707  }
2708 
2709  b->list = NULL;
2710  b->next->prev = b->prev;
2711  b->prev->next = b->next;
2712  b->next = b->prev = NULL;
2713 }
2714 
2715 /*
2716 ================
2717 SetFaceTexdef
2718 
2719  Doesn't set the curve flags.
2720  NOTE: never trust f->d_texture here, f->texdef and f->d_texture are out of sync when
2721  called by Brush_SetTexture use Texture_ForName() to find the right shader
2722  FIXME: send the right shader ( qtexture_t * ) in the parameters ?
2723  TTimo: surface plugin, added an IPluginTexdef* parameter if not NULL,
2724  get ->Copy() of it into the face ( and remember to hook ) if NULL, ask for a default
2725 ================
2726 */
2727 void SetFaceTexdef( brush_t *b, face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale ) {
2728 
2729  if (g_qeglobals.m_bBrushPrimitMode) {
2730  f->texdef = *texdef;
2731  ConvertTexMatWithQTexture(brushprimit_texdef, NULL, &f->brushprimit_texdef, Texture_ForName(f->texdef.name));
2732  }
2733  else if (bFitScale) {
2734  f->texdef = *texdef;
2735 
2736  // fit the scaling of the texture on the actual plane
2737  idVec3 p1, p2, p3; // absolute coordinates
2738 
2739  // compute absolute coordinates
2740  ComputeAbsolute(f, p1, p2, p3);
2741 
2742  // compute the scale
2743  idVec3 vx, vy;
2744  VectorSubtract(p2, p1, vx);
2745  vx.Normalize();
2746  VectorSubtract(p3, p1, vy);
2747  vy.Normalize();
2748 
2749  // assign scale
2750  VectorScale(vx, texdef->scale[0], vx);
2751  VectorScale(vy, texdef->scale[1], vy);
2752  VectorAdd(p1, vx, p2);
2753  VectorAdd(p1, vy, p3);
2754 
2755  // compute back shift scale rot
2756  AbsoluteToLocal(f->plane, f, p1, p2, p3);
2757  }
2758  else {
2759  f->texdef = *texdef;
2760  }
2761 
2762 }
2763 
2764 /*
2765 ================
2766 Brush_SetTexture
2767 ================
2768 */
2769 void Brush_SetTexture(brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale) {
2770  if (b->pPatch) {
2771  Patch_SetTexture(b->pPatch, texdef);
2772  }
2773  else {
2774  for (face_t * f = b->brush_faces; f; f = f->next) {
2775  SetFaceTexdef(b, f, texdef, brushprimit_texdef, bFitScale);
2776  }
2777 
2778  Brush_Build(b);
2779  }
2780 }
2781 
2782 /*
2783 ====================
2784 Brush_SetTextureName
2785 ====================
2786 */
2787 void Brush_SetTextureName(brush_t *b, const char *name) {
2788  if (b->pPatch) {
2789  Patch_SetTextureName(b->pPatch, name);
2790  }
2791  else {
2792  for (face_t * f = b->brush_faces; f; f = f->next) {
2793  f->texdef.SetName(name);
2794  }
2795  Brush_Build(b);
2796  }
2797 }
2798 
2799 /*
2800 ================
2801 ClipLineToFace
2802 ================
2803 */
2804 bool ClipLineToFace(idVec3 &p1, idVec3 &p2, face_t *f) {
2805  float d1, d2, fr;
2806  int i;
2807  float *v;
2808 
2809  d1 = DotProduct(p1, f->plane) + f->plane[3];
2810  d2 = DotProduct(p2, f->plane) + f->plane[3];
2811 
2812  if (d1 >= 0 && d2 >= 0) {
2813  return false; // totally outside
2814  }
2815 
2816  if (d1 <= 0 && d2 <= 0) {
2817  return true; // totally inside
2818  }
2819 
2820  fr = d1 / (d1 - d2);
2821 
2822  if (d1 > 0) {
2823  v = p1.ToFloatPtr();
2824  }
2825  else {
2826  v = p2.ToFloatPtr();
2827  }
2828 
2829  for (i = 0; i < 3; i++) {
2830  v[i] = p1[i] + fr * (p2[i] - p1[i]);
2831  }
2832 
2833  return true;
2834 }
2835 
2836 /*
2837 ================
2838 AddPlanept
2839 ================
2840 */
2842  int i;
2843 
2844  for (i = 0; i < g_qeglobals.d_num_move_points; i++) {
2845  if (g_qeglobals.d_move_points[i] == f) {
2846  return 0;
2847  }
2848  }
2849 
2850  if (g_qeglobals.d_num_move_points < MAX_MOVE_POINTS) {
2851  g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
2852  } else {
2853  Sys_Status("Trying to move too many points\n");
2854  return 0;
2855  }
2856 
2857  return 1;
2858 }
2859 
2860 /*
2861 ================
2862 AddMovePlane
2863 ================
2864 */
2866 
2867  for (int i = 0; i < g_qeglobals.d_num_move_planes; i++) {
2868  if (g_qeglobals.d_move_planes[i] == p) {
2869  return;
2870  }
2871  }
2872 
2873  if (g_qeglobals.d_num_move_planes < MAX_MOVE_PLANES) {
2874  g_qeglobals.d_move_planes[g_qeglobals.d_num_move_planes++] = p;
2875  } else {
2876  Sys_Status("Trying to move too many planes\n");
2877  }
2878 
2879 }
2880 
2881 /*
2882 ================
2883 Brush_SelectFaceForDragging
2884 
2885  Adds the faces planepts to move_points, and rotates and adds the planepts of adjacent face if shear is set
2886 ================
2887 */
2888 void Brush_SelectFaceForDragging(brush_t *b, face_t *f, bool shear) {
2889  int i;
2890  face_t *f2;
2891  idWinding *w;
2892  float d;
2893  brush_t *b2;
2894  int c;
2895 
2896  if (b->owner->eclass->fixedsize || EntityHasModel(b->owner)) {
2897  return;
2898  }
2899 
2900  c = 0;
2901  for (i = 0; i < 3; i++) {
2902  c += AddPlanept(&f->planepts[i]);
2903  }
2904 
2905  //AddMovePlane(&f->plane);
2906 
2907  if (c == 0) {
2908  return; // allready completely added
2909  }
2910 
2911  // select all points on this plane in all brushes the selection
2912  for (b2 = selected_brushes.next; b2 != &selected_brushes; b2 = b2->next) {
2913  if (b2 == b) {
2914  continue;
2915  }
2916 
2917  for (f2 = b2->brush_faces; f2; f2 = f2->next) {
2918  for (i = 0; i < 3; i++) {
2919  if (idMath::Fabs(DotProduct(f2->planepts[i], f->plane) + f->plane[3]) > ON_EPSILON) {
2920  break;
2921  }
2922  }
2923 
2924  if (i == 3) { // move this face as well
2925  Brush_SelectFaceForDragging(b2, f2, shear);
2926  break;
2927  }
2928  }
2929  }
2930 
2931  //
2932  // if shearing, take all the planes adjacent to selected faces and rotate their
2933  // points so the edge clipped by a selcted face has two of the points
2934  //
2935  if (!shear) {
2936  return;
2937  }
2938 
2939  for (f2 = b->brush_faces; f2; f2 = f2->next) {
2940  if (f2 == f) {
2941  continue;
2942  }
2943 
2944  w = Brush_MakeFaceWinding(b, f2, false);
2945  if (!w) {
2946  continue;
2947  }
2948 
2949  // any points on f will become new control points
2950  for (i = 0; i < w->GetNumPoints(); i++) {
2951  d = DotProduct( (*w)[i], f->plane ) + f->plane[3];
2952  if (d > -ON_EPSILON && d < ON_EPSILON) {
2953  break;
2954  }
2955  }
2956 
2957  // if none of the points were on the plane, leave it alone
2958  if (i != w->GetNumPoints()) {
2959  if (i == 0) { // see if the first clockwise point was the
2962  d = DotProduct( (*w)[w->GetNumPoints() - 1], f->plane ) + f->plane[3];
2963  if (d > -ON_EPSILON && d < ON_EPSILON) {
2964  i = w->GetNumPoints() - 1;
2965  }
2966  }
2967 
2968  AddPlanept(&f2->planepts[0]);
2969  //AddMovePlane(&f2->plane);
2970 
2971  VectorCopy((*w)[i], f2->planepts[0]);
2972  if (++i == w->GetNumPoints()) {
2973  i = 0;
2974  }
2975 
2976  // see if the next point is also on the plane
2977  d = DotProduct( (*w)[i], f->plane ) + f->plane[3];
2978  if (d > -ON_EPSILON && d < ON_EPSILON) {
2979  AddPlanept(&f2->planepts[1]);
2980  }
2981 
2982  VectorCopy( (*w)[i], f2->planepts[1] );
2983  if (++i == w->GetNumPoints()) {
2984  i = 0;
2985  }
2986 
2987  // the third point is never on the plane
2988  VectorCopy( (*w)[i], f2->planepts[2] );
2989  }
2990 
2991  delete w;
2992  }
2993 }
2994 
2995 /*
2996 ================
2997 Brush_SideSelect
2998 
2999  The mouse click did not hit the brush, so grab one or more side planes for dragging.
3000 ================
3001 */
3002 void Brush_SideSelect(brush_t *b, idVec3 origin, idVec3 dir, bool shear) {
3003  face_t *f, *f2;
3004  idVec3 p1, p2;
3005 
3006  if (g_moveOnly) {
3007  return;
3008  }
3009 
3010  // if (b->pPatch) return; Patch_SideSelect(b->nPatchID, origin, dir);
3011  for (f = b->brush_faces; f; f = f->next) {
3012  VectorCopy(origin, p1);
3013  VectorMA(origin, MAX_WORLD_SIZE, dir, p2);
3014 
3015  for (f2 = b->brush_faces; f2; f2 = f2->next) {
3016  if (f2 == f) {
3017  continue;
3018  }
3019 
3020  ClipLineToFace(p1, p2, f2);
3021  }
3022 
3023  if (f2) {
3024  continue;
3025  }
3026 
3027  if ( p1.Compare( origin ) ) {
3028  continue;
3029  }
3030 
3031  if (ClipLineToFace(p1, p2, f)) {
3032  continue;
3033  }
3034 
3035  Brush_SelectFaceForDragging(b, f, shear);
3036  }
3037 }
3038 
3039 extern void UpdateSelectablePoint(brush_t *b, idVec3 v, int type);
3040 extern void AddSelectablePoint(brush_t *b, idVec3 v, int type, bool priority);
3041 extern void ClearSelectablePoints(brush_t *b);
3042 
3043 /*
3044 ================
3045 Brush_TransformedPoint
3046 ================
3047 */
3048 extern void VectorSnapGrid(idVec3 &v);
3049 
3051  idMat3 mat;
3052  mat.Identity();
3053  if (!GetMatrixForKey(b->owner, "light_rotation", mat)) {
3054  GetMatrixForKey(b->owner, "rotation", mat);
3055  }
3056  return mat;
3057 }
3058 
3060  idVec3 out = in;
3061  out -= b->owner->origin;
3062  out *= Brush_RotationMatrix(b);
3063  out += b->owner->origin;
3064  return out;
3065 }
3066 /*
3067 ================
3068 Brush_UpdateLightPoints
3069 ================
3070 */
3071 void Brush_UpdateLightPoints(brush_t *b, const idVec3 &offset) {
3072 
3073  if (!(b->owner->eclass->nShowFlags & ECLASS_LIGHT)) {
3074  if (b->modelHandle) {
3075  g_bScreenUpdates = false;
3076  g_pParentWnd->GetCamera()->BuildEntityRenderState(b->owner, true);
3077  g_bScreenUpdates = true;
3078  }
3079  return;
3080  }
3081 
3082  if (b->entityModel) {
3083  return;
3084  }
3085 
3086  idVec3 vCenter;
3087  idVec3 *origin = (b->trackLightOrigin) ? &b->owner->lightOrigin : &b->owner->origin;
3088 
3089  if (!GetVectorForKey(b->owner, "_color", b->lightColor)) {
3090  b->lightColor[0] = b->lightColor[1] = b->lightColor[2] = 1;
3091  }
3092 
3093  const char *str = ValueForKey(b->owner, "texture");
3094  b->lightTexture = -1;
3095  if (str && strlen(str) > 0) {
3096  const idMaterial *q = Texture_LoadLight(str);
3097  if (q) {
3098  b->lightTexture = q->GetEditorImage()->texnum;
3099  }
3100  }
3101 
3102  str = ValueForKey(b->owner, "light_right");
3103  if (str && *str) {
3104  idVec3 vRight, vUp, vTarget, vTemp;
3105 
3106  if (GetVectorForKey(b->owner, "light_start", b->lightStart)) {
3107  b->startEnd = true;
3108  if (!GetVectorForKey(b->owner, "light_end", b->lightEnd)) {
3109  GetVectorForKey(b->owner, "light_target", b->lightEnd);
3110  }
3111 
3112 
3113  VectorAdd(b->lightEnd, *origin, b->lightEnd);
3114  VectorAdd(b->lightStart, *origin, b->lightStart);
3115  VectorAdd(b->lightStart, offset, b->lightStart);
3116  }
3117  else {
3118  b->startEnd = false;
3119  }
3120 
3121  GetVectorForKey(b->owner, "light_right", vRight);
3122  GetVectorForKey(b->owner, "light_up", vUp);
3123  GetVectorForKey(b->owner, "light_target", vTarget);
3124  if (offset.x || offset.y || offset.z) {
3125  CString str;
3126  VectorAdd(vTarget, offset, vTarget);
3127  SetKeyVec3(b->owner, "light_target", vTarget);
3128  }
3129 
3130  VectorAdd(vTarget, *origin, b->lightTarget);
3131  VectorAdd(b->lightTarget, vRight, b->lightRight);
3132  VectorAdd(b->lightTarget, vUp, b->lightUp);
3133 
3134  UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightUp), LIGHT_UP);
3135  UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightRight), LIGHT_RIGHT);
3136  UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightTarget), LIGHT_TARGET);
3137  UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightStart), LIGHT_START);
3138  UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightEnd), LIGHT_END);
3139  b->pointLight = false;
3140  }
3141  else {
3142  b->pointLight = true;
3143 
3144  if (GetVectorForKey(b->owner, "light_center", vCenter)) {
3145 
3146  if (offset.x || offset.y || offset.z) {
3147  CString str;
3148  VectorAdd(vCenter, offset, vCenter);
3149  SetKeyVec3(b->owner, "light_center", vCenter);
3150  }
3151 
3152  VectorAdd(vCenter, *origin, b->lightCenter);
3153  UpdateSelectablePoint(b, b->lightCenter, LIGHT_CENTER);
3154  }
3155 
3156  if (!GetVectorForKey(b->owner, "light_radius", b->lightRadius)) {
3157  float f = FloatForKey(b->owner, "light");
3158  if (f == 0) {
3159  f = 300;
3160  }
3161 
3162  b->lightRadius[0] = b->lightRadius[1] = b->lightRadius[2] = f;
3163  }
3164  else {
3165  }
3166  }
3167 
3168  g_bScreenUpdates = false;
3169  g_pParentWnd->GetCamera()->BuildEntityRenderState(b->owner, true);
3170  g_bScreenUpdates = true;
3171 
3172 }
3173 
3174 /*
3175 ================
3176 Brush_BuildWindings
3177 ================
3178 */
3179 void Brush_BuildWindings(brush_t *b, bool bSnap, bool keepOnPlaneWinding, bool updateLights, bool makeFacePlanes) {
3180  idWinding *w;
3181  face_t *face;
3182  float v;
3183 
3184  // clear the mins/maxs bounds
3185  b->mins[0] = b->mins[1] = b->mins[2] = 999999;
3186  b->maxs[0] = b->maxs[1] = b->maxs[2] = -999999;
3187 
3188  if (makeFacePlanes) {
3190  }
3191 
3192  face = b->brush_faces;
3193 
3194  float fCurveColor = 1.0f;
3195 
3196  for (; face; face = face->next) {
3197  int i, j;
3198  delete face->face_winding;
3199  w = face->face_winding = Brush_MakeFaceWinding(b, face, keepOnPlaneWinding);
3200  face->d_texture = Texture_ForName(face->texdef.name);
3201 
3202  if (!w) {
3203  continue;
3204  }
3205 
3206  for (i = 0; i < w->GetNumPoints(); i++) {
3207  // add to bounding box
3208  for (j = 0; j < 3; j++) {
3209  v = (*w)[i][j];
3210  if (v > b->maxs[j]) {
3211  b->maxs[j] = v;
3212  }
3213 
3214  if (v < b->mins[j]) {
3215  b->mins[j] = v;
3216  }
3217  }
3218  }
3219 
3220  // setup s and t vectors, and set color if (!g_PrefsDlg.m_bGLLighting) {
3221  if (makeFacePlanes) {
3222  Face_SetColor(b, face, fCurveColor);
3223 
3224  // }
3225  fCurveColor -= 0.1f;
3226  if ( fCurveColor <= 0.0f ) {
3227  fCurveColor = 1.0f;
3228  }
3229 
3230  // computing ST coordinates for the windings
3231  if (g_qeglobals.m_bBrushPrimitMode) {
3232  if (g_qeglobals.bNeedConvert) {
3233  //
3234  // we have parsed old brushes format and need conversion convert old brush texture
3235  // representation to new format
3236  //
3237  FaceToBrushPrimitFace(face);
3238  #ifdef _DEBUG
3239  // use old texture coordinates code to check against
3240  for (i = 0; i < w->GetNumPoints(); i++) {
3241  EmitTextureCoordinates((*w)[i], face->d_texture, face);
3242  }
3243  #endif
3244  }
3245 
3246  //
3247  // use new texture representation to compute texture coordinates in debug mode we
3248  // will check against old code and warn if there are differences
3249  //
3251  }
3252  else {
3253  for (i = 0; i < w->GetNumPoints(); i++) {
3254  EmitTextureCoordinates((*w)[i], face->d_texture, face);
3255  }
3256  }
3257  }
3258 
3259  }
3260 
3261  if (updateLights) {
3262  idVec3 offset;
3263  offset.Zero();
3264  Brush_UpdateLightPoints(b, offset);
3265  }
3266 }
3267 
3268 /*
3269 ================
3270 Brush_RemoveEmptyFaces
3271 
3272  Frees any overconstraining faces
3273 ================
3274 */
3275 void Brush_RemoveEmptyFaces(brush_t *b) {
3276  face_t *f, *next;
3277 
3278  f = b->brush_faces;
3279  b->brush_faces = NULL;
3280 
3281  for (; f; f = next) {
3282  next = f->next;
3283  if (!f->face_winding) {
3284  Face_Free(f);
3285  }
3286  else {
3287  f->next = b->brush_faces;
3288  b->brush_faces = f;
3289  }
3290  }
3291 }
3292 
3293 /*
3294 ================
3295 Brush_SnapToGrid
3296 ================
3297 */
3298 void Brush_SnapToGrid(brush_t *pb) {
3299  int i;
3300  for (face_t * f = pb->brush_faces; f; f = f->next) {
3301  idWinding *w = f->face_winding;
3302 
3303  if (!w) {
3304  continue; // freed face
3305  }
3306 
3307  for (i = 0; i < w->GetNumPoints(); i++) {
3308  SnapVectorToGrid( (*w)[i].ToVec3() );
3309  }
3310 
3311  for (i = 0; i < 3; i++) {
3312  f->planepts[i].x = (*w)[i].x;
3313  f->planepts[i].y = (*w)[i].y;
3314  f->planepts[i].z = (*w)[i].z;
3315  }
3316  }
3317  idVec3 v;
3318  idStr str;
3319  if (GetVectorForKey(pb->owner, "origin", v)) {
3320  SnapVectorToGrid(pb->owner->origin);
3321  sprintf(str, "%i %i %i", (int)pb->owner->origin.x, (int)pb->owner->origin.y, (int)pb->owner->origin.z);
3322  SetKeyValue(pb->owner, "origin", str);
3323  }
3324 
3325  if (pb->owner->eclass->nShowFlags & ECLASS_LIGHT) {
3326  if (GetVectorForKey(pb->owner, "light_right", v)) {
3327  // projected
3328  SnapVectorToGrid(v);
3329  pb->lightRight = v;
3330  SetKeyVec3(pb->owner, "light_right", v);
3331  GetVectorForKey(pb->owner, "light_up", v);
3332  SnapVectorToGrid(v);
3333  pb->lightUp = v;
3334  SetKeyVec3(pb->owner, "light_up", v);
3335  GetVectorForKey(pb->owner, "light_target", v);
3336  SnapVectorToGrid(v);
3337  pb->lightTarget = v;
3338  SetKeyVec3(pb->owner, "light_target", v);
3339  if (GetVectorForKey(pb->owner, "light_start", v)) {
3340  SnapVectorToGrid(v);
3341  pb->lightStart = v;
3342  SetKeyVec3(pb->owner, "light_start", v);
3343  GetVectorForKey(pb->owner, "light_end", v);
3344  SnapVectorToGrid(v);
3345  pb->lightEnd = v;
3346  SetKeyVec3(pb->owner, "light_end", v);
3347  }
3348  } else {
3349  // point
3350  if (GetVectorForKey(pb->owner, "light_center", v)) {
3351  SnapVectorToGrid(v);
3352  SetKeyVec3(pb->owner, "light_center", v);
3353  }
3354  }
3355  }
3356 
3357  if ( pb->owner->curve ) {
3358  int c = pb->owner->curve->GetNumValues();
3359  for ( i = 0; i < c; i++ ) {
3360  v = pb->owner->curve->GetValue( i );
3361  SnapVectorToGrid( v );
3362  pb->owner->curve->SetValue( i, v );
3363  }
3364  }
3365 
3366  Brush_Build(pb);
3367 }
3368 
3369 /*
3370 ================
3371 Brush_Rotate
3372 ================
3373 */
3374 void Brush_Rotate(brush_t *b, idMat3 matrix, idVec3 origin, bool bBuild) {
3375  for (face_t * f = b->brush_faces; f; f = f->next) {
3376  for (int i = 0; i < 3; i++) {
3377  f->planepts[i] -= origin;
3378  f->planepts[i] *= matrix;
3379  f->planepts[i] += origin;
3380  }
3381  }
3382 
3383  if (bBuild) {
3384  Brush_Build(b, false, false);
3385  }
3386 }
3387 
3388 extern void VectorRotate3Origin( const idVec3 &vIn, const idVec3 &vRotation, const idVec3 &vOrigin, idVec3 &out );
3389 
3390 /*
3391 ================
3392 Brush_Rotate
3393 ================
3394 */
3395 void Brush_Rotate(brush_t *b, idVec3 vAngle, idVec3 vOrigin, bool bBuild) {
3396  for (face_t * f = b->brush_faces; f; f = f->next) {
3397  for (int i = 0; i < 3; i++) {
3398  VectorRotate3Origin(f->planepts[i], vAngle, vOrigin, f->planepts[i]);
3399  }
3400  }
3401 
3402  if (bBuild) {
3403  Brush_Build(b, false, false);
3404  }
3405 }
3406 
3407 /*
3408 ================
3409 Brush_Center
3410 ================
3411 */
3412 void Brush_Center(brush_t *b, idVec3 vNewCenter) {
3413  idVec3 vMid;
3414 
3415  // get center of the brush
3416  for (int j = 0; j < 3; j++) {
3417  vMid[j] = b->mins[j] + abs((b->maxs[j] - b->mins[j]) * 0.5f);
3418  }
3419 
3420  // calc distance between centers
3421  VectorSubtract(vNewCenter, vMid, vMid);
3422  Brush_Move(b, vMid, true);
3423 }
3424 
3425 /*
3426 ================
3427 Brush_Resize
3428 
3429  the brush must be a true axial box
3430 ================
3431 */
3432 void Brush_Resize( brush_t *b, idVec3 vMin, idVec3 vMax ) {
3433  int i, j;
3434  face_t *f;
3435 
3436  assert( vMin[0] < vMax[0] && vMin[1] < vMax[1] && vMin[2] < vMax[2] );
3437 
3438  Brush_MakeFacePlanes( b );
3439 
3440  for( f = b->brush_faces; f; f = f->next ) {
3441  for ( i = 0; i < 3; i++ ) {
3442  if ( f->plane.Normal()[i] >= 0.999f ) {
3443  for ( j = 0; j < 3; j++ ) {
3444  f->planepts[j][i] = vMax[i];
3445  }
3446  break;
3447  }
3448  if ( f->plane.Normal()[i] <= -0.999f ) {
3449  for ( j = 0; j < 3; j++ ) {
3450  f->planepts[j][i] = vMin[i];
3451  }
3452  break;
3453  }
3454  }
3455  //assert( i < 3 );
3456  }
3457 
3458  Brush_Build( b, true );
3459 }
3460 
3461 /*
3462 ================
3463 HasModel
3464 ================
3465 */
3466 eclass_t *HasModel(brush_t *b) {
3467  idVec3 vMin, vMax;
3468  vMin[0] = vMin[1] = vMin[2] = 999999;
3469  vMax[0] = vMax[1] = vMax[2] = -999999;
3470 
3471  if (b->owner->md3Class != NULL) {
3472  return b->owner->md3Class;
3473  }
3474 
3475  if (b->owner->eclass->modelHandle > 0) {
3476  return b->owner->eclass;
3477  }
3478 
3479  eclass_t *e = NULL;
3480 
3481  // FIXME: entity needs to track whether a cache hit failed and not ask again
3482  if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) {
3483  const char *pModel = ValueForKey(b->owner, "model");
3484  if (pModel != NULL && strlen(pModel) > 0) {
3485  e = GetCachedModel(b->owner, pModel, vMin, vMax);
3486  if (e != NULL) {
3487  //
3488  // we need to scale the brush to the proper size based on the model load recreate
3489  // brush just like in load/save
3490  //
3491  VectorAdd(vMin, b->owner->origin, vMin);
3492  VectorAdd(vMax, b->owner->origin, vMax);
3493  Brush_Resize(b, vMin, vMax);
3494  b->bModelFailed = false;
3495  }
3496  else {
3497  b->bModelFailed = true;
3498  }
3499  }
3500  }
3501 
3502  return e;
3503 }
3504 
3505 /*
3506 ================
3507 Entity_GetRotationMatrixAngles
3508 ================
3509 */
3511  int angle;
3512 
3513  /* the angle keyword is a yaw value, except for two special markers */
3514  if ( GetMatrixForKey( e, "rotation", mat ) ) {
3515  angles = mat.ToAngles();
3516  return true;
3517  }
3518  else if ( e->epairs.GetInt( "angle", "0", angle ) ) {
3519  if ( angle == -1 ) { // up
3520  angles.Set( 270, 0, 0 );
3521  }
3522  else if ( angle == -2 ) { // down
3523  angles.Set( 90, 0, 0 );
3524  }
3525  else {
3526  angles.Set( 0, angle, 0 );
3527  }
3528  mat = angles.ToMat3();
3529  return true;
3530  }
3531  else {
3532  mat.Identity();
3533  angles.Zero();
3534  return false;
3535  }
3536 }
3537 
3538 /*
3539 ================
3540 FacingVectors
3541 ================
3542 */
3543 static void FacingVectors(entity_t *e, idVec3 &forward, idVec3 &right, idVec3 &up) {
3544  idAngles angles;
3545  idMat3 mat;
3546 
3547  Entity_GetRotationMatrixAngles(e, mat, angles);
3548  angles.ToVectors( &forward, &right, &up);
3549 }
3550 
3551 /*
3552 ================
3553 Brush_DrawFacingAngle
3554 ================
3555 */
3556 void Brush_DrawFacingAngle( brush_t *b, entity_t *e, bool particle ) {
3557  idVec3 forward, right, up;
3558  idVec3 endpoint, tip1, tip2;
3559  idVec3 start;
3560  float dist;
3561 
3562  VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);
3563  VectorScale(start, 0.5f, start);
3564  dist = (b->maxs[0] - start[0]) * 2.5f;
3565 
3566  FacingVectors(e, forward, right, up);
3567  VectorMA(start, dist, ( particle ) ? up : forward, endpoint);
3568 
3569  dist = (b->maxs[0] - start[0]) * 0.5f;
3570  VectorMA(endpoint, -dist, ( particle ) ? up : forward, tip1);
3571  VectorMA(tip1, -dist, ( particle ) ? forward : up, tip1);
3572  VectorMA(tip1, 2 * dist, ( particle ) ? forward : up, tip2);
3574  qglColor4f(1, 1, 1, 1);
3575  qglLineWidth(2);
3576  qglBegin(GL_LINES);
3577  qglVertex3fv(start.ToFloatPtr());
3578  qglVertex3fv(endpoint.ToFloatPtr());
3579  qglVertex3fv(endpoint.ToFloatPtr());
3580  qglVertex3fv(tip1.ToFloatPtr());
3581  qglVertex3fv(endpoint.ToFloatPtr());
3582  qglVertex3fv(tip2.ToFloatPtr());
3583  qglEnd();
3584  qglLineWidth(0.5f);
3585 }
3586 
3587 /*
3588 ================
3589 DrawProjectedLight
3590 ================
3591 */
3592 void DrawProjectedLight(brush_t *b, bool bSelected, bool texture) {
3593  int i;
3594  idVec3 v1, v2, cross, vieworg, edge[8][2], v[4];
3595  idVec3 target, start;
3596 
3597  if (!bSelected && !g_bShowLightVolumes) {
3598  return;
3599  }
3600 
3601  // use the renderer to get the volume outline
3602  idPlane lightProject[4];
3603  idPlane planes[6];
3604  srfTriangles_t *tri;
3605 
3606  // use the game's epair parsing code so
3607  // we can use the same renderLight generation
3608  entity_t *ent = b->owner;
3609  idDict spawnArgs;
3610  renderLight_t parms;
3611 
3612  spawnArgs = ent->epairs;
3613  gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &parms );
3614  R_RenderLightFrustum( parms, planes );
3615 
3616  tri = R_PolytopeSurface(6, planes, NULL);
3617 
3618  qglColor3f(1, 0, 1);
3619  for (i = 0; i < tri->numIndexes; i += 3) {
3620  qglBegin(GL_LINE_LOOP);
3621  glVertex3fv(tri->verts[tri->indexes[i]].xyz.ToFloatPtr());
3622  glVertex3fv(tri->verts[tri->indexes[i + 1]].xyz.ToFloatPtr());
3623  glVertex3fv(tri->verts[tri->indexes[i + 2]].xyz.ToFloatPtr());
3624  qglEnd();
3625  }
3626 
3627  R_FreeStaticTriSurf(tri);
3628 
3629  // draw different selection points for point lights or projected
3630  // lights (FIXME: rotate these based on parms!)
3631  if ( !bSelected ) {
3632  return;
3633  }
3634 
3635  idMat3 mat;
3636  bool transform = GetMatrixForKey(b->owner, "light_rotation", mat);
3637  if (!transform) {
3638  transform = GetMatrixForKey(b->owner, "rotation", mat);
3639  }
3640  idVec3 tv;
3641  idVec3 *origin = (b->trackLightOrigin) ? &b->owner->lightOrigin : &b->owner->origin;
3642  if (b->pointLight) {
3643  if ( b->lightCenter[0] || b->lightCenter[1] || b->lightCenter[2] ) {
3644  qglPointSize(8);
3645  qglColor3f( 1.0f, 0.4f, 0.8f );
3646  qglBegin(GL_POINTS);
3647  tv = b->lightCenter;
3648  if (transform) {
3649  tv -= *origin;
3650  tv *= mat;
3651  tv += *origin;
3652  }
3653  qglVertex3fv(tv.ToFloatPtr());
3654  qglEnd();
3655  qglPointSize(1);
3656  }
3657  return;
3658  }
3659 
3660  // projected light
3661  qglPointSize(8);
3662  qglColor3f( 1.0f, 0.4f, 0.8f );
3663  qglBegin(GL_POINTS);
3664  tv = b->lightRight;
3665  if (transform) {
3666  tv -= *origin;
3667  tv *= mat;
3668  tv += *origin;
3669  }
3670  qglVertex3fv(tv.ToFloatPtr());
3671  tv = b->lightTarget;
3672  if (transform) {
3673  tv -= *origin;
3674  tv *= mat;
3675  tv += *origin;
3676  }
3677  qglVertex3fv(tv.ToFloatPtr());
3678  tv = b->lightUp;
3679  if (transform) {
3680  tv -= *origin;
3681  tv *= mat;
3682  tv += *origin;
3683  }
3684  qglVertex3fv(tv.ToFloatPtr());
3685  qglEnd();
3686 
3687  if (b->startEnd) {
3688  qglColor3f( 0.4f, 1.0f, 0.8f );
3689  qglBegin(GL_POINTS);
3690  qglVertex3fv(b->lightStart.ToFloatPtr());
3691  qglVertex3fv(b->lightEnd.ToFloatPtr());
3692  qglEnd();
3693  }
3694 
3695  qglPointSize(1);
3696 }
3697 
3698 /*
3699 ================
3700 GLCircle
3701 ================
3702 */
3703 void GLCircle(float x, float y, float z, float r)
3704 {
3705  float ix = 0;
3706  float iy = r;
3707  float ig = 3 - 2 * r;
3708  float idgr = -6;
3709  float idgd = 4 * r - 10;
3710  qglPointSize(0.5f);
3711  qglBegin(GL_POINTS);
3712  while (ix <= iy) {
3713  if (ig < 0) {
3714  ig += idgd;
3715  idgd -= 8;
3716  iy--;
3717  } else {
3718  ig += idgr;
3719  idgd -= 4;
3720  }
3721  idgr -= 4;
3722  ix++;
3723  qglVertex3f(x + ix, y + iy, z);
3724  qglVertex3f(x - ix, y + iy, z);
3725  qglVertex3f(x + ix, y - iy, z);
3726  qglVertex3f(x - ix, y - iy, z);
3727  qglVertex3f(x + iy, y + ix, z);
3728  qglVertex3f(x - iy, y + ix, z);
3729  qglVertex3f(x + iy, y - ix, z);
3730  qglVertex3f(x - iy, y - ix, z);
3731  }
3732  qglEnd();
3733 }
3734 
3735 /*
3736 ================
3737 DrawSpeaker
3738 ================
3739 */
3740 void DrawSpeaker(brush_t *b, bool bSelected, bool twoD) {
3741 
3742  if (!(g_qeglobals.d_savedinfo.showSoundAlways || (g_qeglobals.d_savedinfo.showSoundWhenSelected && bSelected))) {
3743  return;
3744  }
3745 
3746  // convert to units ( inches )
3747  float min = FloatForKey(b->owner, "s_mindistance");
3748  float max = FloatForKey(b->owner, "s_maxdistance");
3749 
3750  const char *s = b->owner->epairs.GetString("s_shader");
3751  if (s && *s) {
3752  const idSoundShader *shader = declManager->FindSound( s, false );
3753  if ( shader ) {
3754  if ( !min ) {
3755  min = shader->GetMinDistance();
3756  }
3757  if ( !max ) {
3758  max = shader->GetMaxDistance();
3759  }
3760  }
3761  }
3762 
3763  if (min == 0 && max == 0) {
3764  return;
3765  }
3766 
3767 
3768  // convert from meters to doom units
3769  min *= METERS_TO_DOOM;
3770  max *= METERS_TO_DOOM;
3771 
3772  if (twoD) {
3773  if (bSelected) {
3774  qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, .5);
3775  } else {
3776  qglColor4f(b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, .5);
3777  }
3778  qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3779  GLCircle(b->owner->origin.x, b->owner->origin.y, b->owner->origin.z, min);
3780  if (bSelected) {
3781  qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, 1);
3782  } else {
3783  qglColor4f(b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, 1);
3784  }
3785  GLCircle(b->owner->origin.x, b->owner->origin.y, b->owner->origin.z, max);
3786  } else {
3787  qglPushMatrix();
3788  qglTranslatef(b->owner->origin.x, b->owner->origin.y, b->owner->origin.z );
3789  qglColor3f( 0.4f, 0.4f, 0.4f );
3790  qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3791  GLUquadricObj* qobj = gluNewQuadric();
3792  gluSphere(qobj, min, 8, 8);
3793  qglColor3f( 0.8f, 0.8f, 0.8f );
3794  gluSphere(qobj, max, 8, 8);
3795  qglEnable(GL_BLEND);
3796  qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3797  qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3799  if (bSelected) {
3800  qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, 0.35f );
3801  } else {
3802  qglColor4f( b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, 0.35f );
3803  }
3804  gluSphere(qobj, min, 8, 8);
3805  if (bSelected) {
3806  qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, 0.1f );
3807  } else {
3808  qglColor4f( b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, 0.1f );
3809  }
3810  gluSphere(qobj, max, 8, 8);
3811  gluDeleteQuadric(qobj);
3812  qglPopMatrix();
3813  }
3814 
3815 
3816 }
3817 
3818 /*
3819 ================
3820 DrawLight
3821 ================
3822 */
3823 void DrawLight(brush_t *b, bool bSelected) {
3824  idVec3 vTriColor;
3825  bool bTriPaint = false;
3826 
3827  vTriColor[0] = vTriColor[2] = 1.0f;
3828  vTriColor[1] = 1.0f;
3829  bTriPaint = true;
3830 
3831  CString strColor = ValueForKey(b->owner, "_color");
3832  if (strColor.GetLength() > 0) {
3833  float fR, fG, fB;
3834  int n = sscanf(strColor, "%f %f %f", &fR, &fG, &fB);
3835  if (n == 3) {
3836  vTriColor[0] = fR;
3837  vTriColor[1] = fG;
3838  vTriColor[2] = fB;
3839  }
3840  }
3841 
3842  qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
3843 
3844  idVec3 vCorners[4];
3845  float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
3846 
3847  vCorners[0][0] = b->mins[0];
3848  vCorners[0][1] = b->mins[1];
3849  vCorners[0][2] = fMid;
3850 
3851  vCorners[1][0] = b->mins[0];
3852  vCorners[1][1] = b->maxs[1];
3853  vCorners[1][2] = fMid;
3854 
3855  vCorners[2][0] = b->maxs[0];
3856  vCorners[2][1] = b->maxs[1];
3857  vCorners[2][2] = fMid;
3858 
3859  vCorners[3][0] = b->maxs[0];
3860  vCorners[3][1] = b->mins[1];
3861  vCorners[3][2] = fMid;
3862 
3863  idVec3 vTop, vBottom;
3864 
3865  vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
3866  vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
3867  vTop[2] = b->maxs[2];
3868 
3869  VectorCopy(vTop, vBottom);
3870  vBottom[2] = b->mins[2];
3871 
3872  idVec3 vSave;
3873  VectorCopy(vTriColor, vSave);
3874 
3876  qglBegin(GL_TRIANGLE_FAN);
3877  qglVertex3fv(vTop.ToFloatPtr());
3878  int i;
3879  for (i = 0; i <= 3; i++) {
3880  vTriColor[0] *= 0.95f;
3881  vTriColor[1] *= 0.95f;
3882  vTriColor[2] *= 0.95f;
3883  qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
3884  qglVertex3fv(vCorners[i].ToFloatPtr());
3885  }
3886 
3887  qglVertex3fv(vCorners[0].ToFloatPtr());
3888  qglEnd();
3889 
3890  VectorCopy(vSave, vTriColor);
3891  vTriColor[0] *= 0.95f;
3892  vTriColor[1] *= 0.95f;
3893  vTriColor[2] *= 0.95f;
3894 
3895  qglBegin(GL_TRIANGLE_FAN);
3896  qglVertex3fv(vBottom.ToFloatPtr());
3897  qglVertex3fv(vCorners[0].ToFloatPtr());
3898  for (i = 3; i >= 0; i--) {
3899  vTriColor[0] *= 0.95f;
3900  vTriColor[1] *= 0.95f;
3901  vTriColor[2] *= 0.95f;
3902  qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
3903  qglVertex3fv(vCorners[i].ToFloatPtr());
3904  }
3905 
3906  qglEnd();
3907 
3908  DrawProjectedLight(b, bSelected, true);
3909 }
3910 
3911 /*
3912 ================
3913 Control_Draw
3914 ================
3915 */
3916 void Control_Draw(brush_t *b) {
3917  face_t *face;
3918  int i, order;
3919  qtexture_t *prev = 0;
3920  idWinding *w;
3921 
3922  // guarantee the texture will be set first
3923  prev = NULL;
3924  for ( face = b->brush_faces, order = 0; face; face = face->next, order++ ) {
3925  w = face->face_winding;
3926  if (!w) {
3927  continue; // freed face
3928  }
3929 
3930  qglColor4f(1, 1, .5, 1);
3931  qglBegin(GL_POLYGON);
3932  for (i = 0; i < w->GetNumPoints(); i++) {
3933  qglVertex3fv( (*w)[i].ToFloatPtr() );
3934  }
3935 
3936  qglEnd();
3937  }
3938 }
3939 
3940 /*
3941 ================
3942 Brush_DrawModel
3943 ================
3944 */
3945 void Brush_DrawModel( brush_t *b, bool camera, bool bSelected ) {
3946  idMat3 axis;
3947  idAngles angles;
3948  int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
3949 
3950  if ( camera && g_PrefsDlg.m_nEntityShowState != ENTITY_WIREFRAME && nDrawMode != cd_wire ) {
3951  qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
3952  }
3953  else {
3954  qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
3955  }
3956 
3957  idRenderModel *model = b->modelHandle;
3958  if ( model == NULL ) {
3959  model = b->owner->eclass->entityModel;
3960  }
3961  if ( model ) {
3962  idRenderModel *model2;
3963 
3964  model2 = NULL;
3965  bool fixedBounds = false;
3966 
3967  if ( model->IsDynamicModel() != DM_STATIC ) {
3968  if ( dynamic_cast<idRenderModelMD5 *>( model ) ) {
3969  const char *classname = ValueForKey( b->owner, "classname" );
3970  if (stricmp(classname, "func_static") == 0) {
3971  classname = ValueForKey(b->owner, "animclass");
3972  }
3973  const char *anim = ValueForKey( b->owner, "anim" );
3974  int frame = IntForKey( b->owner, "frame" ) + 1;
3975  if ( frame < 1 ) {
3976  frame = 1;
3977  }
3978  if ( !anim || !anim[ 0 ] ) {
3979  anim = "idle";
3980  }
3981  model2 = gameEdit->ANIM_CreateMeshForAnim( model, classname, anim, frame, false );
3982  } else if ( dynamic_cast<idRenderModelPrt*>( model ) || dynamic_cast<idRenderModelLiquid*>( model ) ) {
3983  fixedBounds = true;
3984  }
3985 
3986  if ( !model2 ) {
3987  idBounds bounds;
3988  if (fixedBounds) {
3989  bounds.Zero();
3990  bounds.ExpandSelf(12.0f);
3991  } else {
3992  bounds = model->Bounds( NULL );
3993  }
3994  idVec4 color;
3995  color.w = 1.0f;
3996  if (bSelected) {
3997  color.x = g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x;
3998  color.y = g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y;
3999  color.z = g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z;
4000  } else {
4001  color.x = b->owner->eclass->color.x;
4002  color.y = b->owner->eclass->color.y;
4003  color.z = b->owner->eclass->color.z;
4004  }
4005  idVec3 center = bounds.GetCenter();
4006  glBox(color, b->owner->origin + center, bounds.GetRadius( center ) );
4007  model = renderModelManager->DefaultModel();
4008  } else {
4009  model = model2;
4010  }
4011  }
4012 
4013  Entity_GetRotationMatrixAngles( b->owner, axis, angles );
4014 
4015  idVec4 colorSave;
4016  qglGetFloatv(GL_CURRENT_COLOR, colorSave.ToFloatPtr());
4017 
4018  if ( bSelected ) {
4019  qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr() );
4020  }
4021 
4022  DrawRenderModel( model, b->owner->origin, axis, camera );
4023 
4024  qglColor4fv( colorSave.ToFloatPtr() );
4025 
4026  if ( bSelected && camera )
4027  {
4028  //draw selection tints
4029  /*
4030  if ( camera && g_PrefsDlg.m_nEntityShowState != ENTITY_WIREFRAME ) {
4031  qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL );
4032  qglColor3fv ( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr () );
4033  qglEnable ( GL_BLEND );
4034  qglBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
4035  DrawRenderModel( model, b->owner->origin, axis, camera );
4036  }
4037  */
4038 
4039  //draw white triangle outlines
4041 
4042  qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
4043  qglDisable( GL_BLEND );
4044  qglDisable( GL_DEPTH_TEST );
4045  qglColor3f( 1.0f, 1.0f, 1.0f );
4046  qglPolygonOffset( 1.0f, 3.0f );
4047  DrawRenderModel( model, b->owner->origin, axis, false );
4048  qglEnable( GL_DEPTH_TEST );
4049  }
4050 
4051  if ( model2 ) {
4052  delete model2;
4053  model2 = NULL;
4054  }
4055  }
4056 
4057  if ( bSelected && camera ) {
4058  qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
4059  }
4060  else if ( camera ) {
4062  }
4063 
4064  if ( g_bPatchShowBounds ) {
4065  for ( face_t *face = b->brush_faces; face; face = face->next ) {
4066  // only draw polygons facing in a direction we care about
4067  idWinding *w = face->face_winding;
4068  if (!w) {
4069  continue;
4070  }
4071 
4072  //
4073  // if (b->alphaBrush && !(face->texdef.flags & SURF_ALPHA)) continue;
4074  // draw the polygon
4075  //
4076  qglBegin(GL_LINE_LOOP);
4077  for (int i = 0; i < w->GetNumPoints(); i++) {
4078  qglVertex3fv( (*w)[i].ToFloatPtr() );
4079  }
4080  qglEnd();
4081  }
4082  }
4083 }
4084 
4085 /*
4086 ================
4087 GLTransformedVertex
4088 ================
4089 */
4090 void GLTransformedVertex(float x, float y, float z, idMat3 mat, idVec3 origin, idVec3 color, float maxDist) {
4091  idVec3 v(x,y,z);
4092  v -= origin;
4093  v *= mat;
4094  v += origin;
4095 
4097  float max = n.Length() / maxDist;
4098  if (color.x) {
4099  color.x = max;
4100  } else if (color.y) {
4101  color.y = max;
4102  } else {
4103  color.z = max;
4104  }
4105  qglColor3f(color.x, color.y, color.z);
4106  qglVertex3f(v.x, v.y, v.z);
4107 
4108 }
4109 
4110 /*
4111 ================
4112 GLTransformedCircle
4113 ================
4114 */
4115 void GLTransformedCircle(int type, idVec3 origin, float r, idMat3 mat, float pointSize, idVec3 color, float maxDist) {
4116  qglPointSize(pointSize);
4117  qglBegin(GL_POINTS);
4118  for (int i = 0; i < 360; i++) {
4119  float cx = origin.x;
4120  float cy = origin.y;
4121  float cz = origin.z;
4122  switch (type) {
4123  case 0:
4124  cx += r * cos((float)i);
4125  cy += r * sin((float)i);
4126  break;
4127  case 1:
4128  cx += r * cos((float)i);
4129  cz += r * sin((float)i);
4130  break;
4131  case 2:
4132  cy += r * sin((float)i);
4133  cz += r * cos((float)i);
4134  break;
4135  default:
4136  break;
4137  }
4138  GLTransformedVertex(cx, cy, cz, mat, origin, color, maxDist);
4139  }
4140  qglEnd();
4141 }
4142 
4143 /*
4144 ================
4145 Brush_DrawAxis
4146 ================
4147 */
4148 void Brush_DrawAxis(brush_t *b) {
4149  if ( g_pParentWnd->ActiveXY()->RotateMode() && b->modelHandle ) {
4150  bool matrix = false;
4151  idMat3 mat;
4152  float a, s, c;
4153  if (GetMatrixForKey(b->owner, "rotation", mat)) {
4154  matrix = true;
4155  } else {
4156  a = FloatForKey(b->owner, "angle");
4157  if (a) {
4158  s = sin( DEG2RAD( a ) );
4159  c = cos( DEG2RAD( a ) );
4160  }
4161  else {
4162  s = c = 0;
4163  }
4164  }
4165 
4166  idBounds bo;
4167  bo.FromTransformedBounds(b->modelHandle->Bounds(), b->owner->origin, b->owner->rotation);
4168 
4169  float dist = (g_pParentWnd->GetCamera()->Camera().origin - bo[0]).Length();
4170  float dist2 = (g_pParentWnd->GetCamera()->Camera().origin - bo[1]).Length();
4171  if (dist2 > dist) {
4172  dist = dist2;
4173  }
4174 
4175  float xr, yr, zr;
4176  xr = (b->modelHandle->Bounds()[1].x > b->modelHandle->Bounds()[0].x) ? b->modelHandle->Bounds()[1].x - b->modelHandle->Bounds()[0].x : b->modelHandle->Bounds()[0].x - b->modelHandle->Bounds()[1].x;
4177  yr = (b->modelHandle->Bounds()[1].y > b->modelHandle->Bounds()[0].y) ? b->modelHandle->Bounds()[1].y - b->modelHandle->Bounds()[0].y : b->modelHandle->Bounds()[0].y - b->modelHandle->Bounds()[1].y;
4178  zr = (b->modelHandle->Bounds()[1].z > b->modelHandle->Bounds()[0].z) ? b->modelHandle->Bounds()[1].z - b->modelHandle->Bounds()[0].z : b->modelHandle->Bounds()[0].z - b->modelHandle->Bounds()[1].z;
4179 
4181 
4182  GLTransformedCircle(0, b->owner->origin, xr, mat, 1.25, idVec3(0, 0, 1), dist);
4183  GLTransformedCircle(1, b->owner->origin, yr, mat, 1.25, idVec3(0, 1, 0), dist);
4184  GLTransformedCircle(2, b->owner->origin, zr, mat, 1.25, idVec3(1, 0, 0), dist);
4185 
4186  float wr = xr;
4187  int type = 0;
4188  idVec3 org = b->owner->origin;
4189  if (g_qeglobals.rotateAxis == 0) {
4190  wr = zr;
4191  type = 2;
4192  } else if (g_qeglobals.rotateAxis == 1) {
4193  wr = yr;
4194  type = 1;
4195  }
4196 
4197  if (g_qeglobals.flatRotation) {
4198  if (yr > wr) {
4199  wr = yr;
4200  }
4201  if (zr > wr) {
4202  wr = zr;
4203  }
4204  idVec3 vec = vec3_origin;
4205  vec[g_qeglobals.rotateAxis] = 1.0f;
4206  if (g_qeglobals.flatRotation == 1) {
4207  org = g_pParentWnd->ActiveXY()->RotateOrigin();
4208  float t = (org - bo.GetCenter()).Length();
4209  if (t > wr) {
4210  wr = t;
4211  }
4212  } else {
4213  org = bo.GetCenter();
4214  }
4215  idRotation rot(org, vec, 0);
4216  mat = rot.ToMat3();
4217  }
4218  GLTransformedCircle(type, org, wr * 1.03f, mat, 1.45f, idVec3(1, 1, 1), dist);
4219  }
4220 }
4221 
4222 /*
4223 ================
4224 Brush_DrawModelInfo
4225 ================
4226 */
4227 void Brush_DrawModelInfo(brush_t *b, bool selected) {
4228  if (b->modelHandle > 0) {
4229  GLfloat color[4];
4230  qglGetFloatv(GL_CURRENT_COLOR, &color[0]);
4231  if (selected) {
4232  qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr());
4233  }
4234  else {
4235  qglColor3fv(b->owner->eclass->color.ToFloatPtr());
4236  }
4237 
4238  Brush_DrawModel(b, true, selected);
4239  qglColor4fv(color);
4240 
4241  if ( selected ) {
4242  Brush_DrawAxis(b);
4243  }
4244  return;
4245  }
4246 }
4247 
4248 /*
4249 ================
4250 Brush_DrawEmitter
4251 ================
4252 */
4253 void Brush_DrawEmitter(brush_t *b, bool bSelected, bool cam) {
4254  if ( !( b->owner->eclass->nShowFlags & ECLASS_PARTICLE ) ) {
4255  return;
4256  }
4257 
4258  if (bSelected) {
4259  qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, .5);
4260  } else {
4261  qglColor4f(b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, .5);
4262  }
4263 
4264  if ( cam ) {
4265  Brush_DrawFacingAngle( b, b->owner, true );
4266  }
4267 }
4268 
4269 /*
4270 ================
4271 Brush_DrawEnv
4272 ================
4273 */
4274 void Brush_DrawEnv( brush_t *b, bool cameraView, bool bSelected ) {
4275  idVec3 origin, newOrigin;
4276  idMat3 axis, newAxis;
4277  idAngles newAngles;
4278  bool poseIsSet;
4279 
4280  idRenderModel *model = gameEdit->AF_CreateMesh( b->owner->epairs, origin, axis, poseIsSet );
4281 
4282  if ( !poseIsSet ) {
4283  if ( Entity_GetRotationMatrixAngles( b->owner, newAxis, newAngles ) ) {
4284  axis = newAxis;
4285  }
4286  if ( b->owner->epairs.GetVector( "origin", "0 0 0", newOrigin ) ) {
4287  origin = newOrigin;
4288  }
4289  }
4290 
4291  if ( model ) {
4292  if ( cameraView && g_PrefsDlg.m_nEntityShowState != ENTITY_WIREFRAME ) {
4293  qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
4294  }
4295  else {
4296  qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
4297  }
4298 
4299  idVec4 colorSave;
4300  qglGetFloatv(GL_CURRENT_COLOR, colorSave.ToFloatPtr());
4301 
4302  if ( bSelected ) {
4303  qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr() );
4304  } else {
4305  qglColor3f( 1.f, 1.f, 1.f );
4306  }
4307  DrawRenderModel( model, origin, axis, true );
4309  delete model;
4310  model = NULL;
4311 
4312  qglColor4fv( colorSave.ToFloatPtr() );
4313  }
4314 }
4315 
4316 /*
4317 ================
4318 Brush_DrawCombatNode
4319 ================
4320 */
4321 void Brush_DrawCombatNode( brush_t *b, bool cameraView, bool bSelected ) {
4322  float min_dist = b->owner->epairs.GetFloat( "min" );
4323  float max_dist = b->owner->epairs.GetFloat( "max" );
4324  float fov = b->owner->epairs.GetFloat( "fov", "60" );
4325  float yaw = b->owner->epairs.GetFloat("angle");
4326  idVec3 offset = b->owner->epairs.GetVector("offset");
4327 
4328  idAngles leftang( 0.0f, yaw + fov * 0.5f - 90.0f, 0.0f );
4329  idVec3 cone_left = leftang.ToForward();
4330  idAngles rightang( 0.0f, yaw - fov * 0.5f + 90.0f, 0.0f );
4331  idVec3 cone_right = rightang.ToForward();
4332  bool disabled = b->owner->epairs.GetBool( "start_off" );
4333 
4334  idVec4 color;
4335  if ( bSelected ) {
4336  color = colorRed;
4337  } else {
4338  color = colorBlue;
4339  }
4340 
4341  idVec3 leftDir( -cone_left.y, cone_left.x, 0.0f );
4342  idVec3 rightDir( cone_right.y, -cone_right.x, 0.0f );
4343  leftDir.NormalizeFast();
4344  rightDir.NormalizeFast();
4345 
4346  idMat3 axis = idAngles(0, yaw, 0).ToMat3();
4347  idVec3 org = b->owner->origin + offset;
4348  idVec3 entorg = b->owner->origin;
4349  float cone_dot = cone_right * axis[ 1 ];
4350  if ( idMath::Fabs( cone_dot ) > 0.1 ) {
4351  idVec3 pt, pt1, pt2, pt3, pt4;
4352  float cone_dist = max_dist / cone_dot;
4353  pt1 = org + leftDir * min_dist;
4354  pt2 = org + leftDir * cone_dist;
4355  pt3 = org + rightDir * cone_dist;
4356  pt4 = org + rightDir * min_dist;
4357  qglColor4fv(color.ToFloatPtr());
4358  qglBegin(GL_LINE_STRIP);
4359  qglVertex3fv( pt1.ToFloatPtr());
4360  qglVertex3fv( pt2.ToFloatPtr());
4361  qglVertex3fv( pt3.ToFloatPtr());
4362  qglVertex3fv( pt4.ToFloatPtr());
4363  qglVertex3fv( pt1.ToFloatPtr());
4364  qglEnd();
4365 
4367  qglBegin(GL_LINE_STRIP);
4368  qglVertex3fv( entorg.ToFloatPtr());
4369  pt = (pt1 + pt4) * 0.5f;
4370  qglVertex3fv( pt.ToFloatPtr());
4371  pt = (pt2 + pt3) * 0.5f;
4372  qglVertex3fv( pt.ToFloatPtr());
4373  idVec3 tip = pt;
4374  idVec3 dir = ((pt1 + pt2) * 0.5f) - tip;
4375  dir.Normalize();
4376  pt = tip + dir * 15.0f;
4377  qglVertex3fv( pt.ToFloatPtr());
4378  qglVertex3fv( tip.ToFloatPtr());
4379  dir = ((pt4 + pt3) * 0.5f) - tip;
4380  dir.Normalize();
4381  pt = tip + dir * 15.0f;
4382  qglVertex3fv( pt.ToFloatPtr());
4383  qglEnd();
4384  }
4385 
4386 }
4387 
4388 /*
4389 ================
4390 Brush_Draw
4391 ================
4392 */
4393 void Brush_Draw(brush_t *b, bool bSelected) {
4394  face_t *face;
4395  int i, order;
4396  const idMaterial *prev = NULL;
4397  idWinding *w;
4398  bool model = false;
4399 
4400  //
4401  // (TTimo) NOTE: added by build 173, I check after pPlugEnt so it doesn't
4402  // interfere ?
4403  //
4404  if ( b->hiddenBrush ) {
4405  return;
4406  }
4407 
4408  Brush_DrawCurve( b, bSelected, true );
4409 
4410  if (b->pPatch) {
4411  Patch_DrawCam(b->pPatch, bSelected);
4412  return;
4413  }
4414 
4415  int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
4416 
4417  if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES) && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) {
4418  Brush_DrawFacingAngle(b, b->owner, false);
4419  }
4420 
4421  if ( b->owner->eclass->fixedsize ) {
4422 
4423  DrawSpeaker( b, bSelected, false );
4424 
4425  if ( g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT) && !(b->modelHandle || b->entityModel) ) {
4426  DrawLight( b, bSelected );
4427  return;
4428  }
4429 
4430  if ( b->owner->eclass->nShowFlags & ECLASS_ENV ) {
4431  Brush_DrawEnv( b, true, bSelected );
4432  }
4433 
4434  if ( b->owner->eclass->nShowFlags & ECLASS_COMBATNODE ) {
4435  Brush_DrawCombatNode( b, true, bSelected );
4436  }
4437 
4438  }
4439 
4440 
4441  if (!(b->owner && (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN))) {
4442  qglColor4f( 1.0f, 0.0f, 0.0f, 0.8f );
4443  qglPointSize(4);
4444  qglBegin(GL_POINTS);
4445  qglVertex3fv(b->owner->origin.ToFloatPtr());
4446  qglEnd();
4447  }
4448 
4449  if ( b->owner->eclass->entityModel ) {
4450  qglColor3fv( b->owner->eclass->color.ToFloatPtr() );
4451  Brush_DrawModel( b, true, bSelected );
4452  return;
4453  }
4454 
4455  Brush_DrawEmitter( b, bSelected, true );
4456 
4457  if ( b->modelHandle > 0 && !model ) {
4458  Brush_DrawModelInfo( b, bSelected );
4459  return;
4460  }
4461 
4462  // guarantee the texture will be set first
4463  prev = NULL;
4464  for (face = b->brush_faces, order = 0; face; face = face->next, order++) {
4465  w = face->face_winding;
4466  if (!w) {
4467  continue; // freed face
4468  }
4469 
4470  if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) {
4471  if (strstr(face->texdef.name, "caulk")) {
4472  continue;
4473  }
4474  }
4475 
4476  if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_VISPORTALS) {
4477  if (strstr(face->texdef.name, "visportal")) {
4478  continue;
4479  }
4480  }
4481 
4482  if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_NODRAW) {
4483  if (strstr(face->texdef.name, "nodraw")) {
4484  continue;
4485  }
4486  }
4487 
4488  if ( (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev && !b->forceWireFrame ) {
4489  // set the texture for this face
4490  prev = face->d_texture;
4491  face->d_texture->GetEditorImage()->Bind();
4492  }
4493 
4494  if (model) {
4495  qglEnable(GL_BLEND);
4496  qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4497  qglColor4f( face->d_color.x, face->d_color.y, face->d_color.z, 0.1f );
4498  } else {
4499  qglColor4f( face->d_color.x, face->d_color.y, face->d_color.z, face->d_texture->GetEditorAlpha() );
4500  }
4501 
4502  qglBegin(GL_POLYGON);
4503 
4504  for (i = 0; i < w->GetNumPoints(); i++) {
4505  if ( !b->forceWireFrame && ( nDrawMode == cd_texture || nDrawMode == cd_light ) ) {
4506  qglTexCoord2fv( &(*w)[i][3] );
4507  }
4508 
4509  qglVertex3fv( (*w)[i].ToFloatPtr() );
4510  }
4511 
4512  qglEnd();
4513 
4514  if (model) {
4515  qglDisable(GL_BLEND);
4516  }
4517  }
4518 
4520 }
4521 
4522 /*
4523 ================
4524 Face_Draw
4525 ================
4526 */
4527 void Face_Draw(face_t *f) {
4528  int i;
4529 
4530  if (f->face_winding == NULL) {
4531  return;
4532  }
4533 
4534  qglBegin(GL_POLYGON);
4535  for (i = 0; i < f->face_winding->GetNumPoints(); i++) {
4536  qglVertex3fv( (*f->face_winding)[i].ToFloatPtr() );
4537  }
4538 
4539  qglEnd();
4540 }
4541 
4542 
4544  // expects a vec3 curve and creates a vec4 based swept spline
4545  // must be either nurbs or catmull
4546  idCurve_Spline<idVec4> *newCurve = NULL;
4547  if ( dynamic_cast<idCurve_NURBS<idVec3>*>( curve ) ) {
4548  newCurve = new idCurve_NURBS<idVec4>;
4549  } else if ( dynamic_cast<idCurve_CatmullRomSpline<idVec3>*>( curve ) ) {
4550  newCurve = new idCurve_CatmullRomSpline<idVec4>;
4551  }
4552 
4553  if ( curve == NULL || newCurve == NULL ) {
4554  return NULL;
4555  }
4556 
4557  int c = curve->GetNumValues();
4558  float len = 0.0f;
4559  for ( int i = 0; i < c; i++ ) {
4560  idVec3 v = curve->GetValue( i );
4561  newCurve->AddValue( curve->GetTime( i ), idVec4( v.x, v.y, v.z, len ) );
4562  if ( i < c - 1 ) {
4563  len += curve->GetLengthBetweenKnots( i, i + 1 ) * 0.1f;
4564  }
4565  }
4566 
4568  ss->SetSpline( newCurve );
4569  ss->SetSweptCircle( 10.0f );
4570  ss->Tessellate( newCurve->GetNumValues() * 6, 6 );
4571 
4572  return ss;
4573 }
4574 
4575 /*
4576 ================
4577 Brush_DrawCurve
4578 ================
4579 */
4580 void Brush_DrawCurve( brush_t *b, bool bSelected, bool cam ) {
4581  if ( b == NULL || b->owner->curve == NULL ) {
4582  return;
4583  }
4584 
4585  int maxage = b->owner->curve->GetNumValues();
4586  int i, time = 0;
4587  qglColor3f( 0.0f, 0.0f, 1.0f );
4588  for ( i = 0; i < maxage; i++) {
4589 
4590  if ( bSelected && g_qeglobals.d_select_mode == sel_editpoint ) {
4591  idVec3 v = b->owner->curve->GetValue( i );
4592  if ( cam ) {
4593  glBox( colorBlue, v, 6.0f );
4594  if ( PointInMoveList( b->owner->curve->GetValueAddress( i ) ) >= 0 ) {
4595  glBox(colorBlue, v, 8.0f );
4596  }
4597  } else {
4598  qglPointSize( 4.0f );
4599  qglBegin( GL_POINTS );
4600  qglVertex3f( v.x, v.y, v.z );
4601  qglEnd();
4602 
4603  if ( PointInMoveList( b->owner->curve->GetValueAddress( i ) ) >= 0 ) {
4604  glBox(colorBlue, v, 4.0f );
4605  }
4606  }
4607  }
4608 /*
4609  if ( cam ) {
4610  idSurface_SweptSpline *ss = SplineToSweptSpline( b->owner->curve );
4611  if ( ss ) {
4612  idMaterial *mat = declManager->FindMaterial( "_default" );
4613  mat->GetEditorImage()->Bind();
4614  qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
4615  qglBegin( GL_TRIANGLES );
4616  const int *indexes = ss->GetIndexes();
4617  const idDrawVert *verts = ss->GetVertices();
4618  for ( j = 0; j < ss->GetNumIndexes(); j += 3 ) {
4619  for ( k = 0; k < 3; k++ ) {
4620  int index = indexes[ j + 2 - k ];
4621  float f = ShadeForNormal( verts[index].normal );
4622  qglColor3f( f, f, f );
4623  qglTexCoord2fv( verts[index].st.ToFloatPtr() );
4624  qglVertex3fv( verts[index].xyz.ToFloatPtr() );
4625  }
4626  }
4627  qglEnd();
4628  delete ss;
4629  }
4630  } else {
4631 */
4632 /* qglPointSize( 1.0f );
4633  qglBegin( GL_POINTS );
4634  if ( i + 1 < maxage ) {
4635  int start = b->owner->curve->GetTime( i );
4636  int end = b->owner->curve->GetTime( i + 1 );
4637  int inc = (end - start) / POINTS_PER_KNOT;
4638  for ( int j = 0; j < POINTS_PER_KNOT; j++ ) {
4639  idVec3 v = b->owner->curve->GetCurrentValue( start );
4640  qglVertex3f( v.x, v.y, v.z );
4641  start += inc;
4642  }
4643  }*/
4644  // DHM - _D3XP : Makes it easier to see curve
4645  qglBegin( GL_LINE_STRIP );
4646  if ( i + 1 < maxage ) {
4647  int start = b->owner->curve->GetTime( i );
4648  int end = b->owner->curve->GetTime( i + 1 );
4649  int inc = (end - start) / POINTS_PER_KNOT;
4650  for ( int j = 0; j <= POINTS_PER_KNOT; j++ ) {
4651  idVec3 v = b->owner->curve->GetCurrentValue( start );
4652  qglVertex3f( v.x, v.y, v.z );
4653  start += inc;
4654  }
4655  }
4656  qglEnd();
4657 /*
4658  }
4659 */
4660 
4661  }
4662  qglPointSize(1);
4663 }
4664 
4665 /*
4666 ================
4667 Brush_DrawXY
4668 ================
4669 */
4670 void Brush_DrawXY(brush_t *b, int nViewType, bool bSelected, bool ignoreViewType) {
4671  face_t *face;
4672  int order;
4673  idWinding *w;
4674  int i;
4675 
4676  if ( b->hiddenBrush ) {
4677  return;
4678  }
4679 
4680  idVec4 colorSave;
4681  qglGetFloatv(GL_CURRENT_COLOR, colorSave.ToFloatPtr());
4682 
4683  if (!(b->owner && (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN))) {
4684  qglColor4f( 1.0f, 0.0f, 0.0f, 0.8f );
4685  qglPointSize(4);
4686  qglBegin(GL_POINTS);
4687  qglVertex3fv(b->owner->origin.ToFloatPtr());
4688  qglEnd();
4689  }
4690 
4691  Brush_DrawCurve( b, bSelected, false );
4692 
4693  qglColor4fv(colorSave.ToFloatPtr());
4694 
4695 
4696  if (b->pPatch) {
4697  Patch_DrawXY(b->pPatch);
4698  if (!g_bPatchShowBounds) {
4699  return;
4700  }
4701  }
4702 
4703  if (b->owner->eclass->fixedsize) {
4704 
4705  DrawSpeaker(b, bSelected, true);
4706  if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT) && !(b->modelHandle || b->entityModel)) {
4707  idVec3 vCorners[4];
4708  float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
4709 
4710  vCorners[0][0] = b->mins[0];
4711  vCorners[0][1] = b->mins[1];
4712  vCorners[0][2] = fMid;
4713 
4714  vCorners[1][0] = b->mins[0];
4715  vCorners[1][1] = b->maxs[1];
4716  vCorners[1][2] = fMid;
4717 
4718  vCorners[2][0] = b->maxs[0];
4719  vCorners[2][1] = b->maxs[1];
4720  vCorners[2][2] = fMid;
4721 
4722  vCorners[3][0] = b->maxs[0];
4723  vCorners[3][1] = b->mins[1];
4724  vCorners[3][2] = fMid;
4725 
4726  idVec3 vTop, vBottom;
4727 
4728  vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
4729  vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
4730  vTop[2] = b->maxs[2];
4731 
4732  VectorCopy(vTop, vBottom);
4733  vBottom[2] = b->mins[2];
4734 
4735  qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
4736  qglBegin(GL_TRIANGLE_FAN);
4737  qglVertex3fv(vTop.ToFloatPtr());
4738  qglVertex3fv(vCorners[0].ToFloatPtr());
4739  qglVertex3fv(vCorners[1].ToFloatPtr());
4740  qglVertex3fv(vCorners[2].ToFloatPtr());
4741  qglVertex3fv(vCorners[3].ToFloatPtr());
4742  qglVertex3fv(vCorners[0].ToFloatPtr());
4743  qglEnd();
4744  qglBegin(GL_TRIANGLE_FAN);
4745  qglVertex3fv(vBottom.ToFloatPtr());
4746  qglVertex3fv(vCorners[0].ToFloatPtr());
4747  qglVertex3fv(vCorners[3].ToFloatPtr());
4748  qglVertex3fv(vCorners[2].ToFloatPtr());
4749  qglVertex3fv(vCorners[1].ToFloatPtr());
4750  qglVertex3fv(vCorners[0].ToFloatPtr());
4751  qglEnd();
4753  DrawProjectedLight(b, bSelected, false);
4754  return;
4755  } else if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) {
4756  // if (PaintedModel(b, false)) return;
4757  } else if (b->owner->eclass->nShowFlags & ECLASS_ENV) {
4758  Brush_DrawEnv( b, false, bSelected );
4759  } else if (b->owner->eclass->nShowFlags & ECLASS_COMBATNODE) {
4760  Brush_DrawCombatNode(b, false, bSelected);
4761  }
4762 
4763  if (b->owner->eclass->entityModel) {
4764  Brush_DrawModel( b, false, bSelected );
4766  qglColor4fv(colorSave.ToFloatPtr());
4767  return;
4768  }
4769 
4770  }
4771 
4772  qglColor4fv(colorSave.ToFloatPtr());
4773 
4774  if (b->modelHandle > 0) {
4775  Brush_DrawEmitter( b, bSelected, false );
4776  Brush_DrawModel(b, false, bSelected);
4777  qglColor4fv(colorSave.ToFloatPtr());
4778  return;
4779  }
4780 
4781  for (face = b->brush_faces, order = 0; face; face = face->next, order++) {
4782  // only draw polygons facing in a direction we care about
4783  if (!ignoreViewType) {
4784  if (nViewType == XY) {
4785  if (face->plane[2] <= 0) {
4786  continue;
4787  }
4788  } else {
4789  if (nViewType == XZ) {
4790  if (face->plane[1] <= 0) {
4791  continue;
4792  }
4793  } else {
4794  if (face->plane[0] <= 0) {
4795  continue;
4796  }
4797  }
4798  }
4799  }
4800 
4801  w = face->face_winding;
4802  if (!w) {
4803  continue;
4804  }
4805 
4806  //
4807  // if (b->alphaBrush && !(face->texdef.flags & SURF_ALPHA)) continue;
4808  // draw the polygon
4809  //
4810  qglBegin(GL_LINE_LOOP);
4811  for (i = 0; i < w->GetNumPoints(); i++) {
4812  qglVertex3fv( (*w)[i].ToFloatPtr() );
4813  }
4814  qglEnd();
4815 /*
4816  for (i = 0; i < 3; i++) {
4817  glLabeledPoint(idVec4(1, 0, 0, 1), face->planepts[i], 3, va("%i", i));
4818  }
4819 */
4820  }
4821 
4823 }
4824 
4825 /*
4826 ==================
4827 PointValueInPointList
4828 ==================
4829 */
4830 static int PointValueInPointList( idVec3 v ) {
4831  for ( int i = 0; i < g_qeglobals.d_numpoints; i++ ) {
4832  if ( v == g_qeglobals.d_points[i] ) {
4833  return i;
4834  }
4835  }
4836  return -1;
4837 }
4838 
4839 
4840 extern bool Sys_KeyDown(int key);
4841 /*
4842 ================
4843 Brush_Move
4844 ================
4845 */
4846 void Brush_Move(brush_t *b, const idVec3 move, bool bSnap, bool updateOrigin) {
4847  int i;
4848  face_t *f;
4849  char text[128];
4850 
4851  for (f = b->brush_faces; f; f = f->next) {
4852  idVec3 vTemp;
4853  VectorCopy(move, vTemp);
4854 
4855  if (g_PrefsDlg.m_bTextureLock) {
4856  Face_MoveTexture(f, vTemp);
4857  }
4858 
4859  for (i = 0; i < 3; i++) {
4860  VectorAdd(f->planepts[i], move, f->planepts[i]);
4861  }
4862  }
4863 
4864  bool controlDown = Sys_KeyDown(VK_CONTROL);
4865  Brush_Build(b, bSnap, true, false, !controlDown);
4866 
4867  if (b->pPatch) {
4868  Patch_Move(b->pPatch, move);
4869  }
4870 
4871  if ( b->owner->curve ) {
4872  b->owner->curve->Translate( move );
4873  Entity_UpdateCurveData( b->owner );
4874  }
4875 
4876  idVec3 temp;
4877 
4878  // PGM - keep the origin vector up to date on fixed size entities.
4879  if (b->owner->eclass->fixedsize || EntityHasModel(b->owner) || (updateOrigin && GetVectorForKey(b->owner, "origin", temp))) {
4880 // if (!b->entityModel) {
4881  bool adjustOrigin = true;
4882  if(b->trackLightOrigin) {
4883  b->owner->lightOrigin += move;
4884  sprintf(text, "%i %i %i", (int)b->owner->lightOrigin[0], (int)b->owner->lightOrigin[1], (int)b->owner->lightOrigin[2]);
4885  SetKeyValue(b->owner, "light_origin", text);
4886  if (QE_SingleBrush(true, true)) {
4887  adjustOrigin = false;
4888  }
4889  }
4890 
4891  if (adjustOrigin && updateOrigin) {
4892  b->owner->origin += move;
4893  if (g_moveOnly) {
4894  sprintf(text, "%g %g %g", b->owner->origin[0], b->owner->origin[1], b->owner->origin[2]);
4895  } else {
4896  sprintf(text, "%i %i %i", (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);
4897  }
4898  SetKeyValue(b->owner, "origin", text);
4899  }
4900 
4901  // rebuild the light dragging points now that the origin has changed
4902  idVec3 offset;
4903  offset.Zero();
4904  if (controlDown) {
4905  offset.x = -move.x;
4906  offset.y = -move.y;
4907  offset.z = -move.z;
4908  Brush_UpdateLightPoints(b, offset);
4909  } else {
4910  offset.Zero();
4911  Brush_UpdateLightPoints(b, offset);
4912  }
4913 
4914  //}
4915  if (b->owner->eclass->nShowFlags & ECLASS_ENV) {
4916  const idKeyValue *arg = b->owner->epairs.MatchPrefix( "body ", NULL );
4917  idStr val;
4918  idVec3 org;
4919  idAngles ang;
4920  while ( arg ) {
4921  sscanf( arg->GetValue(), "%f %f %f %f %f %f", &org.x, &org.y, &org.z, &ang.pitch, &ang.yaw, &ang.roll );
4922  org += move;
4923  val = org.ToString(8);
4924  val += " ";
4925  val += ang.ToString(8);
4926  b->owner->epairs.Set(arg->GetKey(), val);
4927  arg = b->owner->epairs.MatchPrefix( "body ", arg );
4928  }
4929  }
4930  }
4931 }
4932 
4933 /*
4934 ================
4935 Select_AddProjectedLight
4936 ================
4937 */
4939  idVec3 vTemp;
4940  CString str;
4941 
4942  // if (!QE_SingleBrush ()) return;
4943  brush_t *b = selected_brushes.next;
4944 
4945  if (b->owner->eclass->nShowFlags & ECLASS_LIGHT) {
4946  vTemp[0] = vTemp[1] = 0;
4947  vTemp[2] = -256;
4948  str.Format("%f %f %f", vTemp[0], vTemp[1], vTemp[2]);
4949  SetKeyValue(b->owner, "light_target", str);
4950 
4951  vTemp[2] = 0;
4952  vTemp[1] = -128;
4953  str.Format("%f %f %f", vTemp[0], vTemp[1], vTemp[2]);
4954  SetKeyValue(b->owner, "light_up", str);
4955 
4956  vTemp[1] = 0;
4957  vTemp[0] = -128;
4958  str.Format("%f %f %f", vTemp[0], vTemp[1], vTemp[2]);
4959  SetKeyValue(b->owner, "light_right", str);
4960  Brush_Build(b);
4961  }
4962 }
4963 
4964 /*
4965 ================
4966 Brush_Print
4967 ================
4968 */
4969 void Brush_Print(brush_t *b) {
4970  int nFace = 0;
4971  for (face_t * f = b->brush_faces; f; f = f->next) {
4972  common->Printf("Face %i\n", nFace++);
4973  common->Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);
4974  common->Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);
4975  common->Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);
4976  }
4977 }
4978 
4979 /*
4980 ================
4981 Brush_MakeSidedCone
4982 
4983  Makes the current brush have the given number of 2d sides and turns it into a cone
4984 ================
4985 */
4986 void Brush_MakeSidedCone(int sides) {
4987  int i;
4988  idVec3 mins, maxs;
4989  brush_t *b;
4990  texdef_t *texdef;
4991  face_t *f;
4992  idVec3 mid;
4993  float width;
4994  float sv, cv;
4995 
4996  if (sides < 3) {
4997  Sys_Status("Bad sides number", 0);
4998  return;
4999  }
5000 
5001  if (!QE_SingleBrush()) {
5002  Sys_Status("Must have a single brush selected", 0);
5003  return;
5004  }
5005 
5006  b = selected_brushes.next;
5007  VectorCopy(b->mins, mins);
5008  VectorCopy(b->maxs, maxs);
5009  texdef = &g_qeglobals.d_texturewin.texdef;
5010 
5011  Brush_Free(b);
5012 
5013  // find center of brush
5014  width = 8;
5015  for (i = 0; i < 2; i++) {
5016  mid[i] = (maxs[i] + mins[i]) * 0.5f;
5017  if (maxs[i] - mins[i] > width) {
5018  width = maxs[i] - mins[i];
5019  }
5020  }
5021 
5022  width *= 0.5f;
5023 
5024  b = Brush_Alloc();
5025 
5026  // create bottom face
5027  f = Face_Alloc();
5028  f->texdef = *texdef;
5029  f->next = b->brush_faces;
5030  b->brush_faces = f;
5031 
5032  f->planepts[0][0] = mins[0];
5033  f->planepts[0][1] = mins[1];
5034  f->planepts[0][2] = mins[2];
5035  f->planepts[1][0] = maxs[0];
5036  f->planepts[1][1] = mins[1];
5037  f->planepts[1][2] = mins[2];
5038  f->planepts[2][0] = maxs[0];
5039  f->planepts[2][1] = maxs[1];
5040  f->planepts[2][2] = mins[2];
5041 
5042  for (i = 0; i < sides; i++) {
5043  f = Face_Alloc();
5044  f->texdef = *texdef;
5045  f->next = b->brush_faces;
5046  b->brush_faces = f;
5047 
5048  sv = sin(i * idMath::TWO_PI / sides);
5049  cv = cos(i * idMath::TWO_PI / sides);
5050 
5051  f->planepts[0][0] = floor( mid[0] + width * cv + 0.5f );
5052  f->planepts[0][1] = floor( mid[1] + width * sv + 0.5f );
5053  f->planepts[0][2] = mins[2];
5054 
5055  f->planepts[1][0] = mid[0];
5056  f->planepts[1][1] = mid[1];
5057  f->planepts[1][2] = maxs[2];
5058 
5059  f->planepts[2][0] = floor( f->planepts[0][0] - width * sv + 0.5f );
5060  f->planepts[2][1] = floor( f->planepts[0][1] + width * cv + 0.5f );
5061  f->planepts[2][2] = maxs[2];
5062  }
5063 
5065 
5067 
5068  Brush_Build(b);
5069 
5070  Sys_UpdateWindows(W_ALL);
5071 }
5072 
5073 /*
5074 ================
5075 Brush_MakeSidedSphere
5076 
5077  Makes the current brushhave the given number of 2d sides and turns it into a sphere
5078 ================
5079 */
5080 void Brush_MakeSidedSphere(int sides) {
5081  int i, j;
5082  idVec3 mins, maxs;
5083  brush_t *b;
5084  texdef_t *texdef;
5085  face_t *f;
5086  idVec3 mid;
5087  float radius;
5088 
5089  if (sides < 4) {
5090  Sys_Status("Bad sides number", 0);
5091  return;
5092  }
5093 
5094  if (!QE_SingleBrush()) {
5095  Sys_Status("Must have a single brush selected", 0);
5096  return;
5097  }
5098 
5099  b = selected_brushes.next;
5100  mins = b->mins;
5101  maxs = b->maxs;
5102  texdef = &g_qeglobals.d_texturewin.texdef;
5103 
5104  Brush_Free(b);
5105 
5106  // find center of brush
5107  radius = 8;
5108  for ( i = 0; i < 3; i++ ) {
5109  mid[i] = (maxs[i] + mins[i]) * 0.5f;
5110  if (maxs[i] - mins[i] > radius) {
5111  radius = maxs[i] - mins[i];
5112  }
5113  }
5114 
5115  radius *= 0.5f;
5116 
5117  b = Brush_Alloc();
5118 
5119  for (i = 0; i < sides; i++) {
5120  for (j = 0; j < sides - 1; j++) {
5121  f = Face_Alloc();
5122  f->texdef = *texdef;
5123  f->next = b->brush_faces;
5124  b->brush_faces = f;
5125 
5126  f->planepts[0] = idPolar3(radius, idMath::TWO_PI * i / sides, idMath::PI * ((float)(j) / sides - 0.5f) ).ToVec3() + mid;
5127  f->planepts[1] = idPolar3(radius, idMath::TWO_PI * i / sides, idMath::PI * ((float)(j+1) / sides - 0.5f) ).ToVec3() + mid;
5128  f->planepts[2] = idPolar3(radius, idMath::TWO_PI * (i+1) / sides, idMath::PI * ((float)(j+1) / sides - 0.5f) ).ToVec3() + mid;
5129  }
5130  }
5131 
5133 
5135 
5136  Brush_Build(b);
5137 
5138  Sys_UpdateWindows(W_ALL);
5139 }
5140 
5141 extern void Face_FitTexture_BrushPrimit(face_t *f, idVec3 mins, idVec3 maxs, float nHeight, float nWidth);
5142 
5143 /*
5144 ================
5145 Face_FitTexture
5146 ================
5147 */
5148 void Face_FitTexture(face_t *face, float nHeight, float nWidth) {
5149  if (g_qeglobals.m_bBrushPrimitMode) {
5150  idVec3 mins, maxs;
5151  mins[0] = maxs[0] = 0;
5152  Face_FitTexture_BrushPrimit(face, mins, maxs, nHeight, nWidth);
5153  }
5154  else {
5155  /*
5156  * winding_t *w; idBounds bounds; int i; float width, height, temp; float rot_width,
5157  * rot_height; float cosv,sinv,ang; float min_t, min_s, max_t, max_s; float s,t;
5158  * idVec3 vecs[2]; idVec3 coords[4]; texdef_t *td; if (nHeight < 1) { nHeight = 1;
5159  * } if (nWidth < 1) { nWidth = 1; } bounds.Clear(); td = &face->texdef; w =
5160  * face->face_winding; if (!w) { return; } for (i=0 ; i<w->numpoints ; i++) {
5161  * bounds.AddPoint( w->p[i] ); } // // get the current angle // ang = td->rotate /
5162  * 180 * Q_PI; sinv = sin(ang); cosv = cos(ang); // get natural texture axis
5163  * TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]); min_s = DotProduct(
5164  * bounds.b[0], vecs[0] ); min_t = DotProduct( bounds.b[0], vecs[1] ); max_s =
5165  * DotProduct( bounds.b[1], vecs[0] ); max_t = DotProduct( bounds.b[1], vecs[1] );
5166  * width = max_s - min_s; height = max_t - min_t; coords[0][0] = min_s;
5167  * coords[0][1] = min_t; coords[1][0] = max_s; coords[1][1] = min_t; coords[2][0]
5168  * = min_s; coords[2][1] = max_t; coords[3][0] = max_s; coords[3][1] = max_t;
5169  * min_s = min_t = 999999; max_s = max_t = -999999; for (i=0; i<4; i++) { s = cosv
5170  * * coords[i][0] - sinv * coords[i][1]; t = sinv * coords[i][0] + cosv *
5171  * coords[i][1]; if (i&1) { if (s > max_s) { max_s = s; } } else { if (s < min_s)
5172  * { min_s = s; } if (i<2) { if (t < min_t) { min_t = t; } } else { if (t > max_t)
5173  * { max_t = t; } } } } rot_width = (max_s - min_s); rot_height = (max_t - min_t);
5174  * td->scale[0] =
5175  * -(rot_width/((float)(face->d_texture->GetEditorImage()->uploadWidth*nWidth)));
5176  * td->scale[1] =
5177  * -(rot_height/((float)(face->d_texture->GetEditorImage()->uploadHeight*nHeight)));
5178  * td->shift[0] = min_s/td->scale[0]; temp = (int)(td->shift[0] /
5179  * (face->d_texture->GetEditorImage()->uploadWidth*nWidth)); temp =
5180  * (temp+1)*face->d_texture->GetEditorImage()->uploadWidth*nWidth; td->shift[0] =
5181  * (int)(temp -
5182  * td->shift[0])%(face->d_texture->GetEditorImage()->uploadWidth*nWidth);
5183  * td->shift[1] = min_t/td->scale[1]; temp = (int)(td->shift[1] /
5184  * (face->d_texture->GetEditorImage()->uploadHeight*nHeight)); temp =
5185  * (temp+1)*(face->d_texture->GetEditorImage()->uploadHeight*nHeight);
5186  * td->shift[1] = (int)(temp -
5187  * td->shift[1])%(face->d_texture->GetEditorImage()->uploadHeight*nHeight);
5188  */
5189  }
5190 }
5191 
5192 /*
5193 ================
5194 Brush_FitTexture
5195 ================
5196 */
5197 void Brush_FitTexture(brush_t *b, float nHeight, float nWidth) {
5198  face_t *face;
5199  for (face = b->brush_faces; face; face = face->next) {
5200  Face_FitTexture(face, nHeight, nWidth);
5201  }
5202 }
5203 
5204 void Brush_GetBounds( brush_t *b, idBounds &bo ) {
5205  if ( b == NULL ) {
5206  return;
5207  }
5208 
5209  bo.Clear();
5210  bo.AddPoint( b->mins );
5211  bo.AddPoint( b->maxs );
5212 
5213  if ( b->owner->curve ) {
5214  int c = b->owner->curve->GetNumValues();
5215  for ( int i = 0; i < c; i++ ) {
5216  bo.AddPoint ( b->owner->curve->GetValue( i ) );
5217  }
5218  }
5219 
5220 }
CMainFrame * g_pParentWnd
Definition: MainFrm.cpp:73
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:2959
brush_t * Brush_FullClone(brush_t *b)
void VectorSnapGrid(idVec3 &v)
Definition: XYWnd.cpp:291
GLdouble GLdouble bottom
Definition: qgl.h:273
byte color[4]
Definition: MegaTexture.cpp:54
void Brush_Print(brush_t *b)
#define strcmp
Definition: Str.h:41
void Face_FitTexture(face_t *face, float nHeight, float nWidth)
idImage * GetEditorImage(void) const
Definition: Material.cpp:190
virtual idRenderModel * DefaultModel()=0
#define stricmp
Definition: Str.h:64
void AddSelectablePoint(brush_t *b, idVec3 v, int type, bool priority)
Definition: XYWnd.cpp:230
void WINAPI Sys_UpdateWindows(int nBits)
Definition: MainFrm.cpp:3974
#define min(a, b)
GLsizei const GLfloat * value
Definition: glext.h:3614
bool Compare(const idVec3 &a) const
Definition: Vector.h:496
type GetValue(const int index) const
Definition: Curve.h:58
float Normalize(void)
Definition: Vector.h:646
idVec4 colorGreen
Definition: Lib.cpp:118
entity_t * world_entity
Definition: EditorMap.cpp:49
int GetInt(const char *key, const char *defaultString="0") const
Definition: Dict.h:252
void DrawLight(brush_t *b, bool bSelected)
face_t * Face_Alloc(void)
void GLTransformedVertex(float x, float y, float z, idMat3 mat, idVec3 origin, idVec3 color, float maxDist)
void cross(float a[], float b[], float c[])
Definition: Model_lwo.cpp:3889
void Brush_Center(brush_t *b, idVec3 vNewCenter)
assert(prefInfo.fullscreenBtn)
virtual const idSoundShader * FindSound(const char *name, bool makeDefault=true)=0
bool FromPoints(const idVec3 &p1, const idVec3 &p2, const idVec3 &p3, bool fixDegenerate=true)
Definition: Plane.h:279
brush_t * Brush_Alloc(void)
const idVec3 & Normal(void) const
Definition: Plane.h:239
void Brush_DrawCombatNode(brush_t *b, bool cameraView, bool bSelected)
idVec3 GetCenter(void) const
Definition: Bounds.h:211
void Brush_SetTextureName(brush_t *b, const char *name)
const float METERS_TO_DOOM
Definition: sound.h:43
#define qglDisable
Definition: qgl_linked.h:92
int Brush_Convex(brush_t *b)
void Brush_MakeSided(int sides)
float lightaxis[3]
void Zero(void)
Definition: Bounds.h:206
void Face_TextureVectors(face_t *f, float STfromXYZ[2][4])
float y
Definition: Vector.h:811
virtual idRenderModel * ANIM_CreateMeshForAnim(idRenderModel *model, const char *classname, const char *animname, int frame, bool remove_origin_offset)
void DrawBrushEntityName(brush_t *b)
brush_t selected_brushes
Definition: EditorMap.cpp:40
float y
Definition: Vector.h:55
virtual float GetMaxDistance() const
Definition: snd_shader.cpp:449
void ClearSelectablePoints(brush_t *b)
Definition: XYWnd.cpp:205
bool WriteFileString(FILE *fp, char *string,...)
Definition: EditorMap.cpp:1427
brush_t active_brushes
Definition: EditorMap.cpp:39
const GLdouble * v
Definition: glext.h:2936
int AddPlanept(idVec3 *f)
const idStr & GetKey(void) const
Definition: Dict.h:52
face_t * Brush_Point(idVec3 origin, brush_t *b)
GLuint GLenum matrix
Definition: glext.h:5179
GLdouble GLdouble x2
Definition: qgl.h:415
#define MAX_WORLD_SIZE
Definition: Lib.h:100
const char * ToString(int precision=2) const
Definition: Angles.cpp:238
void Entity_UnlinkBrush(brush_t *b)
const float * ToFloatPtr(void) const
Definition: Vector.h:719
#define VectorSubtract(a, b, c)
Definition: Vector.h:1995
srfTriangles_t * R_PolytopeSurface(int numPlanes, const idPlane *planes, idWinding **windings)
Definition: tr_polytope.cpp:44
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:4804
face_t * Face_Clone(face_t *f)
idVec3 xyz
Definition: DrawVert.h:42
static const float PI
Definition: Math.h:205
#define MAX_MOVE_FACES
#define qglTexCoord2fv
Definition: qgl_linked.h:297
GLenum GLint GLint y
Definition: glext.h:2849
idWinding * TryMerge(const idWinding &w, const idVec3 &normal, int keep=false) const
Definition: Winding.cpp:998
void SetFaceTexdef(brush_t *b, face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale)
GLenum GLsizei n
Definition: glext.h:3705
eclass_t * HasModel(brush_t *b)
float z
Definition: Vector.h:812
float z
Definition: Vector.h:320
void Brush_DrawCurve(brush_t *b, bool bSelected, bool cam)
#define VectorCopy(a, b)
Definition: Vector.h:1999
void Clamp(float &f, int nClamp)
void BuildEntityRenderState(entity_t *ent, bool update)
Definition: CamWnd.cpp:1237
void Brush_DrawModel(brush_t *b, bool camera, bool bSelected)
brush_t * Brush_Parse(idVec3 origin)
const idMaterial * shader
Definition: Model.h:146
void Brush_SideSelect(brush_t *b, idVec3 origin, idVec3 dir, bool shear)
void Brush_RemoveEmptyFaces(brush_t *b)
#define WINAPI
Definition: qgl.h:64
void Brush_Resize(brush_t *b, idVec3 vMin, idVec3 vMax)
#define qglBegin
Definition: qgl_linked.h:33
void Sys_Status(const char *psz, int part)
Definition: Radiant.cpp:465
CXYWnd * ActiveXY()
Definition: MainFrm.cpp:4034
camera_t & Camera()
Definition: CamWnd.h:90
idVec3 baseaxis[18]
const char * Brush_GetKeyValue(brush_t *b, const char *pKey)
const char * ValueForKey(entity_t *ent, const char *key)
void glBox(idVec4 &color, idVec3 &point, float size)
Definition: splines.cpp:61
Definition: Vector.h:316
bool Entity_GetRotationMatrixAngles(entity_t *e, idMat3 &mat, idAngles &angles)
bool GetMatrixForKey(entity_t *ent, const char *key, idMat3 &mat)
void Face_MoveTexture(face_t *f, idVec3 delta)
#define qglVertex3fv
Definition: qgl_linked.h:350
bool Brush_ModelIntersect(brush_t *b, idVec3 origin, idVec3 dir, float &scale)
FILE * g_File
void Brush_Free(brush_t *b, bool bRemoveNode)
#define VectorAdd(a, b, c)
Definition: Vector.h:1996
virtual float GetMinDistance() const
Definition: snd_shader.cpp:440
void Clear(void)
Definition: Bounds.h:201
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
void Brush_Move(brush_t *b, const idVec3 move, bool bSnap, bool updateOrigin)
bool Patch_Intersect(patchMesh_t *pm, idVec3 origin, idVec3 direction, float &scale)
void Brush_GetBounds(brush_t *b, idBounds &bo)
void MemFile_fprintf(CMemFile *pMemFile, const char *string,...)
Definition: EditorMap.cpp:1526
brush_t * Brush_Clone(brush_t *b)
BOOL m_bNewLightDraw
Definition: PrefsDlg.h:79
GLdouble s
Definition: glext.h:2935
float GetRadius(void) const
Definition: Bounds.cpp:39
idWinding * Clip(const idPlane &plane, const float epsilon=ON_EPSILON, const bool keepOn=false)
Definition: Winding.cpp:234
GLenum GLsizei len
Definition: glext.h:3472
GLdouble right
Definition: qgl.h:273
idVec3 Cross(const idVec3 &a) const
Definition: Vector.h:619
void Identity(void)
Definition: Matrix.h:591
float x
Definition: Vector.h:318
idMat3 Brush_RotationMatrix(brush_t *b)
#define qglTranslatef
Definition: qgl_linked.h:338
static float Rint(float f)
Definition: Math.h:793
void DrawSpeaker(brush_t *b, bool bSelected, bool twoD)
GLenum GLint x
Definition: glext.h:2849
void Brush_DrawModelInfo(brush_t *b, bool selected)
void Face_FitTexture_BrushPrimit(face_t *f, idVec3 mins, idVec3 maxs, float nHeight, float nWidth)
void Brush_DrawAxis(brush_t *b)
int i
Definition: process.py:33
GLintptr offset
Definition: glext.h:3113
void Brush_SetTexture(brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale)
Boolean result
idAngles & Zero(void)
Definition: Angles.h:126
brush_t brushes
Definition: EditorEntity.h:35
bool g_bShowLightTextures
Definition: EditorBrush.cpp:44
void Brush_Build(brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool updateLights)
#define qglEnable
Definition: qgl_linked.h:101
void EmitTextureCoordinates(idVec5 &xyzst, const idMaterial *q, face_t *f, bool force)
#define qglPolygonOffset
Definition: qgl_linked.h:230
int Icmp(const char *text) const
Definition: Str.h:667
void Brush_DrawEnv(brush_t *b, bool cameraView, bool bSelected)
camera_draw_mode draw_mode
Definition: CamWnd.h:51
void Face_Free(face_t *f)
virtual dynamicModel_t IsDynamicModel() const =0
idVec4 colorRed
Definition: Lib.cpp:117
void Select_AddProjectedLight()
void SetKeyValue(entity_t *ent, const char *key, const char *value, bool trackAngles)
idGameEdit * gameEdit
Definition: GameEdit.cpp:668
void InsertPoint(const idVec3 &point, int spot)
Definition: Winding.cpp:1121
#define qglPushMatrix
Definition: qgl_linked.h:239
void Brush_SnapToGrid(brush_t *pb)
void Brush_MakeSidedCone(int sides)
bool AddPoint(const idVec3 &v)
Definition: Bounds.h:226
void Error(const char *pFormat,...)
Definition: cmdlib.cpp:45
GLfloat GLfloat GLfloat v2
Definition: glext.h:3608
idVec2 st
Definition: DrawVert.h:43
void Brush_BuildWindings(brush_t *b, bool bSnap, bool keepOnPlaneWinding, bool updateLights, bool makeFacePlanes)
int Face_MemorySize(face_t *f)
GLuint GLuint GLsizei count
Definition: glext.h:2845
CCamWnd * GetCamera()
Definition: MainFrm.h:123
void Brush_FitTexture(brush_t *b, float nHeight, float nWidth)
void Set(float pitch, float yaw, float roll)
Definition: Angles.h:120
void WINAPI QERApp_MapPrintf_MEMFILE(char *text,...)
void Entity_UpdateCurveData(entity_t *ent)
GLdouble GLdouble GLint GLint order
Definition: qgl.h:339
void GLTransformedCircle(int type, idVec3 origin, float r, idMat3 mat, float pointSize, idVec3 color, float maxDist)
int GetNumPoints(void) const
Definition: Winding.h:238
#define MAX_POINTS_ON_WINDING
Definition: Winding.h:279
GLuint index
Definition: glext.h:3476
const GLubyte * c
Definition: glext.h:4677
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
bool EntityHasModel(entity_t *ent)
Definition: Vector.h:808
float Length(void) const
Definition: Vector.h:631
idVec3 ToForward(void) const
Definition: Angles.cpp:117
void Control_Draw(brush_t *b)
const idMaterial * Texture_ForName(const char *name)
Definition: NewTexWnd.cpp:700
void Brush_SplitBrushByFace(brush_t *in, face_t *f, brush_t **front, brush_t **back)
void Brush_AddToList(brush_t *b, brush_t *list)
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
brush_t * Brush_MakeConvexBrushes(brush_t *b)
GLuint texnum
Definition: Image.h:216
#define qglRasterPos3fv
Definition: qgl_linked.h:252
void SetSweptCircle(const float radius)
GLuint GLuint end
Definition: glext.h:2845
static float Fabs(float f)
Definition: Math.h:779
#define qglPolygonMode
Definition: qgl_linked.h:229
idCommon * common
Definition: Common.cpp:206
idVec3 & RotateOrigin()
Definition: XYWnd.cpp:4361
Definition: Dict.h:65
#define NULL
Definition: Lib.h:88
void Face_MakePlane(face_t *f)
srfTriangles_t * geometry
Definition: Model.h:147
void SnapVectorToGrid(idVec3 &v)
Definition: EditorBrush.cpp:89
float y
Definition: Vector.h:319
#define qglTexCoord2f
Definition: qgl_linked.h:296
void RotateVector(idVec3 &v, idVec3 origin, float a, float c, float s)
idVec3 Brush_TransformedPoint(brush_t *b, const idVec3 &in)
idVec3 ToVec3(void) const
Definition: Vector.h:1978
#define qglEnd
Definition: qgl_linked.h:103
virtual const modelSurface_t * Surface(int surfaceNum) const =0
idImageManager * globalImages
Definition: Image_init.cpp:74
#define qglColor3f
Definition: qgl_linked.h:50
bool RayIntersectsTri(const idVec3 &origin, const idVec3 &direction, const idVec3 &vert0, const idVec3 &vert1, const idVec3 &vert2, float &scale)
Definition: Plane.h:71
brush_t * Brush_CreatePyramid(idVec3 mins, idVec3 maxs, texdef_t *texdef)
#define qglGetFloatv
Definition: qgl_linked.h:132
void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue)
void R_FreeStaticTriSurf(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:489
void WINAPI QERApp_MapPrintf_FILE(char *text,...)
float w
Definition: Vector.h:813
float x
Definition: Vector.h:54
float roll
Definition: Angles.h:55
void Face_MoveTexture_BrushPrimit(face_t *f, idVec3 delta)
void Brush_ResetFaceOriginals(brush_t *b)
void BrushPrimit_Parse(brush_t *b, bool newFormat, const idVec3 origin)
virtual idRenderModel * AF_CreateMesh(const idDict &args, idVec3 &meshOrigin, idMat3 &meshAxis, bool &poseIsSet)
Definition: AFEntity.cpp:2956
const idStr & GetValue(void) const
Definition: Dict.h:53
BOOL m_bHiColorTextures
Definition: PrefsDlg.h:91
int GetViewType()
Definition: XYWnd.h:154
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
const idMaterial * Texture_LoadLight(const char *name)
Definition: NewTexWnd.cpp:668
float NormalizeFast(void)
Definition: Vector.h:524
void VectorRotate3Origin(const idVec3 &vIn, const idVec3 &vRotation, const idVec3 &vOrigin, idVec3 &out)
face_t * Face_FullClone(face_t *f)
void Brush_RemoveFromList(brush_t *b)
idVec3 origin
Definition: CamWnd.h:48
bool g_bShowLightVolumes
Definition: EditorBrush.cpp:43
Definition: CamWnd.h:37
void FromTransformedBounds(const idBounds &bounds, const idVec3 &origin, const idMat3 &axis)
Definition: Bounds.cpp:232
GLenum GLsizei width
Definition: glext.h:2846
void DrawProjectedLight(brush_t *b, bool bSelected, bool texture)
const char * Brush_Name(brush_t *b)
int Brush_InsertVertexBetween(brush_t *b, idVec3 p1, idVec3 p2)
float pitch
Definition: Angles.h:53
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
virtual void Printf(const char *fmt,...) id_attribute((format(printf
int Brush_MemorySize(brush_t *b)
#define DEG2RAD(a)
Definition: Math.h:56
virtual idBounds Bounds(const struct renderEntity_s *ent=NULL) const =0
void Brush_Scale(brush_t *b)
GLdouble GLdouble GLdouble y2
Definition: qgl.h:415
const float * ToFloatPtr(void) const
Definition: Vector.h:1051
#define TINY_EPSILON
#define qglPointSize
Definition: qgl_linked.h:228
GLfloat GLfloat v1
Definition: glext.h:3607
GLdouble GLdouble GLdouble top
Definition: qgl.h:273
int m_nEntityShowState
Definition: PrefsDlg.h:110
float GetTime(const int index) const
Definition: Curve.h:60
void TextureAxisFromPlane(const idPlane &pln, idVec3 &xv, idVec3 &yv)
idDeclManager * declManager
void Brush_Write(brush_t *b, FILE *f, const idVec3 &origin, bool newFormat)
void MarkWorldDirty()
Definition: CamWnd.cpp:1977
int uploadHeight
Definition: Image.h:249
GLubyte GLubyte b
Definition: glext.h:4662
bool IsTiny(void) const
Definition: Winding.cpp:1202
BOOL m_bTextureLock
Definition: PrefsDlg.h:60
static const float TWO_PI
Definition: Math.h:206
void Tessellate(const int splineSubdivisions, const int sweptSplineSubdivisions)
int uploadWidth
Definition: Image.h:249
#define qglPopMatrix
Definition: qgl_linked.h:234
GLfloat GLfloat GLfloat GLfloat v3
Definition: glext.h:3609
GLdouble GLdouble GLdouble r
Definition: glext.h:2951
bool GetVectorForKey(entity_t *ent, const char *key, idVec3 &vec)
void Entity_LinkBrush(entity_t *e, brush_t *b)
idRenderModelManager * renderModelManager
Definition: Matrix.h:333
void R_RenderLightFrustum(const struct renderLight_s &renderLight, idPlane lightFrustum[6])
void AddMovePlane(idPlane *p)
float yaw
Definition: Angles.h:54
GLenum pname
Definition: glext.h:2847
bool Sys_KeyDown(int key)
Definition: NewTexWnd.cpp:49
void ConvertTexMatWithQTexture(float texMat1[2][3], const idMaterial *qtex1, float texMat2[2][3], const idMaterial *qtex2, float sScale=1.0, float tScale=1.0)
int Brush_MoveVertex(brush_t *b, const idVec3 &vertex, const idVec3 &delta, idVec3 &end, bool bSnap)
const int POINTS_PER_KNOT
Definition: EditorBrush.cpp:48
tuple f
Definition: idal.py:89
#define ON_EPSILON
Definition: Plane.h:44
GLuint in
Definition: glext.h:5388
const idMat3 & ToMat3(void) const
Definition: Rotation.cpp:60
void Brush_Rotate(brush_t *b, idMat3 matrix, idVec3 origin, bool bBuild)
idMat3 ToMat3(void) const
Definition: Angles.cpp:199
void GLCircle(float x, float y, float z, float r)
#define qglLineWidth
Definition: qgl_linked.h:184
bool RotateMode()
Definition: XYWnd.cpp:4023
GLuint texture
Definition: glext.h:3871
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
bool ClipLineToFace(idVec3 &p1, idVec3 &p2, face_t *f)
CPrefsDlg & g_PrefsDlg
Definition: MainFrm.cpp:75
void Face_SetColor(brush_t *b, face_t *f, float fCurveColor)
void DrawRenderModel(idRenderModel *model, idVec3 &origin, idMat3 &axis, bool cameraView)
Definition: EditorBrush.cpp:55
idWinding * Copy(void) const
Definition: Winding.cpp:464
float ShadeForNormal(idVec3 normal)
void glVertex3fv(const GLfloat *v)
Definition: stub_gl.cpp:365
void Brush_DrawEmitter(brush_t *b, bool bSelected, bool cam)
#define qglColor4f
Definition: qgl_linked.h:66
Definition: Str.h:116
virtual int AddValue(const float time, const type &value)
Definition: Curve.h:116
int IntForKey(entity_t *ent, const char *key)
brush_t * Brush_Create(idVec3 mins, idVec3 maxs, texdef_t *texdef)
idDict epairs
Definition: EditorEntity.h:42
void Brush_Draw(brush_t *b, bool bSelected)
int vsprintf(idStr &string, const char *fmt, va_list argptr)
Definition: Str.cpp:1549
#define qglBlendFunc
Definition: qgl_linked.h:36
void * Mem_ClearedAlloc(const int size)
Definition: Heap.cpp:1149
int g_nBrushId
Definition: EditorBrush.cpp:42
#define qglColor4fv
Definition: qgl_linked.h:67
#define DotProduct(a, b)
Definition: Vector.h:1994
bool g_bScreenUpdates
Definition: MainFrm.cpp:77
virtual void ParseSpawnArgsToRenderLight(const idDict *args, renderLight_t *renderLight)
Definition: Light.cpp:80
glIndex_t * indexes
Definition: Model.h:102
idAngles ToAngles(void) const
Definition: Matrix.cpp:147
void Brush_MakeSidedSphere(int sides)
idWinding * Brush_MakeFaceWinding(brush_t *b, face_t *face, bool keepOnPlaneWinding)
#define qglCallLists
Definition: qgl_linked.h:38
CMemFile * g_pMemFile
void Brush_DrawXY(brush_t *b, int nViewType, bool bSelected, bool ignoreViewType)
#define qglVertex3f
Definition: qgl_linked.h:349
void Brush_UpdateLightPoints(brush_t *b, const idVec3 &offset)
void RemovePoint(int point)
Definition: Winding.cpp:1106
#define qglColor3fv
Definition: qgl_linked.h:51
#define VectorScale(v, s, o)
Definition: Vector.h:1997
GLint j
Definition: qgl.h:264
void Face_Draw(face_t *f)
idBounds & ExpandSelf(const float d)
Definition: Bounds.h:322
float dot(float a[], float b[])
Definition: Model_lwo.cpp:3883
GLuint GLenum GLenum transform
Definition: glext.h:5179
#define VectorMA(v, s, b, o)
Definition: Vector.h:1998
int numIndexes
Definition: Model.h:101
float GetLengthBetweenKnots(const int i0, const int i1) const
Definition: Curve.h:241
BOOL m_selectByBoundingBrush
Definition: PrefsDlg.h:109
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
int GetNumValues(void) const
Definition: Curve.h:56
void UpdateSelectablePoint(brush_t *b, idVec3 v, int type)
Definition: XYWnd.cpp:238
face_t * Brush_Ray(idVec3 origin, idVec3 dir, brush_t *b, float *dist, bool testPrimitive)
#define max(x, y)
Definition: os.h:70
GLfloat GLfloat p
Definition: glext.h:4674
void SetKeyVec3(entity_t *ent, const char *key, idVec3 v)
void Bind()
float Scale()
Definition: XYWnd.h:156
void SetSpline(idCurve_Spline< idVec4 > *spline)
void ToVectors(idVec3 *forward, idVec3 *right=NULL, idVec3 *up=NULL) const
Definition: Angles.cpp:92
float x
Definition: Vector.h:810
float FloatForKey(entity_t *ent, const char *key)
eclass_t * GetCachedModel(entity_t *pEntity, const char *pName, idVec3 &vMin, idVec3 &vMax)
GLdouble GLdouble z
Definition: glext.h:3067
void Brush_MakeFacePlanes(brush_t *b)
void Zero(void)
Definition: Vector.h:415
void Brush_SelectFaceForDragging(brush_t *b, face_t *f, bool shear)
void Brush_DrawFacingAngle(brush_t *b, entity_t *e, bool particle)
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
face_t * Brush_BestSplitFace(brush_t *b)
GLuint start
Definition: glext.h:2845
void EmitBrushPrimitTextureCoordinates(face_t *f, idWinding *w, patchMesh_t *patch)
void FaceToBrushPrimitFace(face_t *f)
idDrawVert * verts
Definition: Model.h:99
idVec4 colorBlue
Definition: Lib.cpp:119
idSurface_SweptSpline * SplineToSweptSpline(idCurve< idVec3 > *curve)
void SetNumPoints(int n)
Definition: Winding.h:242
GLdouble GLdouble t
Definition: glext.h:2943
virtual int NumSurfaces() const =0