1 /*
2 BobToolz plugin for GtkRadiant
3 Copyright (C) 2001 Gordon Biggans
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 // DBrush.cpp: implementation of the DBrush class.
21 //
22 //////////////////////////////////////////////////////////////////////
23
24 #include "StdAfx.h"
25
26 #ifdef WIN32
27 #pragma warning(disable : 4786)
28 #endif
29
30 #include "StdAfx.h"
31
32 #include "gtkr_list.h"
33 #include "str.h"
34
35 #include "DPoint.h"
36 #include "DPlane.h"
37 #include "DBrush.h"
38 #include "DEPair.h"
39 #include "DPatch.h"
40 #include "DEntity.h"
41 #include "DWinding.h"
42
43 #include "dialogs-gtk.h"
44
45 #include "misc.h"
46
47 #include "iundo.h"
48
49 #include "refcounted_ptr.h"
50
51 #include "scenelib.h"
52
53 //////////////////////////////////////////////////////////////////////
54 // Construction/Destruction
55 //////////////////////////////////////////////////////////////////////
56
DBrush(int ID)57 DBrush::DBrush(int ID)
58 {
59 m_nBrushID = ID;
60 bBoundsBuilt = FALSE;
61 QER_brush = NULL;
62 }
63
~DBrush()64 DBrush::~DBrush()
65 {
66 ClearFaces();
67 ClearPoints();
68 }
69
70 //////////////////////////////////////////////////////////////////////
71 // Implementation
72 //////////////////////////////////////////////////////////////////////
73
AddFace(vec3_t va,vec3_t vb,vec3_t vc,_QERFaceData * texData)74 DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData)
75 {
76 #ifdef _DEBUG
77 // Sys_Printf("(%f %f %f) (%f %f %f) (%f %f %f)\n", va[0], va[1], va[2], vb[0], vb[1], vb[2], vc[0], vc[1], vc[2]);
78 #endif
79 bBoundsBuilt = FALSE;
80 DPlane* newFace = new DPlane(va, vb, vc, texData);
81 faceList.push_back(newFace);
82
83 return newFace;
84 }
85
BuildPoints()86 int DBrush::BuildPoints()
87 {
88 ClearPoints();
89
90 if(faceList.size() <= 3) // if less than 3 faces, there can be no points
91 return 0; // with only 3 faces u can't have a bounded soild
92
93 for(list<DPlane *>::const_iterator p1=faceList.begin(); p1!=faceList.end(); p1++)
94 {
95 list<DPlane *>::const_iterator p2=p1;
96 for(p2++; p2!=faceList.end(); p2++)
97 {
98 list<DPlane *>::const_iterator p3=p2;
99 for(p3++; p3!=faceList.end(); p3++)
100 {
101 vec3_t pnt;
102 if((*p1)->PlaneIntersection(*p2, *p3, pnt))
103 {
104 int pos = PointPosition(pnt);
105
106 if(pos == POINT_IN_BRUSH)
107 { // ???? shouldn't happen here
108 Sys_Printf("ERROR:: Build Brush Points: Point IN brush!!!\n");
109 }
110 else if(pos == POINT_ON_BRUSH)
111 { // normal point
112 if(!HasPoint(pnt))
113 AddPoint(pnt);
114 /* else
115 Sys_Printf("Duplicate Point Found, pyramids ahoy!!!!!\n");*/
116 // point lies on more that 3 planes
117 }
118
119 // otherwise point is removed due to another plane..
120
121 // Sys_Printf("(%f, %f, %f)\n", pnt[0], pnt[1], pnt[2]);
122 }
123 }
124 }
125 }
126
127 #ifdef _DEBUG
128 // Sys_Printf("%i points on brush\n", pointList.size());
129 #endif
130
131 return pointList.size();
132 }
133
LoadFromBrush(scene::Node * brush,bool textured)134 void DBrush::LoadFromBrush(scene::Node* brush, bool textured)
135 {
136 ClearFaces();
137 ClearPoints();
138
139 #if 0
140 for(int i = g_FuncTable.m_pfnGetFaceCount(brush)-1; i >= 0 ; i--)
141 { // running backwards so i dont have to use the count function each time (OPT)
142 _QERFaceData* faceData = g_FuncTable.m_pfnGetFaceData(brush, i);
143
144 if(faceData == NULL)
145 DoMessageBox("Null pointer returned", "WARNING!", MB_OK);
146
147 if(textured)
148 AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, faceData);
149 else
150 AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, NULL);
151 }
152 #endif
153
154 QER_brush = brush;
155 }
156
PointPosition(vec3_t pnt)157 int DBrush::PointPosition(vec3_t pnt)
158 {
159 int state = POINT_IN_BRUSH; // if nothing happens point is inside brush
160
161 for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
162 {
163 float dist = (*chkPlane)->DistanceToPoint(pnt);
164
165 if(dist > MAX_ROUND_ERROR)
166 return POINT_OUT_BRUSH; // if point is in front of plane, it CANT be in the brush
167 else if(fabs(dist) < MAX_ROUND_ERROR)
168 state = POINT_ON_BRUSH; // if point is ON plane point is either ON the brush
169 // or outside it, it can no longer be in it
170 }
171
172 return state;
173 }
174
ClearPoints()175 void DBrush::ClearPoints()
176 {
177 for(list<DPoint *>::const_iterator deadPoint=pointList.begin(); deadPoint!=pointList.end(); deadPoint++) {
178 delete *deadPoint;
179 }
180 pointList.clear();
181 }
182
ClearFaces()183 void DBrush::ClearFaces()
184 {
185 bBoundsBuilt = FALSE;
186 for(list<DPlane *>::const_iterator deadPlane=faceList.begin(); deadPlane!=faceList.end(); deadPlane++)
187 {
188 delete *deadPlane;
189 }
190 faceList.clear();
191 }
192
AddPoint(vec3_t pnt)193 void DBrush::AddPoint(vec3_t pnt)
194 {
195 DPoint* newPoint = new DPoint;
196 VectorCopy(pnt, newPoint->_pnt);
197 pointList.push_back(newPoint);
198 }
199
HasPoint(vec3_t pnt)200 bool DBrush::HasPoint(vec3_t pnt)
201 {
202 for(list<DPoint *>::const_iterator chkPoint=pointList.begin(); chkPoint!=pointList.end(); chkPoint++)
203 {
204 if(**chkPoint == pnt)
205 return TRUE;
206 }
207
208 return FALSE;
209 }
210
RemoveRedundantPlanes()211 int DBrush::RemoveRedundantPlanes()
212 {
213 int cnt = 0;
214 list<DPlane *>::iterator chkPlane;
215
216 // find duplicate planes
217 list<DPlane *>::iterator p1=faceList.begin();
218
219 while( p1!=faceList.end() )
220 {
221 list<DPlane *>::iterator p2 = p1;
222
223 for(p2++; p2!=faceList.end(); p2++)
224 {
225 if(**p1 == **p2)
226 {
227 if(!strcmp((*p1)->texInfo.m_texdef.GetName(), "textures/common/caulk"))
228 {
229 delete *p1;
230 p1 = faceList.erase(p1); // duplicate plane
231 }
232 else
233 {
234 delete *p2;
235 p2 = faceList.erase(p2); // duplicate plane
236 }
237
238 cnt++;
239 break;
240 }
241 }
242
243 if( p2 == faceList.end() )
244 p1++;
245 }
246
247 //+djbob kill planes with bad normal, they are more of a nuisance than losing a brush
248 chkPlane=faceList.begin();
249 while( chkPlane!=faceList.end() )
250 {
251 if(VectorLength((*chkPlane)->normal) == 0) // plane has bad normal
252 {
253 delete *chkPlane;
254 chkPlane = faceList.erase(chkPlane);
255 cnt++;
256 } else {
257 chkPlane++;
258 }
259 }
260 //-djbob
261
262 if(pointList.size() == 0) // if points may not have been built, build them
263 /* if(BuildPoints() == 0) // just let the planes die if they are all bad
264 return cnt;*/
265 BuildPoints();
266
267 chkPlane=faceList.begin();
268 while(chkPlane != faceList.end())
269 {
270 if((*chkPlane)->IsRedundant(pointList)) // checks that plane "0wnz" :), 3 or more points
271 {
272 delete *chkPlane;
273 chkPlane = faceList.erase(chkPlane);
274 cnt++;
275 }
276 else
277 chkPlane++;
278 }
279
280 return cnt;
281 }
282
GetBounds(vec3_t min,vec3_t max)283 bool DBrush::GetBounds(vec3_t min, vec3_t max)
284 {
285 BuildBounds();
286
287 if(!bBoundsBuilt)
288 return FALSE;
289
290 VectorCopy(bbox_min, min);
291 VectorCopy(bbox_max, max);
292
293 return TRUE;
294 }
295
BBoxCollision(DBrush * chkBrush)296 bool DBrush::BBoxCollision(DBrush* chkBrush)
297 {
298 vec3_t min1, min2;
299 vec3_t max1, max2;
300
301 GetBounds(min1, max1);
302 chkBrush->GetBounds(min2, max2);
303
304 if(min1[0] >= max2[0])
305 return FALSE;
306 if(min1[1] >= max2[1])
307 return FALSE;
308 if(min1[2] >= max2[2])
309 return FALSE;
310
311 if(max1[0] <= min2[0])
312 return FALSE;
313 if(max1[1] <= min2[1])
314 return FALSE;
315 if(max1[2] <= min2[2])
316 return FALSE;
317
318 return TRUE;
319 }
320
HasPlane(DPlane * chkPlane)321 DPlane* DBrush::HasPlane(DPlane* chkPlane)
322 {
323 for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)
324 {
325 if(**brushPlane == *chkPlane)
326 return *brushPlane;
327 }
328 return NULL;
329 }
330
IsCutByPlane(DPlane * cuttingPlane)331 bool DBrush::IsCutByPlane(DPlane *cuttingPlane)
332 {
333 bool isInFront;
334
335 if(pointList.size() == 0)
336 if(BuildPoints() == 0)
337 return FALSE;
338
339 list<DPoint *>::const_iterator chkPnt = pointList.begin();
340
341 if(chkPnt == pointList.end())
342 return FALSE;
343
344 float dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);
345
346 if(dist > MAX_ROUND_ERROR)
347 isInFront = FALSE;
348 else if(dist < MAX_ROUND_ERROR)
349 isInFront = TRUE;
350 else
351 return TRUE;
352
353 for(chkPnt++=pointList.begin(); chkPnt!=pointList.end(); chkPnt++)
354 {
355 dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);
356
357 if(dist > MAX_ROUND_ERROR)
358 {
359 if(isInFront)
360 return TRUE;
361 }
362 else if(dist < MAX_ROUND_ERROR)
363 {
364 if(!isInFront)
365 return TRUE;
366 }
367 else
368 return TRUE;
369 }
370
371 return FALSE;
372 }
373
BuildInRadiant(bool allowDestruction,int * changeCnt,scene::Node * entity)374 scene::Node* DBrush::BuildInRadiant(bool allowDestruction, int* changeCnt, scene::Node* entity)
375 {
376 if(allowDestruction)
377 {
378 bool kill = TRUE;
379
380 for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
381 {
382 if((*chkPlane)->m_bChkOk)
383 {
384 kill = FALSE;
385 break;
386 }
387 }
388 if(kill)
389 return NULL;
390 }
391
392 //+djbob: fixed bug when brush had no faces "phantom brush" in radiant.
393 if(faceList.size() < 4)
394 {
395 Sys_Printf("Possible Phantom Brush Found, will not rebuild\n");
396 return NULL;
397 }
398 //-djbob
399
400 NodePtr node(Brush_AllocNode());
401
402 for(list<DPlane *>::const_iterator buildPlane=faceList.begin(); buildPlane!=faceList.end(); buildPlane++) {
403 if((*buildPlane)->AddToBrush(node->m_brush) && changeCnt) {
404 (*changeCnt)++;
405 }
406 }
407
408 if(entity) {
409 entity->m_traverse->insert(node);
410 } else {
411 GetWorldspawn()->m_traverse->insert(node);
412 }
413
414 return node;
415 }
416
CutByPlane(DPlane * cutPlane,DBrush ** newBrush1,DBrush ** newBrush2)417 void DBrush::CutByPlane(DPlane *cutPlane, DBrush **newBrush1, DBrush **newBrush2)
418 {
419 if(!IsCutByPlane(cutPlane))
420 {
421 *newBrush1 = NULL;
422 *newBrush2 = NULL;
423 return;
424 }
425
426 DBrush* b1 = new DBrush;
427 DBrush* b2 = new DBrush;
428
429 for(list<DPlane *>::const_iterator parsePlane=faceList.begin(); parsePlane!=faceList.end(); parsePlane++)
430 {
431 b1->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);
432 b2->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);
433 }
434
435 b1->AddFace(cutPlane->points[0], cutPlane->points[1], cutPlane->points[2], NULL);
436 b2->AddFace(cutPlane->points[2], cutPlane->points[1], cutPlane->points[0], NULL);
437
438 b1->RemoveRedundantPlanes();
439 b2->RemoveRedundantPlanes();
440
441 *newBrush1 = b1;
442 *newBrush2 = b2;
443 }
444
IntersectsWith(DBrush * chkBrush)445 bool DBrush::IntersectsWith(DBrush *chkBrush)
446 {
447 if(pointList.size() == 0)
448 if(BuildPoints() == 0)
449 return FALSE; // invalid brush!!!!
450
451 if(chkBrush->pointList.size() == 0)
452 if(chkBrush->BuildPoints() == 0)
453 return FALSE; // invalid brush!!!!
454
455 if(!BBoxCollision(chkBrush))
456 return FALSE;
457
458 list<DPlane *>::const_iterator iplPlane;
459
460 for( iplPlane=faceList.begin(); iplPlane!=faceList.end(); iplPlane++)
461 {
462
463 bool allInFront = TRUE;
464 for(list<DPoint *>::const_iterator iPoint=chkBrush->pointList.begin(); iPoint!=chkBrush->pointList.end(); iPoint++)
465 {
466 if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)
467 {
468 allInFront = FALSE;
469 break;
470 }
471 }
472 if(allInFront)
473 return FALSE;
474 }
475
476 for( iplPlane=chkBrush->faceList.begin(); iplPlane!=chkBrush->faceList.end(); iplPlane++)
477 {
478 bool allInFront = TRUE;
479 for(list<DPoint *>::const_iterator iPoint=pointList.begin(); iPoint!=pointList.end(); iPoint++)
480 {
481 if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)
482 {
483 allInFront = FALSE;
484 break;
485 }
486 }
487 if(allInFront)
488 return FALSE;
489 }
490
491 return TRUE;
492 }
493
IntersectsWith(DPlane * p1,DPlane * p2,vec3_t v)494 bool DBrush::IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v) {
495 vec3_t vDown = { 0, 0, -1 };
496
497 list<DPlane *>::const_iterator iplPlane;
498 for( iplPlane = faceList.begin(); iplPlane != faceList.end(); iplPlane++) {
499 DPlane* p = (*iplPlane);
500
501 vec_t d = DotProduct( p->normal, vDown );
502 if( d >= 0 ) {
503 continue;
504 }
505 if(p->PlaneIntersection(p1, p2, v)) {
506 if(PointPosition( v ) != POINT_OUT_BRUSH) {
507 return TRUE;
508 }
509 }
510 }
511
512 return FALSE;
513 }
514
BuildBounds()515 void DBrush::BuildBounds()
516 {
517 if(!bBoundsBuilt)
518 {
519 if(pointList.size() == 0) // if points may not have been built, build them
520 if(BuildPoints() == 0)
521 return;
522
523 list<DPoint *>::const_iterator first = pointList.begin();
524 VectorCopy((*first)->_pnt, bbox_min);
525 VectorCopy((*first)->_pnt, bbox_max);
526
527 list<DPoint *>::const_iterator point=pointList.begin();
528 for( point++; point!=pointList.end(); point++)
529 {
530 if((*point)->_pnt[0] > bbox_max[0])
531 bbox_max[0] = (*point)->_pnt[0];
532 if((*point)->_pnt[1] > bbox_max[1])
533 bbox_max[1] = (*point)->_pnt[1];
534 if((*point)->_pnt[2] > bbox_max[2])
535 bbox_max[2] = (*point)->_pnt[2];
536
537 if((*point)->_pnt[0] < bbox_min[0])
538 bbox_min[0] = (*point)->_pnt[0];
539 if((*point)->_pnt[1] < bbox_min[1])
540 bbox_min[1] = (*point)->_pnt[1];
541 if((*point)->_pnt[2] < bbox_min[2])
542 bbox_min[2] = (*point)->_pnt[2];
543 }
544
545 bBoundsBuilt = TRUE;
546 }
547 }
548
BBoxTouch(DBrush * chkBrush)549 bool DBrush::BBoxTouch(DBrush *chkBrush)
550 {
551 vec3_t min1, min2;
552 vec3_t max1, max2;
553
554 GetBounds(min1, max1);
555 chkBrush->GetBounds(min2, max2);
556
557 if((min1[0] - max2[0]) > MAX_ROUND_ERROR)
558 return FALSE;
559 if((min1[1] - max2[1]) > MAX_ROUND_ERROR)
560 return FALSE;
561 if((min1[2] - max2[2]) > MAX_ROUND_ERROR)
562 return FALSE;
563
564 if((min2[0] - max1[0]) > MAX_ROUND_ERROR)
565 return FALSE;
566 if((min2[1] - max1[1]) > MAX_ROUND_ERROR)
567 return FALSE;
568 if((min2[2] - max1[2]) > MAX_ROUND_ERROR)
569 return FALSE;
570
571 int cnt = 0;
572
573 if((min2[0] - max1[0]) == 0)
574 cnt++;
575
576 if((min2[1] - max1[1]) == 0)
577 cnt++;
578
579 if((min2[2] - max1[2]) == 0)
580 cnt++;
581
582 if((min1[0] - max2[0]) == 0)
583 cnt++;
584
585 if((min1[1] - max2[1]) == 0)
586 cnt++;
587
588 if((min1[2] - max2[2]) == 0)
589 cnt++;
590
591 if(cnt > 1)
592 return FALSE;
593
594 return TRUE;
595 }
596
ResetChecks(list<Str> * exclusionList)597 void DBrush::ResetChecks(list<Str>* exclusionList)
598 {
599 for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)
600 {
601 bool set = FALSE;
602
603 if(exclusionList)
604 {
605 for(list<Str>::iterator eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++)
606 {
607 if(strstr((*resetPlane)->texInfo.m_texdef.GetName(), eTexture->GetBuffer()))
608 {
609 set = TRUE;
610 break;
611 }
612 }
613 }
614
615 (*resetPlane)->m_bChkOk = set;
616 }
617 }
618
HasPlaneInverted(DPlane * chkPlane)619 DPlane* DBrush::HasPlaneInverted(DPlane *chkPlane)
620 {
621 for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)
622 {
623 if(**brushPlane != *chkPlane)
624 {
625 if(fabs((*brushPlane)->_d + chkPlane->_d) < 0.1)
626 return (*brushPlane);
627 }
628 }
629 return NULL;
630 }
631
HasTexture(const char * textureName)632 bool DBrush::HasTexture(const char *textureName)
633 {
634 for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
635 {
636 if(strstr((*chkPlane)->texInfo.m_texdef.GetName(), textureName))
637 return TRUE;
638
639 }
640 return FALSE;
641 }
642
IsDetail()643 bool DBrush::IsDetail()
644 {
645 for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
646 {
647 if((*chkPlane)->texInfo.m_texdef.contents & FACE_DETAIL)
648 return TRUE;
649
650 }
651 return FALSE;
652 }
653
BuildFromWinding(DWinding * w)654 void DBrush::BuildFromWinding(DWinding *w)
655 {
656 if(w->numpoints < 3)
657 {
658 Sys_ERROR("Winding has invalid number of points");
659 return;
660 }
661
662 DPlane* wPlane = w->WindingPlane();
663
664 DWinding* w2;
665 w2 = w->CopyWinding();
666 int i;
667 for(i = 0; i < w2->numpoints; i++)
668 VectorAdd(w2->p[i], wPlane->normal, w2->p[i]);
669
670 AddFace(w2->p[0], w2->p[1], w2->p[2], NULL);
671 AddFace(w->p[2], w->p[1], w->p[0], NULL);
672
673 for(i = 0; i < w->numpoints-1; i++)
674 AddFace(w2->p[i], w->p[i], w->p[i+1], NULL);
675 AddFace(w2->p[w->numpoints-1], w->p[w->numpoints-1], w->p[0], NULL);
676
677 delete wPlane;
678 delete w2;
679 }
680
SaveToFile(FILE * pFile)681 void DBrush::SaveToFile(FILE *pFile)
682 {
683 fprintf(pFile, "{\n");
684
685 for(list<DPlane *>::const_iterator pp=faceList.begin(); pp!=faceList.end(); pp++)
686 {
687 char buffer[512];
688
689 sprintf(buffer, "( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) %s %.0f %.0f %f %f %.0f 0 0 0\n",
690 (*pp)->points[0][0], (*pp)->points[0][1], (*pp)->points[0][2],
691 (*pp)->points[1][0], (*pp)->points[1][1], (*pp)->points[1][2],
692 (*pp)->points[2][0], (*pp)->points[2][1], (*pp)->points[2][2],
693 (*pp)->texInfo.m_texdef.GetName(),
694 (*pp)->texInfo.m_texdef.shift[0], (*pp)->texInfo.m_texdef.shift[1],
695 (*pp)->texInfo.m_texdef.scale[0], (*pp)->texInfo.m_texdef.scale[0],
696 (*pp)->texInfo.m_texdef.rotate);
697
698 fprintf(pFile, buffer);
699 }
700
701 fprintf(pFile, "}\n");
702 }
703
Rotate(vec3_t vOrigin,vec3_t vRotation)704 void DBrush::Rotate(vec3_t vOrigin, vec3_t vRotation)
705 {
706 for(list<DPlane *>::const_iterator rotPlane=faceList.begin(); rotPlane!=faceList.end(); rotPlane++)
707 {
708 for(int i = 0; i < 3; i++)
709 VectorRotate((*rotPlane)->points[i], vRotation, vOrigin);
710
711 (*rotPlane)->Rebuild();
712 }
713 }
714
RotateAboutCentre(vec3_t vRotation)715 void DBrush::RotateAboutCentre(vec3_t vRotation)
716 {
717 vec3_t min, max, centre;
718 GetBounds(min, max);
719 VectorAdd(min, max, centre);
720 VectorScale(centre, 0.5f, centre);
721
722 Rotate(centre, vRotation);
723 }
724
ResetTextures(const char * textureName,float fScale[2],float fShift[2],int rotation,const char * newTextureName,int bResetTextureName,int bResetScale[2],int bResetShift[2],int bResetRotation)725 bool DBrush::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName,
726 int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation)
727 {
728 if(textureName)
729 {
730 bool changed = FALSE;
731 for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)
732 {
733 if(!strcmp((*resetPlane)->texInfo.m_texdef.GetName(), textureName))
734 {
735 if(bResetTextureName)
736 (*resetPlane)->texInfo.m_texdef.SetName(newTextureName);
737
738 if(bResetScale[0])
739 (*resetPlane)->texInfo.m_texdef.scale[0] = fScale[0];
740 if(bResetScale[1])
741 (*resetPlane)->texInfo.m_texdef.scale[1] = fScale[1];
742
743 if(bResetShift[0])
744 (*resetPlane)->texInfo.m_texdef.shift[0] = fShift[0];
745 if(bResetShift[1])
746 (*resetPlane)->texInfo.m_texdef.shift[1] = fShift[1];
747
748 if(bResetRotation)
749 (*resetPlane)->texInfo.m_texdef.rotate = (float)rotation;
750
751 changed = TRUE;
752 }
753 }
754 return changed; // no point rebuilding unless we need to, only slows things down
755 }
756 else
757 {
758 for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)
759 {
760 if(bResetTextureName)
761 (*resetPlane)->texInfo.m_texdef.SetName(newTextureName);
762
763 if(bResetScale[0])
764 (*resetPlane)->texInfo.m_texdef.scale[0] = fScale[0];
765 if(bResetScale[1])
766 (*resetPlane)->texInfo.m_texdef.scale[1] = fScale[1];
767
768 if(bResetShift[0])
769 (*resetPlane)->texInfo.m_texdef.shift[0] = fShift[0];
770 if(bResetShift[1])
771 (*resetPlane)->texInfo.m_texdef.shift[1] = fShift[1];
772
773 if(bResetRotation)
774 (*resetPlane)->texInfo.m_texdef.rotate = (float)rotation;
775 }
776 return TRUE;
777 }
778 }
779
operator ==(DBrush * other)780 bool DBrush::operator ==(DBrush* other)
781 {
782 list<DPlane *>::const_iterator chkPlane;
783
784 for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
785 {
786 if(!other->HasPlane((*chkPlane)))
787 return FALSE;
788 }
789
790 for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
791 {
792 if(!HasPlane((*chkPlane)))
793 return FALSE;
794 }
795
796 return TRUE;
797 }
798
AddFace(vec3_t va,vec3_t vb,vec3_t vc,const char * textureName,bool bDetail)799 DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char *textureName, bool bDetail)
800 {
801 bBoundsBuilt = FALSE;
802 DPlane* newFace = new DPlane(va, vb, vc, textureName, bDetail);
803 faceList.push_back(newFace);
804
805 return newFace;
806 }
807
FindPlaneWithClosestNormal(vec_t * normal)808 DPlane* DBrush::FindPlaneWithClosestNormal( vec_t* normal ) {
809 vec_t bestDot = -2;
810 DPlane* bestDotPlane = NULL;
811 list<DPlane *>::const_iterator chkPlane;
812 for( chkPlane = faceList.begin(); chkPlane != faceList.end(); chkPlane++ ) {
813 DPlane* pPlane = (*chkPlane);
814
815 vec_t dot = DotProduct( pPlane->normal, normal );
816 if( dot > bestDot ) {
817 bestDot = dot;
818 bestDotPlane = pPlane;
819 }
820 }
821
822 return bestDotPlane;
823 }
824
FindPointsForPlane(DPlane * plane,DPoint ** pnts,int maxpnts)825 int DBrush::FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ) {
826 int numpnts = 0;
827
828 if(!maxpnts) {
829 return 0;
830 }
831
832 BuildPoints();
833
834 for( list<DPoint *>::const_iterator points = pointList.begin(); points != pointList.end(); points++ ) {
835 DPoint* point = (*points);
836
837 if( fabs(plane->DistanceToPoint( point->_pnt )) < MAX_ROUND_ERROR ) {
838 pnts[numpnts] = point;
839 numpnts++;
840
841 if(numpnts >= maxpnts) {
842 return numpnts;
843 }
844
845 }
846 }
847
848 return numpnts;
849 }
850
RemovePlane(DPlane * plane)851 void DBrush::RemovePlane( DPlane* plane ) {
852 bBoundsBuilt = FALSE;
853 for( list<DPlane *>::const_iterator deadPlane = faceList.begin(); deadPlane != faceList.end(); deadPlane++ ) {
854 if(*deadPlane == plane) {
855 delete *deadPlane;
856 faceList.remove( plane );
857 }
858 }
859 }
860
RemoveFromRadiant(void)861 void DBrush::RemoveFromRadiant( void ) {
862 if(QER_brush) {
863 #if 0
864 g_FuncTable.m_pfnDeleteBrushHandle(QER_brush);
865 #endif
866 }
867 }
868