From bf9d5c3e5b0609dfb54a19830db4388ea4955a47 Mon Sep 17 00:00:00 2001 From: Garux Date: Tue, 21 Oct 2025 15:09:15 +0500 Subject: [PATCH] fix texture alignment deduction during bsp to map decompilation on bmodels with origin avoid different bmodels matching surfs mixture in GetBestSurfaceTriangleMatchForBrushside --- tools/quake3/q3map2/convert_map.cpp | 107 +++++++++++++++------------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/tools/quake3/q3map2/convert_map.cpp b/tools/quake3/q3map2/convert_map.cpp index d37b3961..c2914c7e 100644 --- a/tools/quake3/q3map2/convert_map.cpp +++ b/tools/quake3/q3map2/convert_map.cpp @@ -48,7 +48,7 @@ inline double Det3x3( double a00, double a01, double a02, + a02 * ( a10 * a21 - a11 * a20 ); } -static TriRef GetBestSurfaceTriangleMatchForBrushside( const side_t& buildSide ){ +static TriRef GetBestSurfaceTriangleMatchForBrushside( const side_t& buildSide, const bspModel_t& model ){ float best = 0; float thisarea; const plane_t& buildPlane = mapplanes[buildSide.planenum]; @@ -57,8 +57,8 @@ static TriRef GetBestSurfaceTriangleMatchForBrushside( const side_t& buildSide ) // first, start out with NULLs TriRef bestVert{ nullptr }; - // brute force through all surfaces - for ( const bspDrawSurface_t& s : bspDrawSurfaces ) + // brute force through all bmodel surfaces + for ( const bspDrawSurface_t& s : Span( &bspDrawSurfaces[ model.firstBSPSurface ], model.numBSPSurfaces ) ) { if ( s.surfaceType != MST_PLANAR && s.surfaceType != MST_TRIANGLE_SOUP ) { continue; @@ -238,7 +238,7 @@ static void bspBrush_to_buildBrush( const bspBrush_t& brush ){ } } -static void ConvertBrushFast( FILE *f, int bspBrushNum, const Vector3& origin, bool brushPrimitives ){ +static void ConvertBrushFast( FILE *f, const bspModel_t& model, int bspBrushNum, const Vector3& origin, bool brushPrimitives ){ bspBrush_to_buildBrush( bspBrushes[bspBrushNum] ); @@ -313,7 +313,7 @@ static void ConvertBrushFast( FILE *f, int bspBrushNum, const Vector3& origin, b fprintf( f, "\t}\n\n" ); } -static void ConvertBrush( FILE *f, int bspBrushNum, const Vector3& origin, bool brushPrimitives ){ +static void ConvertBrush( FILE *f, const bspModel_t& model, int bspBrushNum, const Vector3& origin, bool brushPrimitives ){ bspBrush_to_buildBrush( bspBrushes[bspBrushNum] ); @@ -368,7 +368,7 @@ static void ConvertBrush( FILE *f, int bspBrushNum, const Vector3& origin, bool // - meshverts point in pairs of three into verts // - (triangles) // - find the triangle that has most in common with our - const TriRef vert = GetBestSurfaceTriangleMatchForBrushside( buildSide ); + const TriRef vert = GetBestSurfaceTriangleMatchForBrushside( buildSide, model ); /* get texture name */ const char *texture = striEqualPrefix( buildSide.shaderInfo->shader, "textures/" ) @@ -419,6 +419,11 @@ static void ConvertBrush( FILE *f, int bspBrushNum, const Vector3& origin, bool } if ( vert[0] != nullptr && vert[1] != nullptr && vert[2] != nullptr ) { + const Vector3 verts[3] = { vert[0]->xyz + origin, + vert[1]->xyz + origin, + vert[2]->xyz + origin }; + const Vector2 sts[3] = { vert[0]->st, vert[1]->st, vert[2]->st }; + if ( brushPrimitives ) { BasicVector2 xyI, xyJ, xyK; BasicVector2 stI, stJ, stK; @@ -426,15 +431,15 @@ static void ConvertBrush( FILE *f, int bspBrushNum, const Vector3& origin, bool DoubleVector3 texX, texY; ComputeAxisBase( buildPlane.normal(), texX, texY ); - xyI[0] = vector3_dot( vert[0]->xyz, texX ); - xyI[1] = vector3_dot( vert[0]->xyz, texY ); - xyJ[0] = vector3_dot( vert[1]->xyz, texX ); - xyJ[1] = vector3_dot( vert[1]->xyz, texY ); - xyK[0] = vector3_dot( vert[2]->xyz, texX ); - xyK[1] = vector3_dot( vert[2]->xyz, texY ); - stI = vert[0]->st; - stJ = vert[1]->st; - stK = vert[2]->st; + xyI[0] = vector3_dot( verts[0], texX ); + xyI[1] = vector3_dot( verts[0], texY ); + xyJ[0] = vector3_dot( verts[1], texX ); + xyJ[1] = vector3_dot( verts[1], texY ); + xyK[0] = vector3_dot( verts[2], texX ); + xyK[1] = vector3_dot( verts[2], texY ); + stI = sts[0]; + stJ = sts[1]; + stK = sts[2]; // - solve linear equations: // - (x, y) := xyz . (texX, texY) @@ -495,7 +500,7 @@ static void ConvertBrush( FILE *f, int bspBrushNum, const Vector3& origin, bool int sv, tv; BasicVector2 stI, stJ, stK; double D, D0, D1, D2; - DoubleVector3 sts[2]; + DoubleVector3 texMat[2]; float shift[2], scale[2]; float rotate; @@ -505,44 +510,44 @@ static void ConvertBrush( FILE *f, int bspBrushNum, const Vector3& origin, bool tv = vecs[1][0]? 0 : vecs[1][1]? 1: 2; - stI[0] = vert[0]->st[0] * buildSide.shaderInfo->shaderWidth; - stI[1] = vert[0]->st[1] * buildSide.shaderInfo->shaderHeight; - stJ[0] = vert[1]->st[0] * buildSide.shaderInfo->shaderWidth; - stJ[1] = vert[1]->st[1] * buildSide.shaderInfo->shaderHeight; - stK[0] = vert[2]->st[0] * buildSide.shaderInfo->shaderWidth; - stK[1] = vert[2]->st[1] * buildSide.shaderInfo->shaderHeight; + stI[0] = sts[0][0] * buildSide.shaderInfo->shaderWidth; + stI[1] = sts[0][1] * buildSide.shaderInfo->shaderHeight; + stJ[0] = sts[1][0] * buildSide.shaderInfo->shaderWidth; + stJ[1] = sts[1][1] * buildSide.shaderInfo->shaderHeight; + stK[0] = sts[2][0] * buildSide.shaderInfo->shaderWidth; + stK[1] = sts[2][1] * buildSide.shaderInfo->shaderHeight; D = Det3x3( - vert[0]->xyz[sv], vert[0]->xyz[tv], 1, - vert[1]->xyz[sv], vert[1]->xyz[tv], 1, - vert[2]->xyz[sv], vert[2]->xyz[tv], 1 + verts[0][sv], verts[0][tv], 1, + verts[1][sv], verts[1][tv], 1, + verts[2][sv], verts[2][tv], 1 ); if ( D != 0 ) { for ( int i = 0; i < 2; ++i ) { D0 = Det3x3( - stI[i], vert[0]->xyz[tv], 1, - stJ[i], vert[1]->xyz[tv], 1, - stK[i], vert[2]->xyz[tv], 1 + stI[i], verts[0][tv], 1, + stJ[i], verts[1][tv], 1, + stK[i], verts[2][tv], 1 ); D1 = Det3x3( - vert[0]->xyz[sv], stI[i], 1, - vert[1]->xyz[sv], stJ[i], 1, - vert[2]->xyz[sv], stK[i], 1 + verts[0][sv], stI[i], 1, + verts[1][sv], stJ[i], 1, + verts[2][sv], stK[i], 1 ); D2 = Det3x3( - vert[0]->xyz[sv], vert[0]->xyz[tv], stI[i], - vert[1]->xyz[sv], vert[1]->xyz[tv], stJ[i], - vert[2]->xyz[sv], vert[2]->xyz[tv], stK[i] + verts[0][sv], verts[0][tv], stI[i], + verts[1][sv], verts[1][tv], stJ[i], + verts[2][sv], verts[2][tv], stK[i] ); - sts[i] = { D0 / D, D1 / D, D2 / D }; - //Sys_Printf( "%.3f %.3f %.3f \n", sts[i][0], sts[i][1], sts[i][2] ); + texMat[i] = { D0 / D, D1 / D, D2 / D }; + //Sys_Printf( "%.3f %.3f %.3f \n", texMat[i][0], texMat[i][1], texMat[i][2] ); } } else{ fprintf( stderr, "degenerate triangle found when solving texDef equations\n" ); // FIXME add stuff here - sts[0] = { 2.0, 0.0, 0.0 }; - sts[1] = { 0.0, -2.0, 0.0 }; + texMat[0] = { 2.0, 0.0, 0.0 }; + texMat[1] = { 0.0, -2.0, 0.0 }; } // now we must solve: // // now we must invert: @@ -558,26 +563,26 @@ static void ConvertBrush( FILE *f, int bspBrushNum, const Vector3& origin, bool // vecsrotscaled[1][sv] = ns / scale[1]; // vecsrotscaled[1][tv] = nt / scale[1]; #if 0 - scale[0] = 1.0 / vector2_length( sts[0].vec2() ); - scale[1] = 1.0 / vector2_length( sts[1].vec2() ); - rotate = radians_to_degrees( atan2( sts[0][1] * vecs[0][sv] - sts[1][0] * vecs[1][tv], sts[0][0] * vecs[0][sv] + sts[1][1] * vecs[1][tv] ) ); - shift[0] = buildSide.shaderInfo->shaderWidth * FRAC( sts[0][2] / buildSide.shaderInfo->shaderWidth ); - shift[1] = buildSide.shaderInfo->shaderHeight * FRAC( sts[1][2] / buildSide.shaderInfo->shaderHeight ); + scale[0] = 1.0 / vector2_length( texMat[0].vec2() ); + scale[1] = 1.0 / vector2_length( texMat[1].vec2() ); + rotate = radians_to_degrees( atan2( texMat[0][1] * vecs[0][sv] - texMat[1][0] * vecs[1][tv], texMat[0][0] * vecs[0][sv] + texMat[1][1] * vecs[1][tv] ) ); + shift[0] = buildSide.shaderInfo->shaderWidth * FRAC( texMat[0][2] / buildSide.shaderInfo->shaderWidth ); + shift[1] = buildSide.shaderInfo->shaderHeight * FRAC( texMat[1][2] / buildSide.shaderInfo->shaderHeight ); #else // Texdef_fromTransform() from brush_primit.cpp, flawless unlike upper - scale[0] = 1.0 / vector2_length( sts[0].vec2() ); - scale[1] = 1.0 / vector2_length( sts[1].vec2() ); + scale[0] = 1.0 / vector2_length( texMat[0].vec2() ); + scale[1] = 1.0 / vector2_length( texMat[1].vec2() ); - rotate = -radians_to_degrees( atan2( -sts[0][1], sts[0][0] ) ); + rotate = -radians_to_degrees( atan2( -texMat[0][1], texMat[0][0] ) ); if ( rotate == -180.0f ) { rotate = 180.0f; } - shift[0] = buildSide.shaderInfo->shaderWidth * FRAC( sts[0][2] / buildSide.shaderInfo->shaderWidth ); - shift[1] = buildSide.shaderInfo->shaderHeight * FRAC( sts[1][2] / buildSide.shaderInfo->shaderHeight ); + shift[0] = buildSide.shaderInfo->shaderWidth * FRAC( texMat[0][2] / buildSide.shaderInfo->shaderWidth ); + shift[1] = buildSide.shaderInfo->shaderHeight * FRAC( texMat[1][2] / buildSide.shaderInfo->shaderHeight ); // If the 2d cross-product of the x and y axes is positive, one of the axes has a negative scale. - if ( vector2_cross( Vector2( sts[0][0], sts[0][1] ), Vector2( sts[1][0], sts[1][1] ) ) > 0 ) { + if ( vector2_cross( Vector2( texMat[0][0], texMat[0][1] ), Vector2( texMat[1][0], texMat[1][1] ) ) > 0 ) { if ( rotate >= 180.0f ) { rotate -= 180.0f; scale[0] = -scale[0]; @@ -791,9 +796,9 @@ static void ConvertModel( FILE *f, const bspModel_t& model, const Vector3& origi for ( int i = 0; i < model.numBSPBrushes; ++i ) { if( fast ) - ConvertBrushFast( f, model.firstBSPBrush + i, origin, brushPrimitives ); + ConvertBrushFast( f, model, model.firstBSPBrush + i, origin, brushPrimitives ); else - ConvertBrush( f, model.firstBSPBrush + i, origin, brushPrimitives ); + ConvertBrush( f, model, model.firstBSPBrush + i, origin, brushPrimitives ); } /* go through each drawsurf in the model */