2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "debugging/debugging.h"
27 MapModules& ReferenceAPI_getMapModules();
28 #include "iselection.h"
32 #include "ireference.h"
33 #include "ifiletypes.h"
38 #include "ifilesystem.h"
39 #include "namespace.h"
40 #include "moduleobserver.h"
44 #include <gtk/gtkmain.h>
45 #include <gtk/gtkbox.h>
46 #include <gtk/gtkentry.h>
47 #include <gtk/gtklabel.h>
48 #include <gtk/gtktable.h>
49 #include <gtk/gtktreemodel.h>
50 #include <gtk/gtktreeview.h>
51 #include <gtk/gtkliststore.h>
52 #include <gtk/gtkcellrenderertext.h>
55 #include "transformlib.h"
56 #include "selectionlib.h"
57 #include "instancelib.h"
58 #include "traverselib.h"
60 #include "eclasslib.h"
62 #include "stream/textfilestream.h"
64 #include "uniquenames.h"
65 #include "modulesystem/singletonmodule.h"
66 #include "modulesystem/moduleregistry.h"
67 #include "stream/stringstream.h"
68 #include "signal/signal.h"
70 #include "gtkutil/filechooser.h"
74 #include "filetypes.h"
76 #include "entityinspector.h"
79 #include "camwindow.h"
81 #include "mainframe.h"
82 #include "preferences.h"
83 #include "referencecache.h"
87 #include "brushmodule.h"
99 //globalOutputStream() << "construct " << makeQuoted(c_str()) << "\n";
100 m_names.insert(name_read(c_str()));
107 //globalOutputStream() << "destroy " << makeQuoted(c_str()) << "\n";
108 m_names.erase(name_read(c_str()));
112 NameObserver& operator=(const NameObserver& other);
114 NameObserver(UniqueNames& names) : m_names(names)
118 NameObserver(const NameObserver& other) : m_names(other.m_names), m_name(other.m_name)
128 return string_empty(c_str());
130 const char* c_str() const
132 return m_name.c_str();
134 void nameChanged(const char* name)
140 typedef MemberCaller1<NameObserver, const char*, &NameObserver::nameChanged> NameChangedCaller;
143 class BasicNamespace : public Namespace
145 typedef std::map<NameCallback, NameObserver> Names;
147 UniqueNames m_uniqueNames;
151 ASSERT_MESSAGE(m_names.empty(), "namespace: names still registered at shutdown");
153 void attach(const NameCallback& setName, const NameCallbackCallback& attachObserver)
155 std::pair<Names::iterator, bool> result = m_names.insert(Names::value_type(setName, m_uniqueNames));
156 ASSERT_MESSAGE(result.second, "cannot attach name");
157 attachObserver(NameObserver::NameChangedCaller((*result.first).second));
158 //globalOutputStream() << "attach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
160 void detach(const NameCallback& setName, const NameCallbackCallback& detachObserver)
162 Names::iterator i = m_names.find(setName);
163 ASSERT_MESSAGE(i != m_names.end(), "cannot detach name");
164 //globalOutputStream() << "detach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
165 detachObserver(NameObserver::NameChangedCaller((*i).second));
169 void makeUnique(const char* name, const NameCallback& setName) const
172 name_write(buffer, m_uniqueNames.make_unique(name_read(name)));
176 void mergeNames(const BasicNamespace& other) const
178 typedef std::list<NameCallback> SetNameCallbacks;
179 typedef std::map<CopiedString, SetNameCallbacks> NameGroups;
182 UniqueNames uniqueNames(other.m_uniqueNames);
184 for(Names::const_iterator i = m_names.begin(); i != m_names.end(); ++i)
186 groups[(*i).second.c_str()].push_back((*i).first);
189 for(NameGroups::iterator i = groups.begin(); i != groups.end(); ++i)
191 name_t uniqueName(uniqueNames.make_unique(name_read((*i).first.c_str())));
192 uniqueNames.insert(uniqueName);
195 name_write(buffer, uniqueName);
197 //globalOutputStream() << "renaming " << makeQuoted((*i).first.c_str()) << " to " << makeQuoted(buffer) << "\n";
199 SetNameCallbacks& setNameCallbacks = (*i).second;
201 for(SetNameCallbacks::const_iterator j = setNameCallbacks.begin(); j != setNameCallbacks.end(); ++j)
209 BasicNamespace g_defaultNamespace;
210 BasicNamespace g_cloneNamespace;
214 Namespace* m_namespace;
216 typedef Namespace Type;
217 STRING_CONSTANT(Name, "*");
221 m_namespace = &g_defaultNamespace;
223 Namespace* getTable()
229 typedef SingletonModule<NamespaceAPI> NamespaceModule;
230 typedef Static<NamespaceModule> StaticNamespaceModule;
231 StaticRegisterModule staticRegisterDefaultNamespace(StaticNamespaceModule::instance());
234 std::list<Namespaced*> g_cloned;
236 inline Namespaced* Node_getNamespaced(scene::Node& node)
238 return NodeTypeCast<Namespaced>::cast(node);
241 void Node_gatherNamespaced(scene::Node& node)
243 Namespaced* namespaced = Node_getNamespaced(node);
246 g_cloned.push_back(namespaced);
250 class GatherNamespaced : public scene::Traversable::Walker
253 bool pre(scene::Node& node) const
255 Node_gatherNamespaced(node);
260 void Map_gatherNamespaced(scene::Node& root)
262 Node_traverseSubgraph(root, GatherNamespaced());
265 void Map_mergeClonedNames()
267 for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
269 (*i)->setNamespace(g_cloneNamespace);
271 g_cloneNamespace.mergeNames(g_defaultNamespace);
272 for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
274 (*i)->setNamespace(g_defaultNamespace);
288 void set(scene::Node* node)
296 scene::Node* get() const
303 void Map_SetValid(Map& map, bool valid);
304 void Map_UpdateTitle(const Map& map);
305 void Map_SetWorldspawn(Map& map, scene::Node* node);
308 class Map : public ModuleObserver
312 Resource* m_resource;
316 void (*m_modified_changed)(const Map&);
318 Signal0 m_mapValidCallbacks;
320 WorldNode m_world_node; // "classname" "worldspawn" !
322 Map() : m_resource(0), m_valid(false), m_modified_changed(Map_UpdateTitle)
330 if(Map_Unnamed(*this))
332 g_map.m_resource->setNode(NewMapRoot("").get_pointer());
333 MapFile* map = Node_getMapFile(*g_map.m_resource->getNode());
344 GlobalSceneGraph().insert_root(*m_resource->getNode());
348 Map_SetValid(g_map, true);
355 Map_SetValid(g_map, false);
356 Map_SetWorldspawn(g_map, 0);
359 GlobalUndoSystem().clear();
361 GlobalSceneGraph().erase_root();
367 Map* g_currentMap = 0;
369 void Map_addValidCallback(Map& map, const SignalHandler& handler)
371 map.m_mapValidCallbacks.connectLast(handler);
374 bool Map_Valid(const Map& map)
379 void Map_SetValid(Map& map, bool valid)
382 map.m_mapValidCallbacks();
386 const char* Map_Name(const Map& map)
388 return map.m_name.c_str();
391 bool Map_Unnamed(const Map& map)
393 return string_equal(Map_Name(map), "unnamed.map");
396 inline const MapFormat& MapFormat_forFile(const char* filename)
398 const char* moduleName = findModuleName(GetFileTypeRegistry(), MapFormat::Name(), path_get_extension(filename));
399 MapFormat* format = Radiant_getMapModules().findModule(moduleName);
400 ASSERT_MESSAGE(format != 0, "map format not found for file " << makeQuoted(filename));
404 const MapFormat& Map_getFormat(const Map& map)
406 return MapFormat_forFile(Map_Name(map));
410 bool Map_Modified(const Map& map)
412 return map.m_modified;
415 void Map_SetModified(Map& map, bool modified)
417 if(map.m_modified ^ modified)
419 map.m_modified = modified;
421 map.m_modified_changed(map);
425 void Map_UpdateTitle(const Map& map)
427 Sys_SetTitle(map.m_name.c_str(), Map_Modified(map));
432 scene::Node* Map_GetWorldspawn(const Map& map)
434 return map.m_world_node.get();
437 void Map_SetWorldspawn(Map& map, scene::Node* node)
439 map.m_world_node.set(node);
444 // need that in a variable, will have to tweak depending on the game
445 float g_MaxWorldCoord = 64*1024;
446 float g_MinWorldCoord = -64*1024;
448 void AddRegionBrushes (void);
449 void RemoveRegionBrushes (void);
455 free all map elements, reinitialize the structures that depend on them
462 g_map.m_resource->detach(g_map);
463 GlobalReferenceCache().release(g_map.m_name.c_str());
464 g_map.m_resource = 0;
469 Brush_unlatchPreferences();
472 class EntityFindByClassname : public scene::Graph::Walker
477 EntityFindByClassname(const char* name, Entity*& entity) : m_name(name), m_entity(entity)
481 bool pre(const scene::Path& path, scene::Instance& instance) const
485 Entity* entity = Node_getEntity(path.top());
487 && string_equal(m_name, entity->getKeyValue("classname")))
496 Entity* Scene_FindEntityByClass(const char* name)
499 GlobalSceneGraph().traverse(EntityFindByClassname(name, entity));
503 Entity *Scene_FindPlayerStart()
505 typedef const char* StaticString;
506 StaticString strings[] = {
508 "info_player_deathmatch",
509 "team_CTF_redplayer",
510 "team_CTF_blueplayer",
512 "team_CTF_bluespawn",
514 typedef const StaticString* StaticStringIterator;
515 for(StaticStringIterator i = strings, end = strings+(sizeof(strings)/sizeof(StaticString)); i != end; ++i)
517 Entity* entity = Scene_FindEntityByClass(*i);
527 // move the view to a start position
531 void FocusViews(const Vector3& point, float angle)
533 CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
534 Camera_setOrigin(camwnd, point);
535 Vector3 angles(Camera_getAngles(camwnd));
536 angles[CAMERA_PITCH] = 0;
537 angles[CAMERA_YAW] = angle;
538 Camera_setAngles(camwnd, angles);
540 XYWnd* xywnd = g_pParentWnd->GetXYWnd();
541 xywnd->SetOrigin(point);
544 #include "stringio.h"
546 void Map_StartPosition()
548 Entity* entity = Scene_FindPlayerStart();
553 string_parse_vector3(entity->getKeyValue("origin"), origin);
554 FocusViews(origin, string_read_float(entity->getKeyValue("angle")));
558 FocusViews(g_vector3_identity, 0);
563 inline bool node_is_worldspawn(scene::Node& node)
565 Entity* entity = Node_getEntity(node);
566 return entity != 0 && string_equal(entity->getKeyValue("classname"), "worldspawn");
570 // use first worldspawn
571 class entity_updateworldspawn : public scene::Traversable::Walker
574 bool pre(scene::Node& node) const
576 if(node_is_worldspawn(node))
578 if(Map_GetWorldspawn(g_map) == 0)
580 Map_SetWorldspawn(g_map, &node);
587 scene::Node* Map_FindWorldspawn(Map& map)
589 Map_SetWorldspawn(map, 0);
591 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
593 return Map_GetWorldspawn(map);
597 class CollectAllWalker : public scene::Traversable::Walker
600 UnsortedNodeSet& m_nodes;
602 CollectAllWalker(scene::Node& root, UnsortedNodeSet& nodes) : m_root(root), m_nodes(nodes)
605 bool pre(scene::Node& node) const
607 m_nodes.insert(NodeSmartReference(node));
608 Node_getTraversable(m_root)->erase(node);
613 void Node_insertChildFirst(scene::Node& parent, scene::Node& child)
615 UnsortedNodeSet nodes;
616 Node_getTraversable(parent)->traverse(CollectAllWalker(parent, nodes));
617 Node_getTraversable(parent)->insert(child);
619 for(UnsortedNodeSet::iterator i = nodes.begin(); i != nodes.end(); ++i)
621 Node_getTraversable(parent)->insert((*i));
625 scene::Node& createWorldspawn()
627 NodeSmartReference worldspawn(GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("worldspawn", true)));
628 Node_insertChildFirst(GlobalSceneGraph().root(), worldspawn);
632 void Map_UpdateWorldspawn(Map& map)
634 if(Map_FindWorldspawn(map) == 0)
636 Map_SetWorldspawn(map, &createWorldspawn());
640 scene::Node& Map_FindOrInsertWorldspawn(Map& map)
642 Map_UpdateWorldspawn(map);
643 return *Map_GetWorldspawn(map);
647 class MapMergeAll : public scene::Traversable::Walker
649 mutable scene::Path m_path;
651 MapMergeAll(const scene::Path& root)
655 bool pre(scene::Node& node) const
657 Node_getTraversable(m_path.top())->insert(node);
658 m_path.push(makeReference(node));
659 selectPath(m_path, true);
662 void post(scene::Node& node) const
668 class MapMergeEntities : public scene::Traversable::Walker
670 mutable scene::Path m_path;
672 MapMergeEntities(const scene::Path& root)
676 bool pre(scene::Node& node) const
678 if(node_is_worldspawn(node))
680 scene::Node* world_node = Map_FindWorldspawn(g_map);
683 Map_SetWorldspawn(g_map, &node);
684 Node_getTraversable(m_path.top().get())->insert(node);
685 m_path.push(makeReference(node));
686 Node_getTraversable(node)->traverse(SelectChildren(m_path));
690 m_path.push(makeReference(*world_node));
691 Node_getTraversable(node)->traverse(MapMergeAll(m_path));
696 Node_getTraversable(m_path.top())->insert(node);
697 m_path.push(makeReference(node));
698 if(node_is_group(node))
700 Node_getTraversable(node)->traverse(SelectChildren(m_path));
704 selectPath(m_path, true);
709 void post(scene::Node& node) const
715 class BasicContainer : public scene::Node::Symbiot
719 NodeTypeCastTable m_casts;
723 NodeContainedCast<BasicContainer, scene::Traversable>::install(m_casts);
725 NodeTypeCastTable& get()
732 TraversableNodeSet m_traverse;
735 typedef LazyStatic<TypeCasts> StaticTypeCasts;
737 scene::Traversable& get(NullType<scene::Traversable>)
742 BasicContainer() : m_node(this, this, StaticTypeCasts::instance().get())
755 /// Merges the map graph rooted at \p node into the global scene-graph.
756 void MergeMap(scene::Node& node)
758 Node_getTraversable(node)->traverse(MapMergeEntities(scene::Path(makeReference(GlobalSceneGraph().root()))));
760 void Map_ImportSelected(TextInputStream& in, const MapFormat& format)
762 NodeSmartReference node((new BasicContainer)->node());
763 format.readGraph(node, in, GlobalEntityCreator());
764 Map_gatherNamespaced(node);
765 Map_mergeClonedNames();
769 inline scene::Cloneable* Node_getCloneable(scene::Node& node)
771 return NodeTypeCast<scene::Cloneable>::cast(node);
774 inline scene::Node& node_clone(scene::Node& node)
776 scene::Cloneable* cloneable = Node_getCloneable(node);
779 return cloneable->clone();
782 return (new scene::NullNode)->node();
785 class CloneAll : public scene::Traversable::Walker
787 mutable scene::Path m_path;
789 CloneAll(scene::Node& root)
790 : m_path(makeReference(root))
793 bool pre(scene::Node& node) const
800 m_path.push(makeReference(node_clone(node)));
801 m_path.top().get().IncRef();
805 void post(scene::Node& node) const
812 Node_getTraversable(m_path.parent())->insert(m_path.top());
814 m_path.top().get().DecRef();
819 scene::Node& Node_Clone(scene::Node& node)
821 scene::Node& clone = node_clone(node);
822 scene::Traversable* traversable = Node_getTraversable(node);
825 traversable->traverse(CloneAll(clone));
831 typedef std::map<CopiedString, std::size_t> EntityBreakdown;
833 class EntityBreakdownWalker : public scene::Graph::Walker
835 EntityBreakdown& m_entitymap;
837 EntityBreakdownWalker(EntityBreakdown& entitymap)
838 : m_entitymap(entitymap)
841 bool pre(const scene::Path& path, scene::Instance& instance) const
843 Entity* entity = Node_getEntity(path.top());
846 const EntityClass& eclass = entity->getEntityClass();
847 if(m_entitymap.find(eclass.name()) == m_entitymap.end())
849 m_entitymap[eclass.name()] = 1;
851 else ++m_entitymap[eclass.name()];
857 void Scene_EntityBreakdown(EntityBreakdown& entitymap)
859 GlobalSceneGraph().traverse(EntityBreakdownWalker(entitymap));
863 WindowPosition g_posMapInfoWnd(c_default_window_pos);
868 GtkEntry* brushes_entry;
869 GtkEntry* entities_entry;
870 GtkListStore* EntityBreakdownWalker;
872 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Map Info", G_CALLBACK(dialog_delete_callback), &dialog);
874 window_set_position(window, g_posMapInfoWnd);
877 GtkVBox* vbox = create_dialog_vbox(4, 4);
878 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
881 GtkHBox* hbox = create_dialog_hbox(4);
882 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, TRUE, 0);
885 GtkTable* table = create_dialog_table(2, 2, 4, 4);
886 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
889 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
890 gtk_widget_show(GTK_WIDGET(entry));
891 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
892 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
893 (GtkAttachOptions) (0), 0, 0);
894 gtk_entry_set_editable(entry, FALSE);
896 brushes_entry = entry;
899 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
900 gtk_widget_show(GTK_WIDGET(entry));
901 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
902 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
903 (GtkAttachOptions) (0), 0, 0);
904 gtk_entry_set_editable(entry, FALSE);
906 entities_entry = entry;
909 GtkWidget* label = gtk_label_new ("Total Brushes");
910 gtk_widget_show (label);
911 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
912 (GtkAttachOptions) (GTK_FILL),
913 (GtkAttachOptions) (0), 0, 0);
914 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
917 GtkWidget* label = gtk_label_new ("Total Entities");
918 gtk_widget_show (label);
919 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
920 (GtkAttachOptions) (GTK_FILL),
921 (GtkAttachOptions) (0), 0, 0);
922 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
926 GtkVBox* vbox2 = create_dialog_vbox(4);
927 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox2), FALSE, FALSE, 0);
930 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_ok), &dialog);
931 gtk_box_pack_start(GTK_BOX(vbox2), GTK_WIDGET(button), FALSE, FALSE, 0);
936 GtkWidget* label = gtk_label_new ("Entity breakdown");
937 gtk_widget_show (label);
938 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, TRUE, 0);
939 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
942 GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4);
943 gtk_box_pack_start(GTK_BOX (vbox), GTK_WIDGET(scr), TRUE, TRUE, 0);
946 GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
948 GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
949 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(view), TRUE);
952 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
953 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Entity", renderer, "text", 0, 0);
954 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
955 gtk_tree_view_column_set_sort_column_id(column, 0);
959 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
960 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Count", renderer, "text", 1, 0);
961 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
962 gtk_tree_view_column_set_sort_column_id(column, 1);
965 gtk_widget_show(view);
967 gtk_container_add(GTK_CONTAINER(scr), view);
969 EntityBreakdownWalker = store;
977 EntityBreakdown entitymap;
978 Scene_EntityBreakdown(entitymap);
980 for(EntityBreakdown::iterator i=entitymap.begin(); i != entitymap.end(); ++i)
983 sprintf (tmp, "%u", Unsigned((*i).second));
985 gtk_list_store_append(GTK_LIST_STORE(EntityBreakdownWalker), &iter);
986 gtk_list_store_set(GTK_LIST_STORE(EntityBreakdownWalker), &iter, 0, (*i).first.c_str(), 1, tmp, -1);
990 g_object_unref(G_OBJECT(EntityBreakdownWalker));
993 sprintf (tmp, "%u", Unsigned(g_brushCount.get()));
994 gtk_entry_set_text (GTK_ENTRY (brushes_entry), tmp);
995 sprintf (tmp, "%u", Unsigned(g_entityCount.get()));
996 gtk_entry_set_text (GTK_ENTRY (entities_entry), tmp);
998 modal_dialog_show(window, dialog);
1001 window_get_position(window, g_posMapInfoWnd);
1003 gtk_widget_destroy(GTK_WIDGET(window));
1011 const char* m_message;
1013 ScopeTimer(const char* message)
1014 : m_message(message)
1020 double elapsed_time = m_timer.elapsed_msec() / 1000.f;
1021 globalOutputStream() << m_message << " timer: " << FloatFormat(elapsed_time, 5, 2) << " second(s) elapsed\n";
1031 void Map_LoadFile (const char *filename)
1033 globalOutputStream() << "Loading map from " << filename << "\n";
1034 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1037 ScopeTimer timer("map load");
1039 const MapFormat* format = NULL;
1040 const char* moduleName = findModuleName(&GlobalFiletypes(), MapFormat::Name(), path_get_extension(filename));
1041 if(string_not_empty(moduleName))
1042 format = ReferenceAPI_getMapModules().findModule(moduleName);
1044 for(int i = 0; i < Brush_toggleFormatCount(); ++i)
1048 Brush_toggleFormat(i);
1049 g_map.m_name = filename;
1050 Map_UpdateTitle(g_map);
1051 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1053 format->wrongFormat = false;
1054 g_map.m_resource->attach(g_map);
1056 if(!format->wrongFormat)
1060 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
1063 globalOutputStream() << "--- LoadMapFile ---\n";
1064 globalOutputStream() << g_map.m_name.c_str() << "\n";
1066 globalOutputStream() << Unsigned(g_brushCount.get()) << " primitive\n";
1067 globalOutputStream() << Unsigned(g_entityCount.get()) << " entities\n";
1069 //GlobalEntityCreator().printStatistics();
1072 // move the view to a start position
1074 Map_StartPosition();
1076 g_currentMap = &g_map;
1082 virtual bool excluded(scene::Node& node) const = 0;
1085 class ExcludeWalker : public scene::Traversable::Walker
1087 const scene::Traversable::Walker& m_walker;
1088 const Excluder* m_exclude;
1089 mutable bool m_skip;
1091 ExcludeWalker(const scene::Traversable::Walker& walker, const Excluder& exclude)
1092 : m_walker(walker), m_exclude(&exclude), m_skip(false)
1095 bool pre(scene::Node& node) const
1097 if(m_exclude->excluded(node) || node.isRoot())
1108 void post(scene::Node& node) const
1116 m_walker.post(node);
1121 class AnyInstanceSelected : public scene::Instantiable::Visitor
1125 AnyInstanceSelected(bool& selected) : m_selected(selected)
1129 void visit(scene::Instance& instance) const
1131 Selectable* selectable = Instance_getSelectable(instance);
1133 && selectable->isSelected())
1140 bool Node_instanceSelected(scene::Node& node)
1142 scene::Instantiable* instantiable = Node_getInstantiable(node);
1143 ASSERT_NOTNULL(instantiable);
1145 instantiable->forEachInstance(AnyInstanceSelected(selected));
1149 class SelectedDescendantWalker : public scene::Traversable::Walker
1153 SelectedDescendantWalker(bool& selected) : m_selected(selected)
1158 bool pre(scene::Node& node) const
1165 if(Node_instanceSelected(node))
1174 bool Node_selectedDescendant(scene::Node& node)
1177 Node_traverseSubgraph(node, SelectedDescendantWalker(selected));
1181 class SelectionExcluder : public Excluder
1184 bool excluded(scene::Node& node) const
1186 return !Node_selectedDescendant(node);
1190 class IncludeSelectedWalker : public scene::Traversable::Walker
1192 const scene::Traversable::Walker& m_walker;
1193 mutable std::size_t m_selected;
1194 mutable bool m_skip;
1196 bool selectedParent() const
1198 return m_selected != 0;
1201 IncludeSelectedWalker(const scene::Traversable::Walker& walker)
1202 : m_walker(walker), m_selected(0), m_skip(false)
1205 bool pre(scene::Node& node) const
1208 // node is not a 'root' AND ( node is selected OR any child of node is selected OR any parent of node is selected )
1209 if(!node.isRoot() && (Node_selectedDescendant(node) || selectedParent()))
1211 if(Node_instanceSelected(node))
1224 void post(scene::Node& node) const
1232 if(Node_instanceSelected(node))
1236 m_walker.post(node);
1241 void Map_Traverse_Selected(scene::Node& root, const scene::Traversable::Walker& walker)
1243 scene::Traversable* traversable = Node_getTraversable(root);
1244 if(traversable != 0)
1247 traversable->traverse(ExcludeWalker(walker, SelectionExcluder()));
1249 traversable->traverse(IncludeSelectedWalker(walker));
1254 void Map_ExportSelected(TextOutputStream& out, const MapFormat& format)
1256 format.writeGraph(GlobalSceneGraph().root(), Map_Traverse_Selected, out);
1259 void Map_Traverse(scene::Node& root, const scene::Traversable::Walker& walker)
1261 scene::Traversable* traversable = Node_getTraversable(root);
1262 if(traversable != 0)
1264 traversable->traverse(walker);
1268 class RegionExcluder : public Excluder
1271 bool excluded(scene::Node& node) const
1273 return node.excluded();
1277 void Map_Traverse_Region(scene::Node& root, const scene::Traversable::Walker& walker)
1279 scene::Traversable* traversable = Node_getTraversable(root);
1280 if(traversable != 0)
1282 traversable->traverse(ExcludeWalker(walker, RegionExcluder()));
1286 bool Map_SaveRegion(const char *filename)
1290 bool success = MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Region, filename);
1292 RemoveRegionBrushes();
1298 void Map_RenameAbsolute(const char* absolute)
1300 Resource* resource = GlobalReferenceCache().capture(absolute);
1301 NodeSmartReference clone(NewMapRoot(path_make_relative(absolute, GlobalFileSystem().findRoot(absolute))));
1302 resource->setNode(clone.get_pointer());
1305 //ScopeTimer timer("clone subgraph");
1306 Node_getTraversable(GlobalSceneGraph().root())->traverse(CloneAll(clone));
1309 g_map.m_resource->detach(g_map);
1310 GlobalReferenceCache().release(g_map.m_name.c_str());
1312 g_map.m_resource = resource;
1314 g_map.m_name = absolute;
1315 Map_UpdateTitle(g_map);
1317 g_map.m_resource->attach(g_map);
1320 void Map_Rename(const char* filename)
1322 if(!string_equal(g_map.m_name.c_str(), filename))
1324 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1326 Map_RenameAbsolute(filename);
1328 SceneChangeNotify();
1340 ScopeTimer timer("map save");
1342 return true; // assume success..
1353 //globalOutputStream() << "Map_New\n";
1355 g_map.m_name = "unnamed.map";
1356 Map_UpdateTitle(g_map);
1359 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1360 // ASSERT_MESSAGE(g_map.m_resource->getNode() == 0, "bleh");
1361 g_map.m_resource->attach(g_map);
1363 SceneChangeNotify();
1366 FocusViews(g_vector3_identity, 0);
1368 g_currentMap = &g_map;
1371 extern void ConstructRegionBrushes(scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs);
1373 void ConstructRegionStartpoint(scene::Node* startpoint, const Vector3& region_mins, const Vector3& region_maxs)
1376 \todo we need to make sure that the player start IS inside the region and bail out if it's not
1377 the compiler will refuse to compile a map with a player_start somewhere in empty space..
1378 for now, let's just print an error
1381 Vector3 vOrig(Camera_getOrigin(*g_pParentWnd->GetCamWnd()));
1383 for (int i=0 ; i<3 ; i++)
1385 if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
1387 globalErrorStream() << "Camera is NOT in the region, it's likely that the region won't compile correctly\n";
1392 // write the info_playerstart
1394 sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]);
1395 Node_getEntity(*startpoint)->setKeyValue("origin", sTmp);
1396 sprintf(sTmp, "%d", (int)Camera_getAngles(*g_pParentWnd->GetCamWnd())[CAMERA_YAW]);
1397 Node_getEntity(*startpoint)->setKeyValue("angle", sTmp);
1401 ===========================================================
1405 ===========================================================
1408 Vector3 region_mins(g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord);
1409 Vector3 region_maxs(g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord);
1411 scene::Node* region_sides[6];
1412 scene::Node* region_startpoint = 0;
1417 a regioned map will have temp walls put up at the region boundary
1418 \todo TODO TTimo old implementation of region brushes
1419 we still add them straight in the worldspawn and take them out after the map is saved
1420 with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module
1423 void AddRegionBrushes (void)
1429 region_sides[i] = &GlobalBrushCreator().createBrush();
1430 Node_getTraversable(Map_FindOrInsertWorldspawn(g_map))->insert(NodeSmartReference(*region_sides[i]));
1433 region_startpoint = &GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("info_player_start", false));
1435 ConstructRegionBrushes(region_sides, region_mins, region_maxs);
1436 ConstructRegionStartpoint(region_startpoint, region_mins, region_maxs);
1438 Node_getTraversable(GlobalSceneGraph().root())->insert(NodeSmartReference(*region_startpoint));
1441 void RemoveRegionBrushes (void)
1443 for(std::size_t i=0; i<6; i++)
1445 Node_getTraversable(*Map_GetWorldspawn(g_map))->erase(*region_sides[i]);
1447 Node_getTraversable(GlobalSceneGraph().root())->erase(*region_startpoint);
1450 inline void exclude_node(scene::Node& node, bool exclude)
1453 ? node.enable(scene::Node::eExcluded)
1454 : node.disable(scene::Node::eExcluded);
1457 class ExcludeAllWalker : public scene::Graph::Walker
1461 ExcludeAllWalker(bool exclude)
1462 : m_exclude(exclude)
1465 bool pre(const scene::Path& path, scene::Instance& instance) const
1467 exclude_node(path.top(), m_exclude);
1473 void Scene_Exclude_All(bool exclude)
1475 GlobalSceneGraph().traverse(ExcludeAllWalker(exclude));
1478 bool Instance_isSelected(const scene::Instance& instance)
1480 const Selectable* selectable = Instance_getSelectable(instance);
1481 return selectable != 0 && selectable->isSelected();
1484 class ExcludeSelectedWalker : public scene::Graph::Walker
1488 ExcludeSelectedWalker(bool exclude)
1489 : m_exclude(exclude)
1492 bool pre(const scene::Path& path, scene::Instance& instance) const
1494 exclude_node(path.top(), (instance.isSelected() || instance.childSelected() || instance.parentSelected()) == m_exclude);
1499 void Scene_Exclude_Selected(bool exclude)
1501 GlobalSceneGraph().traverse(ExcludeSelectedWalker(exclude));
1504 class ExcludeRegionedWalker : public scene::Graph::Walker
1508 ExcludeRegionedWalker(bool exclude)
1509 : m_exclude(exclude)
1512 bool pre(const scene::Path& path, scene::Instance& instance) const
1518 aabb_intersects_aabb(
1519 instance.worldAABB(),
1520 aabb_for_minmax(region_mins, region_maxs)
1530 void Scene_Exclude_Region(bool exclude)
1532 GlobalSceneGraph().traverse(ExcludeRegionedWalker(exclude));
1539 Other filtering options may still be on
1542 void Map_RegionOff()
1544 region_active = false;
1546 region_maxs[0] = g_MaxWorldCoord - 64;
1547 region_mins[0] = g_MinWorldCoord + 64;
1548 region_maxs[1] = g_MaxWorldCoord - 64;
1549 region_mins[1] = g_MinWorldCoord + 64;
1550 region_maxs[2] = g_MaxWorldCoord - 64;
1551 region_mins[2] = g_MinWorldCoord + 64;
1553 Scene_Exclude_All(false);
1556 void Map_ApplyRegion (void)
1558 region_active = true;
1560 Scene_Exclude_Region(false);
1565 ========================
1566 Map_RegionSelectedBrushes
1567 ========================
1569 void Map_RegionSelectedBrushes (void)
1573 if(GlobalSelectionSystem().countSelected() != 0
1574 && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
1576 region_active = true;
1577 Select_GetBounds (region_mins, region_maxs);
1579 Scene_Exclude_Selected(false);
1581 GlobalSelectionSystem().setSelectedAll(false);
1591 void Map_RegionXY(float x_min, float y_min, float x_max, float y_max)
1595 region_mins[0] = x_min;
1596 region_maxs[0] = x_max;
1597 region_mins[1] = y_min;
1598 region_maxs[1] = y_max;
1599 region_mins[2] = g_MinWorldCoord + 64;
1600 region_maxs[2] = g_MaxWorldCoord - 64;
1605 void Map_RegionBounds(const AABB& bounds)
1609 region_mins = vector3_subtracted(bounds.origin, bounds.extents);
1610 region_maxs = vector3_added(bounds.origin, bounds.extents);
1622 void Map_RegionBrush (void)
1624 if(GlobalSelectionSystem().countSelected() != 0)
1626 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
1627 Map_RegionBounds(instance.worldAABB());
1636 bool Map_ImportFile(const char* filename)
1638 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1640 bool success = false;
1642 if(extension_equal(path_get_extension(filename), "bsp"))
1646 Resource* resource = GlobalReferenceCache().capture(filename);
1647 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1648 if(!resource->load())
1650 GlobalReferenceCache().release(filename);
1653 NodeSmartReference clone(NewMapRoot(""));
1654 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1655 Map_gatherNamespaced(clone);
1656 Map_mergeClonedNames();
1659 GlobalReferenceCache().release(filename);
1662 SceneChangeNotify();
1668 const char *type = GlobalRadiant().getRequiredGameDescriptionKeyValue("q3map2_type");
1669 int n = string_length(path_get_extension(filename));
1670 if(n && (extension_equal(path_get_extension(filename), "bsp") || extension_equal(path_get_extension(filename), "map")))
1672 StringBuffer output;
1673 output.push_string(AppPath_get());
1674 output.push_string("q3map2.");
1675 output.push_string(RADIANT_EXECUTABLE);
1676 output.push_string(" -v -game ");
1677 output.push_string((type && *type) ? type : "quake3");
1678 output.push_string(" -fs_basepath \"");
1679 output.push_string(EnginePath_get());
1680 output.push_string("\" -fs_game ");
1681 output.push_string(gamename_get());
1682 output.push_string(" -convert -format ");
1683 output.push_string(Brush::m_type == eBrushTypeQuake3BP ? "map_bp" : "map");
1684 output.push_string(" \"");
1685 output.push_string(filename);
1686 output.push_string("\"");
1689 Q_Exec(NULL, output.c_str(), NULL, false, true);
1691 // rebuild filename as "filenamewithoutext_converted.map"
1693 output.push_range(filename, filename + string_length(filename) - (n + 1));
1694 output.push_string("_converted.map");
1695 filename = output.c_str();
1698 Resource* resource = GlobalReferenceCache().capture(filename);
1699 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1700 if(!resource->load())
1702 GlobalReferenceCache().release(filename);
1705 NodeSmartReference clone(NewMapRoot(""));
1706 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1707 Map_gatherNamespaced(clone);
1708 Map_mergeClonedNames();
1711 GlobalReferenceCache().release(filename);
1714 SceneChangeNotify();
1723 bool Map_SaveFile(const char* filename)
1725 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1726 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse, filename);
1734 // Saves selected world brushes and whole entities with partial/full selections
1736 bool Map_SaveSelected(const char* filename)
1738 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename);
1742 class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
1744 scene::Node& m_parent;
1746 ParentSelectedBrushesToEntityWalker(scene::Node& parent) : m_parent(parent)
1749 bool pre(const scene::Path& path, scene::Instance& instance) const
1751 if(path.top().get_pointer() != &m_parent
1752 && Node_isPrimitive(path.top()))
1754 Selectable* selectable = Instance_getSelectable(instance);
1756 && selectable->isSelected()
1764 void post(const scene::Path& path, scene::Instance& instance) const
1766 if(path.top().get_pointer() != &m_parent
1767 && Node_isPrimitive(path.top()))
1769 Selectable* selectable = Instance_getSelectable(instance);
1771 && selectable->isSelected()
1774 scene::Node& parent = path.parent();
1775 if(&parent != &m_parent)
1777 NodeSmartReference node(path.top().get());
1778 Node_getTraversable(parent)->erase(node);
1779 Node_getTraversable(m_parent)->insert(node);
1786 void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent)
1788 graph.traverse(ParentSelectedBrushesToEntityWalker(parent));
1791 class CountSelectedBrushes : public scene::Graph::Walker
1793 std::size_t& m_count;
1794 mutable std::size_t m_depth;
1796 CountSelectedBrushes(std::size_t& count) : m_count(count), m_depth(0)
1800 bool pre(const scene::Path& path, scene::Instance& instance) const
1802 if(++m_depth != 1 && path.top().get().isRoot())
1806 Selectable* selectable = Instance_getSelectable(instance);
1808 && selectable->isSelected()
1809 && Node_isPrimitive(path.top()))
1815 void post(const scene::Path& path, scene::Instance& instance) const
1821 std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
1824 graph.traverse(CountSelectedBrushes(count));
1836 const char* nodetype_get_name(ENodeType type)
1838 if(type == eNodeMap)
1840 if(type == eNodeEntity)
1842 if(type == eNodePrimitive)
1847 ENodeType node_get_nodetype(scene::Node& node)
1849 if(Node_isEntity(node))
1853 if(Node_isPrimitive(node))
1855 return eNodePrimitive;
1857 return eNodeUnknown;
1860 bool contains_entity(scene::Node& node)
1862 return Node_getTraversable(node) != 0 && !Node_isBrush(node) && !Node_isPatch(node) && !Node_isEntity(node);
1865 bool contains_primitive(scene::Node& node)
1867 return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
1870 ENodeType node_get_contains(scene::Node& node)
1872 if(contains_entity(node))
1876 if(contains_primitive(node))
1878 return eNodePrimitive;
1880 return eNodeUnknown;
1883 void Path_parent(const scene::Path& parent, const scene::Path& child)
1885 ENodeType contains = node_get_contains(parent.top());
1886 ENodeType type = node_get_nodetype(child.top());
1888 if(contains != eNodeUnknown && contains == type)
1890 NodeSmartReference node(child.top().get());
1891 Path_deleteTop(child);
1892 Node_getTraversable(parent.top())->insert(node);
1893 SceneChangeNotify();
1897 globalErrorStream() << "failed - " << nodetype_get_name(type) << " cannot be parented to " << nodetype_get_name(contains) << " container.\n";
1901 void Scene_parentSelected()
1903 UndoableCommand undo("parentSelected");
1905 if(GlobalSelectionSystem().countSelected() > 1)
1907 class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor
1909 const scene::Path& m_parent;
1911 ParentSelectedBrushesToEntityWalker(const scene::Path& parent) : m_parent(parent)
1914 void visit(scene::Instance& instance) const
1916 if(&m_parent != &instance.path())
1918 Path_parent(m_parent, instance.path());
1923 ParentSelectedBrushesToEntityWalker visitor(GlobalSelectionSystem().ultimateSelected().path());
1924 GlobalSelectionSystem().foreachSelected(visitor);
1928 globalOutputStream() << "failed - did not find two selected nodes.\n";
1936 if (ConfirmModified("New Map"))
1944 CopiedString g_mapsPath;
1946 const char* getMapsPath()
1948 return g_mapsPath.c_str();
1951 const char* map_open(const char* title)
1953 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name(), true, false, false);
1956 const char* map_import(const char* title)
1958 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name(), false, true, false);
1961 const char* map_save(const char* title)
1963 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, getMapsPath(), MapFormat::Name(), false, false, true);
1968 if (!ConfirmModified("Open Map"))
1971 const char* filename = map_open("Open Map");
1975 MRU_AddFile(filename);
1978 Map_LoadFile(filename);
1984 const char* filename = map_import("Import Map");
1988 UndoableCommand undo("mapImport");
1989 Map_ImportFile(filename);
1995 const char* filename = map_save("Save Map");
1999 MRU_AddFile(filename);
2000 Map_Rename(filename);
2013 if(Map_Unnamed(g_map))
2017 else if(Map_Modified(g_map))
2025 const char* filename = map_save("Export Selection");
2029 Map_SaveSelected(filename);
2035 const char* filename = map_save("Export Region");
2039 Map_SaveRegion(filename);
2047 SceneChangeNotify();
2053 g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
2054 g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(),
2055 g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
2056 g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale()
2058 SceneChangeNotify();
2064 SceneChangeNotify();
2067 void RegionSelected()
2069 Map_RegionSelectedBrushes();
2070 SceneChangeNotify();
2077 class BrushFindByIndexWalker : public scene::Traversable::Walker
2079 mutable std::size_t m_index;
2080 scene::Path& m_path;
2082 BrushFindByIndexWalker(std::size_t index, scene::Path& path)
2083 : m_index(index), m_path(path)
2086 bool pre(scene::Node& node) const
2088 if(Node_isPrimitive(node) && m_index-- == 0)
2090 m_path.push(makeReference(node));
2096 class EntityFindByIndexWalker : public scene::Traversable::Walker
2098 mutable std::size_t m_index;
2099 scene::Path& m_path;
2101 EntityFindByIndexWalker(std::size_t index, scene::Path& path)
2102 : m_index(index), m_path(path)
2105 bool pre(scene::Node& node) const
2107 if(Node_isEntity(node) && m_index-- == 0)
2109 m_path.push(makeReference(node));
2115 void Scene_FindEntityBrush(std::size_t entity, std::size_t brush, scene::Path& path)
2117 path.push(makeReference(GlobalSceneGraph().root()));
2119 Node_getTraversable(path.top())->traverse(EntityFindByIndexWalker(entity, path));
2121 if(path.size() == 2)
2123 scene::Traversable* traversable = Node_getTraversable(path.top());
2124 if(traversable != 0)
2126 traversable->traverse(BrushFindByIndexWalker(brush, path));
2131 inline bool Node_hasChildren(scene::Node& node)
2133 scene::Traversable* traversable = Node_getTraversable(node);
2134 return traversable != 0 && !traversable->empty();
2137 void SelectBrush (int entitynum, int brushnum)
2140 Scene_FindEntityBrush(entitynum, brushnum, path);
2141 if(path.size() == 3 || (path.size() == 2 && !Node_hasChildren(path.top())))
2143 scene::Instance* instance = GlobalSceneGraph().find(path);
2144 ASSERT_MESSAGE(instance != 0, "SelectBrush: path not found in scenegraph");
2145 Selectable* selectable = Instance_getSelectable(*instance);
2146 ASSERT_MESSAGE(selectable != 0, "SelectBrush: path not selectable");
2147 selectable->setSelected(true);
2148 g_pParentWnd->GetXYWnd()->PositionView(instance->worldAABB().origin);
2153 class BrushFindIndexWalker : public scene::Graph::Walker
2155 mutable const scene::Node* m_node;
2156 std::size_t& m_count;
2158 BrushFindIndexWalker(const scene::Node& node, std::size_t& count)
2159 : m_node(&node), m_count(count)
2162 bool pre(const scene::Path& path, scene::Instance& instance) const
2164 if(Node_isPrimitive(path.top()))
2166 if(m_node == path.top().get_pointer())
2179 class EntityFindIndexWalker : public scene::Graph::Walker
2181 mutable const scene::Node* m_node;
2182 std::size_t& m_count;
2184 EntityFindIndexWalker(const scene::Node& node, std::size_t& count)
2185 : m_node(&node), m_count(count)
2188 bool pre(const scene::Path& path, scene::Instance& instance) const
2190 if(Node_isEntity(path.top()))
2192 if(m_node == path.top().get_pointer())
2205 static void GetSelectionIndex (int *ent, int *brush)
2207 std::size_t count_brush = 0;
2208 std::size_t count_entity = 0;
2209 if(GlobalSelectionSystem().countSelected() != 0)
2211 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
2213 GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
2214 GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
2216 *brush = int(count_brush);
2217 *ent = int(count_entity);
2226 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
2228 GtkAccelGroup* accel = gtk_accel_group_new();
2229 gtk_window_add_accel_group(window, accel);
2232 GtkVBox* vbox = create_dialog_vbox(4, 4);
2233 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
2235 GtkTable* table = create_dialog_table(2, 2, 4, 4);
2236 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
2238 GtkWidget* label = gtk_label_new ("Entity number");
2239 gtk_widget_show (label);
2240 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2241 (GtkAttachOptions) (0),
2242 (GtkAttachOptions) (0), 0, 0);
2245 GtkWidget* label = gtk_label_new ("Brush number");
2246 gtk_widget_show (label);
2247 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2248 (GtkAttachOptions) (0),
2249 (GtkAttachOptions) (0), 0, 0);
2252 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2253 gtk_widget_show(GTK_WIDGET(entry));
2254 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
2255 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2256 (GtkAttachOptions) (0), 0, 0);
2257 gtk_widget_grab_focus(GTK_WIDGET(entry));
2261 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2262 gtk_widget_show(GTK_WIDGET(entry));
2263 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
2264 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2265 (GtkAttachOptions) (0), 0, 0);
2271 GtkHBox* hbox = create_dialog_hbox(4);
2272 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
2274 GtkButton* button = create_dialog_button("Find", G_CALLBACK(dialog_button_ok), &dialog);
2275 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2276 widget_make_default(GTK_WIDGET(button));
2277 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
2280 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_cancel), &dialog);
2281 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2282 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
2287 // Initialize dialog
2291 GetSelectionIndex (&ent, &br);
2292 sprintf (buf, "%i", ent);
2293 gtk_entry_set_text(entity, buf);
2294 sprintf (buf, "%i", br);
2295 gtk_entry_set_text(brush, buf);
2297 if(modal_dialog_show(window, dialog) == eIDOK)
2299 const char *entstr = gtk_entry_get_text(entity);
2300 const char *brushstr = gtk_entry_get_text(brush);
2301 SelectBrush (atoi(entstr), atoi(brushstr));
2304 gtk_widget_destroy(GTK_WIDGET(window));
2307 void Map_constructPreferences(PreferencesPage& page)
2309 page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
2313 class MapEntityClasses : public ModuleObserver
2315 std::size_t m_unrealised;
2317 MapEntityClasses() : m_unrealised(1)
2322 if(--m_unrealised == 0)
2324 if(g_map.m_resource != 0)
2326 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
2327 g_map.m_resource->realise();
2333 if(++m_unrealised == 1)
2335 if(g_map.m_resource != 0)
2337 g_map.m_resource->flush();
2338 g_map.m_resource->unrealise();
2344 MapEntityClasses g_MapEntityClasses;
2347 class MapModuleObserver : public ModuleObserver
2349 std::size_t m_unrealised;
2351 MapModuleObserver() : m_unrealised(1)
2356 if(--m_unrealised == 0)
2358 ASSERT_MESSAGE(!string_empty(g_qeglobals.m_userGamePath.c_str()), "maps_directory: user-game-path is empty");
2359 StringOutputStream buffer(256);
2360 buffer << g_qeglobals.m_userGamePath.c_str() << "maps/";
2361 Q_mkdir(buffer.c_str());
2362 g_mapsPath = buffer.c_str();
2367 if(++m_unrealised == 1)
2374 MapModuleObserver g_MapModuleObserver;
2376 #include "preferencesystem.h"
2378 CopiedString g_strLastMap;
2379 bool g_bLoadLastMap = false;
2381 void Map_Construct()
2383 GlobalCommands_insert("RegionOff", FreeCaller<RegionOff>());
2384 GlobalCommands_insert("RegionSetXY", FreeCaller<RegionXY>());
2385 GlobalCommands_insert("RegionSetBrush", FreeCaller<RegionBrush>());
2386 GlobalCommands_insert("RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator('R', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
2388 GlobalPreferenceSystem().registerPreference("LastMap", CopiedStringImportStringCaller(g_strLastMap), CopiedStringExportStringCaller(g_strLastMap));
2389 GlobalPreferenceSystem().registerPreference("LoadLastMap", BoolImportStringCaller(g_bLoadLastMap), BoolExportStringCaller(g_bLoadLastMap));
2390 GlobalPreferenceSystem().registerPreference("MapInfoDlg", WindowPositionImportStringCaller(g_posMapInfoWnd), WindowPositionExportStringCaller(g_posMapInfoWnd));
2392 PreferencesDialog_addSettingsPreferences(FreeCaller1<PreferencesPage&, Map_constructPreferences>());
2394 GlobalEntityClassManager().attach(g_MapEntityClasses);
2395 Radiant_attachHomePathsObserver(g_MapModuleObserver);
2400 Radiant_detachHomePathsObserver(g_MapModuleObserver);
2401 GlobalEntityClassManager().detach(g_MapEntityClasses);