* fix deformvertexes autosprite2 on brushes and models

broken for brushes in c166e4214e by new triangualtion
broken for models forever
fixes https://github.com/TTimo/GtkRadiant/issues/658
This commit is contained in:
Garux
2024-12-17 09:29:30 +05:00
parent 44006f8caa
commit dbcdb4044e
2 changed files with 95 additions and 8 deletions
+2
View File
@@ -178,6 +178,7 @@ Q3map2:
* -nobrushsnap: disable brush vertices snapping (of drawsurfs) (experimental, keep eye on meta merge efficiency)
* improved brush faces triangulation wrt degenerate triangles production (non -maxarea algorithm)
* -globalflag <surfaceparm>: add surface flag to every bsp shader. Reusable, e.g. -globalflag slick -globalflag nodamage.
* fix deformvertexes autosprite2 on brushes and models
@@ -195,6 +196,7 @@ MBSPC:
* append _decompiled suffix to decompiled map file names
* improve decompilation quality of Q1, HL maps greatly (texturing correctness, less brushes)
* -lessbrushes switch: less brushes when decompiling Q1, HL maps at the expense of texturing
* fix build speed penalty due to terminal output
+93 -8
View File
@@ -2258,6 +2258,89 @@ static void EmitPatchSurface( const entity_t& e, mapDrawSurface_t *ds ){
numSurfacesByType[ static_cast<std::size_t>( ds->type ) ]++;
}
/*
Autosprite2Deform() function in vanilla Q3 engine and most of sourceports
produces inconsistent results, which depend on vertex order and indexing.
Try to please that windy lady.
*/
static void FixAutosprite2Surface( mapDrawSurface_t *ds ){
if( ds->numVerts != 4 || ds->numIndexes != 6 ){
Sys_Warning( "autosprite2 surface: ds->numVerts != 4 or ds->numIndexes != 6: must be simple rectangle\n" );
return;
}
Plane3f plane;
if( !PlaneFromPoints( plane, ds->verts[ds->indexes[0]].xyz, ds->verts[ds->indexes[1]].xyz, ds->verts[ds->indexes[2]].xyz ) ){
Sys_Warning( "autosprite2 surface: degenerate triangle\n" );
return;
}
// reproduce Autosprite2Deform() calculations
const int edgeVerts[6][2] = {
{ 0, 1 },
{ 0, 2 },
{ 0, 3 },
{ 1, 2 },
{ 1, 3 },
{ 2, 3 }
};
float lengths[2] = { 999999, 999999 };
int edgeIdx[2] = {0};
// identify the two shortest edges
for ( int j = 0; j < 6; ++j ) {
const float l = vector3_length_squared( ds->verts[edgeVerts[j][0]].xyz - ds->verts[edgeVerts[j][1]].xyz );
if ( l < lengths[0] ) {
edgeIdx[1] = edgeIdx[0];
lengths[1] = lengths[0];
edgeIdx[0] = j;
lengths[0] = l;
} else if ( l < lengths[1] ) {
edgeIdx[1] = j;
lengths[1] = l;
}
}
// ref edges
const bspDrawVert_t *edges[2][2] = { { ds->verts + edgeVerts[edgeIdx[0]][0], ds->verts + edgeVerts[edgeIdx[0]][1] },
{ ds->verts + edgeVerts[edgeIdx[1]][0], ds->verts + edgeVerts[edgeIdx[1]][1] } };
if( edges[0][0] == edges[1][0]
|| edges[0][0] == edges[1][1]
|| edges[0][1] == edges[1][0]
|| edges[0][1] == edges[1][1] ){
Sys_Warning( "autosprite2 surface: two shortest edges share a vertex\n" ); // note also fails on exact square
return;
}
// find the midpoints
const Vector3 mid[2] = { vector3_mid( edges[0][0]->xyz, edges[0][1]->xyz ),
vector3_mid( edges[1][0]->xyz, edges[1][1]->xyz ) };
// find the vector of the major axis
const Vector3 major = mid[1] - mid[0];
// cross this with the view direction to get minor axis
const Vector3 minor = vector3_cross( major, -plane.normal() );
/* the rest of Autosprite2Deform() algorithm is srsly hot trash
thus simply force the order and indexing, which are known as working */
/* 1-----------2 C C 1-----------2 A ^minor
| | | | |
B 0-----------3 A B 0-----------3 -----------> major */
if( vector3_dot( edges[0][1]->xyz - edges[0][0]->xyz, minor ) < 0 )
std::swap( edges[0][0], edges[0][1] );
if( vector3_dot( edges[1][1]->xyz - edges[1][0]->xyz, minor ) > 0 )
std::swap( edges[1][0], edges[1][1] );
const bspDrawVert_t outverts[4] = { *edges[0][0], *edges[0][1], *edges[1][0], *edges[1][1] };
std::copy_n( outverts, 4, ds->verts );
std::copy_n( std::array<int, 6>{ 3, 0, 2, 2, 0, 1 }.data(), 6, ds->indexes );
}
/*
OptimizeTriangleSurface() - ydnar
optimizes the vertex/index data in a triangle surface
@@ -2383,16 +2466,12 @@ static void OptimizeTriangleSurface( mapDrawSurface_t *ds ){
*/
static void EmitTriangleSurface( mapDrawSurface_t *ds ){
int i, temp;
/* invert the surface if necessary */
if ( ds->backSide || ds->shaderInfo->invert ) {
/* walk the indexes, reverse the triangle order */
for ( i = 0; i < ds->numIndexes; i += 3 )
for ( int i = 0; i < ds->numIndexes; i += 3 )
{
temp = ds->indexes[ i ];
ds->indexes[ i ] = ds->indexes[ i + 1 ];
ds->indexes[ i + 1 ] = temp;
std::swap( ds->indexes[ i ], ds->indexes[ i + 1 ] );
}
/* walk the verts, flip the normal */
@@ -2403,6 +2482,12 @@ static void EmitTriangleSurface( mapDrawSurface_t *ds ){
vector3_negate( ds->lightmapVecs[ 2 ] );
}
if( ds->shaderInfo->autosprite
&& ds->shaderInfo->shaderText != nullptr
&& strIstr( ds->shaderInfo->shaderText, "autosprite2" ) != nullptr ){
FixAutosprite2Surface( ds );
}
/* allocate a new surface */
bspDrawSurface_t& out = bspDrawSurfaces.emplace_back();
ds->outputNum = bspDrawSurfaces.size() - 1;
@@ -2443,7 +2528,7 @@ static void EmitTriangleSurface( mapDrawSurface_t *ds ){
bspDrawVert_t *a, *b, *c;
/* walk triangle list */
for ( i = 0; i < ds->numIndexes; i += 3 )
for ( int i = 0; i < ds->numIndexes; i += 3 )
{
/* get verts */
a = &ds->verts[ ds->indexes[ i ] ];
@@ -2461,7 +2546,7 @@ static void EmitTriangleSurface( mapDrawSurface_t *ds ){
}
/* RBSP */
for ( i = 0; i < MAX_LIGHTMAPS; i++ )
for ( int i = 0; i < MAX_LIGHTMAPS; i++ )
{
out.lightmapNum[ i ] = -3;
out.lightmapStyles[ i ] = LS_NONE;