From 995104ef44017718abbf7d9b0580eba19f780ad8 Mon Sep 17 00:00:00 2001 From: namespace Date: Mon, 25 Dec 2006 22:22:04 +0000 Subject: [PATCH] - Brushplugin Version 2.0, supports multiple collapse modes and a materialignore list (namespace) - Camera movement speed changes. Increase speed = SHIFT+KP_PLUS, decrease speed = SHIFT+KP_MINUS. New option to link the strafe speed to camera movement speed (default: linked). (Shaderman) - Fixed bug in sample plugin (Shaderman) - Merry Christmas git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@128 8a3a26a2-13c4-0310-b231-cf6edde360e5 --- CHANGES | 8 + SConscript | 13 +- contrib/brushexport/brushexport.vcproj | 27 ++- contrib/brushexport/callbacks.cpp | 104 ++++++++++ contrib/brushexport/callbacks.h | 11 + contrib/brushexport/export.cpp | 274 +++++++++++++++++++++++++ contrib/brushexport/export.h | 15 ++ contrib/brushexport/interface.cpp | 212 +++++++++++++++++++ contrib/brushexport/plugin.cpp | 132 ++---------- contrib/brushexport/support.cpp | 31 +++ contrib/brushexport/support.h | 24 +++ plugins/sample/sample.cpp | 4 +- radiant/camwindow.cpp | 42 +++- 13 files changed, 767 insertions(+), 130 deletions(-) create mode 100644 contrib/brushexport/callbacks.cpp create mode 100644 contrib/brushexport/callbacks.h create mode 100644 contrib/brushexport/export.cpp create mode 100644 contrib/brushexport/export.h create mode 100644 contrib/brushexport/interface.cpp create mode 100644 contrib/brushexport/support.cpp create mode 100644 contrib/brushexport/support.h diff --git a/CHANGES b/CHANGES index 191eb7aa..9afc4b20 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,14 @@ This is the changelog for developers, != changelog for the end user that we distribute with the binaries. (see changelog) +25/12/2006 +namespace + - Brushplugin Version 2.0, supports multiple collapse modes and a materialignore list (namespace) + - Camera movement speed changes. Increase speed = SHIFT+KP_PLUS, decrease speed = SHIFT+KP_MINUS. + New option to link the strafe speed to camera movement speed (default: linked). (Shaderman) + - Fixed bug in sample plugin (Shaderman) + - Merry Christmas + 17/12/2006 namespace - Radiant warzow-support (Topsun + Warzow-Mappers) diff --git a/SConscript b/SConscript index 68a875e9..f4738ed1 100644 --- a/SConscript +++ b/SConscript @@ -479,13 +479,12 @@ prtview_lib = prtview_env.SharedLibrarySafe(target='prtview', source=prtview_lst prtview_env.Depends(prtview_lib, profile_lib) prtview_env.Install(INSTALL + '/plugins', prtview_lib) - -brushexport_env = module_env.Copy() -brushexport_lst = build_list('contrib/brushexport', 'plugin.cpp') -brushexport_env.useGlib2() -brushexport_env.useGtk2() -brushexport_lib = brushexport_env.SharedLibrarySafe(target='brushexport', source=brushexport_lst, LIBPATH='libs') -brushexport_env.Install(INSTALL + '/plugins', brushexport_lib) +brushexport2_env = module_env.Copy() +brushexport2_lst = build_list('contrib/brushexport', ['plugin.cpp','interface.cpp','callbacks.cpp', 'support.cpp', 'export.cpp']) +brushexport2_env.useGlib2() +brushexport2_env.useGtk2() +brushexport2_lib = brushexport2_env.SharedLibrarySafe(target='brushexport', source=brushexport2_lst, LIBPATH='libs') +brushexport2_env.Install(INSTALL + '/plugins', brushexport2_lib) sunplug_env = module_env.Copy() sunplug_lst = build_list('contrib/sunplug', 'sunplug.cpp') diff --git a/contrib/brushexport/brushexport.vcproj b/contrib/brushexport/brushexport.vcproj index 709aa277..5c7f1f82 100644 --- a/contrib/brushexport/brushexport.vcproj +++ b/contrib/brushexport/brushexport.vcproj @@ -55,7 +55,8 @@ +copy "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)install\plugins" +"/> +copy "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)install\plugins" +"/> + + + + + + + + + + + + + + diff --git a/contrib/brushexport/callbacks.cpp b/contrib/brushexport/callbacks.cpp new file mode 100644 index 00000000..1225d00f --- /dev/null +++ b/contrib/brushexport/callbacks.cpp @@ -0,0 +1,104 @@ +#include +#include +#include + +#include "qerplugin.h" +#include "debugging/debugging.h" +#include "support.h" +#include "export.h" + +// stuff from interface.cpp +void DestroyWindow(); + + +namespace callbacks { + +void OnDestroy(GtkWidget* w, gpointer data) +{ + DestroyWindow(); +} + +void OnExportClicked(GtkButton* button, gpointer user_data) +{ + GtkWidget* window = lookup_widget(GTK_WIDGET(button), "w_plugplug2"); + ASSERT_NOTNULL(window); + const char* path = GlobalRadiant().m_pfnFileDialog(window, false, "Save as Obj", 0, 0); + if(!path) + return; + + // get ignore list from ui + std::set ignore; + + GtkTreeView* view = GTK_TREE_VIEW(lookup_widget(GTK_WIDGET(button), "t_materialist")); + GtkListStore* list = GTK_LIST_STORE(gtk_tree_view_get_model(view)); + + GtkTreeIter iter; + bool valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list), &iter); + while(valid) + { + gchar* data; + gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, 0, &data, -1); + globalOutputStream() << data << "\n"; + ignore.insert(std::string(data)); + g_free(data); + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(list), &iter); + } + + for(std::set::iterator it(ignore.begin()); it != ignore.end(); ++it) + globalOutputStream() << it->c_str() << "\n"; + + // collapse mode + collapsemode mode = COLLAPSE_NONE; + + GtkWidget* radio = lookup_widget(GTK_WIDGET(button), "r_collapse"); + ASSERT_NOTNULL(radio); + + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio))) + mode = COLLAPSE_ALL; + else + { + radio = lookup_widget(GTK_WIDGET(button), "r_collapsebymaterial"); + ASSERT_NOTNULL(radio); + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio))) + mode = COLLAPSE_BY_MATERIAL; + else + { + radio = lookup_widget(GTK_WIDGET(button), "r_nocollapse"); + ASSERT_NOTNULL(radio); + ASSERT_NOTNULL(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio))); + mode = COLLAPSE_NONE; + } + } + + // export + ExportSelection(ignore, mode, path); +} + +void OnAddMaterial(GtkButton* button, gpointer user_data) +{ + GtkEntry* edit = GTK_ENTRY(lookup_widget(GTK_WIDGET(button), "ed_materialname")); + ASSERT_NOTNULL(edit); + + const gchar* name = gtk_entry_get_text(edit); + if(g_utf8_strlen(name, -1) > 0) + { + GtkListStore* list = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(lookup_widget(GTK_WIDGET(button), "t_materialist")))); + GtkTreeIter iter; + gtk_list_store_append(list, &iter); + gtk_list_store_set(list, &iter, 0, name, -1); + gtk_entry_set_text(edit, ""); + } +} + +void OnRemoveMaterial(GtkButton* button, gpointer user_data) +{ + GtkTreeView* view = GTK_TREE_VIEW(lookup_widget(GTK_WIDGET(button), "t_materialist")); + GtkListStore* list = GTK_LIST_STORE(gtk_tree_view_get_model(view)); + GtkTreeSelection* sel = gtk_tree_view_get_selection(view); + + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(sel, 0, &iter)) + gtk_list_store_remove(list, &iter); +} + +}// callbacks diff --git a/contrib/brushexport/callbacks.h b/contrib/brushexport/callbacks.h new file mode 100644 index 00000000..afad96c9 --- /dev/null +++ b/contrib/brushexport/callbacks.h @@ -0,0 +1,11 @@ +typedef struct _GtkWidget GtkWidget; +typedef struct _GtkButton GtkButton; + +namespace callbacks { + +void OnDestroy(GtkWidget*, gpointer); +void OnExportClicked(GtkButton*, gpointer); +void OnAddMaterial(GtkButton*, gpointer); +void OnRemoveMaterial(GtkButton*, gpointer); + +}// callbacks diff --git a/contrib/brushexport/export.cpp b/contrib/brushexport/export.cpp new file mode 100644 index 00000000..ac421114 --- /dev/null +++ b/contrib/brushexport/export.cpp @@ -0,0 +1,274 @@ +#include "export.h" +#include "debugging/debugging.h" +#include "ibrush.h" +#include "iscenegraph.h" +#include "iselection.h" +#include "stream/stringstream.h" +#include "stream/textfilestream.h" + +// this is very evil, but right now there is no better way +#include "../../radiant/brush.h" + +/* + Abstract baseclass for modelexporters + the class collects all the data which then gets + exported through the WriteToFile method. +*/ +class ExportData +{ +public: + ExportData(const std::set& ignorelist, collapsemode mode); + virtual ~ExportData(void); + + virtual void BeginBrush(Brush& b); + virtual void AddBrushFace(Face& f); + virtual void EndBrush(void); + + virtual bool WriteToFile(const std::string& path) const = 0; + +protected: + + // a group of faces + class group + { + public: + std::string name; + std::list faces; + }; + + std::list groups; + +private: + + // "textures/common/caulk" -> "caulk" + void GetShaderNameFromShaderPath(const char* path, std::string& name); + + group* current; + collapsemode mode; + const std::set& ignorelist; +}; + +ExportData::ExportData(const std::set& _ignorelist, collapsemode _mode) + : mode(_mode), + ignorelist(_ignorelist) +{ + current = 0; + + // in this mode, we need just one group + if(mode == COLLAPSE_ALL) + { + groups.push_back(group()); + current = &groups.back(); + current->name = "all"; + } +} + +ExportData::~ExportData(void) +{ + +} + +void ExportData::BeginBrush(Brush& b) +{ + // create a new group for each brush + if(mode == COLLAPSE_NONE) + { + groups.push_back(group()); + current = &groups.back(); + + StringOutputStream str(256); + str << "Brush" << (const unsigned int)groups.size(); + current->name = str.c_str(); + } +} + +void ExportData::EndBrush(void) +{ + // all faces of this brush were on the ignorelist, discard the emptygroup + if(mode == COLLAPSE_NONE) + { + ASSERT_NOTNULL(current); + if(current->faces.empty()) + { + groups.pop_back(); + current = 0; + } + } +} + +void ExportData::AddBrushFace(Face& f) +{ + std::string shadername; + GetShaderNameFromShaderPath(f.GetShader(), shadername); + + // faces mit materials auf der ignoreliste ignorieren + if(ignorelist.find(shadername) != ignorelist.end()) + return; + + if(mode == COLLAPSE_BY_MATERIAL) + { + // find a group for this material + current = 0; + const std::list::iterator end(groups.end()); + for(std::list::iterator it(groups.begin()); it != end; ++it) + { + if(it->name == shadername) + current = &(*it); + } + + // no group found, create one + if(!current) + { + groups.push_back(group()); + current = &groups.back(); + current->name = shadername; + } + } + + ASSERT_NOTNULL(current); + + // add face to current group + current->faces.push_back(&f); + +#ifdef _DEBUG + globalOutputStream() << "Added Face to group " << current->name.c_str() << "\n"; +#endif +} + +void ExportData::GetShaderNameFromShaderPath(const char* path, std::string& name) +{ + std::string tmp(path); + + size_t last_slash = tmp.find_last_of("/"); + + if(last_slash != std::string::npos && last_slash == (tmp.length() - 1)) + name = path; + else + name = tmp.substr(last_slash + 1, tmp.length() - last_slash); + + globalOutputStream() << "Last: " << last_slash << " " << "lenght: " << (const unsigned int)tmp.length() << "Name: " << name.c_str() << "\n"; +} + +/* + Exporter writing facedata as wavefront object +*/ +class ExportDataAsWavefront : public ExportData +{ +public: + ExportDataAsWavefront(const std::set& _ignorelist, collapsemode _mode) + : ExportData(_ignorelist, _mode) + { + } + + bool WriteToFile(const std::string& path) const; +}; + +bool ExportDataAsWavefront::WriteToFile(const std::string& path) const +{ + TextFileOutputStream out(path.c_str()); + + if(out.failed()) + { + globalErrorStream() << "Unable to open file\n"; + return false; + } + + out << "# Wavefront Objectfile exported with radiants brushexport plugin 2.0 by Thomas 'namespace' Nitschke, spam@codecreator.net\n\n"; + + unsigned int vertex_count = 0; + + const std::list::const_iterator gend(groups.end()); + for(std::list::const_iterator git(groups.begin()); git != gend; ++git) + { + const std::list::const_iterator end(git->faces.end()); + + // submesh starts here + out << "\ng " << git->name.c_str() << "\n"; + + for(std::list::const_iterator it(git->faces.begin()); it != end; ++it) + { + const Winding& w((*it)->getWinding()); + + // vertices + for(size_t i = 0; i < w.numpoints; ++i) + out << "v " << w[i].vertex.x() << " " << w[i].vertex.y() << " " << w[i].vertex.z() << "\n"; + } + out << "\n"; + + for(std::list::const_iterator it(git->faces.begin()); it != end; ++it) + { + const Winding& w((*it)->getWinding()); + + // texcoords + for(size_t i = 0; i < w.numpoints; ++i) + out << "vt " << w[i].texcoord.x() << " " << w[i].texcoord.y() << "\n"; + } + + for(std::list::const_iterator it(git->faces.begin()); it != end; ++it) + { + const Winding& w((*it)->getWinding()); + + // faces + out << "\nf"; + for(size_t i = 0; i < w.numpoints; ++i, ++vertex_count) + { + out << " " << vertex_count+1 << "/" << vertex_count+1; + } + } + out << "\n"; + } + + return true; +} + + +class ForEachFace : public BrushVisitor +{ +public: + ForEachFace(ExportData& _exporter) + : exporter(_exporter) + {} + + void visit(Face& face) const + { + exporter.AddBrushFace(face); + } + +private: + ExportData& exporter; +}; + +class ForEachSelected : public SelectionSystem::Visitor +{ +public: + ForEachSelected(ExportData& _exporter) + : exporter(_exporter) + {} + + void visit(scene::Instance& instance) const + { + BrushInstance* bptr = InstanceTypeCast::cast(instance); + if(bptr) + { + Brush& brush(bptr->getBrush()); + + exporter.BeginBrush(brush); + ForEachFace face_vis(exporter); + brush.forEachFace(face_vis); + exporter.EndBrush(); + } + } + +private: + ExportData& exporter; +}; + +bool ExportSelection(const std::set& ignorelist, collapsemode m, const std::string& path) +{ + ExportDataAsWavefront exporter(ignorelist, m); + + ForEachSelected vis(exporter); + GlobalSelectionSystem().foreachSelected(vis); + + return exporter.WriteToFile(path); +} diff --git a/contrib/brushexport/export.h b/contrib/brushexport/export.h new file mode 100644 index 00000000..76f937b5 --- /dev/null +++ b/contrib/brushexport/export.h @@ -0,0 +1,15 @@ +#ifndef EXPORT_H +#define EXPORT_H +#include +#include + +enum collapsemode +{ + COLLAPSE_ALL, + COLLAPSE_BY_MATERIAL, + COLLAPSE_NONE +}; + +bool ExportSelection(const std::set& ignorelist, collapsemode m, const std::string& path); + +#endif diff --git a/contrib/brushexport/interface.cpp b/contrib/brushexport/interface.cpp new file mode 100644 index 00000000..dd40f3b9 --- /dev/null +++ b/contrib/brushexport/interface.cpp @@ -0,0 +1,212 @@ +#include +#include + +#include "debugging/debugging.h" +#include "callbacks.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +// created by glade +GtkWidget* +create_w_plugplug2 (void) +{ + GtkWidget *w_plugplug2; + GtkWidget *vbox1; + GtkWidget *hbox2; + GtkWidget *vbox4; + GtkWidget *r_collapse; + GSList *r_collapse_group = NULL; + GtkWidget *r_collapsebymaterial; + GtkWidget *r_nocollapse; + GtkWidget *vbox3; + GtkWidget *b_export; + GtkWidget *b_close; + GtkWidget *vbox2; + GtkWidget *label1; + GtkWidget *scrolledwindow1; + GtkWidget *t_materialist; + GtkWidget *ed_materialname; + GtkWidget *hbox1; + GtkWidget *b_addmaterial; + GtkWidget *b_removematerial; + + 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 2.0 by namespace"); + gtk_window_set_position (GTK_WINDOW (w_plugplug2), GTK_WIN_POS_CENTER); + 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_widget_show (r_collapse); + gtk_box_pack_start (GTK_BOX (vbox4), r_collapse, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (r_collapse), r_collapse_group); + 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_widget_show (r_collapsebymaterial); + gtk_box_pack_start (GTK_BOX (vbox4), r_collapsebymaterial, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (r_collapsebymaterial), r_collapse_group); + 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_widget_show (r_nocollapse); + gtk_box_pack_start (GTK_BOX (vbox4), r_nocollapse, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (r_nocollapse), r_collapse_group); + r_collapse_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (r_nocollapse)); + + 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); + + using namespace callbacks; + g_signal_connect(G_OBJECT(w_plugplug2), "destroy", G_CALLBACK(OnDestroy), NULL); + g_signal_connect_swapped(G_OBJECT(b_close), "clicked", G_CALLBACK (OnDestroy), NULL); + + g_signal_connect ((gpointer) b_export, "clicked", G_CALLBACK (OnExportClicked), NULL); + g_signal_connect ((gpointer) b_addmaterial, "clicked", G_CALLBACK (OnAddMaterial), NULL); + g_signal_connect ((gpointer) b_removematerial, "clicked", G_CALLBACK (OnRemoveMaterial), NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (w_plugplug2, w_plugplug2, "w_plugplug2"); + GLADE_HOOKUP_OBJECT (w_plugplug2, vbox1, "vbox1"); + GLADE_HOOKUP_OBJECT (w_plugplug2, hbox2, "hbox2"); + GLADE_HOOKUP_OBJECT (w_plugplug2, vbox4, "vbox4"); + GLADE_HOOKUP_OBJECT (w_plugplug2, r_collapse, "r_collapse"); + GLADE_HOOKUP_OBJECT (w_plugplug2, r_collapsebymaterial, "r_collapsebymaterial"); + GLADE_HOOKUP_OBJECT (w_plugplug2, r_nocollapse, "r_nocollapse"); + GLADE_HOOKUP_OBJECT (w_plugplug2, vbox3, "vbox3"); + GLADE_HOOKUP_OBJECT (w_plugplug2, b_export, "b_export"); + GLADE_HOOKUP_OBJECT (w_plugplug2, b_close, "b_close"); + GLADE_HOOKUP_OBJECT (w_plugplug2, vbox2, "vbox2"); + GLADE_HOOKUP_OBJECT (w_plugplug2, label1, "label1"); + GLADE_HOOKUP_OBJECT (w_plugplug2, scrolledwindow1, "scrolledwindow1"); + GLADE_HOOKUP_OBJECT (w_plugplug2, t_materialist, "t_materialist"); + GLADE_HOOKUP_OBJECT (w_plugplug2, ed_materialname, "ed_materialname"); + GLADE_HOOKUP_OBJECT (w_plugplug2, hbox1, "hbox1"); + GLADE_HOOKUP_OBJECT (w_plugplug2, b_addmaterial, "b_addmaterial"); + GLADE_HOOKUP_OBJECT (w_plugplug2, b_removematerial, "b_removematerial"); + + return w_plugplug2; +} + +// global main window, is 0 when not created +GtkWidget* g_brushexp_window = 0; + +// spawn plugin window (and make sure it got destroyed first or never created) +void CreateWindow(void) +{ + ASSERT_NOTNULL(!g_brushexp_window); + + GtkWidget* wnd = create_w_plugplug2(); + + // column & renderer + GtkTreeViewColumn* col = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(col, "materials"); + gtk_tree_view_append_column(GTK_TREE_VIEW(lookup_widget(wnd, "t_materialist")), col); + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(lookup_widget(wnd, "t_materialist")), -1, "", renderer, "text", 0, NULL); + + // list store + GtkListStore* ignorelist = gtk_list_store_new(1, G_TYPE_STRING); + gtk_tree_view_set_model(GTK_TREE_VIEW(lookup_widget(wnd, "t_materialist")), GTK_TREE_MODEL(ignorelist)); + g_object_unref(ignorelist); + + gtk_widget_show_all(wnd); + g_brushexp_window = wnd; +} + +void DestroyWindow(void) +{ + ASSERT_NOTNULL(g_brushexp_window); + gtk_widget_destroy(g_brushexp_window); + g_brushexp_window = 0; +} + +bool IsWindowOpen(void) +{ + return g_brushexp_window != 0; +} diff --git a/contrib/brushexport/plugin.cpp b/contrib/brushexport/plugin.cpp index 8954473d..1b5e7c19 100644 --- a/contrib/brushexport/plugin.cpp +++ b/contrib/brushexport/plugin.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "qerplugin.h" #include +#include #include "debugging/debugging.h" #include "string/string.h" @@ -39,109 +40,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "ifilesystem.h" #include "ifiletypes.h" -#include "../../radiant/brush.h" +#include "support.h" + +#include "typesystem.h" + +void CreateWindow (void); +void DestroyWindow(void); +bool IsWindowOpen(void); namespace BrushExport -{ +{ GtkWindow* g_mainwnd; - class CExportFormatWavefront : public BrushVisitor - { - TextFileOutputStream& m_file; - - StringOutputStream vertexbuffer; - StringOutputStream texcoordbuffer; - StringOutputStream facebuffer; - - size_t vertices; - size_t exported; - - public: - - CExportFormatWavefront(TextFileOutputStream& file) - : m_file(file) - { - exported = 0; - vertices = 0; - } - - virtual ~CExportFormatWavefront(void) {} - - void visit(scene::Instance& instance) - { - BrushInstance* bptr = InstanceTypeCast::cast(instance); - if(bptr) - { - Brush& brush(bptr->getBrush()); - - m_file << "\ng " << brush.name() << exported << "\n"; - - brush.forEachFace(*this); - - m_file << vertexbuffer.c_str() << "\n"; - m_file << texcoordbuffer.c_str(); - m_file << facebuffer.c_str() << "\n"; - - vertexbuffer.clear(); - texcoordbuffer.clear(); - facebuffer.clear(); - ++exported; - } - } - - void visit(Face& face) const - { - // cast the stupid const away - const_cast(this)->visit(face); - } - - void visit(Face& face) - { - size_t v_start = vertices; - const Winding& w(face.getWinding()); - for(size_t i = 0; i < w.numpoints; ++i) - { - vertexbuffer << "v " << w[i].vertex.x() << " " << w[i].vertex.y() << " " << w[i].vertex.z() << "\n"; - texcoordbuffer << "vt " << w[i].texcoord.x() << " " << w[i].texcoord.y() << "\n"; - ++vertices; - } - - facebuffer << "\nf"; - for(size_t i = v_start; i < vertices; ++i) - facebuffer << " " << i+1 << "/" << i+1; - } - }; - - /** - Exporterclass which will pass every visit-call - to a special formatexporter. - */ - template - class CExporter : public SelectionSystem::Visitor - { - public: - CExporter(TextFileOutputStream& file) - : m_exporter(file) - {} - - virtual ~CExporter(void) {} - - void visit(scene::Instance& instance) const - { - m_exporter.visit(instance); - } - - private: - mutable TExporterFormat m_exporter; - }; - - template - void export_selected(TextFileOutputStream& file) - { - CExporter exporter(file); - GlobalSelectionSystem().foreachSelected(exporter); - } - const char* init(void* hApp, void* pMainWidget) { g_mainwnd = (GtkWindow*)pMainWidget; @@ -165,31 +75,19 @@ namespace BrushExport { if(string_equal(command, "About")) { - GlobalRadiant().m_pfnMessageBox(GTK_WIDGET(g_mainwnd), "Brushexport plugin v 1.0 by namespace (www.codecreator.net)\n" + GlobalRadiant().m_pfnMessageBox(GTK_WIDGET(g_mainwnd), "Brushexport plugin v 2.0 by namespace (www.codecreator.net)\n" "Enjoy!\n\nSend feedback to spam@codecreator.net", "About me...", eMB_OK, eMB_ICONDEFAULT); } else if(string_equal(command, "Export selected as Wavefront Object")) { - if(const char* path = GlobalRadiant().m_pfnFileDialog(GTK_WIDGET(g_mainwnd), false, "Save as Obj", 0, 0)) - { - TextFileOutputStream file(path); - if(file.failed()) - { - GlobalRadiant().m_pfnMessageBox(GTK_WIDGET(g_mainwnd), "Unable to write to file", "Error", - eMB_OK, - eMB_ICONERROR); - } - else - { - export_selected(file); - } - } + if(IsWindowOpen()) + DestroyWindow(); + CreateWindow(); } } - -} // namespace +} class BrushExportDependencies : public GlobalRadiantModuleRef, @@ -210,7 +108,7 @@ class BrushExportModule : public TypeSystemRef _QERPluginTable m_plugin; public: typedef _QERPluginTable Type; - STRING_CONSTANT(Name, "brushexport"); + STRING_CONSTANT(Name, "brushexport2"); BrushExportModule() { diff --git a/contrib/brushexport/support.cpp b/contrib/brushexport/support.cpp new file mode 100644 index 00000000..736c6b2f --- /dev/null +++ b/contrib/brushexport/support.cpp @@ -0,0 +1,31 @@ +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + + diff --git a/contrib/brushexport/support.h b/contrib/brushexport/support.h new file mode 100644 index 00000000..d1cce97c --- /dev/null +++ b/contrib/brushexport/support.h @@ -0,0 +1,24 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + diff --git a/plugins/sample/sample.cpp b/plugins/sample/sample.cpp index 80900b10..41aa9bf8 100644 --- a/plugins/sample/sample.cpp +++ b/plugins/sample/sample.cpp @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "string/string.h" #include "modulesystem/singletonmodule.h" - +#include "typesystem.h" namespace Sample { @@ -61,7 +61,7 @@ namespace Sample } // namespace -class SamplePluginModule +class SamplePluginModule : public TypeSystemRef { _QERPluginTable m_plugin; public: diff --git a/radiant/camwindow.cpp b/radiant/camwindow.cpp index 9e882b12..0c054b43 100644 --- a/radiant/camwindow.cpp +++ b/radiant/camwindow.cpp @@ -76,6 +76,7 @@ void CameraMovedNotify() struct camwindow_globals_private_t { int m_nMoveSpeed; + bool m_bCamLinkSpeed; int m_nAngleSpeed; bool m_bCamInverseMouse; bool m_bCamDiscrete; @@ -84,6 +85,7 @@ struct camwindow_globals_private_t camwindow_globals_private_t() : m_nMoveSpeed(100), + m_bCamLinkSpeed(true), m_nAngleSpeed(3), m_bCamInverseMouse(false), m_bCamDiscrete(true), @@ -286,7 +288,12 @@ void Camera_FreeMove(camera_t& camera, int dx, int dy) // free strafe mode, toggled by the ctrl key with optional shift for forward movement if(camera.m_strafe) { - const float strafespeed = 0.65f; + float strafespeed = 0.65f; + + if(g_camwindow_globals_private.m_bCamLinkSpeed) + { + strafespeed = (float)g_camwindow_globals_private.m_nMoveSpeed / 100; + } camera.origin -= camera.vright * strafespeed * dx; if(camera.m_strafe_forward) @@ -558,6 +565,9 @@ typedef ReferenceCaller FreeMoveCameraMoveDown #define SPEED_MOVE 32 #define SPEED_TURN 22.5 +#define MIN_CAM_SPEED 10 +#define MAX_CAM_SPEED 610 +#define CAM_SPEED_STEP 50 void Camera_MoveForward_Discrete(camera_t& camera) { @@ -1803,6 +1813,9 @@ void CamWnd_registerShortcuts() { command_connect_accelerator("TogglePreview"); } + + command_connect_accelerator("CameraSpeedInc"); + command_connect_accelerator("CameraSpeedDec"); } @@ -1939,7 +1952,8 @@ typedef FreeCaller1 RenderModeExport void Camera_constructPreferences(PreferencesPage& page) { - page.appendSlider("Movement Speed", g_camwindow_globals_private.m_nMoveSpeed, TRUE, 0, 0, 100, 50, 300, 1, 10, 10); + page.appendSlider("Movement Speed", g_camwindow_globals_private.m_nMoveSpeed, TRUE, 0, 0, 100, MIN_CAM_SPEED, MAX_CAM_SPEED, 1, 10, 10); + page.appendCheckBox("", "Link strafe speed to movement speed", g_camwindow_globals_private.m_bCamLinkSpeed); page.appendSlider("Rotation Speed", g_camwindow_globals_private.m_nAngleSpeed, TRUE, 0, 0, 3, 1, 180, 1, 10, 10); page.appendCheckBox("", "Invert mouse vertical axis", g_camwindow_globals_private.m_bCamInverseMouse); page.appendCheckBox( @@ -1992,6 +2006,26 @@ void Camera_registerPreferencesPage() typedef FreeCaller1 CamWndMoveDiscreteImportCaller; +void CameraSpeed_increase() +{ + if(g_camwindow_globals_private.m_nMoveSpeed <= (MAX_CAM_SPEED - CAM_SPEED_STEP - 10)) + { + g_camwindow_globals_private.m_nMoveSpeed += CAM_SPEED_STEP; + } else { + g_camwindow_globals_private.m_nMoveSpeed = MAX_CAM_SPEED - 10; + } +} + +void CameraSpeed_decrease() +{ + if(g_camwindow_globals_private.m_nMoveSpeed >= (MIN_CAM_SPEED + CAM_SPEED_STEP)) + { + g_camwindow_globals_private.m_nMoveSpeed -= CAM_SPEED_STEP; + } else { + g_camwindow_globals_private.m_nMoveSpeed = MIN_CAM_SPEED; + } +} + /// \brief Initialisation for things that have the same lifespan as this module. void CamWnd_Construct() { @@ -2013,6 +2047,9 @@ void CamWnd_Construct() GlobalCommands_insert("TogglePreview", FreeCaller(), Accelerator(GDK_F3)); } + GlobalCommands_insert("CameraSpeedInc", FreeCaller(), Accelerator(GDK_KP_Add, (GdkModifierType)GDK_SHIFT_MASK)); + GlobalCommands_insert("CameraSpeedDec", FreeCaller(), Accelerator(GDK_KP_Subtract, (GdkModifierType)GDK_SHIFT_MASK)); + GlobalShortcuts_insert("CameraForward", Accelerator(GDK_Up)); GlobalShortcuts_insert("CameraBack", Accelerator(GDK_Down)); GlobalShortcuts_insert("CameraLeft", Accelerator(GDK_Left)); @@ -2034,6 +2071,7 @@ void CamWnd_Construct() GlobalPreferenceSystem().registerPreference("ShowStats", BoolImportStringCaller(g_camwindow_globals_private.m_showStats), BoolExportStringCaller(g_camwindow_globals_private.m_showStats)); GlobalPreferenceSystem().registerPreference("MoveSpeed", IntImportStringCaller(g_camwindow_globals_private.m_nMoveSpeed), IntExportStringCaller(g_camwindow_globals_private.m_nMoveSpeed)); + GlobalPreferenceSystem().registerPreference("CamLinkSpeed", BoolImportStringCaller(g_camwindow_globals_private.m_bCamLinkSpeed), BoolExportStringCaller(g_camwindow_globals_private.m_bCamLinkSpeed)); GlobalPreferenceSystem().registerPreference("AngleSpeed", IntImportStringCaller(g_camwindow_globals_private.m_nAngleSpeed), IntExportStringCaller(g_camwindow_globals_private.m_nAngleSpeed)); GlobalPreferenceSystem().registerPreference("CamInverseMouse", BoolImportStringCaller(g_camwindow_globals_private.m_bCamInverseMouse), BoolExportStringCaller(g_camwindow_globals_private.m_bCamInverseMouse)); GlobalPreferenceSystem().registerPreference("CamDiscrete", makeBoolStringImportCallback(CamWndMoveDiscreteImportCaller()), BoolExportStringCaller(g_camwindow_globals_private.m_bCamDiscrete)); -- 2.39.2