* Brush->AutoCaulk Selected (F4); camera must be there, where legit player respawn could be, i.e. close to selection and not inside of a brush
This commit is contained in:
parent
00bb22e458
commit
12d010446b
|
|
@ -1578,6 +1578,7 @@ void Brush_constructMenu( GtkMenu* menu ){
|
||||||
create_menu_item_with_mnemonic( menu, "Reset Texture", "TextureReset/Cap" );
|
create_menu_item_with_mnemonic( menu, "Reset Texture", "TextureReset/Cap" );
|
||||||
create_menu_item_with_mnemonic( menu, "Copy Face Texture", "Copy" );
|
create_menu_item_with_mnemonic( menu, "Copy Face Texture", "Copy" );
|
||||||
create_menu_item_with_mnemonic( menu, "Paste Face Texture", "Paste" );
|
create_menu_item_with_mnemonic( menu, "Paste Face Texture", "Paste" );
|
||||||
|
create_menu_item_with_mnemonic( menu, "AutoCaulk Selected", "AutoCaulkSelected" );
|
||||||
|
|
||||||
command_connect_accelerator( "Brush3Sided" );
|
command_connect_accelerator( "Brush3Sided" );
|
||||||
command_connect_accelerator( "Brush4Sided" );
|
command_connect_accelerator( "Brush4Sided" );
|
||||||
|
|
|
||||||
255
radiant/map.cpp
255
radiant/map.cpp
|
|
@ -2330,6 +2330,260 @@ void DoFind(){
|
||||||
gtk_widget_destroy( GTK_WIDGET( window ) );
|
gtk_widget_destroy( GTK_WIDGET( window ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "filterbar.h"
|
||||||
|
////
|
||||||
|
void map_autocaulk_selected(){
|
||||||
|
if ( Map_Unnamed( g_map ) ) {
|
||||||
|
if( !Map_SaveAs() )
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
class DeselectTriggers : public scene::Graph::Walker
|
||||||
|
{
|
||||||
|
mutable const scene::Instance* m_trigger = 0;
|
||||||
|
public:
|
||||||
|
bool pre( const scene::Path& path, scene::Instance& instance ) const {
|
||||||
|
if( path.size() == 2 ){
|
||||||
|
Entity* entity = Node_getEntity( path.top() );
|
||||||
|
if( entity != 0 && entity->isContainer() && string_equal_nocase_n( entity->getEntityClass().name(), "trigger_", 8 )
|
||||||
|
&& ( instance.childSelected() || instance.isSelected() ) )
|
||||||
|
m_trigger = &instance;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void post( const scene::Path& path, scene::Instance& instance ) const {
|
||||||
|
if( m_trigger )
|
||||||
|
Instance_setSelected( instance, false );
|
||||||
|
if( m_trigger == &instance )
|
||||||
|
m_trigger = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
GlobalSceneGraph().traverse( DeselectTriggers() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( GlobalSelectionSystem().countSelected() == 0 ){
|
||||||
|
globalErrorStream() << "map_autocaulk_selected(): nothing is selected\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopeDisableScreenUpdates disableScreenUpdates( "processing", "autocaulk" );
|
||||||
|
|
||||||
|
StringOutputStream filename( 256 );
|
||||||
|
filename << StringRange( g_map.m_name.c_str(), path_get_filename_base_end( g_map.m_name.c_str() ) ) << "_ac.map";
|
||||||
|
|
||||||
|
{// write .map
|
||||||
|
const Vector3 spawn( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ) );
|
||||||
|
Vector3 mins, maxs;
|
||||||
|
Select_GetBounds( mins, maxs );
|
||||||
|
mins -= Vector3( 1024, 1024, 1024 );
|
||||||
|
maxs += Vector3( 1024, 1024, 1024 );
|
||||||
|
|
||||||
|
if( !aabb_intersects_point( aabb_for_minmax( mins, maxs ), spawn ) ){
|
||||||
|
globalErrorStream() << "map_autocaulk_selected(): camera must be near selection!\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFileOutputStream file( filename.c_str() );
|
||||||
|
if ( file.failed() ) {
|
||||||
|
globalErrorStream() << "writting " << filename.c_str() << " failure\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// all brushes to the worldspawn
|
||||||
|
file << "{\n"
|
||||||
|
"\"classname\" \"worldspawn\"";
|
||||||
|
TokenWriter& writer = GlobalScripLibModule::getTable().m_pfnNewSimpleTokenWriter( file );
|
||||||
|
class WriteBrushesWalker : public scene::Traversable::Walker
|
||||||
|
{
|
||||||
|
TokenWriter& m_writer;
|
||||||
|
public:
|
||||||
|
WriteBrushesWalker( TokenWriter& writer )
|
||||||
|
: m_writer( writer ){
|
||||||
|
}
|
||||||
|
bool pre( scene::Node& node ) const {
|
||||||
|
if( Node_getBrush( node ) ){
|
||||||
|
NodeTypeCast<MapExporter>::cast( node )->exportTokens( m_writer );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Map_Traverse_Selected( GlobalSceneGraph().root(), WriteBrushesWalker( writer ) );
|
||||||
|
// plus box
|
||||||
|
scene::Node* box[6];
|
||||||
|
for ( std::size_t i = 0; i < 6; ++i ){
|
||||||
|
box[i] = &GlobalBrushCreator().createBrush();
|
||||||
|
box[i]->IncRef();
|
||||||
|
}
|
||||||
|
ConstructRegionBrushes( box, mins, maxs );
|
||||||
|
for ( std::size_t i = 0; i < 6; ++i ){
|
||||||
|
NodeTypeCast<MapExporter>::cast( *box[i] )->exportTokens( writer );
|
||||||
|
box[i]->DecRef();
|
||||||
|
}
|
||||||
|
// close world
|
||||||
|
file << "\n}\n";
|
||||||
|
// spawn
|
||||||
|
file << "{\n"
|
||||||
|
"\"classname\" \"info_player_start\"\n"
|
||||||
|
"\"origin\" \"" << spawn[0] << " " << spawn[1] << " " << spawn[2] << "\"\n"
|
||||||
|
"}\n";
|
||||||
|
// point entities
|
||||||
|
const MapFormat& format = MapFormat_forFile( filename.c_str() );
|
||||||
|
auto traverse_selected_point_entities = []( scene::Node& root, const scene::Traversable::Walker& walker ){
|
||||||
|
scene::Traversable* traversable = Node_getTraversable( root );
|
||||||
|
if ( traversable != 0 ) {
|
||||||
|
class selected_point_entities_walker : public scene::Traversable::Walker
|
||||||
|
{
|
||||||
|
const scene::Traversable::Walker& m_walker;
|
||||||
|
mutable bool m_skip;
|
||||||
|
public:
|
||||||
|
selected_point_entities_walker( const scene::Traversable::Walker& walker )
|
||||||
|
: m_walker( walker ), m_skip( false ){
|
||||||
|
}
|
||||||
|
bool pre( scene::Node& node ) const {
|
||||||
|
Entity* entity = Node_getEntity( node );
|
||||||
|
if( !node.isRoot() && entity != 0 && !entity->isContainer() && Node_instanceSelected( node ) ) {
|
||||||
|
m_walker.pre( node );
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
m_skip = true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void post( scene::Node& node ) const {
|
||||||
|
if( m_skip )
|
||||||
|
m_skip = false;
|
||||||
|
else
|
||||||
|
m_walker.post( node );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
traversable->traverse( selected_point_entities_walker( walker ) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
format.writeGraph( GlobalSceneGraph().root(), traverse_selected_point_entities, file );
|
||||||
|
|
||||||
|
writer.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // compile
|
||||||
|
StringOutputStream str( 256 );
|
||||||
|
str << AppPath_get() << "q3map2." << RADIANT_EXECUTABLE
|
||||||
|
<< " -game quake3"
|
||||||
|
<< " -fs_basepath \"" << EnginePath_get()
|
||||||
|
<< "\" -fs_homepath \"" << g_qeglobals.m_userEnginePath.c_str()
|
||||||
|
<< "\" -fs_game " << gamename_get()
|
||||||
|
<< " -autocaulk -fulldetail"
|
||||||
|
<< " \"" << filename.c_str() << "\"";
|
||||||
|
// run
|
||||||
|
Q_Exec( NULL, str.c_str(), NULL, false, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::map<std::size_t, CopiedString> CaulkMap;
|
||||||
|
CaulkMap map;
|
||||||
|
{ // load
|
||||||
|
filename.clear();
|
||||||
|
filename << StringRange( g_map.m_name.c_str(), path_get_filename_base_end( g_map.m_name.c_str() ) ) << "_ac.caulk";
|
||||||
|
|
||||||
|
TextFileInputStream file( filename.c_str() );
|
||||||
|
if( file.failed() ){
|
||||||
|
globalErrorStream() << "reading " << filename.c_str() << " failure\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( file );
|
||||||
|
while( 1 ){
|
||||||
|
const char* num = tokeniser.getToken();
|
||||||
|
if( !num )
|
||||||
|
break;
|
||||||
|
std::size_t n;
|
||||||
|
string_parse_size( num, n );
|
||||||
|
|
||||||
|
const char* faces = tokeniser.getToken();
|
||||||
|
if( !faces )
|
||||||
|
break;
|
||||||
|
tokeniser.nextLine();
|
||||||
|
|
||||||
|
map.emplace( n, faces );
|
||||||
|
}
|
||||||
|
tokeniser.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // apply
|
||||||
|
class CaulkBrushesWalker : public scene::Traversable::Walker
|
||||||
|
{
|
||||||
|
const CaulkMap& m_map;
|
||||||
|
mutable std::size_t m_brushIndex = 0;
|
||||||
|
const CopiedString m_caulk = GetCommonShader( "caulk" );
|
||||||
|
const CopiedString m_watercaulk = GetCommonShader( "watercaulk" );
|
||||||
|
const CopiedString m_lavacaulk = GetCommonShader( "lavacaulk" );
|
||||||
|
const CopiedString m_slimecaulk = GetCommonShader( "slimecaulk" );
|
||||||
|
const CopiedString m_nodraw = GetCommonShader( "nodraw" );
|
||||||
|
const CopiedString m_nodrawnonsolid = GetCommonShader( "nodrawnonsolid" );
|
||||||
|
public:
|
||||||
|
mutable std::size_t m_caulkedCount = 0;
|
||||||
|
CaulkBrushesWalker( CaulkMap& map )
|
||||||
|
: m_map( map ){
|
||||||
|
}
|
||||||
|
bool pre( scene::Node& node ) const {
|
||||||
|
Brush* brush = Node_getBrush( node );
|
||||||
|
if( brush ){
|
||||||
|
CaulkMap::const_iterator iter = m_map.find( m_brushIndex );
|
||||||
|
if( iter != m_map.end() ){
|
||||||
|
const char* faces = ( *iter ).second.c_str();
|
||||||
|
for ( Brush::const_iterator f = brush->begin(); f != brush->end() && *faces; ++f ){
|
||||||
|
Face& face = *( *f );
|
||||||
|
if ( face.contributes() ){
|
||||||
|
++m_caulkedCount;
|
||||||
|
switch ( *faces )
|
||||||
|
{
|
||||||
|
case 'c':
|
||||||
|
face.SetShader( m_caulk.c_str() );
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
face.SetShader( m_watercaulk.c_str() );
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
face.SetShader( m_lavacaulk.c_str() );
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
face.SetShader( m_slimecaulk.c_str() );
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
face.SetShader( m_nodraw.c_str() );
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
face.SetShader( m_nodrawnonsolid.c_str() );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
--m_caulkedCount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++faces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++m_brushIndex;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
CaulkBrushesWalker caulkBrushesWalker( map );
|
||||||
|
GlobalUndoSystem().start();
|
||||||
|
Map_Traverse_Selected( GlobalSceneGraph().root(), caulkBrushesWalker );
|
||||||
|
StringOutputStream str( 32 );
|
||||||
|
str << "AutoCaulk " << caulkBrushesWalker.m_caulkedCount << " faces";
|
||||||
|
GlobalUndoSystem().finish( str.c_str() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Map_constructPreferences( PreferencesPage& page ){
|
void Map_constructPreferences( PreferencesPage& page ){
|
||||||
page.appendCheckBox( "", "Load last map at startup", g_bLoadLastMap );
|
page.appendCheckBox( "", "Load last map at startup", g_bLoadLastMap );
|
||||||
}
|
}
|
||||||
|
|
@ -2397,6 +2651,7 @@ void Map_Construct(){
|
||||||
GlobalCommands_insert( "RegionSetBrush", FreeCaller<RegionBrush>() );
|
GlobalCommands_insert( "RegionSetBrush", FreeCaller<RegionBrush>() );
|
||||||
//GlobalCommands_insert( "RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator( 'R', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
|
//GlobalCommands_insert( "RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator( 'R', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
|
||||||
GlobalToggles_insert( "RegionSetSelection", FreeCaller<RegionSelected>(), ToggleItem::AddCallbackCaller( g_region_item ), Accelerator( 'R', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
|
GlobalToggles_insert( "RegionSetSelection", FreeCaller<RegionSelected>(), ToggleItem::AddCallbackCaller( g_region_item ), Accelerator( 'R', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
|
||||||
|
GlobalCommands_insert( "AutoCaulkSelected", FreeCaller<map_autocaulk_selected>(), Accelerator( GDK_F4 ) );
|
||||||
|
|
||||||
GlobalPreferenceSystem().registerPreference( "LastMap", CopiedStringImportStringCaller( g_strLastMap ), CopiedStringExportStringCaller( g_strLastMap ) );
|
GlobalPreferenceSystem().registerPreference( "LastMap", CopiedStringImportStringCaller( g_strLastMap ), CopiedStringExportStringCaller( g_strLastMap ) );
|
||||||
GlobalPreferenceSystem().registerPreference( "LoadLastMap", BoolImportStringCaller( g_bLoadLastMap ), BoolExportStringCaller( g_bLoadLastMap ) );
|
GlobalPreferenceSystem().registerPreference( "LoadLastMap", BoolImportStringCaller( g_bLoadLastMap ), BoolExportStringCaller( g_bLoadLastMap ) );
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,56 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
qboolean g_autocaulk = qfalse;
|
||||||
|
|
||||||
|
static void autocaulk_write(){
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
Sys_FPrintf( SYS_VRB, "--- autocaulk_write ---\n" );
|
||||||
|
sprintf( filename, "%s.caulk", source );
|
||||||
|
Sys_Printf( "writing %s\n", filename );
|
||||||
|
|
||||||
|
FILE* file = fopen( filename, "w" );
|
||||||
|
if ( !file ) {
|
||||||
|
Error( "Error opening %s", filename );
|
||||||
|
}
|
||||||
|
|
||||||
|
int fslime = 16;
|
||||||
|
ApplySurfaceParm( "slime", &fslime, NULL, NULL );
|
||||||
|
int flava = 8;
|
||||||
|
ApplySurfaceParm( "lava", &flava, NULL, NULL );
|
||||||
|
|
||||||
|
for ( brush_t* b = entities[0].brushes; b; b = b->next ) {
|
||||||
|
fprintf( file, "%i ", b->brushNum );
|
||||||
|
shaderInfo_t* contentShader = b->contentShader;
|
||||||
|
for( int i = 0; i < b->numsides; ++i ){
|
||||||
|
if( b->sides[i].visibleHull || ( b->sides[i].compileFlags & C_NODRAW ) ){
|
||||||
|
fprintf( file, "-" );
|
||||||
|
}
|
||||||
|
else if( contentShader->compileFlags & C_LIQUID ){
|
||||||
|
if( contentShader->contentFlags & flava )
|
||||||
|
fprintf( file, "l" );
|
||||||
|
else if( contentShader->contentFlags & fslime )
|
||||||
|
fprintf( file, "s" );
|
||||||
|
else
|
||||||
|
fprintf( file, "w" );
|
||||||
|
}
|
||||||
|
else if( b->compileFlags & C_TRANSLUCENT ){
|
||||||
|
if( contentShader->compileFlags & C_SOLID )
|
||||||
|
fprintf( file, "N" );
|
||||||
|
else
|
||||||
|
fprintf( file, "n" );
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
fprintf( file, "c" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf( file, "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose( file );
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------------
|
||||||
|
|
||||||
functions
|
functions
|
||||||
|
|
@ -375,6 +425,11 @@ void ProcessWorldModel( void ){
|
||||||
MakeTreePortals( tree );
|
MakeTreePortals( tree );
|
||||||
FilterStructuralBrushesIntoTree( e, tree );
|
FilterStructuralBrushesIntoTree( e, tree );
|
||||||
|
|
||||||
|
if( g_autocaulk == qtrue ){
|
||||||
|
autocaulk_write();
|
||||||
|
exit( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
/* ydnar: flood again for skybox */
|
/* ydnar: flood again for skybox */
|
||||||
if ( skyboxPresent ) {
|
if ( skyboxPresent ) {
|
||||||
FloodEntities( tree );
|
FloodEntities( tree );
|
||||||
|
|
@ -1003,6 +1058,10 @@ int BSPMain( int argc, char **argv ){
|
||||||
Sys_Printf( "No oBs!\n" );
|
Sys_Printf( "No oBs!\n" );
|
||||||
noob = qtrue;
|
noob = qtrue;
|
||||||
}
|
}
|
||||||
|
else if ( !strcmp( argv[ i ], "-autocaulk" ) ) {
|
||||||
|
Sys_Printf( "\trunning in autocaulk mode\n" );
|
||||||
|
g_autocaulk = qtrue;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Sys_Warning( "Unknown option \"%s\"\n", argv[ i ] );
|
Sys_Warning( "Unknown option \"%s\"\n", argv[ i ] );
|
||||||
|
|
@ -1049,10 +1108,10 @@ int BSPMain( int argc, char **argv ){
|
||||||
|
|
||||||
/* load original file from temp spot in case it was renamed by the editor on the way in */
|
/* load original file from temp spot in case it was renamed by the editor on the way in */
|
||||||
if ( strlen( tempSource ) > 0 ) {
|
if ( strlen( tempSource ) > 0 ) {
|
||||||
LoadMapFile( tempSource, qfalse, qfalse );
|
LoadMapFile( tempSource, qfalse, g_autocaulk );
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
LoadMapFile( name, qfalse, qfalse );
|
LoadMapFile( name, qfalse, g_autocaulk );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* div0: inject command line parameters */
|
/* div0: inject command line parameters */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user