r3595 - trunk/misc/gtkradiant
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Thu Apr 24 01:59:41 EDT 2008
Author: div0
Date: 2008-04-24 01:59:41 -0400 (Thu, 24 Apr 2008)
New Revision: 3595
Modified:
trunk/misc/gtkradiant/gtkradiant-nexuiz-patchset.diff
Log:
apply the patch rename to the diff too
Modified: trunk/misc/gtkradiant/gtkradiant-nexuiz-patchset.diff
===================================================================
--- trunk/misc/gtkradiant/gtkradiant-nexuiz-patchset.diff 2008-04-24 05:45:43 UTC (rev 3594)
+++ trunk/misc/gtkradiant/gtkradiant-nexuiz-patchset.diff 2008-04-24 05:59:41 UTC (rev 3595)
@@ -8,6 +8,89 @@
+Index: libs/picomodel/pm_obj.c
+===================================================================
+--- libs/picomodel/pm_obj.c (revision 193)
++++ libs/picomodel/pm_obj.c (working copy)
+@@ -265,7 +265,7 @@
+ /* get next token in material file */
+ if (_pico_parse( p,1 ) == NULL)
+ break;
+-#if 0
++#if 1
+
+ /* skip empty lines */
+ if (p->token == NULL || !strlen( p->token ))
+@@ -307,6 +307,7 @@
+ else if (!_pico_stricmp(p->token,"map_kd"))
+ {
+ char *mapName;
++ picoShader_t *shader;
+
+ /* pointer to current shader must be valid */
+ if (curShader == NULL)
+@@ -321,6 +322,10 @@
+ _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
+ _obj_mtl_error_return;
+ }
++ /* create a new pico shader */
++ shader = PicoNewShader( model );
++ if (shader == NULL)
++ _obj_mtl_error_return;
+ /* set shader map name */
+ PicoSetShaderMapName( shader,mapName );
+ }
+@@ -521,7 +526,7 @@
+ PicoSetModelFileName( model,fileName );
+
+ /* try loading the materials; we don't handle the result */
+-#if 0
++#if 1
+ _obj_mtl_load( model );
+ #endif
+
+@@ -830,6 +835,41 @@
+ curVertex += max;
+ }
+ }
++ else if (!_pico_stricmp(p->token,"usemtl"))
++ {
++ picoShader_t *shader;
++ char *name;
++
++ /* get material name */
++ name = _pico_parse( p,0 );
++
++ /* validate material name */
++ if (name == NULL || !strlen(name))
++ {
++ _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
++ }
++ else
++ {
++ shader = PicoFindShader( model, name, 1 );
++ if (shader == NULL)
++ {
++ _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
++
++ /* create a new pico shader */
++ shader = PicoNewShader( model );
++ if (shader != NULL)
++ {
++ PicoSetShaderName( shader,name );
++ PicoSetShaderMapName( shader,name );
++ PicoSetSurfaceShader( curSurface, shader );
++ }
++ }
++ else
++ {
++ PicoSetSurfaceShader( curSurface, shader );
++ }
++ }
++ }
+ /* skip unparsed rest of line and continue */
+ _pico_parse_skip_rest( p );
+ }
Index: libs/picomodel/pm_ase.c
===================================================================
--- libs/picomodel/pm_ase.c (revision 191)
@@ -568,89 +651,6 @@
}
+
+
-Index: libs/picomodel/pm_obj.c
-===================================================================
---- libs/picomodel/pm_obj.c (revision 193)
-+++ libs/picomodel/pm_obj.c (working copy)
-@@ -265,7 +265,7 @@
- /* get next token in material file */
- if (_pico_parse( p,1 ) == NULL)
- break;
--#if 0
-+#if 1
-
- /* skip empty lines */
- if (p->token == NULL || !strlen( p->token ))
-@@ -307,6 +307,7 @@
- else if (!_pico_stricmp(p->token,"map_kd"))
- {
- char *mapName;
-+ picoShader_t *shader;
-
- /* pointer to current shader must be valid */
- if (curShader == NULL)
-@@ -321,6 +322,10 @@
- _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
- _obj_mtl_error_return;
- }
-+ /* create a new pico shader */
-+ shader = PicoNewShader( model );
-+ if (shader == NULL)
-+ _obj_mtl_error_return;
- /* set shader map name */
- PicoSetShaderMapName( shader,mapName );
- }
-@@ -521,7 +526,7 @@
- PicoSetModelFileName( model,fileName );
-
- /* try loading the materials; we don't handle the result */
--#if 0
-+#if 1
- _obj_mtl_load( model );
- #endif
-
-@@ -830,6 +835,41 @@
- curVertex += max;
- }
- }
-+ else if (!_pico_stricmp(p->token,"usemtl"))
-+ {
-+ picoShader_t *shader;
-+ char *name;
-+
-+ /* get material name */
-+ name = _pico_parse( p,0 );
-+
-+ /* validate material name */
-+ if (name == NULL || !strlen(name))
-+ {
-+ _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
-+ }
-+ else
-+ {
-+ shader = PicoFindShader( model, name, 1 );
-+ if (shader == NULL)
-+ {
-+ _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
-+
-+ /* create a new pico shader */
-+ shader = PicoNewShader( model );
-+ if (shader != NULL)
-+ {
-+ PicoSetShaderName( shader,name );
-+ PicoSetShaderMapName( shader,name );
-+ PicoSetSurfaceShader( curSurface, shader );
-+ }
-+ }
-+ else
-+ {
-+ PicoSetSurfaceShader( curSurface, shader );
-+ }
-+ }
-+ }
- /* skip unparsed rest of line and continue */
- _pico_parse_skip_rest( p );
- }
Index: plugins/model/model.cpp
===================================================================
--- plugins/model/model.cpp (revision 193)
@@ -698,6 +698,562 @@
maptypes="mapq3"
shaders="quake3"
entityclass="quake3"
+Index: tools/quake3/q3map2/convert_map.c
+===================================================================
+--- tools/quake3/q3map2/convert_map.c (revision 191)
++++ tools/quake3/q3map2/convert_map.c (working copy)
+@@ -46,6 +46,105 @@
+ #define SNAP_FLOAT_TO_INT 4
+ #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT)
+
++typedef vec_t vec2_t[2];
++
++static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
++ vec_t a10, vec_t a11, vec_t a12,
++ vec_t a20, vec_t a21, vec_t a22)
++{
++ return
++ a00 * (a11 * a22 - a12 * a21)
++ - a01 * (a10 * a22 - a12 * a20)
++ + a02 * (a10 * a21 - a11 * a20);
++}
++
++void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
++{
++ bspDrawSurface_t *s;
++ int i;
++ int t;
++ vec_t best = 0;
++ vec_t thisarea;
++ vec3_t normdiff;
++ vec3_t v1v0, v2v0, norm;
++ bspDrawVert_t *vert[3];
++ winding_t *polygon;
++ plane_t *buildPlane = &mapplanes[buildSide->planenum];
++ int matches = 0;
++
++ // first, start out with NULLs
++ bestVert[0] = bestVert[1] = bestVert[2] = NULL;
++
++ // brute force through all surfaces
++ for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
++ {
++ if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
++ continue;
++ if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
++ continue;
++ for(t = 0; t + 3 <= s->numIndexes; t += 3)
++ {
++ vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
++ vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
++ vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
++ if(s->surfaceType == MST_PLANAR)
++ {
++ VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
++ VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
++ VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
++ }
++ else
++ {
++ // this is more prone to roundoff errors, but with embedded
++ // models, there is no better way
++ VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
++ VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
++ CrossProduct(v2v0, v1v0, norm);
++ VectorNormalize(norm, norm);
++ VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
++ }
++ if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
++ if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
++ if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
++ // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
++ polygon = CopyWinding(buildSide->winding);
++ for(i = 0; i < 3; ++i)
++ {
++ // 0: 1, 2
++ // 1: 2, 0
++ // 2; 0, 1
++ vec3_t *v1 = &vert[(i+1)%3]->xyz;
++ vec3_t *v2 = &vert[(i+2)%3]->xyz;
++ vec3_t triNormal;
++ vec_t triDist;
++ vec3_t sideDirection;
++ // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
++ VectorSubtract(*v2, *v1, sideDirection);
++ CrossProduct(sideDirection, buildPlane->normal, triNormal);
++ triDist = DotProduct(*v1, triNormal);
++ ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
++ if(!polygon)
++ goto exwinding;
++ }
++ thisarea = WindingArea(polygon);
++ if(thisarea > 0)
++ ++matches;
++ if(thisarea > best)
++ {
++ best = thisarea;
++ bestVert[0] = vert[0];
++ bestVert[1] = vert[1];
++ bestVert[2] = vert[2];
++ }
++ FreeWinding(polygon);
++exwinding:
++ ;
++ }
++ }
++ //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
++ // fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
++}
++
+ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
+ {
+ int i, j;
+@@ -54,12 +153,17 @@
+ bspShader_t *shader;
+ char *texture;
+ bspPlane_t *plane;
++ plane_t *buildPlane;
+ vec3_t pts[ 3 ];
++ bspDrawVert_t *vert[3];
++ int valid;
+
+
+ /* start brush */
+ fprintf( f, "\t// brush %d\n", num );
+ fprintf( f, "\t{\n" );
++ fprintf( f, "\tbrushDef\n" );
++ fprintf( f, "\t{\n" );
+
+ /* clear out build brush */
+ for( i = 0; i < buildBrush->numsides; i++ )
+@@ -109,9 +213,88 @@
+ /* get build side */
+ buildSide = &buildBrush->sides[ i ];
+
++ /* get plane */
++ buildPlane = &mapplanes[ buildSide->planenum ];
++
+ /* dummy check */
+ if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
+ continue;
++
++ // st-texcoords -> texMat block
++ // start out with dummy
++ VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
++ VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
++
++ // find surface for this side (by brute force)
++ // surface format:
++ // - meshverts point in pairs of three into verts
++ // - (triangles)
++ // - find the triangle that has most in common with our side
++ GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
++ valid = 0;
++
++ if(vert[0] && vert[1] && vert[2])
++ {
++ int i;
++ vec3_t texX, texY;
++ vec3_t xy1I, xy1J, xy1K;
++ vec2_t stI, stJ, stK;
++ vec_t D, D0, D1, D2;
++
++ ComputeAxisBase(buildPlane->normal, texX, texY);
++
++ VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
++ VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
++ VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
++ stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
++ stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
++ stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
++
++ // - solve linear equations:
++ // - (x, y) := xyz . (texX, texY)
++ // - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
++ // (for three vertices)
++ D = Det3x3(
++ xy1I[0], xy1I[1], 1,
++ xy1J[0], xy1J[1], 1,
++ xy1K[0], xy1K[1], 1
++ );
++ if(D != 0)
++ {
++ for(i = 0; i < 2; ++i)
++ {
++ D0 = Det3x3(
++ stI[i], xy1I[1], 1,
++ stJ[i], xy1J[1], 1,
++ stK[i], xy1K[1], 1
++ );
++ D1 = Det3x3(
++ xy1I[0], stI[i], 1,
++ xy1J[0], stJ[i], 1,
++ xy1K[0], stK[i], 1
++ );
++ D2 = Det3x3(
++ xy1I[0], xy1I[1], stI[i],
++ xy1J[0], xy1J[1], stJ[i],
++ xy1K[0], xy1K[1], stK[i]
++ );
++ VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
++ valid = 1;
++ }
++ }
++ else
++ fprintf(stderr, "degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n",
++ buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
++ vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2],
++ texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
++ vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1],
++ vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1],
++ vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]
++ );
++ }
++ else
++ if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
++ fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
+
+ /* get texture name */
+ if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
+@@ -130,14 +313,21 @@
+
+ /* print brush side */
+ /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
+- fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n",
++ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
+ pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
+ pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
+ pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
+- texture );
++ buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2],
++ buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2],
++ texture,
++ // DEBUG: valid ? 0 : C_DETAIL
++ 0
++ );
++ // TODO write brush primitives format here
+ }
+
+ /* end brush */
++ fprintf( f, "\t}\n" );
+ fprintf( f, "\t}\n\n" );
+ }
+
+Index: tools/quake3/q3map2/main.c
+===================================================================
+--- tools/quake3/q3map2/main.c (revision 191)
++++ tools/quake3/q3map2/main.c (working copy)
+@@ -541,6 +541,18 @@
+ Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
+ }
+ }
++ else if( !strcmp( argv[ i ], "-ne" ) )
++ {
++ normalEpsilon = atof( argv[ i + 1 ] );
++ i++;
++ Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
++ }
++ else if( !strcmp( argv[ i ], "-de" ) )
++ {
++ distanceEpsilon = atof( argv[ i + 1 ] );
++ i++;
++ Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
++ }
+ }
+
+ /* clean up map name */
+Index: tools/quake3/q3map2/model.c
+===================================================================
+--- tools/quake3/q3map2/model.c (revision 193)
++++ tools/quake3/q3map2/model.c (working copy)
+@@ -222,6 +222,8 @@
+ byte *color;
+ picoIndex_t *indexes;
+ remap_t *rm, *glob;
++ double normalEpsilon_save;
++ double distanceEpsilon_save;
+
+
+ /* get model */
+@@ -398,9 +400,8 @@
+ /* ydnar: giant hack land: generate clipping brushes for model triangles */
+ if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
+ {
+- vec3_t points[ 3 ], backs[ 3 ];
++ vec3_t points[ 4 ], backs[ 3 ];
+ vec4_t plane, reverse, pa, pb, pc;
+- vec3_t nadir;
+
+
+ /* temp hack */
+@@ -437,90 +438,141 @@
+ /* note: this doesn't work as well as simply using the plane of the triangle, below */
+ for( k = 0; k < 3; k++ )
+ {
+- if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
+- fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
++ if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
++ fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
+ {
+ backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
+ break;
+ }
+ }
+ }
++
++ VectorCopy( points[0], points[3] ); // for cyclic usage
+
+ /* make plane for triangle */
++ // div0: add some extra spawnflags:
++ // 0: snap normals to axial planes for extrusion
++ // 8: extrude with the original normals
++ // 16: extrude only with up/down normals (ideal for terrain)
++ // 24: extrude by distance zero (may need engine changes)
+ if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
+ {
++ vec3_t bestNormal;
++ float backPlaneDistance = 2;
++
++ if(spawnFlags & 8) // use a DOWN normal
++ {
++ if(spawnFlags & 16)
++ {
++ // 24: normal as is, and zero width (broken)
++ VectorCopy(plane, bestNormal);
++ }
++ else
++ {
++ // 8: normal as is
++ VectorCopy(plane, bestNormal);
++ }
++ }
++ else
++ {
++ if(spawnFlags & 16)
++ {
++ // 16: UP/DOWN normal
++ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
++ }
++ else
++ {
++ // 0: axial normal
++ if(fabs(plane[0]) > fabs(plane[1])) // x>y
++ if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
++ VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
++ else // x>y, z>=y
++ if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
++ VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
++ else // z>=x, x>y
++ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
++ else // y>=x
++ if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
++ VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
++ else // z>=y, y>=x
++ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
++ }
++ }
++
++ /* build a brush */
++ buildBrush = AllocBrush( 48 );
++ buildBrush->entityNum = mapEntityNum;
++ buildBrush->original = buildBrush;
++ buildBrush->contentShader = si;
++ buildBrush->compileFlags = si->compileFlags;
++ buildBrush->contentFlags = si->contentFlags;
++ normalEpsilon_save = normalEpsilon;
++ distanceEpsilon_save = distanceEpsilon;
++ if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
++ {
++ buildBrush->detail = qfalse;
++
++ // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
++ if(normalEpsilon > 0)
++ normalEpsilon = 0;
++ if(distanceEpsilon > 0)
++ distanceEpsilon = 0;
++ }
++ else
++ buildBrush->detail = qtrue;
++
+ /* regenerate back points */
+ for( j = 0; j < 3; j++ )
+ {
+ /* get vertex */
+ dv = &ds->verts[ ds->indexes[ i + j ] ];
+-
+- /* copy xyz */
+- VectorCopy( dv->xyz, backs[ j ] );
+-
+- /* find nearest axial to plane normal and push back points opposite */
+- for( k = 0; k < 3; k++ )
+- {
+- if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
+- fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
+- {
+- backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
+- break;
+- }
+- }
++
++ // shift by some units
++ VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
+ }
+-
++
+ /* make back plane */
+ VectorScale( plane, -1.0f, reverse );
+- reverse[ 3 ] = -(plane[ 3 ] - 1);
+-
+- /* make back pyramid point */
+- VectorCopy( points[ 0 ], nadir );
+- VectorAdd( nadir, points[ 1 ], nadir );
+- VectorAdd( nadir, points[ 2 ], nadir );
+- VectorScale( nadir, 0.3333333333333f, nadir );
+- VectorMA( nadir, -2.0f, plane, nadir );
+-
+- /* make 3 more planes */
+- //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
+- //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
+- //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
++ reverse[ 3 ] = -plane[ 3 ];
++ if((spawnFlags & 24) != 24)
++ reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
++ // that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)
++
+ if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
+- PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
+- PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
++ PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
++ PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
+ {
+- /* build a brush */
+- buildBrush = AllocBrush( 48 );
+-
+- buildBrush->entityNum = mapEntityNum;
+- buildBrush->original = buildBrush;
+- buildBrush->contentShader = si;
+- buildBrush->compileFlags = si->compileFlags;
+- buildBrush->contentFlags = si->contentFlags;
+- buildBrush->detail = qtrue;
+-
+ /* set up brush sides */
+ buildBrush->numsides = 5;
+ for( j = 0; j < buildBrush->numsides; j++ )
+ buildBrush->sides[ j ].shaderInfo = si;
++
+ buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
+- buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
+- buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
+- buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
+- buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
+-
+- /* add to entity */
+- if( CreateBrushWindings( buildBrush ) )
+- {
+- AddBrushBevels();
+- //% EmitBrushes( buildBrush, NULL, NULL );
+- buildBrush->next = entities[ mapEntityNum ].brushes;
+- entities[ mapEntityNum ].brushes = buildBrush;
+- entities[ mapEntityNum ].numBrushes++;
+- }
+- else
+- free( buildBrush );
++ buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
++ buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
++ buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
++ buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
+ }
++ else
++ {
++ free(buildBrush);
++ continue;
++ }
++
++ normalEpsilon = normalEpsilon_save;
++ distanceEpsilon = distanceEpsilon_save;
++
++ /* add to entity */
++ if( CreateBrushWindings( buildBrush ) )
++ {
++ AddBrushBevels();
++ //% EmitBrushes( buildBrush, NULL, NULL );
++ buildBrush->next = entities[ mapEntityNum ].brushes;
++ entities[ mapEntityNum ].brushes = buildBrush;
++ entities[ mapEntityNum ].numBrushes++;
++ }
++ else
++ free( buildBrush );
+ }
+ }
+ }
+Index: tools/quake3/q3map2/map.c
+===================================================================
+--- tools/quake3/q3map2/map.c (revision 193)
++++ tools/quake3/q3map2/map.c (working copy)
+@@ -184,7 +184,7 @@
+ snaps a plane to normal/distance epsilons
+ */
+
+-void SnapPlane( vec3_t normal, vec_t *dist )
++void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
+ {
+ // SnapPlane disabled by LordHavoc because it often messes up collision
+ // brushes made from triangles of embedded models, and it has little effect
+@@ -193,7 +193,13 @@
+ SnapPlane reenabled by namespace because of multiple reports of
+ q3map2-crashes which were triggered by this patch.
+ */
++ // div0: ensure the point "center" stays on the plane (actually, this
++ // rotates the plane around the point center).
++ // if center lies on the plane, it is guaranteed to stay on the plane by
++ // this fix.
++ vec_t centerDist = DotProduct(normal, center);
+ SnapNormal( normal );
++ *dist += (DotProduct(normal, center) - centerDist);
+
+ if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
+ *dist = Q_rint( *dist );
+@@ -207,7 +213,7 @@
+ must be within an epsilon distance of the plane
+ */
+
+-int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
++int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
+
+ #ifdef USE_HASHING
+
+@@ -215,10 +221,14 @@
+ int i, j, hash, h;
+ plane_t *p;
+ vec_t d;
++ vec3_t centerofweight;
++
++ VectorClear(centerofweight);
++ for(i = 0; i < numPoints; ++i)
++ VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
+
+-
+ /* hash the plane */
+- SnapPlane( normal, &dist );
++ SnapPlane( normal, &dist, centerofweight );
+ hash = (PLANE_HASHES - 1) & (int) fabs( dist );
+
+ /* search the border bins as well */
+@@ -259,7 +269,13 @@
+ plane_t *p;
+
+
+- SnapPlane( normal, &dist );
++ vec3_t centerofweight;
++
++ VectorClear(centerofweight);
++ for(i = 0; i < numPoints; ++i)
++ VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
++
++ SnapPlane( normal, &dist, centerofweight );
+ for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
+ {
+ if( PlaneEqual( p, normal, dist ) )
Index: tools/quake3/q3map2/shaders.c
===================================================================
--- tools/quake3/q3map2/shaders.c (revision 191)
@@ -1837,562 +2393,6 @@
/* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
if( deluxemap )
-Index: tools/quake3/q3map2/convert_map.c
-===================================================================
---- tools/quake3/q3map2/convert_map.c (revision 191)
-+++ tools/quake3/q3map2/convert_map.c (working copy)
-@@ -46,6 +46,105 @@
- #define SNAP_FLOAT_TO_INT 4
- #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT)
-
-+typedef vec_t vec2_t[2];
-+
-+static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
-+ vec_t a10, vec_t a11, vec_t a12,
-+ vec_t a20, vec_t a21, vec_t a22)
-+{
-+ return
-+ a00 * (a11 * a22 - a12 * a21)
-+ - a01 * (a10 * a22 - a12 * a20)
-+ + a02 * (a10 * a21 - a11 * a20);
-+}
-+
-+void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
-+{
-+ bspDrawSurface_t *s;
-+ int i;
-+ int t;
-+ vec_t best = 0;
-+ vec_t thisarea;
-+ vec3_t normdiff;
-+ vec3_t v1v0, v2v0, norm;
-+ bspDrawVert_t *vert[3];
-+ winding_t *polygon;
-+ plane_t *buildPlane = &mapplanes[buildSide->planenum];
-+ int matches = 0;
-+
-+ // first, start out with NULLs
-+ bestVert[0] = bestVert[1] = bestVert[2] = NULL;
-+
-+ // brute force through all surfaces
-+ for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
-+ {
-+ if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
-+ continue;
-+ if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
-+ continue;
-+ for(t = 0; t + 3 <= s->numIndexes; t += 3)
-+ {
-+ vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
-+ vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
-+ vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
-+ if(s->surfaceType == MST_PLANAR)
-+ {
-+ VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
-+ VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
-+ VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
-+ }
-+ else
-+ {
-+ // this is more prone to roundoff errors, but with embedded
-+ // models, there is no better way
-+ VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
-+ VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
-+ CrossProduct(v2v0, v1v0, norm);
-+ VectorNormalize(norm, norm);
-+ VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
-+ }
-+ if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
-+ if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
-+ if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
-+ // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
-+ polygon = CopyWinding(buildSide->winding);
-+ for(i = 0; i < 3; ++i)
-+ {
-+ // 0: 1, 2
-+ // 1: 2, 0
-+ // 2; 0, 1
-+ vec3_t *v1 = &vert[(i+1)%3]->xyz;
-+ vec3_t *v2 = &vert[(i+2)%3]->xyz;
-+ vec3_t triNormal;
-+ vec_t triDist;
-+ vec3_t sideDirection;
-+ // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
-+ VectorSubtract(*v2, *v1, sideDirection);
-+ CrossProduct(sideDirection, buildPlane->normal, triNormal);
-+ triDist = DotProduct(*v1, triNormal);
-+ ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
-+ if(!polygon)
-+ goto exwinding;
-+ }
-+ thisarea = WindingArea(polygon);
-+ if(thisarea > 0)
-+ ++matches;
-+ if(thisarea > best)
-+ {
-+ best = thisarea;
-+ bestVert[0] = vert[0];
-+ bestVert[1] = vert[1];
-+ bestVert[2] = vert[2];
-+ }
-+ FreeWinding(polygon);
-+exwinding:
-+ ;
-+ }
-+ }
-+ //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
-+ // fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
-+}
-+
- static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
- {
- int i, j;
-@@ -54,12 +153,17 @@
- bspShader_t *shader;
- char *texture;
- bspPlane_t *plane;
-+ plane_t *buildPlane;
- vec3_t pts[ 3 ];
-+ bspDrawVert_t *vert[3];
-+ int valid;
-
-
- /* start brush */
- fprintf( f, "\t// brush %d\n", num );
- fprintf( f, "\t{\n" );
-+ fprintf( f, "\tbrushDef\n" );
-+ fprintf( f, "\t{\n" );
-
- /* clear out build brush */
- for( i = 0; i < buildBrush->numsides; i++ )
-@@ -109,9 +213,88 @@
- /* get build side */
- buildSide = &buildBrush->sides[ i ];
-
-+ /* get plane */
-+ buildPlane = &mapplanes[ buildSide->planenum ];
-+
- /* dummy check */
- if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
- continue;
-+
-+ // st-texcoords -> texMat block
-+ // start out with dummy
-+ VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
-+ VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
-+
-+ // find surface for this side (by brute force)
-+ // surface format:
-+ // - meshverts point in pairs of three into verts
-+ // - (triangles)
-+ // - find the triangle that has most in common with our side
-+ GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
-+ valid = 0;
-+
-+ if(vert[0] && vert[1] && vert[2])
-+ {
-+ int i;
-+ vec3_t texX, texY;
-+ vec3_t xy1I, xy1J, xy1K;
-+ vec2_t stI, stJ, stK;
-+ vec_t D, D0, D1, D2;
-+
-+ ComputeAxisBase(buildPlane->normal, texX, texY);
-+
-+ VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
-+ VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
-+ VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
-+ stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
-+ stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
-+ stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
-+
-+ // - solve linear equations:
-+ // - (x, y) := xyz . (texX, texY)
-+ // - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
-+ // (for three vertices)
-+ D = Det3x3(
-+ xy1I[0], xy1I[1], 1,
-+ xy1J[0], xy1J[1], 1,
-+ xy1K[0], xy1K[1], 1
-+ );
-+ if(D != 0)
-+ {
-+ for(i = 0; i < 2; ++i)
-+ {
-+ D0 = Det3x3(
-+ stI[i], xy1I[1], 1,
-+ stJ[i], xy1J[1], 1,
-+ stK[i], xy1K[1], 1
-+ );
-+ D1 = Det3x3(
-+ xy1I[0], stI[i], 1,
-+ xy1J[0], stJ[i], 1,
-+ xy1K[0], stK[i], 1
-+ );
-+ D2 = Det3x3(
-+ xy1I[0], xy1I[1], stI[i],
-+ xy1J[0], xy1J[1], stJ[i],
-+ xy1K[0], xy1K[1], stK[i]
-+ );
-+ VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
-+ valid = 1;
-+ }
-+ }
-+ else
-+ fprintf(stderr, "degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n",
-+ buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
-+ vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2],
-+ texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
-+ vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1],
-+ vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1],
-+ vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]
-+ );
-+ }
-+ else
-+ if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
-+ fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
-
- /* get texture name */
- if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
-@@ -130,14 +313,21 @@
-
- /* print brush side */
- /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
-- fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n",
-+ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
- pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
- pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
- pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
-- texture );
-+ buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2],
-+ buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2],
-+ texture,
-+ // DEBUG: valid ? 0 : C_DETAIL
-+ 0
-+ );
-+ // TODO write brush primitives format here
- }
-
- /* end brush */
-+ fprintf( f, "\t}\n" );
- fprintf( f, "\t}\n\n" );
- }
-
-Index: tools/quake3/q3map2/main.c
-===================================================================
---- tools/quake3/q3map2/main.c (revision 191)
-+++ tools/quake3/q3map2/main.c (working copy)
-@@ -541,6 +541,18 @@
- Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
- }
- }
-+ else if( !strcmp( argv[ i ], "-ne" ) )
-+ {
-+ normalEpsilon = atof( argv[ i + 1 ] );
-+ i++;
-+ Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
-+ }
-+ else if( !strcmp( argv[ i ], "-de" ) )
-+ {
-+ distanceEpsilon = atof( argv[ i + 1 ] );
-+ i++;
-+ Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
-+ }
- }
-
- /* clean up map name */
-Index: tools/quake3/q3map2/model.c
-===================================================================
---- tools/quake3/q3map2/model.c (revision 193)
-+++ tools/quake3/q3map2/model.c (working copy)
-@@ -222,6 +222,8 @@
- byte *color;
- picoIndex_t *indexes;
- remap_t *rm, *glob;
-+ double normalEpsilon_save;
-+ double distanceEpsilon_save;
-
-
- /* get model */
-@@ -398,9 +400,8 @@
- /* ydnar: giant hack land: generate clipping brushes for model triangles */
- if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
- {
-- vec3_t points[ 3 ], backs[ 3 ];
-+ vec3_t points[ 4 ], backs[ 3 ];
- vec4_t plane, reverse, pa, pb, pc;
-- vec3_t nadir;
-
-
- /* temp hack */
-@@ -437,90 +438,141 @@
- /* note: this doesn't work as well as simply using the plane of the triangle, below */
- for( k = 0; k < 3; k++ )
- {
-- if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
-- fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
-+ if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
-+ fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
- {
- backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
- break;
- }
- }
- }
-+
-+ VectorCopy( points[0], points[3] ); // for cyclic usage
-
- /* make plane for triangle */
-+ // div0: add some extra spawnflags:
-+ // 0: snap normals to axial planes for extrusion
-+ // 8: extrude with the original normals
-+ // 16: extrude only with up/down normals (ideal for terrain)
-+ // 24: extrude by distance zero (may need engine changes)
- if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
- {
-+ vec3_t bestNormal;
-+ float backPlaneDistance = 2;
-+
-+ if(spawnFlags & 8) // use a DOWN normal
-+ {
-+ if(spawnFlags & 16)
-+ {
-+ // 24: normal as is, and zero width (broken)
-+ VectorCopy(plane, bestNormal);
-+ }
-+ else
-+ {
-+ // 8: normal as is
-+ VectorCopy(plane, bestNormal);
-+ }
-+ }
-+ else
-+ {
-+ if(spawnFlags & 16)
-+ {
-+ // 16: UP/DOWN normal
-+ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
-+ }
-+ else
-+ {
-+ // 0: axial normal
-+ if(fabs(plane[0]) > fabs(plane[1])) // x>y
-+ if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
-+ VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
-+ else // x>y, z>=y
-+ if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
-+ VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
-+ else // z>=x, x>y
-+ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
-+ else // y>=x
-+ if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
-+ VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
-+ else // z>=y, y>=x
-+ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
-+ }
-+ }
-+
-+ /* build a brush */
-+ buildBrush = AllocBrush( 48 );
-+ buildBrush->entityNum = mapEntityNum;
-+ buildBrush->original = buildBrush;
-+ buildBrush->contentShader = si;
-+ buildBrush->compileFlags = si->compileFlags;
-+ buildBrush->contentFlags = si->contentFlags;
-+ normalEpsilon_save = normalEpsilon;
-+ distanceEpsilon_save = distanceEpsilon;
-+ if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
-+ {
-+ buildBrush->detail = qfalse;
-+
-+ // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
-+ if(normalEpsilon > 0)
-+ normalEpsilon = 0;
-+ if(distanceEpsilon > 0)
-+ distanceEpsilon = 0;
-+ }
-+ else
-+ buildBrush->detail = qtrue;
-+
- /* regenerate back points */
- for( j = 0; j < 3; j++ )
- {
- /* get vertex */
- dv = &ds->verts[ ds->indexes[ i + j ] ];
--
-- /* copy xyz */
-- VectorCopy( dv->xyz, backs[ j ] );
--
-- /* find nearest axial to plane normal and push back points opposite */
-- for( k = 0; k < 3; k++ )
-- {
-- if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
-- fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
-- {
-- backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
-- break;
-- }
-- }
-+
-+ // shift by some units
-+ VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
- }
--
-+
- /* make back plane */
- VectorScale( plane, -1.0f, reverse );
-- reverse[ 3 ] = -(plane[ 3 ] - 1);
--
-- /* make back pyramid point */
-- VectorCopy( points[ 0 ], nadir );
-- VectorAdd( nadir, points[ 1 ], nadir );
-- VectorAdd( nadir, points[ 2 ], nadir );
-- VectorScale( nadir, 0.3333333333333f, nadir );
-- VectorMA( nadir, -2.0f, plane, nadir );
--
-- /* make 3 more planes */
-- //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
-- //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
-- //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
-+ reverse[ 3 ] = -plane[ 3 ];
-+ if((spawnFlags & 24) != 24)
-+ reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
-+ // that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)
-+
- if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
-- PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
-- PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
-+ PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
-+ PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
- {
-- /* build a brush */
-- buildBrush = AllocBrush( 48 );
--
-- buildBrush->entityNum = mapEntityNum;
-- buildBrush->original = buildBrush;
-- buildBrush->contentShader = si;
-- buildBrush->compileFlags = si->compileFlags;
-- buildBrush->contentFlags = si->contentFlags;
-- buildBrush->detail = qtrue;
--
- /* set up brush sides */
- buildBrush->numsides = 5;
- for( j = 0; j < buildBrush->numsides; j++ )
- buildBrush->sides[ j ].shaderInfo = si;
-+
- buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
-- buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
-- buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
-- buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
-- buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
--
-- /* add to entity */
-- if( CreateBrushWindings( buildBrush ) )
-- {
-- AddBrushBevels();
-- //% EmitBrushes( buildBrush, NULL, NULL );
-- buildBrush->next = entities[ mapEntityNum ].brushes;
-- entities[ mapEntityNum ].brushes = buildBrush;
-- entities[ mapEntityNum ].numBrushes++;
-- }
-- else
-- free( buildBrush );
-+ buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
-+ buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
-+ buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
-+ buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
- }
-+ else
-+ {
-+ free(buildBrush);
-+ continue;
-+ }
-+
-+ normalEpsilon = normalEpsilon_save;
-+ distanceEpsilon = distanceEpsilon_save;
-+
-+ /* add to entity */
-+ if( CreateBrushWindings( buildBrush ) )
-+ {
-+ AddBrushBevels();
-+ //% EmitBrushes( buildBrush, NULL, NULL );
-+ buildBrush->next = entities[ mapEntityNum ].brushes;
-+ entities[ mapEntityNum ].brushes = buildBrush;
-+ entities[ mapEntityNum ].numBrushes++;
-+ }
-+ else
-+ free( buildBrush );
- }
- }
- }
-Index: tools/quake3/q3map2/map.c
-===================================================================
---- tools/quake3/q3map2/map.c (revision 193)
-+++ tools/quake3/q3map2/map.c (working copy)
-@@ -184,7 +184,7 @@
- snaps a plane to normal/distance epsilons
- */
-
--void SnapPlane( vec3_t normal, vec_t *dist )
-+void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
- {
- // SnapPlane disabled by LordHavoc because it often messes up collision
- // brushes made from triangles of embedded models, and it has little effect
-@@ -193,7 +193,13 @@
- SnapPlane reenabled by namespace because of multiple reports of
- q3map2-crashes which were triggered by this patch.
- */
-+ // div0: ensure the point "center" stays on the plane (actually, this
-+ // rotates the plane around the point center).
-+ // if center lies on the plane, it is guaranteed to stay on the plane by
-+ // this fix.
-+ vec_t centerDist = DotProduct(normal, center);
- SnapNormal( normal );
-+ *dist += (DotProduct(normal, center) - centerDist);
-
- if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
- *dist = Q_rint( *dist );
-@@ -207,7 +213,7 @@
- must be within an epsilon distance of the plane
- */
-
--int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
-+int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
-
- #ifdef USE_HASHING
-
-@@ -215,10 +221,14 @@
- int i, j, hash, h;
- plane_t *p;
- vec_t d;
-+ vec3_t centerofweight;
-+
-+ VectorClear(centerofweight);
-+ for(i = 0; i < numPoints; ++i)
-+ VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
-
--
- /* hash the plane */
-- SnapPlane( normal, &dist );
-+ SnapPlane( normal, &dist, centerofweight );
- hash = (PLANE_HASHES - 1) & (int) fabs( dist );
-
- /* search the border bins as well */
-@@ -259,7 +269,13 @@
- plane_t *p;
-
-
-- SnapPlane( normal, &dist );
-+ vec3_t centerofweight;
-+
-+ VectorClear(centerofweight);
-+ for(i = 0; i < numPoints; ++i)
-+ VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
-+
-+ SnapPlane( normal, &dist, centerofweight );
- for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
- {
- if( PlaneEqual( p, normal, dist ) )
Index: tools/quake3/q3map2/q3map2.h
===================================================================
--- tools/quake3/q3map2/q3map2.h (revision 193)
@@ -2403,7 +2403,7 @@
/* version */
-#define Q3MAP_VERSION "2.5.17"
-#define Q3MAP_MOTD "Last one turns the lights off"
-+#define Q3MAP_VERSION "2.5.17-div0-UTpicomodelase-UTpicomodelnormals-obj-UTbouncefix-UTfloodlight-UTlmexposure-UTtrianglecheck-decomptexcoords-snapplane"
++#define Q3MAP_VERSION "2.5.17-div0-obj-UTpicomodelase-UTpicomodelnormals-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTlmexposure-UTtrianglecheck"
+#define Q3MAP_MOTD "Blackhole Box ate all the light"
@@ -2414,4 +2414,4 @@
+++ include/version.default (working copy)
@@ -1 +1 @@
-1.5.0
-+1.5.0-div0-UTpicomodelase-UTpicomodelnormals-obj-modelnormals-nexuizfixes
++1.5.0-div0-obj-UTpicomodelase-UTpicomodelnormals-modelnormals-nexuizfixes
More information about the nexuiz-commits
mailing list