2 GenSurf plugin for GtkRadiant
\r
3 Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
\r
5 This library is free software; you can redistribute it and/or
\r
6 modify it under the terms of the GNU Lesser General Public
\r
7 License as published by the Free Software Foundation; either
\r
8 version 2.1 of the License, or (at your option) any later version.
\r
10 This library is distributed in the hope that it will be useful,
\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
13 Lesser General Public License for more details.
\r
15 You should have received a copy of the GNU Lesser General Public
\r
16 License along with this library; if not, write to the Free Software
\r
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
22 #include "gensurf.h"
\r
24 #define MAX_FACES 128 // Maximum number of faces on a brush
\r
25 #define MAX_POINTS_ON_WINDING 64
\r
26 #define SIDE_FRONT 0
\r
29 #define SIDE_CROSS -2
\r
31 vec3 vec3_origin = {0,0,0};
\r
33 void PlaneFromPoints (float *p0, float *p1, float *p2, PLANE *plane)
\r
38 VectorSubtract (p0, p1, t1);
\r
39 VectorSubtract (p2, p1, t2);
\r
40 plane->normal[0] = t1[1]*t2[2] - t1[2]*t2[1];
\r
41 plane->normal[1] = t1[2]*t2[0] - t1[0]*t2[2];
\r
42 plane->normal[2] = t1[0]*t2[1] - t1[1]*t2[0];
\r
44 length = (vec)(sqrt(plane->normal[0]*plane->normal[0] +
\r
45 plane->normal[1]*plane->normal[1] +
\r
46 plane->normal[2]*plane->normal[2] ));
\r
49 VectorClear(plane->normal);
\r
53 plane->normal[0] /= length;
\r
54 plane->normal[1] /= length;
\r
55 plane->normal[2] /= length;
\r
57 plane->dist = DotProduct (p0, plane->normal);
\r
60 void VectorMA (vec3 va, vec scale, vec3 vb, vec3 vc)
\r
62 vc[0] = va[0] + scale*vb[0];
\r
63 vc[1] = va[1] + scale*vb[1];
\r
64 vc[2] = va[2] + scale*vb[2];
\r
67 void CrossProduct (vec3 v1, vec3 v2, vec3 cross)
\r
69 cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
\r
70 cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
\r
71 cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
\r
79 MY_WINDING *AllocWinding (int points)
\r
84 s = sizeof(vec)*3*points + sizeof(int);
\r
85 w = (MY_WINDING*)malloc (s);
\r
90 vec VectorNormalize (vec3 in, vec3 out)
\r
92 vec length, ilength;
\r
94 length = (vec)(sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]));
\r
101 ilength = (vec)1.0/length;
\r
102 out[0] = in[0]*ilength;
\r
103 out[1] = in[1]*ilength;
\r
104 out[2] = in[2]*ilength;
\r
111 BaseWindingForPlane
\r
114 MY_WINDING *BaseWindingForPlane (vec3 normal, vec dist)
\r
118 vec3 org, vright, vup;
\r
121 // find the major axis
\r
123 max = -BOGUS_RANGE;
\r
125 for (i=0 ; i<3; i++)
\r
127 v = (vec)(fabs(normal[i]));
\r
136 VectorCopy(vec3_origin,vup);
\r
148 v = DotProduct (vup, normal);
\r
149 VectorMA (vup, -v, normal, vup);
\r
150 VectorNormalize (vup, vup);
\r
152 VectorScale (normal, dist, org);
\r
154 CrossProduct (vup, normal, vright);
\r
156 VectorScale (vup, 65536, vup);
\r
157 VectorScale (vright, 65536, vright);
\r
159 // project a really big axis aligned box onto the plane
\r
160 w = AllocWinding (4);
\r
162 VectorSubtract (org, vright, w->p[0]);
\r
163 VectorAdd (w->p[0], vup, w->p[0]);
\r
165 VectorAdd (org, vright, w->p[1]);
\r
166 VectorAdd (w->p[1], vup, w->p[1]);
\r
168 VectorAdd (org, vright, w->p[2]);
\r
169 VectorSubtract (w->p[2], vup, w->p[2]);
\r
171 VectorSubtract (org, vright, w->p[3]);
\r
172 VectorSubtract (w->p[3], vup, w->p[3]);
\r
179 void FreeWinding (MY_WINDING *w)
\r
181 if (*(unsigned *)w == 0xdeaddead)
\r
182 // Error ("FreeWinding: freed a freed winding");
\r
184 *(unsigned *)w = 0xdeaddead;
\r
194 void ChopWindingInPlace (MY_WINDING **inout, vec3 normal, vec dist, vec epsilon)
\r
197 vec dists[MAX_POINTS_ON_WINDING+4];
\r
198 int sides[MAX_POINTS_ON_WINDING+4];
\r
200 static vec dot; // VC 4.2 optimizer bug if not static
\r
208 counts[0] = counts[1] = counts[2] = 0;
\r
210 // determine sides for each point
\r
211 for (i=0 ; i<in->numpoints ; i++)
\r
213 dot = DotProduct (in->p[i], normal);
\r
217 sides[i] = SIDE_FRONT;
\r
218 else if (dot < -epsilon)
\r
219 sides[i] = SIDE_BACK;
\r
222 sides[i] = SIDE_ON;
\r
224 counts[sides[i]]++;
\r
226 sides[i] = sides[0];
\r
227 dists[i] = dists[0];
\r
236 return; // inout stays the same
\r
238 maxpts = in->numpoints+4; // cant use counts[0]+2 because
\r
239 // of fp grouping errors
\r
241 f = AllocWinding (maxpts);
\r
243 for (i=0 ; i<in->numpoints ; i++)
\r
247 if (sides[i] == SIDE_ON)
\r
249 VectorCopy (p1, f->p[f->numpoints]);
\r
254 if (sides[i] == SIDE_FRONT)
\r
256 VectorCopy (p1, f->p[f->numpoints]);
\r
260 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
\r
263 // generate a split point
\r
264 p2 = in->p[(i+1)%in->numpoints];
\r
266 dot = dists[i] / (dists[i]-dists[i+1]);
\r
267 for (j=0 ; j<3 ; j++)
\r
268 { // avoid round off error when possible
\r
269 if (normal[j] == 1)
\r
271 else if (normal[j] == -1)
\r
274 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
\r
277 VectorCopy (mid, f->p[f->numpoints]);
\r
281 // if (f->numpoints > maxpts)
\r
282 // Error ("ClipWinding: points exceeded estimate");
\r
283 // if (f->numpoints > MAX_POINTS_ON_WINDING)
\r
284 // Error ("ClipWinding: MAX_POINTS_ON_WINDING");
\r
290 void UseFaceBounds()
\r
293 float Dot, BestDot;
\r
294 float planepts[3][3];
\r
300 _QERFaceData *QERFaceData;
\r
301 PLANE plane[MAX_FACES*2];
\r
308 SurfNormal[0] = 0.0;
\r
309 SurfNormal[1] = 0.0;
\r
310 SurfNormal[2] =-1.0;
\r
313 SurfNormal[0] = 0.0;
\r
314 SurfNormal[1] = 1.0;
\r
315 SurfNormal[2] = 0.0;
\r
318 SurfNormal[0] = 0.0;
\r
319 SurfNormal[1] =-1.0;
\r
320 SurfNormal[2] = 0.0;
\r
323 SurfNormal[0] = 1.0;
\r
324 SurfNormal[1] = 0.0;
\r
325 SurfNormal[2] = 0.0;
\r
328 SurfNormal[0] =-1.0;
\r
329 SurfNormal[1] = 0.0;
\r
330 SurfNormal[2] = 0.0;
\r
333 SurfNormal[0] = 0.0;
\r
334 SurfNormal[1] = 0.0;
\r
335 SurfNormal[2] = 1.0;
\r
338 i = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
\r
339 vp = g_FuncTable.m_pfnGetSelectedBrushHandle(0);
\r
340 NumFaces = g_FuncTable.m_pfnGetFaceCount(vp);
\r
345 for(i=0; i<NumFaces; i++)
\r
347 QERFaceData = g_FuncTable.m_pfnGetFaceData(vp,i);
\r
348 planepts[0][0] = QERFaceData->m_v1[0];
\r
349 planepts[0][1] = QERFaceData->m_v1[1];
\r
350 planepts[0][2] = QERFaceData->m_v1[2];
\r
351 planepts[1][0] = QERFaceData->m_v2[0];
\r
352 planepts[1][1] = QERFaceData->m_v2[1];
\r
353 planepts[1][2] = QERFaceData->m_v2[2];
\r
354 planepts[2][0] = QERFaceData->m_v3[0];
\r
355 planepts[2][1] = QERFaceData->m_v3[1];
\r
356 planepts[2][2] = QERFaceData->m_v3[2];
\r
358 PlaneFromPoints (planepts[0], planepts[1], planepts[2], &plane[2*i]);
\r
359 VectorSubtract (vec3_origin, plane[2*i].normal, plane[2*i+1].normal);
\r
360 plane[2*i+1].dist = -plane[2*i].dist;
\r
362 Dot = DotProduct(plane[2*i].normal,SurfNormal);
\r
367 if(strlen(QERFaceData->m_TextureName))
\r
368 strcpy(Texture[Game][0],QERFaceData->m_TextureName);
\r
371 for(i=0; i<NumFaces; i++)
\r
373 if(i==BestFace) continue;
\r
374 QERFaceData = g_FuncTable.m_pfnGetFaceData(vp,i);
\r
375 if(strlen(QERFaceData->m_TextureName))
\r
377 if(strcmp(Texture[Game][0],QERFaceData->m_TextureName))
\r
378 strcpy(Texture[Game][1],QERFaceData->m_TextureName);
\r
383 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
\r
385 w = BaseWindingForPlane (plane[BestFace*2].normal, plane[BestFace*2].dist);
\r
387 for (i=0 ; i<NumFaces && w; i++)
\r
391 ChopWindingInPlace (&w, plane[i*2+1].normal, plane[i*2+1].dist, 0);
\r
395 // Get bounding box for this face
\r
396 vmin[0] = vmax[0] = w->p[0][0];
\r
397 vmin[1] = vmax[1] = w->p[0][1];
\r
398 vmin[2] = vmax[2] = w->p[0][2];
\r
399 for(j=1; j<w->numpoints; j++)
\r
401 vmin[0] = min(vmin[0],w->p[j][0]);
\r
402 vmin[1] = min(vmin[1],w->p[j][1]);
\r
403 vmin[2] = min(vmin[2],w->p[j][2]);
\r
404 vmax[0] = max(vmax[0],w->p[j][0]);
\r
405 vmax[1] = max(vmax[1],w->p[j][1]);
\r
406 vmax[2] = max(vmax[2],w->p[j][2]);
\r
411 VectorCopy(plane[BestFace*2].normal,pface.normal);
\r
412 pface.dist = plane[BestFace*2].dist;
\r
417 if(pface.normal[1] == 0.) return;
\r
422 Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vll)/pface.normal[1];
\r
423 Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vur)/pface.normal[1];
\r
424 Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vll)/pface.normal[1];
\r
425 Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vur)/pface.normal[1];
\r
429 if(pface.normal[0] == 0.) return;
\r
434 Z00 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vll)/pface.normal[0];
\r
435 Z01 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vur)/pface.normal[0];
\r
436 Z10 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vll)/pface.normal[0];
\r
437 Z11 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vur)/pface.normal[0];
\r
440 if(pface.normal[2] == 0.) return;
\r
445 Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vll)/pface.normal[2];
\r
446 Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vur)/pface.normal[2];
\r
447 Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vll)/pface.normal[2];
\r
448 Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vur)/pface.normal[2];
\r