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 const MapFormat* format = NULL;
1647 const char* moduleName = findModuleName(&GlobalFiletypes(), MapFormat::Name(), path_get_extension(filename));
1648 if(string_not_empty(moduleName))
1649 format = ReferenceAPI_getMapModules().findModule(moduleName);
1652 format->wrongFormat = false;
1653 Resource* resource = GlobalReferenceCache().capture(filename);
1654 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1655 if(!resource->load())
1657 GlobalReferenceCache().release(filename);
1661 if(format->wrongFormat)
1663 GlobalReferenceCache().release(filename);
1666 NodeSmartReference clone(NewMapRoot(""));
1667 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1668 Map_gatherNamespaced(clone);
1669 Map_mergeClonedNames();
1672 GlobalReferenceCache().release(filename);
1675 SceneChangeNotify();
1681 const char *type = GlobalRadiant().getRequiredGameDescriptionKeyValue("q3map2_type");
1682 int n = string_length(path_get_extension(filename));
1683 if(n && (extension_equal(path_get_extension(filename), "bsp") || extension_equal(path_get_extension(filename), "map")))
1685 StringBuffer output;
1686 output.push_string(AppPath_get());
1687 output.push_string("q3map2.");
1688 output.push_string(RADIANT_EXECUTABLE);
1689 output.push_string(" -v -game ");
1690 output.push_string((type && *type) ? type : "quake3");
1691 output.push_string(" -fs_basepath \"");
1692 output.push_string(EnginePath_get());
1693 output.push_string(" -fs_homepath \"");
1694 output.push_string(g_qeglobals.m_userEnginePath.c_str());
1695 output.push_string("\" -fs_game ");
1696 output.push_string(gamename_get());
1697 output.push_string(" -convert -format ");
1698 output.push_string(Brush::m_type == eBrushTypeQuake3BP ? "map_bp" : "map");
1699 output.push_string(" -readmap \"");
1700 output.push_string(filename);
1701 output.push_string("\"");
1704 Q_Exec(NULL, output.c_str(), NULL, false, true);
1706 // rebuild filename as "filenamewithoutext_converted.map"
1708 output.push_range(filename, filename + string_length(filename) - (n + 1));
1709 output.push_string("_converted.map");
1710 filename = output.c_str();
1713 Resource* resource = GlobalReferenceCache().capture(filename);
1714 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1715 if(!resource->load())
1717 GlobalReferenceCache().release(filename);
1720 NodeSmartReference clone(NewMapRoot(""));
1721 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1722 Map_gatherNamespaced(clone);
1723 Map_mergeClonedNames();
1726 GlobalReferenceCache().release(filename);
1729 SceneChangeNotify();
1738 bool Map_SaveFile(const char* filename)
1740 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1741 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse, filename);
1749 // Saves selected world brushes and whole entities with partial/full selections
1751 bool Map_SaveSelected(const char* filename)
1753 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename);
1757 class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
1759 scene::Node& m_parent;
1761 ParentSelectedBrushesToEntityWalker(scene::Node& parent) : m_parent(parent)
1764 bool pre(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()
1779 void post(const scene::Path& path, scene::Instance& instance) const
1781 if(path.top().get_pointer() != &m_parent
1782 && Node_isPrimitive(path.top()))
1784 Selectable* selectable = Instance_getSelectable(instance);
1786 && selectable->isSelected()
1789 scene::Node& parent = path.parent();
1790 if(&parent != &m_parent)
1792 NodeSmartReference node(path.top().get());
1793 Node_getTraversable(parent)->erase(node);
1794 Node_getTraversable(m_parent)->insert(node);
1801 void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent)
1803 graph.traverse(ParentSelectedBrushesToEntityWalker(parent));
1806 class CountSelectedBrushes : public scene::Graph::Walker
1808 std::size_t& m_count;
1809 mutable std::size_t m_depth;
1811 CountSelectedBrushes(std::size_t& count) : m_count(count), m_depth(0)
1815 bool pre(const scene::Path& path, scene::Instance& instance) const
1817 if(++m_depth != 1 && path.top().get().isRoot())
1821 Selectable* selectable = Instance_getSelectable(instance);
1823 && selectable->isSelected()
1824 && Node_isPrimitive(path.top()))
1830 void post(const scene::Path& path, scene::Instance& instance) const
1836 std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
1839 graph.traverse(CountSelectedBrushes(count));
1851 const char* nodetype_get_name(ENodeType type)
1853 if(type == eNodeMap)
1855 if(type == eNodeEntity)
1857 if(type == eNodePrimitive)
1862 ENodeType node_get_nodetype(scene::Node& node)
1864 if(Node_isEntity(node))
1868 if(Node_isPrimitive(node))
1870 return eNodePrimitive;
1872 return eNodeUnknown;
1875 bool contains_entity(scene::Node& node)
1877 return Node_getTraversable(node) != 0 && !Node_isBrush(node) && !Node_isPatch(node) && !Node_isEntity(node);
1880 bool contains_primitive(scene::Node& node)
1882 return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
1885 ENodeType node_get_contains(scene::Node& node)
1887 if(contains_entity(node))
1891 if(contains_primitive(node))
1893 return eNodePrimitive;
1895 return eNodeUnknown;
1898 void Path_parent(const scene::Path& parent, const scene::Path& child)
1900 ENodeType contains = node_get_contains(parent.top());
1901 ENodeType type = node_get_nodetype(child.top());
1903 if(contains != eNodeUnknown && contains == type)
1905 NodeSmartReference node(child.top().get());
1906 Path_deleteTop(child);
1907 Node_getTraversable(parent.top())->insert(node);
1908 SceneChangeNotify();
1912 globalErrorStream() << "failed - " << nodetype_get_name(type) << " cannot be parented to " << nodetype_get_name(contains) << " container.\n";
1916 void Scene_parentSelected()
1918 UndoableCommand undo("parentSelected");
1920 if(GlobalSelectionSystem().countSelected() > 1)
1922 class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor
1924 const scene::Path& m_parent;
1926 ParentSelectedBrushesToEntityWalker(const scene::Path& parent) : m_parent(parent)
1929 void visit(scene::Instance& instance) const
1931 if(&m_parent != &instance.path())
1933 Path_parent(m_parent, instance.path());
1938 ParentSelectedBrushesToEntityWalker visitor(GlobalSelectionSystem().ultimateSelected().path());
1939 GlobalSelectionSystem().foreachSelected(visitor);
1943 globalOutputStream() << "failed - did not find two selected nodes.\n";
1951 if (ConfirmModified("New Map"))
1959 CopiedString g_mapsPath;
1961 const char* getMapsPath()
1963 return g_mapsPath.c_str();
1966 const char* map_open(const char* title)
1968 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name(), true, false, false);
1971 const char* map_import(const char* title)
1973 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name(), false, true, false);
1976 const char* map_save(const char* title)
1978 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, getMapsPath(), MapFormat::Name(), false, false, true);
1983 if (!ConfirmModified("Open Map"))
1986 const char* filename = map_open("Open Map");
1990 MRU_AddFile(filename);
1993 Map_LoadFile(filename);
1999 const char* filename = map_import("Import Map");
2003 UndoableCommand undo("mapImport");
2004 Map_ImportFile(filename);
2010 const char* filename = map_save("Save Map");
2014 MRU_AddFile(filename);
2015 Map_Rename(filename);
2028 if(Map_Unnamed(g_map))
2032 else if(Map_Modified(g_map))
2040 const char* filename = map_save("Export Selection");
2044 Map_SaveSelected(filename);
2050 const char* filename = map_save("Export Region");
2054 Map_SaveRegion(filename);
2062 SceneChangeNotify();
2068 g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
2069 g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(),
2070 g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
2071 g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale()
2073 SceneChangeNotify();
2079 SceneChangeNotify();
2082 void RegionSelected()
2084 Map_RegionSelectedBrushes();
2085 SceneChangeNotify();
2092 class BrushFindByIndexWalker : public scene::Traversable::Walker
2094 mutable std::size_t m_index;
2095 scene::Path& m_path;
2097 BrushFindByIndexWalker(std::size_t index, scene::Path& path)
2098 : m_index(index), m_path(path)
2101 bool pre(scene::Node& node) const
2103 if(Node_isPrimitive(node) && m_index-- == 0)
2105 m_path.push(makeReference(node));
2111 class EntityFindByIndexWalker : public scene::Traversable::Walker
2113 mutable std::size_t m_index;
2114 scene::Path& m_path;
2116 EntityFindByIndexWalker(std::size_t index, scene::Path& path)
2117 : m_index(index), m_path(path)
2120 bool pre(scene::Node& node) const
2122 if(Node_isEntity(node) && m_index-- == 0)
2124 m_path.push(makeReference(node));
2130 void Scene_FindEntityBrush(std::size_t entity, std::size_t brush, scene::Path& path)
2132 path.push(makeReference(GlobalSceneGraph().root()));
2134 Node_getTraversable(path.top())->traverse(EntityFindByIndexWalker(entity, path));
2136 if(path.size() == 2)
2138 scene::Traversable* traversable = Node_getTraversable(path.top());
2139 if(traversable != 0)
2141 traversable->traverse(BrushFindByIndexWalker(brush, path));
2146 inline bool Node_hasChildren(scene::Node& node)
2148 scene::Traversable* traversable = Node_getTraversable(node);
2149 return traversable != 0 && !traversable->empty();
2152 void SelectBrush (int entitynum, int brushnum)
2155 Scene_FindEntityBrush(entitynum, brushnum, path);
2156 if(path.size() == 3 || (path.size() == 2 && !Node_hasChildren(path.top())))
2158 scene::Instance* instance = GlobalSceneGraph().find(path);
2159 ASSERT_MESSAGE(instance != 0, "SelectBrush: path not found in scenegraph");
2160 Selectable* selectable = Instance_getSelectable(*instance);
2161 ASSERT_MESSAGE(selectable != 0, "SelectBrush: path not selectable");
2162 selectable->setSelected(true);
2163 g_pParentWnd->GetXYWnd()->PositionView(instance->worldAABB().origin);
2168 class BrushFindIndexWalker : public scene::Graph::Walker
2170 mutable const scene::Node* m_node;
2171 std::size_t& m_count;
2173 BrushFindIndexWalker(const scene::Node& node, std::size_t& count)
2174 : m_node(&node), m_count(count)
2177 bool pre(const scene::Path& path, scene::Instance& instance) const
2179 if(Node_isPrimitive(path.top()))
2181 if(m_node == path.top().get_pointer())
2194 class EntityFindIndexWalker : public scene::Graph::Walker
2196 mutable const scene::Node* m_node;
2197 std::size_t& m_count;
2199 EntityFindIndexWalker(const scene::Node& node, std::size_t& count)
2200 : m_node(&node), m_count(count)
2203 bool pre(const scene::Path& path, scene::Instance& instance) const
2205 if(Node_isEntity(path.top()))
2207 if(m_node == path.top().get_pointer())
2220 static void GetSelectionIndex (int *ent, int *brush)
2222 std::size_t count_brush = 0;
2223 std::size_t count_entity = 0;
2224 if(GlobalSelectionSystem().countSelected() != 0)
2226 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
2228 GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
2229 GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
2231 *brush = int(count_brush);
2232 *ent = int(count_entity);
2241 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
2243 GtkAccelGroup* accel = gtk_accel_group_new();
2244 gtk_window_add_accel_group(window, accel);
2247 GtkVBox* vbox = create_dialog_vbox(4, 4);
2248 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
2250 GtkTable* table = create_dialog_table(2, 2, 4, 4);
2251 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
2253 GtkWidget* label = gtk_label_new ("Entity number");
2254 gtk_widget_show (label);
2255 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2256 (GtkAttachOptions) (0),
2257 (GtkAttachOptions) (0), 0, 0);
2260 GtkWidget* label = gtk_label_new ("Brush number");
2261 gtk_widget_show (label);
2262 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2263 (GtkAttachOptions) (0),
2264 (GtkAttachOptions) (0), 0, 0);
2267 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2268 gtk_widget_show(GTK_WIDGET(entry));
2269 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
2270 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2271 (GtkAttachOptions) (0), 0, 0);
2272 gtk_widget_grab_focus(GTK_WIDGET(entry));
2276 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2277 gtk_widget_show(GTK_WIDGET(entry));
2278 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
2279 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2280 (GtkAttachOptions) (0), 0, 0);
2286 GtkHBox* hbox = create_dialog_hbox(4);
2287 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
2289 GtkButton* button = create_dialog_button("Find", G_CALLBACK(dialog_button_ok), &dialog);
2290 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2291 widget_make_default(GTK_WIDGET(button));
2292 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
2295 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_cancel), &dialog);
2296 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2297 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
2302 // Initialize dialog
2306 GetSelectionIndex (&ent, &br);
2307 sprintf (buf, "%i", ent);
2308 gtk_entry_set_text(entity, buf);
2309 sprintf (buf, "%i", br);
2310 gtk_entry_set_text(brush, buf);
2312 if(modal_dialog_show(window, dialog) == eIDOK)
2314 const char *entstr = gtk_entry_get_text(entity);
2315 const char *brushstr = gtk_entry_get_text(brush);
2316 SelectBrush (atoi(entstr), atoi(brushstr));
2319 gtk_widget_destroy(GTK_WIDGET(window));
2322 void Map_constructPreferences(PreferencesPage& page)
2324 page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
2328 class MapEntityClasses : public ModuleObserver
2330 std::size_t m_unrealised;
2332 MapEntityClasses() : m_unrealised(1)
2337 if(--m_unrealised == 0)
2339 if(g_map.m_resource != 0)
2341 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
2342 g_map.m_resource->realise();
2348 if(++m_unrealised == 1)
2350 if(g_map.m_resource != 0)
2352 g_map.m_resource->flush();
2353 g_map.m_resource->unrealise();
2359 MapEntityClasses g_MapEntityClasses;
2362 class MapModuleObserver : public ModuleObserver
2364 std::size_t m_unrealised;
2366 MapModuleObserver() : m_unrealised(1)
2371 if(--m_unrealised == 0)
2373 ASSERT_MESSAGE(!string_empty(g_qeglobals.m_userGamePath.c_str()), "maps_directory: user-game-path is empty");
2374 StringOutputStream buffer(256);
2375 buffer << g_qeglobals.m_userGamePath.c_str() << "maps/";
2376 Q_mkdir(buffer.c_str());
2377 g_mapsPath = buffer.c_str();
2382 if(++m_unrealised == 1)
2389 MapModuleObserver g_MapModuleObserver;
2391 #include "preferencesystem.h"
2393 CopiedString g_strLastMap;
2394 bool g_bLoadLastMap = false;
2396 void Map_Construct()
2398 GlobalCommands_insert("RegionOff", FreeCaller<RegionOff>());
2399 GlobalCommands_insert("RegionSetXY", FreeCaller<RegionXY>());
2400 GlobalCommands_insert("RegionSetBrush", FreeCaller<RegionBrush>());
2401 GlobalCommands_insert("RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator('R', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
2403 GlobalPreferenceSystem().registerPreference("LastMap", CopiedStringImportStringCaller(g_strLastMap), CopiedStringExportStringCaller(g_strLastMap));
2404 GlobalPreferenceSystem().registerPreference("LoadLastMap", BoolImportStringCaller(g_bLoadLastMap), BoolExportStringCaller(g_bLoadLastMap));
2405 GlobalPreferenceSystem().registerPreference("MapInfoDlg", WindowPositionImportStringCaller(g_posMapInfoWnd), WindowPositionExportStringCaller(g_posMapInfoWnd));
2407 PreferencesDialog_addSettingsPreferences(FreeCaller1<PreferencesPage&, Map_constructPreferences>());
2409 GlobalEntityClassManager().attach(g_MapEntityClasses);
2410 Radiant_attachHomePathsObserver(g_MapModuleObserver);
2415 Radiant_detachHomePathsObserver(g_MapModuleObserver);
2416 GlobalEntityClassManager().detach(g_MapEntityClasses);