+ ConvertBrush()
+ exports a map brush
+ */
+
+#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 && VectorCompare( vert[0]->normal, vert[1]->normal ) && VectorCompare( vert[1]->normal, vert[2]->normal ) ) {
+ 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);
+}
+
+#define FRAC( x ) ( ( x ) - floor( x ) )
+static void ConvertOriginBrush( FILE *f, int num, vec3_t origin, qboolean brushPrimitives ){
+ int originSize = 256;
+
+ char pattern[6][7][3] = {
+ { "+++", "+-+", "-++", "- ", " + ", " - ", "- " },
+ { "+++", "-++", "++-", "- ", " +", "+ ", " +" },
+ { "+++", "++-", "+-+", " - ", " +", " - ", " +" },
+ { "---", "+--", "-+-", "- ", " + ", " - ", "+ " },
+ { "---", "--+", "+--", "- ", " +", "- ", " +" },
+ { "---", "-+-", "--+", " - ", " +", " + ", " +" }
+ };
+ int i;
+#define S( a,b,c ) ( pattern[a][b][c] == '+' ? +1 : pattern[a][b][c] == '-' ? -1 : 0 )
+
+ /* start brush */
+ fprintf( f, "\t// brush %d\n", num );
+ fprintf( f, "\t{\n" );
+ if ( brushPrimitives ) {
+ fprintf( f, "\tbrushDef\n" );
+ fprintf( f, "\t{\n" );
+ }
+ /* print brush side */
+ /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
+
+ for ( i = 0; i < 6; ++i )
+ {
+ if ( brushPrimitives ) {
+ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
+ origin[0] + 8 * S( i,0,0 ), origin[1] + 8 * S( i,0,1 ), origin[2] + 8 * S( i,0,2 ),
+ origin[0] + 8 * S( i,1,0 ), origin[1] + 8 * S( i,1,1 ), origin[2] + 8 * S( i,1,2 ),
+ origin[0] + 8 * S( i,2,0 ), origin[1] + 8 * S( i,2,1 ), origin[2] + 8 * S( i,2,2 ),
+ 1.0f / 16.0f, 0.0f, FRAC( ( S( i,5,0 ) * origin[0] + S( i,5,1 ) * origin[1] + S( i,5,2 ) * origin[2] ) / 16.0 + 0.5 ),
+ 0.0f, 1.0f / 16.0f, FRAC( ( S( i,6,0 ) * origin[0] + S( i,6,1 ) * origin[1] + S( i,6,2 ) * origin[2] ) / 16.0 + 0.5 ),
+ "common/origin",
+ 0
+ );
+ }
+ else
+ {
+ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
+ origin[0] + 8 * S( i,0,0 ), origin[1] + 8 * S( i,0,1 ), origin[2] + 8 * S( i,0,2 ),
+ origin[0] + 8 * S( i,1,0 ), origin[1] + 8 * S( i,1,1 ), origin[2] + 8 * S( i,1,2 ),
+ origin[0] + 8 * S( i,2,0 ), origin[1] + 8 * S( i,2,1 ), origin[2] + 8 * S( i,2,2 ),
+ "common/origin",
+ FRAC( ( S( i,3,0 ) * origin[0] + S( i,3,1 ) * origin[1] + S( i,3,2 ) * origin[2] ) / 16.0 + 0.5 ) * originSize,
+ FRAC( ( S( i,4,0 ) * origin[0] + S( i,4,1 ) * origin[1] + S( i,4,2 ) * origin[2] ) / 16.0 + 0.5 ) * originSize,
+ 0.0f, 16.0 / originSize, 16.0 / originSize,
+ 0
+ );
+ }
+ }
+#undef S
+
+ /* end brush */
+ if ( brushPrimitives ) {
+ fprintf( f, "\t}\n" );
+ }
+ fprintf( f, "\t}\n\n" );
+}
+
+static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qboolean brushPrimitives ){
+ int i, j;
+ bspBrushSide_t *side;
+ side_t *buildSide;
+ bspShader_t *shader;
+ char *texture;
+ plane_t *buildPlane;
+ vec3_t pts[ 3 ];
+ bspDrawVert_t *vert[3];