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