more eol-style
[xonotic/netradiant.git] / contrib / gtkgensurf / face.cpp
1 /*
2 GenSurf plugin for GtkRadiant
3 Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
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 #include <stdlib.h>
21 #include <math.h>
22 #include "gensurf.h"
23
24 #define MAX_FACES 128    // Maximum number of faces on a brush
25 #define MAX_POINTS_ON_WINDING   64
26 #define SIDE_FRONT              0
27 #define SIDE_ON                 2
28 #define SIDE_BACK               1
29 #define SIDE_CROSS              -2
30
31 vec3 vec3_origin = {0,0,0};
32
33 void PlaneFromPoints (float *p0, float *p1, float *p2, PLANE *plane)
34 {
35         vec3 t1, t2;
36         vec     length;
37         
38         VectorSubtract (p0, p1, t1);
39         VectorSubtract (p2, p1, t2);
40         plane->normal[0] = t1[1]*t2[2] - t1[2]*t2[1];
41         plane->normal[1] = t1[2]*t2[0] - t1[0]*t2[2];
42         plane->normal[2] = t1[0]*t2[1] - t1[1]*t2[0];
43         
44         length = (vec)(sqrt(plane->normal[0]*plane->normal[0] +
45                                 plane->normal[1]*plane->normal[1] +
46                                                 plane->normal[2]*plane->normal[2]  ));
47         if (length == 0)
48         {
49                 VectorClear(plane->normal);
50         }
51         else
52         {
53                 plane->normal[0] /= length;
54                 plane->normal[1] /= length;
55                 plane->normal[2] /= length;
56         }
57         plane->dist = DotProduct (p0, plane->normal);
58 }
59
60 void VectorMA (vec3 va, vec scale, vec3 vb, vec3 vc)
61 {
62         vc[0] = va[0] + scale*vb[0];
63         vc[1] = va[1] + scale*vb[1];
64         vc[2] = va[2] + scale*vb[2];
65 }
66
67 void CrossProduct (vec3 v1, vec3 v2, vec3 cross)
68 {
69         cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
70         cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
71         cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
72 }
73
74 /*
75 =============
76 AllocWinding
77 =============
78 */
79 MY_WINDING      *AllocWinding (int points)
80 {
81         MY_WINDING      *w;
82         int                     s;
83
84         s = sizeof(vec)*3*points + sizeof(int);
85         w = (MY_WINDING*)malloc (s);
86         memset (w, 0, s); 
87         return w;
88 }
89
90 vec VectorNormalize (vec3 in, vec3 out)
91 {
92         vec     length, ilength;
93
94         length = (vec)(sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]));
95         if (length == 0)
96         {
97                 VectorClear (out);
98                 return 0;
99         }
100
101         ilength = (vec)1.0/length;
102         out[0] = in[0]*ilength;
103         out[1] = in[1]*ilength;
104         out[2] = in[2]*ilength;
105
106         return length;
107 }
108
109 /*
110 =================
111 BaseWindingForPlane
112 =================
113 */
114 MY_WINDING *BaseWindingForPlane (vec3 normal, vec dist)
115 {
116         int                i, x;
117         vec        max, v;
118         vec3       org, vright, vup;
119         MY_WINDING *w;
120
121 // find the major axis
122
123         max = -BOGUS_RANGE;
124         x = -1;
125         for (i=0 ; i<3; i++)
126         {
127                 v = (vec)(fabs(normal[i]));
128                 if (v > max)
129                 {
130                         x = i;
131                         max = v;
132                 }
133         }
134         if (x==-1) x = 2;
135                 
136         VectorCopy(vec3_origin,vup);
137         switch (x)
138         {
139         case 0:
140         case 1:
141                 vup[2] = 1;
142                 break;          
143         case 2:
144                 vup[0] = 1;
145                 break;          
146         }
147
148         v = DotProduct (vup, normal);
149         VectorMA (vup, -v, normal, vup);
150         VectorNormalize (vup, vup);
151                 
152         VectorScale (normal, dist, org);
153         
154         CrossProduct (vup, normal, vright);
155         
156         VectorScale (vup, 65536, vup);
157         VectorScale (vright, 65536, vright);
158
159 // project a really big axis aligned box onto the plane
160         w = AllocWinding (4);
161         
162         VectorSubtract (org, vright, w->p[0]);
163         VectorAdd (w->p[0], vup, w->p[0]);
164         
165         VectorAdd (org, vright, w->p[1]);
166         VectorAdd (w->p[1], vup, w->p[1]);
167         
168         VectorAdd (org, vright, w->p[2]);
169         VectorSubtract (w->p[2], vup, w->p[2]);
170         
171         VectorSubtract (org, vright, w->p[3]);
172         VectorSubtract (w->p[3], vup, w->p[3]);
173         
174         w->numpoints = 4;
175         
176         return w;       
177 }
178
179 void FreeWinding (MY_WINDING *w)
180 {
181         if (*(unsigned *)w == 0xdeaddead)
182 //              Error ("FreeWinding: freed a freed winding");
183                 return;
184         *(unsigned *)w = 0xdeaddead;
185
186         free (w);
187 }
188
189 /*
190 =============
191 ChopWindingInPlace
192 =============
193 */
194 void ChopWindingInPlace (MY_WINDING **inout, vec3 normal, vec dist, vec epsilon)
195 {
196         MY_WINDING *in;
197         vec        dists[MAX_POINTS_ON_WINDING+4];
198         int        sides[MAX_POINTS_ON_WINDING+4];
199         int        counts[3];
200         static vec dot;         // VC 4.2 optimizer bug if not static
201         int        i, j;
202         vec        *p1, *p2;
203         vec3       mid;
204         MY_WINDING *f;
205         int        maxpts;
206
207         in = *inout;
208         counts[0] = counts[1] = counts[2] = 0;
209
210 // determine sides for each point
211         for (i=0 ; i<in->numpoints ; i++)
212         {
213                 dot = DotProduct (in->p[i], normal);
214                 dot -= dist;
215                 dists[i] = dot;
216                 if (dot > epsilon)
217                         sides[i] = SIDE_FRONT;
218                 else if (dot < -epsilon)
219                         sides[i] = SIDE_BACK;
220                 else
221                 {
222                         sides[i] = SIDE_ON;
223                 }
224                 counts[sides[i]]++;
225         }
226         sides[i] = sides[0];
227         dists[i] = dists[0];
228         
229         if (!counts[0])
230         {
231                 FreeWinding(in);
232                 *inout = NULL;
233                 return;
234         }
235         if (!counts[1])
236                 return;         // inout stays the same
237
238         maxpts = in->numpoints+4;       // cant use counts[0]+2 because
239                                                                 // of fp grouping errors
240
241         f = AllocWinding (maxpts);
242                 
243         for (i=0 ; i<in->numpoints ; i++)
244         {
245                 p1 = in->p[i];
246                 
247                 if (sides[i] == SIDE_ON)
248                 {
249                         VectorCopy (p1, f->p[f->numpoints]);
250                         f->numpoints++;
251                         continue;
252                 }
253         
254                 if (sides[i] == SIDE_FRONT)
255                 {
256                         VectorCopy (p1, f->p[f->numpoints]);
257                         f->numpoints++;
258                 }
259
260                 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
261                         continue;
262                         
263         // generate a split point
264                 p2 = in->p[(i+1)%in->numpoints];
265                 
266                 dot = dists[i] / (dists[i]-dists[i+1]);
267                 for (j=0 ; j<3 ; j++)
268                 {       // avoid round off error when possible
269                         if (normal[j] == 1)
270                                 mid[j] = dist;
271                         else if (normal[j] == -1)
272                                 mid[j] = -dist;
273                         else
274                                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
275                 }
276                         
277                 VectorCopy (mid, f->p[f->numpoints]);
278                 f->numpoints++;
279         }
280         
281 //      if (f->numpoints > maxpts)
282 //              Error ("ClipWinding: points exceeded estimate");
283 //      if (f->numpoints > MAX_POINTS_ON_WINDING)
284 //              Error ("ClipWinding: MAX_POINTS_ON_WINDING");
285
286         FreeWinding(in);
287         *inout = f;
288 }
289
290 void UseFaceBounds()
291 {
292         LPVOID       vp;
293         float        Dot, BestDot;
294         float            planepts[3][3];
295         int          BestFace;
296         int          i, j;
297         int          NumFaces;
298         vec3         SurfNormal;
299         vec3         vmin,vmax;
300         _QERFaceData *QERFaceData;
301         PLANE        plane[MAX_FACES*2];
302         PLANE        pface;
303         MY_WINDING   *w;
304
305         switch(Plane)
306         {
307         case PLANE_XY1:
308                 SurfNormal[0] = 0.0;
309                 SurfNormal[1] = 0.0;
310                 SurfNormal[2] =-1.0;
311                 break;
312         case PLANE_XZ0:
313                 SurfNormal[0] = 0.0;
314                 SurfNormal[1] = 1.0;
315                 SurfNormal[2] = 0.0;
316                 break;
317         case PLANE_XZ1:
318                 SurfNormal[0] = 0.0;
319                 SurfNormal[1] =-1.0;
320                 SurfNormal[2] = 0.0;
321                 break;
322         case PLANE_YZ0:
323                 SurfNormal[0] = 1.0;
324                 SurfNormal[1] = 0.0;
325                 SurfNormal[2] = 0.0;
326                 break;
327         case PLANE_YZ1:
328                 SurfNormal[0] =-1.0;
329                 SurfNormal[1] = 0.0;
330                 SurfNormal[2] = 0.0;
331                 break;
332         default:
333                 SurfNormal[0] = 0.0;
334                 SurfNormal[1] = 0.0;
335                 SurfNormal[2] = 1.0;
336         }
337
338         i  = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
339         vp = g_FuncTable.m_pfnGetSelectedBrushHandle(0);
340         NumFaces = g_FuncTable.m_pfnGetFaceCount(vp);
341
342         BestFace = -1;
343         BestDot  = 0.0;
344
345         for(i=0; i<NumFaces; i++)
346         {
347                 QERFaceData = g_FuncTable.m_pfnGetFaceData(vp,i);
348                 planepts[0][0] = QERFaceData->m_v1[0];
349                 planepts[0][1] = QERFaceData->m_v1[1];
350                 planepts[0][2] = QERFaceData->m_v1[2];
351                 planepts[1][0] = QERFaceData->m_v2[0];
352                 planepts[1][1] = QERFaceData->m_v2[1];
353                 planepts[1][2] = QERFaceData->m_v2[2];
354                 planepts[2][0] = QERFaceData->m_v3[0];
355                 planepts[2][1] = QERFaceData->m_v3[1];
356                 planepts[2][2] = QERFaceData->m_v3[2];
357
358                 PlaneFromPoints (planepts[0], planepts[1], planepts[2], &plane[2*i]);
359                 VectorSubtract (vec3_origin, plane[2*i].normal, plane[2*i+1].normal);
360                 plane[2*i+1].dist = -plane[2*i].dist;
361
362                 Dot = DotProduct(plane[2*i].normal,SurfNormal);
363                 if(Dot > BestDot)
364                 {
365                         BestDot  = Dot;
366                         BestFace = i;
367                         if(strlen(QERFaceData->m_TextureName))
368                                 strcpy(Texture[Game][0],QERFaceData->m_TextureName);
369                 }
370         }
371         for(i=0; i<NumFaces; i++)
372         {
373                 if(i==BestFace) continue;
374                 QERFaceData = g_FuncTable.m_pfnGetFaceData(vp,i);
375                 if(strlen(QERFaceData->m_TextureName))
376                 {
377                         if(strcmp(Texture[Game][0],QERFaceData->m_TextureName))
378                                 strcpy(Texture[Game][1],QERFaceData->m_TextureName);
379                 }
380         }
381
382
383         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
384
385         w = BaseWindingForPlane (plane[BestFace*2].normal, plane[BestFace*2].dist);
386
387         for (i=0 ; i<NumFaces && w; i++)
388         {
389                 if (BestFace == i)
390                         continue;
391                 ChopWindingInPlace (&w, plane[i*2+1].normal, plane[i*2+1].dist, 0);
392         }
393         if(!w) return;
394
395         // Get bounding box for this face
396         vmin[0] = vmax[0] = w->p[0][0];
397         vmin[1] = vmax[1] = w->p[0][1];
398         vmin[2] = vmax[2] = w->p[0][2];
399         for(j=1; j<w->numpoints; j++)
400         {
401                 vmin[0] = min(vmin[0],w->p[j][0]);
402                 vmin[1] = min(vmin[1],w->p[j][1]);
403                 vmin[2] = min(vmin[2],w->p[j][2]);
404                 vmax[0] = max(vmax[0],w->p[j][0]);
405                 vmax[1] = max(vmax[1],w->p[j][1]);
406                 vmax[2] = max(vmax[2],w->p[j][2]);
407         }
408
409         FreeWinding(w);
410
411         VectorCopy(plane[BestFace*2].normal,pface.normal);
412         pface.dist = plane[BestFace*2].dist;
413         switch(Plane)
414         {
415         case PLANE_XZ0:
416         case PLANE_XZ1:
417                 if(pface.normal[1] == 0.) return;
418                 Hll = vmin[0];
419                 Hur = vmax[0];
420                 Vll = vmin[2];
421                 Vur = vmax[2];
422                 Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vll)/pface.normal[1];
423                 Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vur)/pface.normal[1];
424                 Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vll)/pface.normal[1];
425                 Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vur)/pface.normal[1];
426                 break;
427         case PLANE_YZ0:
428         case PLANE_YZ1:
429                 if(pface.normal[0] == 0.) return;
430                 Hll = vmin[1];
431                 Hur = vmax[1];
432                 Vll = vmin[2];
433                 Vur = vmax[2];
434                 Z00 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vll)/pface.normal[0];
435                 Z01 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vur)/pface.normal[0];
436                 Z10 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vll)/pface.normal[0];
437                 Z11 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vur)/pface.normal[0];
438                 break;
439         default:
440                 if(pface.normal[2] == 0.) return;
441                 Hll = vmin[0];
442                 Hur = vmax[0];
443                 Vll = vmin[1];
444                 Vur = vmax[1];
445                 Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vll)/pface.normal[2];
446                 Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vur)/pface.normal[2];
447                 Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vll)/pface.normal[2];
448                 Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vur)/pface.normal[2];
449         }
450 }