2 GenSurf plugin for GtkRadiant
3 Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
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.
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.
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
24 #define MAX_FACES 128 // Maximum number of faces on a brush
25 #define MAX_POINTS_ON_WINDING 64
31 //vec3 vec3_origin = {0,0,0};
33 void PlaneFromPoints(float *p0, float *p1, float *p2, PLANE *plane)
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];
44 length = (vec) (sqrt(plane->normal[0] * plane->normal[0] +
45 plane->normal[1] * plane->normal[1] +
46 plane->normal[2] * plane->normal[2]));
48 VectorClear(plane->normal);
50 plane->normal[0] /= length;
51 plane->normal[1] /= length;
52 plane->normal[2] /= length;
54 plane->dist = DotProduct(p0, plane->normal);
57 void VectorMA (vec3 va, vec scale, vec3 vb, vec3 vc)
59 vc[0] = va[0] + scale*vb[0];
60 vc[1] = va[1] + scale*vb[1];
61 vc[2] = va[2] + scale*vb[2];
64 void CrossProduct (vec3 v1, vec3 v2, vec3 cross)
66 cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
67 cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
68 cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
76 MY_WINDING *AllocWinding(int points)
81 s = sizeof(vec) * 3 * points + sizeof(int);
82 w = (MY_WINDING *) malloc(s);
87 vec VectorNormalize (vec3 in, vec3 out)
91 length = (vec)(sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]));
98 ilength = (vec)1.0/length;
99 out[0] = in[0]*ilength;
100 out[1] = in[1]*ilength;
101 out[2] = in[2]*ilength;
112 MY_WINDING *BaseWindingForPlane(vec3 normal, vec dist)
116 vec3 org, vright, vup;
119 // find the major axis
123 for (i = 0; i < 3; i++) {
124 v = (vec) (fabs(normal[i]));
134 VectorCopy(vec3_origin, vup);
145 v = DotProduct(vup, normal);
146 VectorMA(vup, -v, normal, vup);
147 VectorNormalize(vup, vup);
149 VectorScale(normal, dist, org);
151 CrossProduct(vup, normal, vright);
153 VectorScale(vup, 65536, vup);
154 VectorScale(vright, 65536, vright);
156 // project a really big axis aligned box onto the plane
159 VectorSubtract(org, vright, w->p[0]);
160 VectorAdd(w->p[0], vup, w->p[0]);
162 VectorAdd(org, vright, w->p[1]);
163 VectorAdd(w->p[1], vup, w->p[1]);
165 VectorAdd(org, vright, w->p[2]);
166 VectorSubtract(w->p[2], vup, w->p[2]);
168 VectorSubtract(org, vright, w->p[3]);
169 VectorSubtract(w->p[3], vup, w->p[3]);
176 void FreeWinding(MY_WINDING *w)
178 if (*(unsigned *) w == 0xdeaddead) {
179 // Error ("FreeWinding: freed a freed winding");
182 *(unsigned *) w = 0xdeaddead;
192 void ChopWindingInPlace(MY_WINDING **inout, vec3 normal, vec dist, vec epsilon)
195 vec dists[MAX_POINTS_ON_WINDING + 4];
196 int sides[MAX_POINTS_ON_WINDING + 4];
198 static vec dot; // VC 4.2 optimizer bug if not static
206 counts[0] = counts[1] = counts[2] = 0;
208 // determine sides for each point
209 for (i = 0; i < in->numpoints; i++) {
210 dot = DotProduct(in->p[i], normal);
214 sides[i] = SIDE_FRONT;
215 } else if (dot < -epsilon) {
216 sides[i] = SIDE_BACK;
231 return; // inout stays the same
234 maxpts = in->numpoints + 4; // cant use counts[0]+2 because
235 // of fp grouping errors
237 f = AllocWinding(maxpts);
239 for (i = 0; i < in->numpoints; i++) {
242 if (sides[i] == SIDE_ON) {
243 VectorCopy(p1, f->p[f->numpoints]);
248 if (sides[i] == SIDE_FRONT) {
249 VectorCopy(p1, f->p[f->numpoints]);
253 if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i]) {
257 // generate a split point
258 p2 = in->p[(i + 1) % in->numpoints];
260 dot = dists[i] / (dists[i] - dists[i + 1]);
261 for (j = 0; j < 3; j++) { // avoid round off error when possible
262 if (normal[j] == 1) {
264 } else if (normal[j] == -1) {
267 mid[j] = p1[j] + dot * (p2[j] - p1[j]);
271 VectorCopy(mid, f->p[f->numpoints]);
275 // if (f->numpoints > maxpts)
276 // Error ("ClipWinding: points exceeded estimate");
277 // if (f->numpoints > MAX_POINTS_ON_WINDING)
278 // Error ("ClipWinding: MAX_POINTS_ON_WINDING");
288 float planepts[3][3];
294 PLANE plane[MAX_FACES * 2];
302 SurfNormal[2] = -1.0;
311 SurfNormal[1] = -1.0;
320 SurfNormal[0] = -1.0;
331 i = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
332 vp = g_FuncTable.m_pfnGetSelectedBrushHandle( 0 );
333 NumFaces = g_FuncTable.m_pfnGetFaceCount( vp );
338 for ( i = 0; i < NumFaces; i++ )
340 _QERFaceData* QERFaceData = g_FuncTable.m_pfnGetFaceData( vp,i );
341 planepts[0][0] = QERFaceData->m_v1[0];
342 planepts[0][1] = QERFaceData->m_v1[1];
343 planepts[0][2] = QERFaceData->m_v1[2];
344 planepts[1][0] = QERFaceData->m_v2[0];
345 planepts[1][1] = QERFaceData->m_v2[1];
346 planepts[1][2] = QERFaceData->m_v2[2];
347 planepts[2][0] = QERFaceData->m_v3[0];
348 planepts[2][1] = QERFaceData->m_v3[1];
349 planepts[2][2] = QERFaceData->m_v3[2];
351 PlaneFromPoints( planepts[0], planepts[1], planepts[2], &plane[2 * i] );
352 VectorSubtract( vec3_origin, plane[2 * i].normal, plane[2 * i + 1].normal );
353 plane[2 * i + 1].dist = -plane[2 * i].dist;
355 Dot = DotProduct( plane[2 * i].normal,SurfNormal );
356 if ( Dot > BestDot ) {
359 if ( strlen( QERFaceData->m_TextureName ) ) {
360 strcpy( Texture[Game][0],QERFaceData->m_TextureName );
364 for ( i = 0; i < NumFaces; i++ )
366 if ( i == BestFace ) {
369 _QERFaceData* QERFaceData = g_FuncTable.m_pfnGetFaceData( vp,i );
370 if ( strlen( QERFaceData->m_TextureName ) ) {
371 if ( strcmp( Texture[Game][0],QERFaceData->m_TextureName ) ) {
372 strcpy( Texture[Game][1],QERFaceData->m_TextureName );
378 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
380 w = BaseWindingForPlane( plane[BestFace * 2].normal, plane[BestFace * 2].dist );
382 for ( i = 0 ; i < NumFaces && w; i++ )
384 if ( BestFace == i ) {
387 ChopWindingInPlace( &w, plane[i * 2 + 1].normal, plane[i * 2 + 1].dist, 0 );
393 // Get bounding box for this face
394 vmin[0] = vmax[0] = w->p[0][0];
395 vmin[1] = vmax[1] = w->p[0][1];
396 vmin[2] = vmax[2] = w->p[0][2];
397 for ( j = 1; j < w->numpoints; j++ )
399 vmin[0] = min( vmin[0],w->p[j][0] );
400 vmin[1] = min( vmin[1],w->p[j][1] );
401 vmin[2] = min( vmin[2],w->p[j][2] );
402 vmax[0] = max( vmax[0],w->p[j][0] );
403 vmax[1] = max( vmax[1],w->p[j][1] );
404 vmax[2] = max( vmax[2],w->p[j][2] );
409 VectorCopy( plane[BestFace * 2].normal,pface.normal );
410 pface.dist = plane[BestFace * 2].dist;
415 if ( pface.normal[1] == 0. ) {
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];
429 if ( pface.normal[0] == 0. ) {
436 Z00 = ( pface.dist - pface.normal[1] * Hll - pface.normal[2] * Vll ) / pface.normal[0];
437 Z01 = ( pface.dist - pface.normal[1] * Hll - pface.normal[2] * Vur ) / pface.normal[0];
438 Z10 = ( pface.dist - pface.normal[1] * Hur - pface.normal[2] * Vll ) / pface.normal[0];
439 Z11 = ( pface.dist - pface.normal[1] * Hur - pface.normal[2] * Vur ) / pface.normal[0];
442 if ( pface.normal[2] == 0. ) {
449 Z00 = ( pface.dist - pface.normal[0] * Hll - pface.normal[1] * Vll ) / pface.normal[2];
450 Z01 = ( pface.dist - pface.normal[0] * Hll - pface.normal[1] * Vur ) / pface.normal[2];
451 Z10 = ( pface.dist - pface.normal[0] * Hur - pface.normal[1] * Vll ) / pface.normal[2];
452 Z11 = ( pface.dist - pface.normal[0] * Hur - pface.normal[1] * Vur ) / pface.normal[2];