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_game ");
1694 output.push_string(gamename_get());
1695 output.push_string(" -convert -format ");
1696 output.push_string(Brush::m_type == eBrushTypeQuake3BP ? "map_bp" : "map");
1697 output.push_string(" -readmap \"");
1698 output.push_string(filename);
1699 output.push_string("\"");
1702 Q_Exec(NULL, output.c_str(), NULL, false, true);
1704 // rebuild filename as "filenamewithoutext_converted.map"
1706 output.push_range(filename, filename + string_length(filename) - (n + 1));
1707 output.push_string("_converted.map");
1708 filename = output.c_str();
1711 Resource* resource = GlobalReferenceCache().capture(filename);
1712 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1713 if(!resource->load())
1715 GlobalReferenceCache().release(filename);
1718 NodeSmartReference clone(NewMapRoot(""));
1719 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1720 Map_gatherNamespaced(clone);
1721 Map_mergeClonedNames();
1724 GlobalReferenceCache().release(filename);
1727 SceneChangeNotify();
1736 bool Map_SaveFile(const char* filename)
1738 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1739 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse, filename);
1747 // Saves selected world brushes and whole entities with partial/full selections
1749 bool Map_SaveSelected(const char* filename)
1751 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename);
1755 class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
1757 scene::Node& m_parent;
1759 ParentSelectedBrushesToEntityWalker(scene::Node& parent) : m_parent(parent)
1762 bool pre(const scene::Path& path, scene::Instance& instance) const
1764 if(path.top().get_pointer() != &m_parent
1765 && Node_isPrimitive(path.top()))
1767 Selectable* selectable = Instance_getSelectable(instance);
1769 && selectable->isSelected()
1777 void post(const scene::Path& path, scene::Instance& instance) const
1779 if(path.top().get_pointer() != &m_parent
1780 && Node_isPrimitive(path.top()))
1782 Selectable* selectable = Instance_getSelectable(instance);
1784 && selectable->isSelected()
1787 scene::Node& parent = path.parent();
1788 if(&parent != &m_parent)
1790 NodeSmartReference node(path.top().get());
1791 Node_getTraversable(parent)->erase(node);
1792 Node_getTraversable(m_parent)->insert(node);
1799 void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent)
1801 graph.traverse(ParentSelectedBrushesToEntityWalker(parent));
1804 class CountSelectedBrushes : public scene::Graph::Walker
1806 std::size_t& m_count;
1807 mutable std::size_t m_depth;
1809 CountSelectedBrushes(std::size_t& count) : m_count(count), m_depth(0)
1813 bool pre(const scene::Path& path, scene::Instance& instance) const
1815 if(++m_depth != 1 && path.top().get().isRoot())
1819 Selectable* selectable = Instance_getSelectable(instance);
1821 && selectable->isSelected()
1822 && Node_isPrimitive(path.top()))
1828 void post(const scene::Path& path, scene::Instance& instance) const
1834 std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
1837 graph.traverse(CountSelectedBrushes(count));
1849 const char* nodetype_get_name(ENodeType type)
1851 if(type == eNodeMap)
1853 if(type == eNodeEntity)
1855 if(type == eNodePrimitive)
1860 ENodeType node_get_nodetype(scene::Node& node)
1862 if(Node_isEntity(node))
1866 if(Node_isPrimitive(node))
1868 return eNodePrimitive;
1870 return eNodeUnknown;
1873 bool contains_entity(scene::Node& node)
1875 return Node_getTraversable(node) != 0 && !Node_isBrush(node) && !Node_isPatch(node) && !Node_isEntity(node);
1878 bool contains_primitive(scene::Node& node)
1880 return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
1883 ENodeType node_get_contains(scene::Node& node)
1885 if(contains_entity(node))
1889 if(contains_primitive(node))
1891 return eNodePrimitive;
1893 return eNodeUnknown;
1896 void Path_parent(const scene::Path& parent, const scene::Path& child)
1898 ENodeType contains = node_get_contains(parent.top());
1899 ENodeType type = node_get_nodetype(child.top());
1901 if(contains != eNodeUnknown && contains == type)
1903 NodeSmartReference node(child.top().get());
1904 Path_deleteTop(child);
1905 Node_getTraversable(parent.top())->insert(node);
1906 SceneChangeNotify();
1910 globalErrorStream() << "failed - " << nodetype_get_name(type) << " cannot be parented to " << nodetype_get_name(contains) << " container.\n";
1914 void Scene_parentSelected()
1916 UndoableCommand undo("parentSelected");
1918 if(GlobalSelectionSystem().countSelected() > 1)
1920 class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor
1922 const scene::Path& m_parent;
1924 ParentSelectedBrushesToEntityWalker(const scene::Path& parent) : m_parent(parent)
1927 void visit(scene::Instance& instance) const
1929 if(&m_parent != &instance.path())
1931 Path_parent(m_parent, instance.path());
1936 ParentSelectedBrushesToEntityWalker visitor(GlobalSelectionSystem().ultimateSelected().path());
1937 GlobalSelectionSystem().foreachSelected(visitor);
1941 globalOutputStream() << "failed - did not find two selected nodes.\n";
1949 if (ConfirmModified("New Map"))
1957 CopiedString g_mapsPath;
1959 const char* getMapsPath()
1961 return g_mapsPath.c_str();
1964 const char* map_open(const char* title)
1966 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name(), true, false, false);
1969 const char* map_import(const char* title)
1971 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name(), false, true, false);
1974 const char* map_save(const char* title)
1976 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, getMapsPath(), MapFormat::Name(), false, false, true);
1981 if (!ConfirmModified("Open Map"))
1984 const char* filename = map_open("Open Map");
1988 MRU_AddFile(filename);
1991 Map_LoadFile(filename);
1997 const char* filename = map_import("Import Map");
2001 UndoableCommand undo("mapImport");
2002 Map_ImportFile(filename);
2008 const char* filename = map_save("Save Map");
2012 MRU_AddFile(filename);
2013 Map_Rename(filename);
2026 if(Map_Unnamed(g_map))
2030 else if(Map_Modified(g_map))
2038 const char* filename = map_save("Export Selection");
2042 Map_SaveSelected(filename);
2048 const char* filename = map_save("Export Region");
2052 Map_SaveRegion(filename);
2060 SceneChangeNotify();
2066 g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
2067 g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(),
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()
2071 SceneChangeNotify();
2077 SceneChangeNotify();
2080 void RegionSelected()
2082 Map_RegionSelectedBrushes();
2083 SceneChangeNotify();
2090 class BrushFindByIndexWalker : public scene::Traversable::Walker
2092 mutable std::size_t m_index;
2093 scene::Path& m_path;
2095 BrushFindByIndexWalker(std::size_t index, scene::Path& path)
2096 : m_index(index), m_path(path)
2099 bool pre(scene::Node& node) const
2101 if(Node_isPrimitive(node) && m_index-- == 0)
2103 m_path.push(makeReference(node));
2109 class EntityFindByIndexWalker : public scene::Traversable::Walker
2111 mutable std::size_t m_index;
2112 scene::Path& m_path;
2114 EntityFindByIndexWalker(std::size_t index, scene::Path& path)
2115 : m_index(index), m_path(path)
2118 bool pre(scene::Node& node) const
2120 if(Node_isEntity(node) && m_index-- == 0)
2122 m_path.push(makeReference(node));
2128 void Scene_FindEntityBrush(std::size_t entity, std::size_t brush, scene::Path& path)
2130 path.push(makeReference(GlobalSceneGraph().root()));
2132 Node_getTraversable(path.top())->traverse(EntityFindByIndexWalker(entity, path));
2134 if(path.size() == 2)
2136 scene::Traversable* traversable = Node_getTraversable(path.top());
2137 if(traversable != 0)
2139 traversable->traverse(BrushFindByIndexWalker(brush, path));
2144 inline bool Node_hasChildren(scene::Node& node)
2146 scene::Traversable* traversable = Node_getTraversable(node);
2147 return traversable != 0 && !traversable->empty();
2150 void SelectBrush (int entitynum, int brushnum)
2153 Scene_FindEntityBrush(entitynum, brushnum, path);
2154 if(path.size() == 3 || (path.size() == 2 && !Node_hasChildren(path.top())))
2156 scene::Instance* instance = GlobalSceneGraph().find(path);
2157 ASSERT_MESSAGE(instance != 0, "SelectBrush: path not found in scenegraph");
2158 Selectable* selectable = Instance_getSelectable(*instance);
2159 ASSERT_MESSAGE(selectable != 0, "SelectBrush: path not selectable");
2160 selectable->setSelected(true);
2161 g_pParentWnd->GetXYWnd()->PositionView(instance->worldAABB().origin);
2166 class BrushFindIndexWalker : public scene::Graph::Walker
2168 mutable const scene::Node* m_node;
2169 std::size_t& m_count;
2171 BrushFindIndexWalker(const scene::Node& node, std::size_t& count)
2172 : m_node(&node), m_count(count)
2175 bool pre(const scene::Path& path, scene::Instance& instance) const
2177 if(Node_isPrimitive(path.top()))
2179 if(m_node == path.top().get_pointer())
2192 class EntityFindIndexWalker : public scene::Graph::Walker
2194 mutable const scene::Node* m_node;
2195 std::size_t& m_count;
2197 EntityFindIndexWalker(const scene::Node& node, std::size_t& count)
2198 : m_node(&node), m_count(count)
2201 bool pre(const scene::Path& path, scene::Instance& instance) const
2203 if(Node_isEntity(path.top()))
2205 if(m_node == path.top().get_pointer())
2218 static void GetSelectionIndex (int *ent, int *brush)
2220 std::size_t count_brush = 0;
2221 std::size_t count_entity = 0;
2222 if(GlobalSelectionSystem().countSelected() != 0)
2224 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
2226 GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
2227 GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
2229 *brush = int(count_brush);
2230 *ent = int(count_entity);
2239 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
2241 GtkAccelGroup* accel = gtk_accel_group_new();
2242 gtk_window_add_accel_group(window, accel);
2245 GtkVBox* vbox = create_dialog_vbox(4, 4);
2246 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
2248 GtkTable* table = create_dialog_table(2, 2, 4, 4);
2249 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
2251 GtkWidget* label = gtk_label_new ("Entity number");
2252 gtk_widget_show (label);
2253 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2254 (GtkAttachOptions) (0),
2255 (GtkAttachOptions) (0), 0, 0);
2258 GtkWidget* label = gtk_label_new ("Brush number");
2259 gtk_widget_show (label);
2260 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2261 (GtkAttachOptions) (0),
2262 (GtkAttachOptions) (0), 0, 0);
2265 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2266 gtk_widget_show(GTK_WIDGET(entry));
2267 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
2268 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2269 (GtkAttachOptions) (0), 0, 0);
2270 gtk_widget_grab_focus(GTK_WIDGET(entry));
2274 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2275 gtk_widget_show(GTK_WIDGET(entry));
2276 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
2277 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2278 (GtkAttachOptions) (0), 0, 0);
2284 GtkHBox* hbox = create_dialog_hbox(4);
2285 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
2287 GtkButton* button = create_dialog_button("Find", G_CALLBACK(dialog_button_ok), &dialog);
2288 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2289 widget_make_default(GTK_WIDGET(button));
2290 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
2293 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_cancel), &dialog);
2294 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2295 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
2300 // Initialize dialog
2304 GetSelectionIndex (&ent, &br);
2305 sprintf (buf, "%i", ent);
2306 gtk_entry_set_text(entity, buf);
2307 sprintf (buf, "%i", br);
2308 gtk_entry_set_text(brush, buf);
2310 if(modal_dialog_show(window, dialog) == eIDOK)
2312 const char *entstr = gtk_entry_get_text(entity);
2313 const char *brushstr = gtk_entry_get_text(brush);
2314 SelectBrush (atoi(entstr), atoi(brushstr));
2317 gtk_widget_destroy(GTK_WIDGET(window));
2320 void Map_constructPreferences(PreferencesPage& page)
2322 page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
2326 class MapEntityClasses : public ModuleObserver
2328 std::size_t m_unrealised;
2330 MapEntityClasses() : m_unrealised(1)
2335 if(--m_unrealised == 0)
2337 if(g_map.m_resource != 0)
2339 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
2340 g_map.m_resource->realise();
2346 if(++m_unrealised == 1)
2348 if(g_map.m_resource != 0)
2350 g_map.m_resource->flush();
2351 g_map.m_resource->unrealise();
2357 MapEntityClasses g_MapEntityClasses;
2360 class MapModuleObserver : public ModuleObserver
2362 std::size_t m_unrealised;
2364 MapModuleObserver() : m_unrealised(1)
2369 if(--m_unrealised == 0)
2371 ASSERT_MESSAGE(!string_empty(g_qeglobals.m_userGamePath.c_str()), "maps_directory: user-game-path is empty");
2372 StringOutputStream buffer(256);
2373 buffer << g_qeglobals.m_userGamePath.c_str() << "maps/";
2374 Q_mkdir(buffer.c_str());
2375 g_mapsPath = buffer.c_str();
2380 if(++m_unrealised == 1)
2387 MapModuleObserver g_MapModuleObserver;
2389 #include "preferencesystem.h"
2391 CopiedString g_strLastMap;
2392 bool g_bLoadLastMap = false;
2394 void Map_Construct()
2396 GlobalCommands_insert("RegionOff", FreeCaller<RegionOff>());
2397 GlobalCommands_insert("RegionSetXY", FreeCaller<RegionXY>());
2398 GlobalCommands_insert("RegionSetBrush", FreeCaller<RegionBrush>());
2399 GlobalCommands_insert("RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator('R', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
2401 GlobalPreferenceSystem().registerPreference("LastMap", CopiedStringImportStringCaller(g_strLastMap), CopiedStringExportStringCaller(g_strLastMap));
2402 GlobalPreferenceSystem().registerPreference("LoadLastMap", BoolImportStringCaller(g_bLoadLastMap), BoolExportStringCaller(g_bLoadLastMap));
2403 GlobalPreferenceSystem().registerPreference("MapInfoDlg", WindowPositionImportStringCaller(g_posMapInfoWnd), WindowPositionExportStringCaller(g_posMapInfoWnd));
2405 PreferencesDialog_addSettingsPreferences(FreeCaller1<PreferencesPage&, Map_constructPreferences>());
2407 GlobalEntityClassManager().attach(g_MapEntityClasses);
2408 Radiant_attachHomePathsObserver(g_MapModuleObserver);
2413 Radiant_detachHomePathsObserver(g_MapModuleObserver);
2414 GlobalEntityClassManager().detach(g_MapEntityClasses);