* brushexport plugin: "Weld vertices" option (welds inside group or object, thus result depends on collapse option)

rephrase, shorten code
disable debug prints about exclusions in release
print error to console with nothing selected
more picky conditions in ExportData::GetShaderNameFromShaderPath slash search
This commit is contained in:
Garux 2019-12-20 17:37:10 +03:00
parent 48444683ee
commit 0f6e20a334
4 changed files with 103 additions and 114 deletions

View File

@ -10,7 +10,13 @@
// stuff from interface.cpp
void DestroyWindow();
//! TODO add tooltip for ignore: shader name after last slash, case sensitive // or make insensitive
//! TODO console print on success
//! TODO make togglebuttons inactive on !exportmat
//! TODO add ignore mat on ENTER, del on del
//! TODO add entry with path to save to (to resave faster)
//! TODO tooltip for weld //inside groups
//! TODO ignore case in mat name comparison materials_comparator
namespace callbacks {
void OnDestroy( GtkWidget* w, gpointer data ){
@ -39,15 +45,17 @@ void OnExportClicked( GtkButton* button, gpointer user_data ){
{
gchar* data;
gtk_tree_model_get( GTK_TREE_MODEL( list ), &iter, 0, &data, -1 );
#ifdef _DEBUG
globalOutputStream() << data << "\n";
#endif
ignore.insert( std::string( data ) );
g_free( data );
valid = gtk_tree_model_iter_next( GTK_TREE_MODEL( list ), &iter );
}
for ( std::set<std::string>::iterator it( ignore.begin() ); it != ignore.end(); ++it )
globalOutputStream() << it->c_str() << "\n";
#ifdef _DEBUG
for ( const std::string& str : ignore )
globalOutputStream() << str.c_str() << "\n";
#endif
// collapse mode
collapsemode mode = COLLAPSE_NONE;
@ -77,34 +85,27 @@ void OnExportClicked( GtkButton* button, gpointer user_data ){
GtkWidget* toggle = lookup_widget( GTK_WIDGET( button ), "t_exportmaterials" );
ASSERT_NOTNULL( toggle );
bool exportmat = FALSE;
if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggle ) ) ) {
exportmat = TRUE;
}
const bool exportmat = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggle ) );
// limit material names?
toggle = lookup_widget( GTK_WIDGET( button ), "t_limitmatnames" );
ASSERT_NOTNULL( toggle );
bool limitMatNames = FALSE;
if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggle ) ) && exportmat ) {
limitMatNames = TRUE;
}
const bool limitMatNames = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggle ) ) && exportmat;
// create objects instead of groups?
toggle = lookup_widget( GTK_WIDGET( button ), "t_objects" );
ASSERT_NOTNULL( toggle );
bool objects = FALSE;
const bool objects = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggle ) ) && exportmat;
if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggle ) ) && exportmat ) {
objects = TRUE;
}
toggle = lookup_widget( GTK_WIDGET( button ), "t_weld" );
ASSERT_NOTNULL( toggle );
const bool weld = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggle ) );
// export
ExportSelection( ignore, mode, exportmat, path, limitMatNames, objects );
ExportSelection( ignore, mode, exportmat, path, limitMatNames, objects, weld );
}
void OnAddMaterial( GtkButton* button, gpointer user_data ){

View File

@ -22,7 +22,7 @@
class ExportData
{
public:
ExportData( const std::set<std::string>& ignorelist, collapsemode mode, bool limNames, bool objs );
ExportData( const std::set<std::string>& ignorelist, collapsemode mode );
virtual ~ExportData( void );
virtual void BeginBrush( Brush& b );
@ -49,11 +49,11 @@ private:
void GetShaderNameFromShaderPath( const char* path, std::string& name );
group* current;
collapsemode mode;
const collapsemode mode;
const std::set<std::string>& ignorelist;
};
ExportData::ExportData( const std::set<std::string>& _ignorelist, collapsemode _mode, bool _limNames, bool _objs )
ExportData::ExportData( const std::set<std::string>& _ignorelist, collapsemode _mode )
: mode( _mode ),
ignorelist( _ignorelist ){
current = 0;
@ -136,7 +136,7 @@ void ExportData::GetShaderNameFromShaderPath( const char* path, std::string& nam
size_t last_slash = tmp.find_last_of( "/" );
if ( last_slash != std::string::npos && last_slash == ( tmp.length() - 1 ) ) {
if ( last_slash == std::string::npos || last_slash == ( tmp.length() - 1 ) ) {
name = path;
}
else{
@ -154,16 +154,18 @@ void ExportData::GetShaderNameFromShaderPath( const char* path, std::string& nam
class ExportDataAsWavefront : public ExportData
{
private:
bool expmat;
bool limNames;
bool objs;
const bool expmat;
const bool limNames;
const bool objs;
const bool weld;
public:
ExportDataAsWavefront( const std::set<std::string>& _ignorelist, collapsemode _mode, bool _expmat, bool _limNames, bool _objs )
: ExportData( _ignorelist, _mode, _limNames, _objs ){
expmat = _expmat;
limNames = _limNames;
objs = _objs;
ExportDataAsWavefront( const std::set<std::string>& _ignorelist, collapsemode _mode, bool _expmat, bool _limNames, bool _objs, bool _weld )
: ExportData( _ignorelist, _mode ),
expmat( _expmat ),
limNames( _limNames ),
objs( _objs ),
weld( _weld ){
}
bool WriteToFile( const std::string& path, collapsemode mode ) const;
@ -178,11 +180,10 @@ bool ExportDataAsWavefront::WriteToFile( const std::string& path, collapsemode m
std::string mtlFile = objFile.substr( 0, objFile.length() - 4 ) + ".mtl";
typedef std::pair<std::string, Colour3> Material;
auto materials_comparator = []( const Material& ma1, const Material& ma2 ) {
return ma1.first < ma2.first;
auto materials_comparator = []( const std::string& lhs, const std::string& rhs ) {
return lhs < rhs;
};
auto materials = std::set<Material, decltype( materials_comparator )>( materials_comparator );
auto materials = std::map<std::string, Colour3, decltype( materials_comparator )>( materials_comparator );
TextFileOutputStream out( objFile.c_str() );
@ -200,15 +201,13 @@ bool ExportDataAsWavefront::WriteToFile( const std::string& path, collapsemode m
}
unsigned int vertex_count = 0;
unsigned int texcoord_count = 0;
const std::list<ExportData::group>::const_iterator gend( groups.end() );
for ( std::list<ExportData::group>::const_iterator git( groups.begin() ); git != gend; ++git )
for ( const ExportData::group& group : groups )
{
typedef std::multimap<std::string, std::string> bm;
bm brushMaterials;
typedef std::pair<std::string, std::string> String_Pair;
std::multimap<std::string, std::string> brushMaterials;
const std::list<const Face*>::const_iterator end( git->faces.end() );
std::vector<Vector3> vertices; // unique vertices list for welding
// submesh starts here
if ( objs ) {
@ -217,31 +216,59 @@ bool ExportDataAsWavefront::WriteToFile( const std::string& path, collapsemode m
else {
out << "\ng ";
}
out << git->name.c_str() << "\n";
out << group.name.c_str() << "\n";
// material
if ( expmat && mode == COLLAPSE_ALL ) {
out << "usemtl material" << "\n\n";
materials.insert( std::make_pair( std::string( "material" ), Colour3( 0.5, 0.5, 0.5 ) ) );
materials.emplace( "material", Colour3( 0.5, 0.5, 0.5 ) );
}
for ( std::list<const Face*>::const_iterator it( git->faces.begin() ); it != end; ++it )
for ( const Face* face : group.faces )
{
const Winding& w( ( *it )->getWinding() );
const Winding& w( face->getWinding() );
// faces
StringOutputStream faceLine( 256 );
faceLine << "\nf";
// vertices
size_t i = w.numpoints;
do{
--i;
out << "v " << FloatFormat( w[i].vertex.x(), 1, 6 ) << " " << FloatFormat( w[i].vertex.z(), 1, 6 ) << " " << FloatFormat( -w[i].vertex.y(), 1, 6 ) << "\n";
++texcoord_count;
std::size_t vertexN = 0; // vertex index to use, 0 is special value = no vertex to weld to found
const Vector3& vertex = w[i].vertex;
if( weld ){
auto found = std::find_if( vertices.begin(), vertices.end(), [&vertex]( const Vector3& othervertex ){
return Edge_isDegenerate( vertex, othervertex );
} );
if( found == vertices.end() ){ // unique vertex, add to the list
vertices.emplace_back( vertex );
}
else{
vertexN = vertex_count - std::distance( found, vertices.end() ) + 1; // reuse existing index
}
}
// write vertices
if( vertexN == 0 ){
vertexN = ++vertex_count;
out << "v " << FloatFormat( vertex.x(), 1, 6 ) << " " << FloatFormat( vertex.z(), 1, 6 ) << " " << FloatFormat( -vertex.y(), 1, 6 ) << "\n";
}
faceLine << " " << vertexN << "/" << texcoord_count; // store faces
}
while( i != 0 );
if ( mode != COLLAPSE_ALL )
materials.emplace( face->getShader().getShader(), face->getShader().state()->getTexture().color );
brushMaterials.emplace( face->getShader().getShader(), faceLine.c_str() );
}
out << "\n";
for ( std::list<const Face*>::const_iterator it( git->faces.begin() ); it != end; ++it )
for ( const Face* face : group.faces )
{
const Winding& w( ( *it )->getWinding() );
const Winding& w( face->getWinding() );
// texcoords
size_t i = w.numpoints;
@ -252,55 +279,25 @@ bool ExportDataAsWavefront::WriteToFile( const std::string& path, collapsemode m
while( i != 0 );
}
for ( std::list<const Face*>::const_iterator it( git->faces.begin() ); it != end; ++it )
{
const Winding& w( ( *it )->getWinding() );
// faces
StringOutputStream faceLine( 256 );
faceLine << "\nf";
size_t i = w.numpoints;
do{
--i;
++vertex_count;
faceLine << " " << vertex_count << "/" << vertex_count;
}
while( i != 0 );
if ( mode != COLLAPSE_ALL ) {
materials.insert( std::make_pair( std::string( ( *it )->getShader().getShader() ), ( *it )->getShader().state()->getTexture().color ) );
brushMaterials.insert( String_Pair( ( *it )->getShader().getShader(), faceLine.c_str() ) );
}
else {
out << faceLine.c_str();
}
}
if ( mode != COLLAPSE_ALL ) {
std::string lastMat;
std::string mat;
std::string faces;
for ( bm::iterator iter = brushMaterials.begin(); iter != brushMaterials.end(); iter++ )
for ( const auto& stringpair : brushMaterials )
{
mat = ( *iter ).first.c_str();
faces = ( *iter ).second.c_str();
const std::string& mat = stringpair.first;
const std::string& faces = stringpair.second;
if ( mat != lastMat ) {
if ( mode != COLLAPSE_ALL && mat != lastMat ) {
if ( limNames && mat.size() > MAX_MATERIAL_NAME ) {
out << "\nusemtl " << mat.substr( mat.size() - MAX_MATERIAL_NAME, mat.size() ).c_str();
}
else {
out << "\nusemtl " << mat.c_str();
}
}
out << faces.c_str();
lastMat = mat;
}
// write faces
out << faces.c_str();
}
}
out << "\n";
@ -315,10 +312,10 @@ bool ExportDataAsWavefront::WriteToFile( const std::string& path, collapsemode m
outMtl << "# Wavefront material file exported with NetRadiants brushexport plugin.\n";
outMtl << "# Material Count: " << (const Unsigned)materials.size() << "\n\n";
for ( std::set<std::pair<std::string, Colour3>>::const_iterator it( materials.begin() ); it != materials.end(); ++it )
for ( const auto& material : materials )
{
const std::string& str = it->first;
const Colour3& clr = it->second;
const std::string& str = material.first;
const Colour3& clr = material.second;
if ( limNames && str.size() > MAX_MATERIAL_NAME ) {
outMtl << "newmtl " << str.substr( str.size() - MAX_MATERIAL_NAME, str.size() ).c_str() << "\n";
}
@ -374,8 +371,13 @@ private:
ExportData& exporter;
};
bool ExportSelection( const std::set<std::string>& ignorelist, collapsemode m, bool exmat, const std::string& path, bool limNames, bool objs ){
ExportDataAsWavefront exporter( ignorelist, m, exmat, limNames, objs );
bool ExportSelection( const std::set<std::string>& ignorelist, collapsemode m, bool exmat, const std::string& path, bool limNames, bool objs, bool weld ){
ExportDataAsWavefront exporter( ignorelist, m, exmat, limNames, objs, weld );
if( GlobalSelectionSystem().countSelected() == 0 ){
globalErrorStream() << "Nothing is selected.\n";
return false;
}
ForEachSelected vis( exporter );
GlobalSelectionSystem().foreachSelected( vis );

View File

@ -10,6 +10,6 @@ enum collapsemode
COLLAPSE_NONE
};
bool ExportSelection( const std::set<std::string>& ignorelist, collapsemode m, bool exmat, const std::string& path, bool limitMatNames, bool objects );
bool ExportSelection( const std::set<std::string>& ignorelist, collapsemode m, bool exmat, const std::string& path, bool limitMatNames, bool objects, bool weld );
#endif

View File

@ -38,36 +38,32 @@ create_w_plugplug2( void ){
GtkWidget *t_exportmaterials;
GtkWidget *t_limitmatnames;
GtkWidget *t_objects;
GtkWidget *t_weld;
GtkTooltips *tooltips;
tooltips = gtk_tooltips_new();
w_plugplug2 = gtk_window_new( GTK_WINDOW_TOPLEVEL );
gtk_widget_set_name( w_plugplug2, "w_plugplug2" );
gtk_window_set_title( GTK_WINDOW( w_plugplug2 ), "BrushExport-Plugin 3.0 by namespace" );
gtk_window_set_position( GTK_WINDOW( w_plugplug2 ), GTK_WIN_POS_CENTER_ON_PARENT );
gtk_window_set_transient_for( GTK_WINDOW( w_plugplug2 ), GTK_WINDOW( g_pRadiantWnd ) );
gtk_window_set_destroy_with_parent( GTK_WINDOW( w_plugplug2 ), TRUE );
vbox1 = gtk_vbox_new( FALSE, 0 );
gtk_widget_set_name( vbox1, "vbox1" );
gtk_widget_show( vbox1 );
gtk_container_add( GTK_CONTAINER( w_plugplug2 ), vbox1 );
gtk_container_set_border_width( GTK_CONTAINER( vbox1 ), 5 );
hbox2 = gtk_hbox_new( TRUE, 5 );
gtk_widget_set_name( hbox2, "hbox2" );
gtk_widget_show( hbox2 );
gtk_box_pack_start( GTK_BOX( vbox1 ), hbox2, FALSE, FALSE, 0 );
gtk_container_set_border_width( GTK_CONTAINER( hbox2 ), 5 );
vbox4 = gtk_vbox_new( TRUE, 0 );
gtk_widget_set_name( vbox4, "vbox4" );
gtk_widget_show( vbox4 );
gtk_box_pack_start( GTK_BOX( hbox2 ), vbox4, TRUE, FALSE, 0 );
r_collapse = gtk_radio_button_new_with_mnemonic( NULL, "Collapse mesh" );
gtk_widget_set_name( r_collapse, "r_collapse" );
gtk_tooltips_set_tip( GTK_TOOLTIPS( tooltips ), r_collapse, "Collapse all brushes into a single group", "Collapse all brushes into a single group" );
gtk_widget_show( r_collapse );
gtk_box_pack_start( GTK_BOX( vbox4 ), r_collapse, FALSE, FALSE, 0 );
@ -75,7 +71,6 @@ create_w_plugplug2( void ){
r_collapse_group = gtk_radio_button_get_group( GTK_RADIO_BUTTON( r_collapse ) );
r_collapsebymaterial = gtk_radio_button_new_with_mnemonic( NULL, "Collapse by material" );
gtk_widget_set_name( r_collapsebymaterial, "r_collapsebymaterial" );
gtk_tooltips_set_tip( GTK_TOOLTIPS( tooltips ), r_collapsebymaterial, "Collapse into groups by material", "Collapse into groups by material" );
gtk_widget_show( r_collapsebymaterial );
gtk_box_pack_start( GTK_BOX( vbox4 ), r_collapsebymaterial, FALSE, FALSE, 0 );
@ -83,7 +78,6 @@ create_w_plugplug2( void ){
r_collapse_group = gtk_radio_button_get_group( GTK_RADIO_BUTTON( r_collapsebymaterial ) );
r_nocollapse = gtk_radio_button_new_with_mnemonic( NULL, "Don't collapse" );
gtk_widget_set_name( r_nocollapse, "r_nocollapse" );
gtk_tooltips_set_tip( GTK_TOOLTIPS( tooltips ), r_nocollapse, "Every brush is stored in its own group", "Every brush is stored in its own group" );
gtk_widget_show( r_nocollapse );
gtk_box_pack_start( GTK_BOX( vbox4 ), r_nocollapse, FALSE, FALSE, 0 );
@ -92,80 +86,71 @@ create_w_plugplug2( void ){
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( r_nocollapse ), TRUE );
vbox3 = gtk_vbox_new( FALSE, 0 );
gtk_widget_set_name( vbox3, "vbox3" );
gtk_widget_show( vbox3 );
gtk_box_pack_start( GTK_BOX( hbox2 ), vbox3, FALSE, FALSE, 0 );
b_export = gtk_button_new_from_stock( "gtk-save" );
gtk_widget_set_name( b_export, "b_export" );
gtk_widget_show( b_export );
gtk_box_pack_start( GTK_BOX( vbox3 ), b_export, TRUE, FALSE, 0 );
gtk_container_set_border_width( GTK_CONTAINER( b_export ), 5 );
b_close = gtk_button_new_from_stock( "gtk-cancel" );
gtk_widget_set_name( b_close, "b_close" );
gtk_widget_show( b_close );
gtk_box_pack_start( GTK_BOX( vbox3 ), b_close, TRUE, FALSE, 0 );
gtk_container_set_border_width( GTK_CONTAINER( b_close ), 5 );
vbox2 = gtk_vbox_new( FALSE, 5 );
gtk_widget_set_name( vbox2, "vbox2" );
gtk_widget_show( vbox2 );
gtk_box_pack_start( GTK_BOX( vbox1 ), vbox2, TRUE, TRUE, 0 );
gtk_container_set_border_width( GTK_CONTAINER( vbox2 ), 2 );
label1 = gtk_label_new( "Ignored materials:" );
gtk_widget_set_name( label1, "label1" );
gtk_widget_show( label1 );
gtk_box_pack_start( GTK_BOX( vbox2 ), label1, FALSE, FALSE, 0 );
scrolledwindow1 = gtk_scrolled_window_new( NULL, NULL );
gtk_widget_set_name( scrolledwindow1, "scrolledwindow1" );
gtk_widget_show( scrolledwindow1 );
gtk_box_pack_start( GTK_BOX( vbox2 ), scrolledwindow1, TRUE, TRUE, 0 );
gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolledwindow1 ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scrolledwindow1 ), GTK_SHADOW_IN );
t_materialist = gtk_tree_view_new();
gtk_widget_set_name( t_materialist, "t_materialist" );
gtk_widget_show( t_materialist );
gtk_container_add( GTK_CONTAINER( scrolledwindow1 ), t_materialist );
gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( t_materialist ), FALSE );
gtk_tree_view_set_enable_search( GTK_TREE_VIEW( t_materialist ), FALSE );
ed_materialname = gtk_entry_new();
gtk_widget_set_name( ed_materialname, "ed_materialname" );
gtk_widget_show( ed_materialname );
gtk_box_pack_start( GTK_BOX( vbox2 ), ed_materialname, FALSE, FALSE, 0 );
hbox1 = gtk_hbox_new( TRUE, 0 );
gtk_widget_set_name( hbox1, "hbox1" );
gtk_widget_show( hbox1 );
gtk_box_pack_start( GTK_BOX( vbox2 ), hbox1, FALSE, FALSE, 0 );
b_addmaterial = gtk_button_new_from_stock( "gtk-add" );
gtk_widget_set_name( b_addmaterial, "b_addmaterial" );
gtk_widget_show( b_addmaterial );
gtk_box_pack_start( GTK_BOX( hbox1 ), b_addmaterial, FALSE, FALSE, 0 );
b_removematerial = gtk_button_new_from_stock( "gtk-remove" );
gtk_widget_set_name( b_removematerial, "b_removematerial" );
gtk_widget_show( b_removematerial );
gtk_box_pack_start( GTK_BOX( hbox1 ), b_removematerial, FALSE, FALSE, 0 );
t_limitmatnames = gtk_check_button_new_with_mnemonic( "Use short material names (max. 20 chars)" );
gtk_widget_set_name( t_limitmatnames, "t_limitmatnames" );
gtk_widget_show( t_limitmatnames );
gtk_box_pack_end( GTK_BOX( vbox2 ), t_limitmatnames, FALSE, FALSE, 0 );
t_objects = gtk_check_button_new_with_mnemonic( "Create (o)bjects instead of (g)roups" );
gtk_widget_set_name( t_objects, "t_objects" );
gtk_widget_show( t_objects );
gtk_box_pack_end( GTK_BOX( vbox2 ), t_objects, FALSE, FALSE, 0 );
t_weld = gtk_check_button_new_with_mnemonic( "Weld vertices" );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( t_weld ), TRUE );
gtk_widget_show( t_weld );
gtk_box_pack_end( GTK_BOX( vbox2 ), t_weld, FALSE, FALSE, 0 );
t_exportmaterials = gtk_check_button_new_with_mnemonic( "Create material information (.mtl file)" );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( t_exportmaterials ), true );
gtk_widget_set_name( t_exportmaterials, "t_exportmaterials" );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( t_exportmaterials ), TRUE );
gtk_widget_show( t_exportmaterials );
gtk_box_pack_end( GTK_BOX( vbox2 ), t_exportmaterials, FALSE, FALSE, 10 );
@ -200,6 +185,7 @@ create_w_plugplug2( void ){
GLADE_HOOKUP_OBJECT( w_plugplug2, t_exportmaterials, "t_exportmaterials" );
GLADE_HOOKUP_OBJECT( w_plugplug2, t_limitmatnames, "t_limitmatnames" );
GLADE_HOOKUP_OBJECT( w_plugplug2, t_objects, "t_objects" );
GLADE_HOOKUP_OBJECT( w_plugplug2, t_weld, "t_weld" );
return w_plugplug2;
}