From f8b2b1f25e7e195c0c11e3d2e2ddf308562de77f Mon Sep 17 00:00:00 2001 From: Garux Date: Tue, 1 Aug 2017 13:59:31 +0300 Subject: [PATCH] Q3map2: * decompiling: fix: broken brushes, empty brush definitions; shut down too usual warnings; with -force tries to decompile model autoclip too * decompiling: -fast mode for BSPToMap conversion Radiant: misc... * _setmaxstdio(2048): tested max pk3s count: 1021 * curve: deform (randomize Z points coord at given amount) --- radiant/main.cpp | 1 + radiant/patchmanip.cpp | 96 +++++++++++ tools/quake3/q3map2/convert_map.c | 268 +++++++++++++++++++++++++++--- tools/quake3/q3map2/main.c | 3 + tools/quake3/q3map2/q3map2.h | 1 + 5 files changed, 347 insertions(+), 22 deletions(-) diff --git a/radiant/main.cpp b/radiant/main.cpp index addfd576..f19eb4db 100644 --- a/radiant/main.cpp +++ b/radiant/main.cpp @@ -559,6 +559,7 @@ int main( int argc, char* argv[] ){ } FreeLibrary( lib ); } + _setmaxstdio(2048); #endif gtk_disable_setlocale(); diff --git a/radiant/patchmanip.cpp b/radiant/patchmanip.cpp index fbb89e05..9ea7c5d8 100644 --- a/radiant/patchmanip.cpp +++ b/radiant/patchmanip.cpp @@ -112,6 +112,7 @@ void Patch_makeCaps( Patch& patch, scene::Instance& instance, EPatchCap type, co } } + typedef std::vector InstanceVector; class PatchStoreInstance @@ -171,6 +172,30 @@ void Scene_PatchDoCap_Selected( scene::Graph& graph, const char* shader ){ } } +void Patch_deform( Patch& patch, scene::Instance& instance, const int deform ){ + patch.undoSave(); + + for (PatchControlIter i = patch.begin(); i != patch.end(); ++i) + { + PatchControl& control = *i; + int randomNumber = int( deform * (float(std::rand()) / float(RAND_MAX))); + control.m_vertex[2] += randomNumber; + } + + patch.controlPointsChanged(); +} + +void Scene_PatchDeform( scene::Graph& graph, const int deform ) +{ + InstanceVector instances; + Scene_forEachVisibleSelectedPatchInstance( PatchStoreInstance( instances ) ); + for ( InstanceVector::const_iterator i = instances.begin(); i != instances.end(); ++i ) + { + Patch_deform( *Node_getPatch( ( *i )->path().top() ), *( *i ), deform ); + } + +} + Patch* Scene_GetUltimateSelectedVisiblePatch(){ if ( GlobalSelectionSystem().countSelected() != 0 ) { scene::Node& node = GlobalSelectionSystem().ultimateSelected().path().top(); @@ -585,6 +610,14 @@ void Patch_NaturalTexture(){ Scene_PatchNaturalTexture_Selected( GlobalSceneGraph() ); } +void DoPatchDeformDlg(); + +void Patch_Deform(){ + UndoableCommand undo( "patchDeform" ); + + DoPatchDeformDlg(); +} + @@ -698,6 +731,7 @@ void Patch_registerCommands(){ GlobalCommands_insert( "CycleCapTexturePatch", FreeCaller(), Accelerator( 'N', (GdkModifierType)GDK_SHIFT_MASK ) ); GlobalCommands_insert( "MakeOverlayPatch", FreeCaller(), Accelerator( 'Y' ) ); GlobalCommands_insert( "ClearPatchOverlays", FreeCaller(), Accelerator( 'L', (GdkModifierType)GDK_CONTROL_MASK ) ); + GlobalCommands_insert( "PatchDeform", FreeCaller() ); } void Patch_constructToolbar( GtkToolbar* toolbar ){ @@ -804,6 +838,8 @@ void Patch_constructMenu( GtkMenu* menu ){ create_menu_item_with_mnemonic( menu_in_menu, "Set", "MakeOverlayPatch" ); create_menu_item_with_mnemonic( menu_in_menu, "Clear", "ClearPatchOverlays" ); } + menu_separator( menu ); + create_menu_item_with_mnemonic( menu, "Deform...", "PatchDeform" ); } @@ -936,6 +972,66 @@ void DoNewPatchDlg( EPatchPrefab prefab, int minrows, int mincols, int defrows, } +void DoPatchDeformDlg(){ + ModalDialog dialog; + GtkWidget* deformW; + + GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Patch deform", G_CALLBACK( dialog_delete_callback ), &dialog ); + + GtkAccelGroup* accel = gtk_accel_group_new(); + gtk_window_add_accel_group( window, accel ); + + { + GtkHBox* hbox = create_dialog_hbox( 4, 4 ); + gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) ); + { + GtkTable* table = create_dialog_table( 2, 2, 4, 4 ); + gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 ); + { + GtkLabel* label = GTK_LABEL( gtk_label_new( "Max deform:" ) ); + gtk_widget_show( GTK_WIDGET( label ) ); + gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1, + (GtkAttachOptions) ( GTK_FILL ), + (GtkAttachOptions) ( 0 ), 0, 0 ); + gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + } + { + GtkWidget* entry = gtk_entry_new(); + gtk_entry_set_text( GTK_ENTRY( entry ), "16" ); + gtk_widget_show( entry ); + gtk_table_attach( table, entry, 1, 2, 0, 1, + (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ), + (GtkAttachOptions) ( 0 ), 0, 0 ); + + deformW = entry; + } + } + { + GtkVBox* vbox = create_dialog_vbox( 4 ); + gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 ); + { + GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &dialog ); + gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 ); + widget_make_default( GTK_WIDGET( button ) ); + gtk_widget_grab_focus( GTK_WIDGET( button ) ); + gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 ); + } + { + GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &dialog ); + gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 ); + gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 ); + } + } + } + + if ( modal_dialog_show( window, dialog ) == eIDOK ) { + int deform = static_cast( atoi( gtk_entry_get_text( GTK_ENTRY( deformW ) ) ) ); + Scene_PatchDeform( GlobalSceneGraph(), deform ); + } + + gtk_widget_destroy( GTK_WIDGET( window ) ); +} + EMessageBoxReturn DoCapDlg( ECapDialog* type ){ diff --git a/tools/quake3/q3map2/convert_map.c b/tools/quake3/q3map2/convert_map.c index 04c4a4d0..3081ef77 100644 --- a/tools/quake3/q3map2/convert_map.c +++ b/tools/quake3/q3map2/convert_map.c @@ -88,13 +88,16 @@ void GetBestSurfaceTriangleMatchForBrushside( side_t *buildSide, bspDrawVert_t * 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 ) { + VectorSubtract( vert[0]->normal, buildPlane->normal, normdiff ); + if ( VectorLength( normdiff ) >= normalEpsilon ) { continue; } - VectorSubtract( vert[1]->normal, buildPlane->normal, normdiff ); if ( VectorLength( normdiff ) >= normalEpsilon ) { + VectorSubtract( vert[1]->normal, buildPlane->normal, normdiff ); + if ( VectorLength( normdiff ) >= normalEpsilon ) { continue; } - VectorSubtract( vert[2]->normal, buildPlane->normal, normdiff ); if ( VectorLength( normdiff ) >= normalEpsilon ) { + VectorSubtract( vert[2]->normal, buildPlane->normal, normdiff ); + if ( VectorLength( normdiff ) >= normalEpsilon ) { continue; } } @@ -106,7 +109,8 @@ void GetBestSurfaceTriangleMatchForBrushside( side_t *buildSide, bspDrawVert_t * VectorSubtract( vert[2]->xyz, vert[0]->xyz, v2v0 ); CrossProduct( v2v0, v1v0, norm ); VectorNormalize( norm, norm ); - VectorSubtract( norm, buildPlane->normal, normdiff ); if ( VectorLength( normdiff ) >= normalEpsilon ) { + VectorSubtract( norm, buildPlane->normal, normdiff ); + if ( VectorLength( normdiff ) >= normalEpsilon ) { continue; } } @@ -220,17 +224,83 @@ static void ConvertOriginBrush( FILE *f, int num, vec3_t origin, qboolean brushP fprintf( f, "\t}\n\n" ); } -static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qboolean brushPrimitives ){ - int i, j; +static void ConvertBrushFast( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qboolean brushPrimitives ){ + int i; bspBrushSide_t *side; side_t *buildSide; bspShader_t *shader; char *texture; plane_t *buildPlane; vec3_t pts[ 3 ]; - bspDrawVert_t *vert[3]; + /* clear out build brush */ + for ( i = 0; i < buildBrush->numsides; i++ ) + { + buildSide = &buildBrush->sides[ i ]; + if ( buildSide->winding != NULL ) { + FreeWinding( buildSide->winding ); + buildSide->winding = NULL; + } + } + buildBrush->numsides = 0; + + qboolean modelclip = qfalse; + /* try to guess if thats model clip */ + if ( force ){ + int notNoShader = 0; + modelclip = qtrue; + for ( i = 0; i < brush->numSides; i++ ) + { + /* get side */ + side = &bspBrushSides[ brush->firstSide + i ]; + + /* get shader */ + if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) { + continue; + } + shader = &bspShaders[ side->shaderNum ]; + //"noshader" happens on modelclip and unwanted sides ( usually breaking complex brushes ) + if( Q_stricmp( shader->shader, "noshader" ) ){ + notNoShader++; + } + if( notNoShader > 1 ){ + modelclip = qfalse; + break; + } + } + } + + /* iterate through bsp brush sides */ + for ( i = 0; i < brush->numSides; i++ ) + { + /* get side */ + side = &bspBrushSides[ brush->firstSide + i ]; + + /* get shader */ + if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) { + continue; + } + shader = &bspShaders[ side->shaderNum ]; + //"noshader" happens on modelclip and unwanted sides ( usually breaking complex brushes ) + if( !Q_stricmp( shader->shader, "default" ) || ( !Q_stricmp( shader->shader, "noshader" ) && !modelclip ) ) + continue; + + /* add build side */ + buildSide = &buildBrush->sides[ buildBrush->numsides ]; + buildBrush->numsides++; + + /* tag it */ + buildSide->shaderInfo = ShaderInfoForShader( shader->shader ); + buildSide->planenum = side->planeNum; + buildSide->winding = NULL; + } + + if ( !CreateBrushWindings( buildBrush ) ) { + //Sys_Printf( "CreateBrushWindings failed\n" ); + return; + } + /* start brush */ fprintf( f, "\t// brush %d\n", num ); fprintf( f, "\t{\n" ); @@ -239,6 +309,81 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qb fprintf( f, "\t{\n" ); } + /* iterate through build brush sides */ + for ( i = 0; i < buildBrush->numsides; i++ ) + { + /* get build side */ + buildSide = &buildBrush->sides[ i ]; + + /* get plane */ + buildPlane = &mapplanes[ buildSide->planenum ]; + + /* dummy check */ + if ( buildSide->shaderInfo == NULL || buildSide->winding == NULL ) { + continue; + } + + /* get texture name */ + if ( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) ) { + texture = buildSide->shaderInfo->shader + 9; + } + else{ + texture = buildSide->shaderInfo->shader; + } + + { + vec3_t vecs[ 2 ]; + MakeNormalVectors( buildPlane->normal, vecs[ 0 ], vecs[ 1 ] ); + VectorMA( vec3_origin, buildPlane->dist, buildPlane->normal, pts[ 0 ] ); + VectorAdd( pts[ 0 ], origin, pts[ 0 ] ); + VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] ); + VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] ); + } + + { + 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", + 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 ], + 1.0f / 32.0f, 0.0f, 0.0f, + 0.0f, 1.0f / 32.0f, 0.0f, + texture, + 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", + 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, + 0.0f, 0.0f, 0.0f, 0.5f, 0.5f, + 0 + ); + } + } + } + + /* 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]; + + /* clear out build brush */ for ( i = 0; i < buildBrush->numsides; i++ ) { @@ -250,6 +395,32 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qb } buildBrush->numsides = 0; + qboolean modelclip = qfalse; + /* try to guess if thats model clip */ + if ( force ){ + int notNoShader = 0; + modelclip = qtrue; + for ( i = 0; i < brush->numSides; i++ ) + { + /* get side */ + side = &bspBrushSides[ brush->firstSide + i ]; + + /* get shader */ + if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) { + continue; + } + shader = &bspShaders[ side->shaderNum ]; + //"noshader" happens on modelclip and unwanted sides ( usually breaking complex brushes ) + if( Q_stricmp( shader->shader, "noshader" ) ){ + notNoShader++; + } + if( notNoShader > 1 ){ + modelclip = qfalse; + break; + } + } + } + /* iterate through bsp brush sides */ for ( i = 0; i < brush->numSides; i++ ) { @@ -261,8 +432,9 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qb continue; } shader = &bspShaders[ side->shaderNum ]; - //if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) ) - // continue; + //"noshader" happens on modelclip and unwanted sides ( usually breaking complex brushes ) + if( !Q_stricmp( shader->shader, "default" ) || ( !Q_stricmp( shader->shader, "noshader" ) && !modelclip ) ) + continue; /* add build side */ buildSide = &buildBrush->sides[ buildBrush->numsides ]; @@ -276,10 +448,18 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qb /* make brush windings */ if ( !CreateBrushWindings( buildBrush ) ) { - Sys_Printf( "CreateBrushWindings failed\n" ); + //Sys_Printf( "CreateBrushWindings failed\n" ); return; } + /* start brush */ + fprintf( f, "\t// brush %d\n", num ); + fprintf( f, "\t{\n" ); + if ( brushPrimitives ) { + fprintf( f, "\tbrushDef\n" ); + fprintf( f, "\t{\n" ); + } + /* iterate through build brush sides */ for ( i = 0; i < buildBrush->numsides; i++ ) { @@ -314,13 +494,51 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qb texture = buildSide->shaderInfo->shader; } - /* get plane points and offset by origin */ - for ( j = 0; j < 3; j++ ) - { - VectorAdd( buildSide->winding->p[ j ], origin, pts[ j ] ); - //% pts[ j ][ 0 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 0 ] * SNAP_FLOAT_TO_INT + 0.5f ); - //% pts[ j ][ 1 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 1 ] * SNAP_FLOAT_TO_INT + 0.5f ); - //% pts[ j ][ 2 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 2 ] * SNAP_FLOAT_TO_INT + 0.5f ); + /* recheck and fix winding points, fails occur somehow */ + int match = 0; + for ( j = 0; j < buildSide->winding->numpoints; j++ ){ + if ( fabs( DotProduct( buildSide->winding->p[ j ], buildPlane->normal ) - buildPlane->dist ) >= distanceEpsilon ) { + continue; + } + else{ + VectorCopy( buildSide->winding->p[ j ], pts[ match ] ); + match++; + /* got 3 fine points? */ + if( match > 2 ) + break; + } + } + + if( match > 2 ){ + //Sys_Printf( "pointsKK " ); + vec4_t testplane; + if ( PlaneFromPoints( testplane, pts[0], pts[1], pts[2] ) ){ + if( !PlaneEqual( buildPlane, testplane, testplane[3] ) ){ + //Sys_Printf( "1: %f %f %f %f\n2: %f %f %f %f\n", buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2], buildPlane->dist, testplane[0], testplane[1], testplane[2], testplane[3] ); + match--; + //Sys_Printf( "planentEQ " ); + } + } + else{ + match--; + } + } + + + if( match > 2 ){ + //Sys_Printf( "ok " ); + /* offset by origin */ + for ( j = 0; j < 3; j++ ) + VectorAdd( pts[ j ], origin, pts[ j ] ); + } + else{ + vec3_t vecs[ 2 ]; + MakeNormalVectors( buildPlane->normal, vecs[ 0 ], vecs[ 1 ] ); + VectorMA( vec3_origin, buildPlane->dist, buildPlane->normal, pts[ 0 ] ); + VectorAdd( pts[ 0 ], origin, pts[ 0 ] ); + VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] ); + VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] ); + //Sys_Printf( "not\n" ); } if ( vert[0] && vert[1] && vert[2] ) { @@ -495,20 +713,21 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qb } else { - vec3_t vecs[ 2 ]; + //vec3_t vecs[ 2 ]; if ( strncmp( buildSide->shaderInfo->shader, "textures/common/", 16 ) ) { if ( strcmp( buildSide->shaderInfo->shader, "noshader" ) ) { if ( strcmp( buildSide->shaderInfo->shader, "default" ) ) { - fprintf( stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader ); + //fprintf( stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader ); texture = "common/WTF"; } } } - +/* MakeNormalVectors( buildPlane->normal, vecs[ 0 ], vecs[ 1 ] ); VectorMA( vec3_origin, buildPlane->dist, buildPlane->normal, pts[ 0 ] ); - VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] ); VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] ); + VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] ); +*/ 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", pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ], @@ -717,7 +936,12 @@ static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origi { num = i + model->firstBSPBrush; brush = &bspBrushes[ num ]; - ConvertBrush( f, num, brush, origin, brushPrimitives ); + if( fast ){ + ConvertBrushFast( f, num, brush, origin, brushPrimitives ); + } + else{ + ConvertBrush( f, num, brush, origin, brushPrimitives ); + } } /* free the build brush */ diff --git a/tools/quake3/q3map2/main.c b/tools/quake3/q3map2/main.c index 9841b4f1..2e97c89d 100644 --- a/tools/quake3/q3map2/main.c +++ b/tools/quake3/q3map2/main.c @@ -3628,6 +3628,9 @@ int ConvertBSPMain( int argc, char **argv ){ meta = qtrue; patchMeta = qtrue; } + else if ( !strcmp( argv[ i ], "-fast" ) ) { + fast = qtrue; + } } LoadShaderInfo(); diff --git a/tools/quake3/q3map2/q3map2.h b/tools/quake3/q3map2/q3map2.h index e0c7a0cb..fbc2b5e5 100644 --- a/tools/quake3/q3map2/q3map2.h +++ b/tools/quake3/q3map2/q3map2.h @@ -1590,6 +1590,7 @@ void MakeNormalVectors( vec3_t forward, vec3_t right, vec /* map.c */ void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups ); int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ); +qboolean PlaneEqual( plane_t *p, vec3_t normal, vec_t dist ); int PlaneTypeForNormal( vec3_t normal ); void AddBrushBevels( void ); brush_t *FinishBrush( qboolean noCollapseGroups ); -- 2.39.2