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"
98 //globalOutputStream() << "construct " << makeQuoted(c_str()) << "\n";
99 m_names.insert(name_read(c_str()));
106 //globalOutputStream() << "destroy " << makeQuoted(c_str()) << "\n";
107 m_names.erase(name_read(c_str()));
111 NameObserver& operator=(const NameObserver& other);
113 NameObserver(UniqueNames& names) : m_names(names)
117 NameObserver(const NameObserver& other) : m_names(other.m_names), m_name(other.m_name)
127 return string_empty(c_str());
129 const char* c_str() const
131 return m_name.c_str();
133 void nameChanged(const char* name)
139 typedef MemberCaller1<NameObserver, const char*, &NameObserver::nameChanged> NameChangedCaller;
142 class BasicNamespace : public Namespace
144 typedef std::map<NameCallback, NameObserver> Names;
146 UniqueNames m_uniqueNames;
150 ASSERT_MESSAGE(m_names.empty(), "namespace: names still registered at shutdown");
152 void attach(const NameCallback& setName, const NameCallbackCallback& attachObserver)
154 std::pair<Names::iterator, bool> result = m_names.insert(Names::value_type(setName, m_uniqueNames));
155 ASSERT_MESSAGE(result.second, "cannot attach name");
156 attachObserver(NameObserver::NameChangedCaller((*result.first).second));
157 //globalOutputStream() << "attach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
159 void detach(const NameCallback& setName, const NameCallbackCallback& detachObserver)
161 Names::iterator i = m_names.find(setName);
162 ASSERT_MESSAGE(i != m_names.end(), "cannot detach name");
163 //globalOutputStream() << "detach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
164 detachObserver(NameObserver::NameChangedCaller((*i).second));
168 void makeUnique(const char* name, const NameCallback& setName) const
171 name_write(buffer, m_uniqueNames.make_unique(name_read(name)));
175 void mergeNames(const BasicNamespace& other) const
177 typedef std::list<NameCallback> SetNameCallbacks;
178 typedef std::map<CopiedString, SetNameCallbacks> NameGroups;
181 UniqueNames uniqueNames(other.m_uniqueNames);
183 for(Names::const_iterator i = m_names.begin(); i != m_names.end(); ++i)
185 groups[(*i).second.c_str()].push_back((*i).first);
188 for(NameGroups::iterator i = groups.begin(); i != groups.end(); ++i)
190 name_t uniqueName(uniqueNames.make_unique(name_read((*i).first.c_str())));
191 uniqueNames.insert(uniqueName);
194 name_write(buffer, uniqueName);
196 //globalOutputStream() << "renaming " << makeQuoted((*i).first.c_str()) << " to " << makeQuoted(buffer) << "\n";
198 SetNameCallbacks& setNameCallbacks = (*i).second;
200 for(SetNameCallbacks::const_iterator j = setNameCallbacks.begin(); j != setNameCallbacks.end(); ++j)
208 BasicNamespace g_defaultNamespace;
209 BasicNamespace g_cloneNamespace;
213 Namespace* m_namespace;
215 typedef Namespace Type;
216 STRING_CONSTANT(Name, "*");
220 m_namespace = &g_defaultNamespace;
222 Namespace* getTable()
228 typedef SingletonModule<NamespaceAPI> NamespaceModule;
229 typedef Static<NamespaceModule> StaticNamespaceModule;
230 StaticRegisterModule staticRegisterDefaultNamespace(StaticNamespaceModule::instance());
233 std::list<Namespaced*> g_cloned;
235 inline Namespaced* Node_getNamespaced(scene::Node& node)
237 return NodeTypeCast<Namespaced>::cast(node);
240 void Node_gatherNamespaced(scene::Node& node)
242 Namespaced* namespaced = Node_getNamespaced(node);
245 g_cloned.push_back(namespaced);
249 class GatherNamespaced : public scene::Traversable::Walker
252 bool pre(scene::Node& node) const
254 Node_gatherNamespaced(node);
259 void Map_gatherNamespaced(scene::Node& root)
261 Node_traverseSubgraph(root, GatherNamespaced());
264 void Map_mergeClonedNames()
266 for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
268 (*i)->setNamespace(g_cloneNamespace);
270 g_cloneNamespace.mergeNames(g_defaultNamespace);
271 for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
273 (*i)->setNamespace(g_defaultNamespace);
287 void set(scene::Node* node)
295 scene::Node* get() const
302 void Map_SetValid(Map& map, bool valid);
303 void Map_UpdateTitle(const Map& map);
304 void Map_SetWorldspawn(Map& map, scene::Node* node);
307 class Map : public ModuleObserver
311 Resource* m_resource;
315 void (*m_modified_changed)(const Map&);
317 Signal0 m_mapValidCallbacks;
319 WorldNode m_world_node; // "classname" "worldspawn" !
321 Map() : m_resource(0), m_valid(false), m_modified_changed(Map_UpdateTitle)
329 if(Map_Unnamed(*this))
331 g_map.m_resource->setNode(NewMapRoot("").get_pointer());
332 MapFile* map = Node_getMapFile(*g_map.m_resource->getNode());
343 GlobalSceneGraph().insert_root(*m_resource->getNode());
347 Map_SetValid(g_map, true);
354 Map_SetValid(g_map, false);
355 Map_SetWorldspawn(g_map, 0);
358 GlobalUndoSystem().clear();
360 GlobalSceneGraph().erase_root();
366 Map* g_currentMap = 0;
368 void Map_addValidCallback(Map& map, const SignalHandler& handler)
370 map.m_mapValidCallbacks.connectLast(handler);
373 bool Map_Valid(const Map& map)
378 void Map_SetValid(Map& map, bool valid)
381 map.m_mapValidCallbacks();
385 const char* Map_Name(const Map& map)
387 return map.m_name.c_str();
390 bool Map_Unnamed(const Map& map)
392 return string_equal(Map_Name(map), "unnamed.map");
395 inline const MapFormat& MapFormat_forFile(const char* filename)
397 const char* moduleName = findModuleName(GetFileTypeRegistry(), MapFormat::Name(), path_get_extension(filename));
398 MapFormat* format = Radiant_getMapModules().findModule(moduleName);
399 ASSERT_MESSAGE(format != 0, "map format not found for file " << makeQuoted(filename));
403 const MapFormat& Map_getFormat(const Map& map)
405 return MapFormat_forFile(Map_Name(map));
409 bool Map_Modified(const Map& map)
411 return map.m_modified;
414 void Map_SetModified(Map& map, bool modified)
416 if(map.m_modified ^ modified)
418 map.m_modified = modified;
420 map.m_modified_changed(map);
424 void Map_UpdateTitle(const Map& map)
426 Sys_SetTitle(map.m_name.c_str(), Map_Modified(map));
431 scene::Node* Map_GetWorldspawn(const Map& map)
433 return map.m_world_node.get();
436 void Map_SetWorldspawn(Map& map, scene::Node* node)
438 map.m_world_node.set(node);
443 // need that in a variable, will have to tweak depending on the game
444 float g_MaxWorldCoord = 64*1024;
445 float g_MinWorldCoord = -64*1024;
447 void AddRegionBrushes (void);
448 void RemoveRegionBrushes (void);
454 free all map elements, reinitialize the structures that depend on them
461 g_map.m_resource->detach(g_map);
462 GlobalReferenceCache().release(g_map.m_name.c_str());
463 g_map.m_resource = 0;
468 Brush_unlatchPreferences();
471 class EntityFindByClassname : public scene::Graph::Walker
476 EntityFindByClassname(const char* name, Entity*& entity) : m_name(name), m_entity(entity)
480 bool pre(const scene::Path& path, scene::Instance& instance) const
484 Entity* entity = Node_getEntity(path.top());
486 && string_equal(m_name, entity->getKeyValue("classname")))
495 Entity* Scene_FindEntityByClass(const char* name)
498 GlobalSceneGraph().traverse(EntityFindByClassname(name, entity));
502 Entity *Scene_FindPlayerStart()
504 typedef const char* StaticString;
505 StaticString strings[] = {
507 "info_player_deathmatch",
508 "team_CTF_redplayer",
509 "team_CTF_blueplayer",
511 "team_CTF_bluespawn",
513 typedef const StaticString* StaticStringIterator;
514 for(StaticStringIterator i = strings, end = strings+(sizeof(strings)/sizeof(StaticString)); i != end; ++i)
516 Entity* entity = Scene_FindEntityByClass(*i);
526 // move the view to a start position
530 void FocusViews(const Vector3& point, float angle)
532 CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
533 Camera_setOrigin(camwnd, point);
534 Vector3 angles(Camera_getAngles(camwnd));
535 angles[CAMERA_PITCH] = 0;
536 angles[CAMERA_YAW] = angle;
537 Camera_setAngles(camwnd, angles);
539 XYWnd* xywnd = g_pParentWnd->GetXYWnd();
540 xywnd->SetOrigin(point);
543 #include "stringio.h"
545 void Map_StartPosition()
547 Entity* entity = Scene_FindPlayerStart();
552 string_parse_vector3(entity->getKeyValue("origin"), origin);
553 FocusViews(origin, string_read_float(entity->getKeyValue("angle")));
557 FocusViews(g_vector3_identity, 0);
562 inline bool node_is_worldspawn(scene::Node& node)
564 Entity* entity = Node_getEntity(node);
565 return entity != 0 && string_equal(entity->getKeyValue("classname"), "worldspawn");
569 // use first worldspawn
570 class entity_updateworldspawn : public scene::Traversable::Walker
573 bool pre(scene::Node& node) const
575 if(node_is_worldspawn(node))
577 if(Map_GetWorldspawn(g_map) == 0)
579 Map_SetWorldspawn(g_map, &node);
586 scene::Node* Map_FindWorldspawn(Map& map)
588 Map_SetWorldspawn(map, 0);
590 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
592 return Map_GetWorldspawn(map);
596 class CollectAllWalker : public scene::Traversable::Walker
599 UnsortedNodeSet& m_nodes;
601 CollectAllWalker(scene::Node& root, UnsortedNodeSet& nodes) : m_root(root), m_nodes(nodes)
604 bool pre(scene::Node& node) const
606 m_nodes.insert(NodeSmartReference(node));
607 Node_getTraversable(m_root)->erase(node);
612 void Node_insertChildFirst(scene::Node& parent, scene::Node& child)
614 UnsortedNodeSet nodes;
615 Node_getTraversable(parent)->traverse(CollectAllWalker(parent, nodes));
616 Node_getTraversable(parent)->insert(child);
618 for(UnsortedNodeSet::iterator i = nodes.begin(); i != nodes.end(); ++i)
620 Node_getTraversable(parent)->insert((*i));
624 scene::Node& createWorldspawn()
626 NodeSmartReference worldspawn(GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("worldspawn", true)));
627 Node_insertChildFirst(GlobalSceneGraph().root(), worldspawn);
631 void Map_UpdateWorldspawn(Map& map)
633 if(Map_FindWorldspawn(map) == 0)
635 Map_SetWorldspawn(map, &createWorldspawn());
639 scene::Node& Map_FindOrInsertWorldspawn(Map& map)
641 Map_UpdateWorldspawn(map);
642 return *Map_GetWorldspawn(map);
646 class MapMergeAll : public scene::Traversable::Walker
648 mutable scene::Path m_path;
650 MapMergeAll(const scene::Path& root)
654 bool pre(scene::Node& node) const
656 Node_getTraversable(m_path.top())->insert(node);
657 m_path.push(makeReference(node));
658 selectPath(m_path, true);
661 void post(scene::Node& node) const
667 class MapMergeEntities : public scene::Traversable::Walker
669 mutable scene::Path m_path;
671 MapMergeEntities(const scene::Path& root)
675 bool pre(scene::Node& node) const
677 if(node_is_worldspawn(node))
679 scene::Node* world_node = Map_FindWorldspawn(g_map);
682 Map_SetWorldspawn(g_map, &node);
683 Node_getTraversable(m_path.top().get())->insert(node);
684 m_path.push(makeReference(node));
685 Node_getTraversable(node)->traverse(SelectChildren(m_path));
689 m_path.push(makeReference(*world_node));
690 Node_getTraversable(node)->traverse(MapMergeAll(m_path));
695 Node_getTraversable(m_path.top())->insert(node);
696 m_path.push(makeReference(node));
697 if(node_is_group(node))
699 Node_getTraversable(node)->traverse(SelectChildren(m_path));
703 selectPath(m_path, true);
708 void post(scene::Node& node) const
714 class BasicContainer : public scene::Node::Symbiot
718 NodeTypeCastTable m_casts;
722 NodeContainedCast<BasicContainer, scene::Traversable>::install(m_casts);
724 NodeTypeCastTable& get()
731 TraversableNodeSet m_traverse;
734 typedef LazyStatic<TypeCasts> StaticTypeCasts;
736 scene::Traversable& get(NullType<scene::Traversable>)
741 BasicContainer() : m_node(this, this, StaticTypeCasts::instance().get())
754 /// Merges the map graph rooted at \p node into the global scene-graph.
755 void MergeMap(scene::Node& node)
757 Node_getTraversable(node)->traverse(MapMergeEntities(scene::Path(makeReference(GlobalSceneGraph().root()))));
759 void Map_ImportSelected(TextInputStream& in, const MapFormat& format)
761 NodeSmartReference node((new BasicContainer)->node());
762 format.readGraph(node, in, GlobalEntityCreator());
763 Map_gatherNamespaced(node);
764 Map_mergeClonedNames();
768 inline scene::Cloneable* Node_getCloneable(scene::Node& node)
770 return NodeTypeCast<scene::Cloneable>::cast(node);
773 inline scene::Node& node_clone(scene::Node& node)
775 scene::Cloneable* cloneable = Node_getCloneable(node);
778 return cloneable->clone();
781 return (new scene::NullNode)->node();
784 class CloneAll : public scene::Traversable::Walker
786 mutable scene::Path m_path;
788 CloneAll(scene::Node& root)
789 : m_path(makeReference(root))
792 bool pre(scene::Node& node) const
799 m_path.push(makeReference(node_clone(node)));
800 m_path.top().get().IncRef();
804 void post(scene::Node& node) const
811 Node_getTraversable(m_path.parent())->insert(m_path.top());
813 m_path.top().get().DecRef();
818 scene::Node& Node_Clone(scene::Node& node)
820 scene::Node& clone = node_clone(node);
821 scene::Traversable* traversable = Node_getTraversable(node);
824 traversable->traverse(CloneAll(clone));
830 typedef std::map<CopiedString, std::size_t> EntityBreakdown;
832 class EntityBreakdownWalker : public scene::Graph::Walker
834 EntityBreakdown& m_entitymap;
836 EntityBreakdownWalker(EntityBreakdown& entitymap)
837 : m_entitymap(entitymap)
840 bool pre(const scene::Path& path, scene::Instance& instance) const
842 Entity* entity = Node_getEntity(path.top());
845 const EntityClass& eclass = entity->getEntityClass();
846 if(m_entitymap.find(eclass.name()) == m_entitymap.end())
848 m_entitymap[eclass.name()] = 1;
850 else ++m_entitymap[eclass.name()];
856 void Scene_EntityBreakdown(EntityBreakdown& entitymap)
858 GlobalSceneGraph().traverse(EntityBreakdownWalker(entitymap));
862 WindowPosition g_posMapInfoWnd(c_default_window_pos);
867 GtkEntry* brushes_entry;
868 GtkEntry* entities_entry;
869 GtkListStore* EntityBreakdownWalker;
871 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Map Info", G_CALLBACK(dialog_delete_callback), &dialog);
873 window_set_position(window, g_posMapInfoWnd);
876 GtkVBox* vbox = create_dialog_vbox(4, 4);
877 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
880 GtkHBox* hbox = create_dialog_hbox(4);
881 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, TRUE, 0);
884 GtkTable* table = create_dialog_table(2, 2, 4, 4);
885 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
888 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
889 gtk_widget_show(GTK_WIDGET(entry));
890 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
891 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
892 (GtkAttachOptions) (0), 0, 0);
893 gtk_entry_set_editable(entry, FALSE);
895 brushes_entry = entry;
898 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
899 gtk_widget_show(GTK_WIDGET(entry));
900 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
901 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
902 (GtkAttachOptions) (0), 0, 0);
903 gtk_entry_set_editable(entry, FALSE);
905 entities_entry = entry;
908 GtkWidget* label = gtk_label_new ("Total Brushes");
909 gtk_widget_show (label);
910 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
911 (GtkAttachOptions) (GTK_FILL),
912 (GtkAttachOptions) (0), 0, 0);
913 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
916 GtkWidget* label = gtk_label_new ("Total Entities");
917 gtk_widget_show (label);
918 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
919 (GtkAttachOptions) (GTK_FILL),
920 (GtkAttachOptions) (0), 0, 0);
921 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
925 GtkVBox* vbox2 = create_dialog_vbox(4);
926 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox2), FALSE, FALSE, 0);
929 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_ok), &dialog);
930 gtk_box_pack_start(GTK_BOX(vbox2), GTK_WIDGET(button), FALSE, FALSE, 0);
935 GtkWidget* label = gtk_label_new ("Entity breakdown");
936 gtk_widget_show (label);
937 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, TRUE, 0);
938 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
941 GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4);
942 gtk_box_pack_start(GTK_BOX (vbox), GTK_WIDGET(scr), TRUE, TRUE, 0);
945 GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
947 GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
948 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(view), TRUE);
951 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
952 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Entity", renderer, "text", 0, 0);
953 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
954 gtk_tree_view_column_set_sort_column_id(column, 0);
958 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
959 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Count", renderer, "text", 1, 0);
960 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
961 gtk_tree_view_column_set_sort_column_id(column, 1);
964 gtk_widget_show(view);
966 gtk_container_add(GTK_CONTAINER(scr), view);
968 EntityBreakdownWalker = store;
976 EntityBreakdown entitymap;
977 Scene_EntityBreakdown(entitymap);
979 for(EntityBreakdown::iterator i=entitymap.begin(); i != entitymap.end(); ++i)
982 sprintf (tmp, "%u", Unsigned((*i).second));
984 gtk_list_store_append(GTK_LIST_STORE(EntityBreakdownWalker), &iter);
985 gtk_list_store_set(GTK_LIST_STORE(EntityBreakdownWalker), &iter, 0, (*i).first.c_str(), 1, tmp, -1);
989 g_object_unref(G_OBJECT(EntityBreakdownWalker));
992 sprintf (tmp, "%u", Unsigned(g_brushCount.get()));
993 gtk_entry_set_text (GTK_ENTRY (brushes_entry), tmp);
994 sprintf (tmp, "%u", Unsigned(g_entityCount.get()));
995 gtk_entry_set_text (GTK_ENTRY (entities_entry), tmp);
997 modal_dialog_show(window, dialog);
1000 window_get_position(window, g_posMapInfoWnd);
1002 gtk_widget_destroy(GTK_WIDGET(window));
1010 const char* m_message;
1012 ScopeTimer(const char* message)
1013 : m_message(message)
1019 double elapsed_time = m_timer.elapsed_msec() / 1000.f;
1020 globalOutputStream() << m_message << " timer: " << FloatFormat(elapsed_time, 5, 2) << " second(s) elapsed\n";
1030 void Map_LoadFile (const char *filename)
1032 globalOutputStream() << "Loading map from " << filename << "\n";
1033 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1035 g_map.m_name = filename;
1036 Map_UpdateTitle(g_map);
1039 ScopeTimer timer("map load");
1041 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1043 const MapFormat* format = ReferenceAPI_getMapModules().findModule("mapq3");
1044 format->wrongFormat = false;
1045 g_map.m_resource->attach(g_map);
1046 if(format->wrongFormat)
1048 // try toggling BrushPrimitives
1050 Brush_toggleProjection();
1051 g_map.m_name = filename;
1052 Map_UpdateTitle(g_map);
1053 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1054 g_map.m_resource->attach(g_map);
1057 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
1060 globalOutputStream() << "--- LoadMapFile ---\n";
1061 globalOutputStream() << g_map.m_name.c_str() << "\n";
1063 globalOutputStream() << Unsigned(g_brushCount.get()) << " primitive\n";
1064 globalOutputStream() << Unsigned(g_entityCount.get()) << " entities\n";
1066 //GlobalEntityCreator().printStatistics();
1069 // move the view to a start position
1071 Map_StartPosition();
1073 g_currentMap = &g_map;
1079 virtual bool excluded(scene::Node& node) const = 0;
1082 class ExcludeWalker : public scene::Traversable::Walker
1084 const scene::Traversable::Walker& m_walker;
1085 const Excluder* m_exclude;
1086 mutable bool m_skip;
1088 ExcludeWalker(const scene::Traversable::Walker& walker, const Excluder& exclude)
1089 : m_walker(walker), m_exclude(&exclude), m_skip(false)
1092 bool pre(scene::Node& node) const
1094 if(m_exclude->excluded(node) || node.isRoot())
1105 void post(scene::Node& node) const
1113 m_walker.post(node);
1118 class AnyInstanceSelected : public scene::Instantiable::Visitor
1122 AnyInstanceSelected(bool& selected) : m_selected(selected)
1126 void visit(scene::Instance& instance) const
1128 Selectable* selectable = Instance_getSelectable(instance);
1130 && selectable->isSelected())
1137 bool Node_instanceSelected(scene::Node& node)
1139 scene::Instantiable* instantiable = Node_getInstantiable(node);
1140 ASSERT_NOTNULL(instantiable);
1142 instantiable->forEachInstance(AnyInstanceSelected(selected));
1146 class SelectedDescendantWalker : public scene::Traversable::Walker
1150 SelectedDescendantWalker(bool& selected) : m_selected(selected)
1155 bool pre(scene::Node& node) const
1162 if(Node_instanceSelected(node))
1171 bool Node_selectedDescendant(scene::Node& node)
1174 Node_traverseSubgraph(node, SelectedDescendantWalker(selected));
1178 class SelectionExcluder : public Excluder
1181 bool excluded(scene::Node& node) const
1183 return !Node_selectedDescendant(node);
1187 class IncludeSelectedWalker : public scene::Traversable::Walker
1189 const scene::Traversable::Walker& m_walker;
1190 mutable std::size_t m_selected;
1191 mutable bool m_skip;
1193 bool selectedParent() const
1195 return m_selected != 0;
1198 IncludeSelectedWalker(const scene::Traversable::Walker& walker)
1199 : m_walker(walker), m_selected(0), m_skip(false)
1202 bool pre(scene::Node& node) const
1205 // node is not a 'root' AND ( node is selected OR any child of node is selected OR any parent of node is selected )
1206 if(!node.isRoot() && (Node_selectedDescendant(node) || selectedParent()))
1208 if(Node_instanceSelected(node))
1221 void post(scene::Node& node) const
1229 if(Node_instanceSelected(node))
1233 m_walker.post(node);
1238 void Map_Traverse_Selected(scene::Node& root, const scene::Traversable::Walker& walker)
1240 scene::Traversable* traversable = Node_getTraversable(root);
1241 if(traversable != 0)
1244 traversable->traverse(ExcludeWalker(walker, SelectionExcluder()));
1246 traversable->traverse(IncludeSelectedWalker(walker));
1251 void Map_ExportSelected(TextOutputStream& out, const MapFormat& format)
1253 format.writeGraph(GlobalSceneGraph().root(), Map_Traverse_Selected, out);
1256 void Map_Traverse(scene::Node& root, const scene::Traversable::Walker& walker)
1258 scene::Traversable* traversable = Node_getTraversable(root);
1259 if(traversable != 0)
1261 traversable->traverse(walker);
1265 class RegionExcluder : public Excluder
1268 bool excluded(scene::Node& node) const
1270 return node.excluded();
1274 void Map_Traverse_Region(scene::Node& root, const scene::Traversable::Walker& walker)
1276 scene::Traversable* traversable = Node_getTraversable(root);
1277 if(traversable != 0)
1279 traversable->traverse(ExcludeWalker(walker, RegionExcluder()));
1283 bool Map_SaveRegion(const char *filename)
1287 bool success = MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Region, filename);
1289 RemoveRegionBrushes();
1295 void Map_RenameAbsolute(const char* absolute)
1297 Resource* resource = GlobalReferenceCache().capture(absolute);
1298 NodeSmartReference clone(NewMapRoot(path_make_relative(absolute, GlobalFileSystem().findRoot(absolute))));
1299 resource->setNode(clone.get_pointer());
1302 //ScopeTimer timer("clone subgraph");
1303 Node_getTraversable(GlobalSceneGraph().root())->traverse(CloneAll(clone));
1306 g_map.m_resource->detach(g_map);
1307 GlobalReferenceCache().release(g_map.m_name.c_str());
1309 g_map.m_resource = resource;
1311 g_map.m_name = absolute;
1312 Map_UpdateTitle(g_map);
1314 g_map.m_resource->attach(g_map);
1317 void Map_Rename(const char* filename)
1319 if(!string_equal(g_map.m_name.c_str(), filename))
1321 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1323 Map_RenameAbsolute(filename);
1325 SceneChangeNotify();
1337 ScopeTimer timer("map save");
1339 return true; // assume success..
1350 //globalOutputStream() << "Map_New\n";
1352 g_map.m_name = "unnamed.map";
1353 Map_UpdateTitle(g_map);
1356 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1357 // ASSERT_MESSAGE(g_map.m_resource->getNode() == 0, "bleh");
1358 g_map.m_resource->attach(g_map);
1360 SceneChangeNotify();
1363 FocusViews(g_vector3_identity, 0);
1365 g_currentMap = &g_map;
1368 extern void ConstructRegionBrushes(scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs);
1370 void ConstructRegionStartpoint(scene::Node* startpoint, const Vector3& region_mins, const Vector3& region_maxs)
1373 \todo we need to make sure that the player start IS inside the region and bail out if it's not
1374 the compiler will refuse to compile a map with a player_start somewhere in empty space..
1375 for now, let's just print an error
1378 Vector3 vOrig(Camera_getOrigin(*g_pParentWnd->GetCamWnd()));
1380 for (int i=0 ; i<3 ; i++)
1382 if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
1384 globalErrorStream() << "Camera is NOT in the region, it's likely that the region won't compile correctly\n";
1389 // write the info_playerstart
1391 sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]);
1392 Node_getEntity(*startpoint)->setKeyValue("origin", sTmp);
1393 sprintf(sTmp, "%d", (int)Camera_getAngles(*g_pParentWnd->GetCamWnd())[CAMERA_YAW]);
1394 Node_getEntity(*startpoint)->setKeyValue("angle", sTmp);
1398 ===========================================================
1402 ===========================================================
1405 Vector3 region_mins(g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord);
1406 Vector3 region_maxs(g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord);
1408 scene::Node* region_sides[6];
1409 scene::Node* region_startpoint = 0;
1414 a regioned map will have temp walls put up at the region boundary
1415 \todo TODO TTimo old implementation of region brushes
1416 we still add them straight in the worldspawn and take them out after the map is saved
1417 with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module
1420 void AddRegionBrushes (void)
1426 region_sides[i] = &GlobalBrushCreator().createBrush();
1427 Node_getTraversable(Map_FindOrInsertWorldspawn(g_map))->insert(NodeSmartReference(*region_sides[i]));
1430 region_startpoint = &GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("info_player_start", false));
1432 ConstructRegionBrushes(region_sides, region_mins, region_maxs);
1433 ConstructRegionStartpoint(region_startpoint, region_mins, region_maxs);
1435 Node_getTraversable(GlobalSceneGraph().root())->insert(NodeSmartReference(*region_startpoint));
1438 void RemoveRegionBrushes (void)
1440 for(std::size_t i=0; i<6; i++)
1442 Node_getTraversable(*Map_GetWorldspawn(g_map))->erase(*region_sides[i]);
1444 Node_getTraversable(GlobalSceneGraph().root())->erase(*region_startpoint);
1447 inline void exclude_node(scene::Node& node, bool exclude)
1450 ? node.enable(scene::Node::eExcluded)
1451 : node.disable(scene::Node::eExcluded);
1454 class ExcludeAllWalker : public scene::Graph::Walker
1458 ExcludeAllWalker(bool exclude)
1459 : m_exclude(exclude)
1462 bool pre(const scene::Path& path, scene::Instance& instance) const
1464 exclude_node(path.top(), m_exclude);
1470 void Scene_Exclude_All(bool exclude)
1472 GlobalSceneGraph().traverse(ExcludeAllWalker(exclude));
1475 bool Instance_isSelected(const scene::Instance& instance)
1477 const Selectable* selectable = Instance_getSelectable(instance);
1478 return selectable != 0 && selectable->isSelected();
1481 class ExcludeSelectedWalker : public scene::Graph::Walker
1485 ExcludeSelectedWalker(bool exclude)
1486 : m_exclude(exclude)
1489 bool pre(const scene::Path& path, scene::Instance& instance) const
1491 exclude_node(path.top(), (instance.isSelected() || instance.childSelected() || instance.parentSelected()) == m_exclude);
1496 void Scene_Exclude_Selected(bool exclude)
1498 GlobalSceneGraph().traverse(ExcludeSelectedWalker(exclude));
1501 class ExcludeRegionedWalker : public scene::Graph::Walker
1505 ExcludeRegionedWalker(bool exclude)
1506 : m_exclude(exclude)
1509 bool pre(const scene::Path& path, scene::Instance& instance) const
1515 aabb_intersects_aabb(
1516 instance.worldAABB(),
1517 aabb_for_minmax(region_mins, region_maxs)
1527 void Scene_Exclude_Region(bool exclude)
1529 GlobalSceneGraph().traverse(ExcludeRegionedWalker(exclude));
1536 Other filtering options may still be on
1539 void Map_RegionOff()
1541 region_active = false;
1543 region_maxs[0] = g_MaxWorldCoord - 64;
1544 region_mins[0] = g_MinWorldCoord + 64;
1545 region_maxs[1] = g_MaxWorldCoord - 64;
1546 region_mins[1] = g_MinWorldCoord + 64;
1547 region_maxs[2] = g_MaxWorldCoord - 64;
1548 region_mins[2] = g_MinWorldCoord + 64;
1550 Scene_Exclude_All(false);
1553 void Map_ApplyRegion (void)
1555 region_active = true;
1557 Scene_Exclude_Region(false);
1562 ========================
1563 Map_RegionSelectedBrushes
1564 ========================
1566 void Map_RegionSelectedBrushes (void)
1570 if(GlobalSelectionSystem().countSelected() != 0
1571 && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
1573 region_active = true;
1574 Select_GetBounds (region_mins, region_maxs);
1576 Scene_Exclude_Selected(false);
1578 GlobalSelectionSystem().setSelectedAll(false);
1588 void Map_RegionXY(float x_min, float y_min, float x_max, float y_max)
1592 region_mins[0] = x_min;
1593 region_maxs[0] = x_max;
1594 region_mins[1] = y_min;
1595 region_maxs[1] = y_max;
1596 region_mins[2] = g_MinWorldCoord + 64;
1597 region_maxs[2] = g_MaxWorldCoord - 64;
1602 void Map_RegionBounds(const AABB& bounds)
1606 region_mins = vector3_subtracted(bounds.origin, bounds.extents);
1607 region_maxs = vector3_added(bounds.origin, bounds.extents);
1619 void Map_RegionBrush (void)
1621 if(GlobalSelectionSystem().countSelected() != 0)
1623 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
1624 Map_RegionBounds(instance.worldAABB());
1633 bool Map_ImportFile(const char* filename)
1635 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1637 bool success = false;
1639 Resource* resource = GlobalReferenceCache().capture(filename);
1640 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1641 if(resource->load())
1643 NodeSmartReference clone(NewMapRoot(""));
1646 //ScopeTimer timer("clone subgraph");
1647 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1650 Map_gatherNamespaced(clone);
1651 Map_mergeClonedNames();
1655 GlobalReferenceCache().release(filename);
1658 SceneChangeNotify();
1668 bool Map_SaveFile(const char* filename)
1670 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1671 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse, filename);
1679 // Saves selected world brushes and whole entities with partial/full selections
1681 bool Map_SaveSelected(const char* filename)
1683 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename);
1687 class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
1689 scene::Node& m_parent;
1691 ParentSelectedBrushesToEntityWalker(scene::Node& parent) : m_parent(parent)
1694 bool pre(const scene::Path& path, scene::Instance& instance) const
1696 if(path.top().get_pointer() != &m_parent
1697 && Node_isPrimitive(path.top()))
1699 Selectable* selectable = Instance_getSelectable(instance);
1701 && selectable->isSelected()
1709 void post(const scene::Path& path, scene::Instance& instance) const
1711 if(path.top().get_pointer() != &m_parent
1712 && Node_isPrimitive(path.top()))
1714 Selectable* selectable = Instance_getSelectable(instance);
1716 && selectable->isSelected()
1719 scene::Node& parent = path.parent();
1720 if(&parent != &m_parent)
1722 NodeSmartReference node(path.top().get());
1723 Node_getTraversable(parent)->erase(node);
1724 Node_getTraversable(m_parent)->insert(node);
1731 void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent)
1733 graph.traverse(ParentSelectedBrushesToEntityWalker(parent));
1736 class CountSelectedBrushes : public scene::Graph::Walker
1738 std::size_t& m_count;
1739 mutable std::size_t m_depth;
1741 CountSelectedBrushes(std::size_t& count) : m_count(count), m_depth(0)
1745 bool pre(const scene::Path& path, scene::Instance& instance) const
1747 if(++m_depth != 1 && path.top().get().isRoot())
1751 Selectable* selectable = Instance_getSelectable(instance);
1753 && selectable->isSelected()
1754 && Node_isPrimitive(path.top()))
1760 void post(const scene::Path& path, scene::Instance& instance) const
1766 std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
1769 graph.traverse(CountSelectedBrushes(count));
1781 const char* nodetype_get_name(ENodeType type)
1783 if(type == eNodeMap)
1785 if(type == eNodeEntity)
1787 if(type == eNodePrimitive)
1792 ENodeType node_get_nodetype(scene::Node& node)
1794 if(Node_isEntity(node))
1798 if(Node_isPrimitive(node))
1800 return eNodePrimitive;
1802 return eNodeUnknown;
1805 bool contains_entity(scene::Node& node)
1807 return Node_getTraversable(node) != 0 && !Node_isBrush(node) && !Node_isPatch(node) && !Node_isEntity(node);
1810 bool contains_primitive(scene::Node& node)
1812 return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
1815 ENodeType node_get_contains(scene::Node& node)
1817 if(contains_entity(node))
1821 if(contains_primitive(node))
1823 return eNodePrimitive;
1825 return eNodeUnknown;
1828 void Path_parent(const scene::Path& parent, const scene::Path& child)
1830 ENodeType contains = node_get_contains(parent.top());
1831 ENodeType type = node_get_nodetype(child.top());
1833 if(contains != eNodeUnknown && contains == type)
1835 NodeSmartReference node(child.top().get());
1836 Path_deleteTop(child);
1837 Node_getTraversable(parent.top())->insert(node);
1838 SceneChangeNotify();
1842 globalErrorStream() << "failed - " << nodetype_get_name(type) << " cannot be parented to " << nodetype_get_name(contains) << " container.\n";
1846 void Scene_parentSelected()
1848 UndoableCommand undo("parentSelected");
1850 if(GlobalSelectionSystem().countSelected() > 1)
1852 class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor
1854 const scene::Path& m_parent;
1856 ParentSelectedBrushesToEntityWalker(const scene::Path& parent) : m_parent(parent)
1859 void visit(scene::Instance& instance) const
1861 if(&m_parent != &instance.path())
1863 Path_parent(m_parent, instance.path());
1868 ParentSelectedBrushesToEntityWalker visitor(GlobalSelectionSystem().ultimateSelected().path());
1869 GlobalSelectionSystem().foreachSelected(visitor);
1873 globalOutputStream() << "failed - did not find two selected nodes.\n";
1881 if (ConfirmModified("New Map"))
1889 CopiedString g_mapsPath;
1891 const char* getMapsPath()
1893 return g_mapsPath.c_str();
1896 const char* map_open(const char* title)
1898 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name());
1901 const char* map_save(const char* title)
1903 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, getMapsPath(), MapFormat::Name());
1908 if (!ConfirmModified("Open Map"))
1911 const char* filename = map_open("Open Map");
1915 MRU_AddFile(filename);
1918 Map_LoadFile(filename);
1924 const char* filename = map_open("Import Map");
1928 UndoableCommand undo("mapImport");
1929 Map_ImportFile(filename);
1935 const char* filename = map_save("Save Map");
1939 MRU_AddFile(filename);
1940 Map_Rename(filename);
1953 if(Map_Unnamed(g_map))
1957 else if(Map_Modified(g_map))
1965 const char* filename = map_save("Export Selection");
1969 Map_SaveSelected(filename);
1975 const char* filename = map_save("Export Region");
1979 Map_SaveRegion(filename);
1987 SceneChangeNotify();
1993 g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
1994 g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(),
1995 g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
1996 g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale()
1998 SceneChangeNotify();
2004 SceneChangeNotify();
2007 void RegionSelected()
2009 Map_RegionSelectedBrushes();
2010 SceneChangeNotify();
2017 class BrushFindByIndexWalker : public scene::Traversable::Walker
2019 mutable std::size_t m_index;
2020 scene::Path& m_path;
2022 BrushFindByIndexWalker(std::size_t index, scene::Path& path)
2023 : m_index(index), m_path(path)
2026 bool pre(scene::Node& node) const
2028 if(Node_isPrimitive(node) && m_index-- == 0)
2030 m_path.push(makeReference(node));
2036 class EntityFindByIndexWalker : public scene::Traversable::Walker
2038 mutable std::size_t m_index;
2039 scene::Path& m_path;
2041 EntityFindByIndexWalker(std::size_t index, scene::Path& path)
2042 : m_index(index), m_path(path)
2045 bool pre(scene::Node& node) const
2047 if(Node_isEntity(node) && m_index-- == 0)
2049 m_path.push(makeReference(node));
2055 void Scene_FindEntityBrush(std::size_t entity, std::size_t brush, scene::Path& path)
2057 path.push(makeReference(GlobalSceneGraph().root()));
2059 Node_getTraversable(path.top())->traverse(EntityFindByIndexWalker(entity, path));
2061 if(path.size() == 2)
2063 scene::Traversable* traversable = Node_getTraversable(path.top());
2064 if(traversable != 0)
2066 traversable->traverse(BrushFindByIndexWalker(brush, path));
2071 inline bool Node_hasChildren(scene::Node& node)
2073 scene::Traversable* traversable = Node_getTraversable(node);
2074 return traversable != 0 && !traversable->empty();
2077 void SelectBrush (int entitynum, int brushnum)
2080 Scene_FindEntityBrush(entitynum, brushnum, path);
2081 if(path.size() == 3 || (path.size() == 2 && !Node_hasChildren(path.top())))
2083 scene::Instance* instance = GlobalSceneGraph().find(path);
2084 ASSERT_MESSAGE(instance != 0, "SelectBrush: path not found in scenegraph");
2085 Selectable* selectable = Instance_getSelectable(*instance);
2086 ASSERT_MESSAGE(selectable != 0, "SelectBrush: path not selectable");
2087 selectable->setSelected(true);
2088 g_pParentWnd->GetXYWnd()->PositionView(instance->worldAABB().origin);
2093 class BrushFindIndexWalker : public scene::Graph::Walker
2095 mutable const scene::Node* m_node;
2096 std::size_t& m_count;
2098 BrushFindIndexWalker(const scene::Node& node, std::size_t& count)
2099 : m_node(&node), m_count(count)
2102 bool pre(const scene::Path& path, scene::Instance& instance) const
2104 if(Node_isPrimitive(path.top()))
2106 if(m_node == path.top().get_pointer())
2119 class EntityFindIndexWalker : public scene::Graph::Walker
2121 mutable const scene::Node* m_node;
2122 std::size_t& m_count;
2124 EntityFindIndexWalker(const scene::Node& node, std::size_t& count)
2125 : m_node(&node), m_count(count)
2128 bool pre(const scene::Path& path, scene::Instance& instance) const
2130 if(Node_isEntity(path.top()))
2132 if(m_node == path.top().get_pointer())
2145 static void GetSelectionIndex (int *ent, int *brush)
2147 std::size_t count_brush = 0;
2148 std::size_t count_entity = 0;
2149 if(GlobalSelectionSystem().countSelected() != 0)
2151 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
2153 GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
2154 GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
2156 *brush = int(count_brush);
2157 *ent = int(count_entity);
2166 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
2168 GtkAccelGroup* accel = gtk_accel_group_new();
2169 gtk_window_add_accel_group(window, accel);
2172 GtkVBox* vbox = create_dialog_vbox(4, 4);
2173 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
2175 GtkTable* table = create_dialog_table(2, 2, 4, 4);
2176 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
2178 GtkWidget* label = gtk_label_new ("Entity number");
2179 gtk_widget_show (label);
2180 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2181 (GtkAttachOptions) (0),
2182 (GtkAttachOptions) (0), 0, 0);
2185 GtkWidget* label = gtk_label_new ("Brush number");
2186 gtk_widget_show (label);
2187 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2188 (GtkAttachOptions) (0),
2189 (GtkAttachOptions) (0), 0, 0);
2192 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2193 gtk_widget_show(GTK_WIDGET(entry));
2194 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
2195 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2196 (GtkAttachOptions) (0), 0, 0);
2197 gtk_widget_grab_focus(GTK_WIDGET(entry));
2201 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2202 gtk_widget_show(GTK_WIDGET(entry));
2203 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
2204 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2205 (GtkAttachOptions) (0), 0, 0);
2211 GtkHBox* hbox = create_dialog_hbox(4);
2212 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
2214 GtkButton* button = create_dialog_button("Find", G_CALLBACK(dialog_button_ok), &dialog);
2215 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2216 widget_make_default(GTK_WIDGET(button));
2217 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
2220 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_cancel), &dialog);
2221 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2222 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
2227 // Initialize dialog
2231 GetSelectionIndex (&ent, &br);
2232 sprintf (buf, "%i", ent);
2233 gtk_entry_set_text(entity, buf);
2234 sprintf (buf, "%i", br);
2235 gtk_entry_set_text(brush, buf);
2237 if(modal_dialog_show(window, dialog) == eIDOK)
2239 const char *entstr = gtk_entry_get_text(entity);
2240 const char *brushstr = gtk_entry_get_text(brush);
2241 SelectBrush (atoi(entstr), atoi(brushstr));
2244 gtk_widget_destroy(GTK_WIDGET(window));
2247 void Map_constructPreferences(PreferencesPage& page)
2249 page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
2253 class MapEntityClasses : public ModuleObserver
2255 std::size_t m_unrealised;
2257 MapEntityClasses() : m_unrealised(1)
2262 if(--m_unrealised == 0)
2264 if(g_map.m_resource != 0)
2266 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
2267 g_map.m_resource->realise();
2273 if(++m_unrealised == 1)
2275 if(g_map.m_resource != 0)
2277 g_map.m_resource->flush();
2278 g_map.m_resource->unrealise();
2284 MapEntityClasses g_MapEntityClasses;
2287 class MapModuleObserver : public ModuleObserver
2289 std::size_t m_unrealised;
2291 MapModuleObserver() : m_unrealised(1)
2296 if(--m_unrealised == 0)
2298 ASSERT_MESSAGE(!string_empty(g_qeglobals.m_userGamePath.c_str()), "maps_directory: user-game-path is empty");
2299 StringOutputStream buffer(256);
2300 buffer << g_qeglobals.m_userGamePath.c_str() << "maps/";
2301 Q_mkdir(buffer.c_str());
2302 g_mapsPath = buffer.c_str();
2307 if(++m_unrealised == 1)
2314 MapModuleObserver g_MapModuleObserver;
2316 #include "preferencesystem.h"
2318 CopiedString g_strLastMap;
2319 bool g_bLoadLastMap = false;
2321 void Map_Construct()
2323 GlobalCommands_insert("RegionOff", FreeCaller<RegionOff>());
2324 GlobalCommands_insert("RegionSetXY", FreeCaller<RegionXY>());
2325 GlobalCommands_insert("RegionSetBrush", FreeCaller<RegionBrush>());
2326 GlobalCommands_insert("RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator('R', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
2328 GlobalPreferenceSystem().registerPreference("LastMap", CopiedStringImportStringCaller(g_strLastMap), CopiedStringExportStringCaller(g_strLastMap));
2329 GlobalPreferenceSystem().registerPreference("LoadLastMap", BoolImportStringCaller(g_bLoadLastMap), BoolExportStringCaller(g_bLoadLastMap));
2330 GlobalPreferenceSystem().registerPreference("MapInfoDlg", WindowPositionImportStringCaller(g_posMapInfoWnd), WindowPositionExportStringCaller(g_posMapInfoWnd));
2332 PreferencesDialog_addSettingsPreferences(FreeCaller1<PreferencesPage&, Map_constructPreferences>());
2334 GlobalEntityClassManager().attach(g_MapEntityClasses);
2335 Radiant_attachHomePathsObserver(g_MapModuleObserver);
2340 Radiant_detachHomePathsObserver(g_MapModuleObserver);
2341 GlobalEntityClassManager().detach(g_MapEntityClasses);