]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/autocaulk.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / tools / radiant / autocaulk.cpp
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 "Radiant.h"
34 #include "autocaulk.h"
35
36 // Note: the code in here looks pretty goofy in places, and probably doesn't use the new Q4 class stuff fully, 
37 //   but I just got it in and compiling from the JK2/SOF2 Radiants via some ugly code replaces, and it works, so there.
38 // Also, a bunch of Radiant fields no longer exist in this codebase, likewise the whole point of passing in the bool
39 //      to this code, but I've just left it as-is. A designer tested it and pronounced it fine.
40  
41 //#pragma warning( disable : 4786)
42 //#include <list>
43 //using namespace std;
44 //#pragma warning( disable : 4786)
45
46 #undef strnicmp
47 #define strnicmp                idStr::Icmpn
48
49 #if 1
50
51
52 //extern void ClearBounds (idVec3 mins, idVec3 maxs);
53 //extern void AddPointToBounds (const idVec3 v, idVec3 mins, idVec3 maxs);
54 void ClearBounds (idVec3 &mins, idVec3 &maxs)
55 {
56         mins[0] = mins[1] = mins[2] = 99999;
57         maxs[0] = maxs[1] = maxs[2] = -99999;
58 }
59
60 void AddPointToBounds( const idVec3 &v, idVec3 &mins, idVec3 &maxs ) 
61 {
62         int             i;
63         float   val;
64
65         for (i=0 ; i<3 ; i++)
66         {
67                 val = v[i];
68                 if (val < mins[i])
69                         mins[i] = val;
70                 if (val > maxs[i])
71                         maxs[i] = val;
72         }
73 }
74
75
76 static void FloorBounds(idVec3 &mins, idVec3 &maxs)
77 {
78         for (int i=0 ; i<3 ; i++)
79         {
80                 mins[i] = floor(mins[i] + 0.5);
81                 maxs[i] = floor(maxs[i] + 0.5);
82         }
83 }
84
85
86 static LPCSTR vtos(idVec3 &v3)
87 {
88         return va("%.3ff,%.3f,%.3f",v3[0],v3[1],v3[2]);
89 }
90 struct PairBrushFace_t
91 {
92         face_t*         pFace;
93         brush_t*        pBrush;
94 };
95 idList < PairBrushFace_t > FacesToCaulk;
96 void Select_AutoCaulk()
97 {
98         /*Sys_Printf*/common->Printf("Caulking...\n");  
99
100         FacesToCaulk.Clear();
101
102         int iSystemBrushesSkipped = 0;
103         face_t *pSelectedFace;
104
105         brush_t *next;
106         for (brush_t *pSelectedBrush = selected_brushes.next ; pSelectedBrush != &selected_brushes ; pSelectedBrush = next)
107         {
108                 next = pSelectedBrush->next;
109                 
110                 if (pSelectedBrush->owner->eclass->fixedsize)
111                         continue;       // apparently this means it's a model, so skip it...
112
113                 // new check, we can't caulk a brush that has any "system/" faces...
114                 //
115                 bool bSystemFacePresent = false;
116                 for ( pSelectedFace = pSelectedBrush->brush_faces; pSelectedFace; pSelectedFace = pSelectedFace->next)
117                 {       
118                         if (!strnicmp(pSelectedFace->d_texture->GetName(),"system/",7))
119                         {
120                                 bSystemFacePresent = true;
121                                 break;
122                         }
123                 }
124                 if (bSystemFacePresent)
125                 {
126                         iSystemBrushesSkipped++;
127                         continue;       // verboten to caulk this.
128                 }               
129
130                 for (int iBrushListToScan = 0; iBrushListToScan<2; iBrushListToScan++)
131                 {               
132                         brush_t *snext;
133                         for (brush_t *pScannedBrush = (iBrushListToScan?active_brushes.next:selected_brushes.next); pScannedBrush != (iBrushListToScan?&active_brushes:&selected_brushes) ; pScannedBrush = snext)
134                         {
135                                 snext = pScannedBrush->next;
136
137                                 if ( pScannedBrush == pSelectedBrush)
138                                         continue;
139                                 
140                                 if (pScannedBrush->owner->eclass->fixedsize || pScannedBrush->pPatch || pScannedBrush->hiddenBrush)
141                                         continue;
142
143                                 if (FilterBrush(pScannedBrush))
144                                         continue;
145
146 // idMaterial stuff no longer support this, not sure what else to do. 
147 //   Searching for other occurences of QER_NOCARVE just shows people REMing the code and ignoring ths issue...
148 //                              
149 //                              if (pScannedBrush->brush_faces->d_texture->bFromShader && (pScannedBrush->brush_faces->d_texture->TestMaterialFlag(QER_NOCARVE)))
150 //                                      continue;
151                                 
152                                 // basic-reject first to see if brushes can even possibly touch (coplanar counts as touching)
153                                 //
154                                 int i;
155                                 for (i=0 ; i<3 ; i++)
156                                 {
157                                         if (pSelectedBrush->mins[i] > pScannedBrush->maxs[i] ||
158                                                 pSelectedBrush->maxs[i] < pScannedBrush->mins[i])
159                                         {
160                                                 break;
161                                         }
162                                 }
163                                 if (i != 3)
164                                         continue;       // can't be touching
165
166                                 // ok, now for the clever stuff, we need to detect only those faces that are both coplanar and smaller
167                                 //      or equal to the face they're coplanar with...
168                                 //
169                                 for (pSelectedFace = pSelectedBrush->brush_faces; pSelectedFace; pSelectedFace = pSelectedFace->next)
170                                 {
171                                         idWinding *pSelectedWinding = pSelectedFace->face_winding;
172
173                                         if (!pSelectedWinding)
174                                                 continue;       // freed face, probably won't happen here, but who knows with this program?
175
176         //                              SquaredFace_t SelectedSquaredFace;
177         //                              WindingToSquaredFace( &SelectedSquaredFace, pSelectedWinding);
178
179                                         for (face_t *pScannedFace = pScannedBrush->brush_faces; pScannedFace; pScannedFace = pScannedFace->next)
180                                         {
181                                                 // don't even try caulking against a system face, because these are often transparent and will leave holes
182                                                 //
183                                                 if (!strnicmp(pScannedFace->d_texture->GetName(),"system/",7))
184                                                         continue;
185
186                                                 // and don't try caulking against something inherently transparent...
187                                                 //
188                                                 if (pScannedFace->d_texture->TestMaterialFlag(QER_TRANS))
189                                                         continue;
190
191                                                 idWinding *pScannedWinding = pScannedFace->face_winding;
192
193                                                 if (!pScannedWinding)
194                                                         continue;       // freed face, probably won't happen here, but who knows with this program?
195
196         //                                      SquaredFace_t ScannedSquaredFace;
197         //                                      WindingToSquaredFace( &ScannedSquaredFace, pScannedWinding);
198
199         /*                                      if (VectorCompare(ScannedSquaredFace.v3NormalisedRotationVector, SelectedSquaredFace.v3NormalisedRotationVector)
200                                                         && 
201                                                         VectorCompare(ScannedSquaredFace.v3NormalisedElevationVector, SelectedSquaredFace.v3NormalisedElevationVector)
202                                                         )
203         */
204                                                 {
205                                                         // brush faces are in parallel planes to each other, so check that their normals
206                                                         //      are opposite, by adding them together and testing for zero...
207                                                         // (if normals are opposite, then faces can be against/touching each other?)                                            
208                                                         //
209                                                         idVec3 v3ZeroTest;                                                      
210                                                         idVec3 v3Zero;v3Zero.Zero();    //static idVec3 v3Zero={0,0,0};
211                                                         
212                                                         VectorAdd(pSelectedFace->plane.Normal(),pScannedFace->plane.Normal(),v3ZeroTest);
213                                                         if (v3ZeroTest == v3Zero)
214                                                         {
215                                                                 // planes are facing each other...
216                                                                 //
217                                                                 // coplanar? (this is some maths of Gil's, which I don't even pretend to understand)
218                                                                 //
219                                                                 float fTotalDist = 0;
220                                                                 for (int _i=0; _i<3; _i++)
221                                                                 {
222                                                                         fTotalDist += fabs(     DotProduct(pSelectedFace->plane.Normal(),(*pSelectedWinding)[0]) 
223                                                                                                                 - 
224                                                                                                                 DotProduct(pSelectedFace->plane.Normal(),(*pScannedWinding)[i])
225                                                                                                                 );
226                                                                 }
227                                                                 //OutputDebugString(va("Dist = %g\n",fTotalDist));
228                                                                 
229                                                                 if (fTotalDist > 0.01)
230                                                                         continue;
231
232                                                                 // every point in the selected face must be within (or equal to) the bounds of the
233                                                                 //      scanned face...
234                                                                 //
235                                                                 // work out the bounds first...
236                                                                 //
237                                                                 idVec3 v3ScannedBoundsMins, v3ScannedBoundsMaxs;
238                                                                 ClearBounds (v3ScannedBoundsMins, v3ScannedBoundsMaxs);
239                                                                 int iPoint;
240                                                                 for (iPoint=0; iPoint<pScannedWinding->GetNumPoints(); iPoint++)
241                                                                 {
242                                                                         AddPointToBounds( (*pScannedWinding)[iPoint].ToVec3(), v3ScannedBoundsMins, v3ScannedBoundsMaxs);
243                                                                 }
244                                                                 // floor 'em... (or .001 differences mess things up...
245                                                                 //
246                                                                 FloorBounds(v3ScannedBoundsMins, v3ScannedBoundsMaxs);
247
248                                                                 
249                                                                 // now check points from selected face...
250                                                                 //
251                                                                 bool bWithin = true;
252                                                                 for (iPoint=0; iPoint < pSelectedWinding->GetNumPoints(); iPoint++)
253                                                                 {
254                                                                         for (int iXYZ=0; iXYZ<3; iXYZ++)
255                                                                         {
256                                                                                 float f = floor((*pSelectedWinding)[iPoint][iXYZ] + 0.5);
257                                                                                 if (!
258                                                                                                 (
259                                                                                                 f >= v3ScannedBoundsMins[iXYZ] 
260                                                                                                 &&
261                                                                                                 f <= v3ScannedBoundsMaxs[iXYZ]
262                                                                                                 )
263                                                                                          )
264                                                                                 {
265                                                                                         bWithin = false;
266                                                                                 }
267                                                                         }
268                                                                 }
269
270                                                                 if (bWithin)
271                                                                 {
272                                                                         PairBrushFace_t PairBrushFace;
273                                                                                                         PairBrushFace.pFace = pSelectedFace;
274                                                                                                         PairBrushFace.pBrush= pSelectedBrush;
275                                                                         FacesToCaulk.Append(PairBrushFace);                                                                     
276                                                                 }
277                                                         }
278                                                 }
279                                         }
280                                 }                       
281                         }
282                 }
283         }
284
285         
286         // apply caulk...
287         //
288         int iFacesCaulked = 0;
289         if (FacesToCaulk.Num())
290         {
291                 LPCSTR psCaulkName = "textures/common/caulk";
292                 const idMaterial *pCaulk = Texture_ForName(psCaulkName);
293
294                 if (pCaulk)
295                 {
296                         //
297                         // and call some other junk that Radiant wants so so we can use it later...
298                         //
299                         texdef_t tex;
300                         memset (&tex, 0, sizeof(tex));
301                         tex.scale[0] = 1;
302                         tex.scale[1] = 1;
303                         //tex.flags = pCaulk->flags;    // field missing in Q4
304                         //tex.value = pCaulk->value;    // ditto
305                         //tex.contents = pCaulk->contents;      // ditto
306                         tex.SetName( pCaulk->GetName() );
307
308                         //Texture_SetTexture (&tex);
309
310                         for (int iListEntry = 0; iListEntry < FacesToCaulk.Num(); iListEntry++)
311                         {
312                                 PairBrushFace_t &PairBrushFace = FacesToCaulk[iListEntry];
313                                 face_t *pFace = PairBrushFace.pFace;
314                                 brush_t*pBrush= PairBrushFace.pBrush;
315
316                                 pFace->d_texture = pCaulk;                              
317                                 pFace->texdef = tex;
318
319                                 Face_FitTexture(pFace, 1, 1);   // this doesn't work here for some reason... duh.
320                                 Brush_Build(pBrush);
321
322                                 iFacesCaulked++;
323                         }               
324                 }
325                 else
326                 {
327                         /*Sys_Printf*/common->Printf(" Unable to locate caulk texture at: \"%s\"!\n",psCaulkName);
328                 }
329         }
330
331         /*Sys_Printf*/common->Printf("( %d faces caulked )\n",iFacesCaulked);
332
333         if (iSystemBrushesSkipped)
334         {
335                 /*Sys_Printf*/common->Printf("( %d system-faced brushes skipped )\n",iSystemBrushesSkipped);
336         }
337
338         Sys_UpdateWindows (W_ALL);
339 }
340 #endif