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");
1036 ScopeTimer timer("map load");
1038 const MapFormat* format = NULL;
1039 const char* moduleName = findModuleName(&GlobalFiletypes(), MapFormat::Name(), path_get_extension(filename));
1040 if(string_not_empty(moduleName))
1041 format = ReferenceAPI_getMapModules().findModule(moduleName);
1043 for(int i = 0; i < Brush_toggleFormatCount(); ++i)
1047 Brush_toggleFormat(i);
1048 g_map.m_name = filename;
1049 Map_UpdateTitle(g_map);
1050 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1052 format->wrongFormat = false;
1053 g_map.m_resource->attach(g_map);
1055 if(!format->wrongFormat)
1059 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
1062 globalOutputStream() << "--- LoadMapFile ---\n";
1063 globalOutputStream() << g_map.m_name.c_str() << "\n";
1065 globalOutputStream() << Unsigned(g_brushCount.get()) << " primitive\n";
1066 globalOutputStream() << Unsigned(g_entityCount.get()) << " entities\n";
1068 //GlobalEntityCreator().printStatistics();
1071 // move the view to a start position
1073 Map_StartPosition();
1075 g_currentMap = &g_map;
1081 virtual bool excluded(scene::Node& node) const = 0;
1084 class ExcludeWalker : public scene::Traversable::Walker
1086 const scene::Traversable::Walker& m_walker;
1087 const Excluder* m_exclude;
1088 mutable bool m_skip;
1090 ExcludeWalker(const scene::Traversable::Walker& walker, const Excluder& exclude)
1091 : m_walker(walker), m_exclude(&exclude), m_skip(false)
1094 bool pre(scene::Node& node) const
1096 if(m_exclude->excluded(node) || node.isRoot())
1107 void post(scene::Node& node) const
1115 m_walker.post(node);
1120 class AnyInstanceSelected : public scene::Instantiable::Visitor
1124 AnyInstanceSelected(bool& selected) : m_selected(selected)
1128 void visit(scene::Instance& instance) const
1130 Selectable* selectable = Instance_getSelectable(instance);
1132 && selectable->isSelected())
1139 bool Node_instanceSelected(scene::Node& node)
1141 scene::Instantiable* instantiable = Node_getInstantiable(node);
1142 ASSERT_NOTNULL(instantiable);
1144 instantiable->forEachInstance(AnyInstanceSelected(selected));
1148 class SelectedDescendantWalker : public scene::Traversable::Walker
1152 SelectedDescendantWalker(bool& selected) : m_selected(selected)
1157 bool pre(scene::Node& node) const
1164 if(Node_instanceSelected(node))
1173 bool Node_selectedDescendant(scene::Node& node)
1176 Node_traverseSubgraph(node, SelectedDescendantWalker(selected));
1180 class SelectionExcluder : public Excluder
1183 bool excluded(scene::Node& node) const
1185 return !Node_selectedDescendant(node);
1189 class IncludeSelectedWalker : public scene::Traversable::Walker
1191 const scene::Traversable::Walker& m_walker;
1192 mutable std::size_t m_selected;
1193 mutable bool m_skip;
1195 bool selectedParent() const
1197 return m_selected != 0;
1200 IncludeSelectedWalker(const scene::Traversable::Walker& walker)
1201 : m_walker(walker), m_selected(0), m_skip(false)
1204 bool pre(scene::Node& node) const
1207 // node is not a 'root' AND ( node is selected OR any child of node is selected OR any parent of node is selected )
1208 if(!node.isRoot() && (Node_selectedDescendant(node) || selectedParent()))
1210 if(Node_instanceSelected(node))
1223 void post(scene::Node& node) const
1231 if(Node_instanceSelected(node))
1235 m_walker.post(node);
1240 void Map_Traverse_Selected(scene::Node& root, const scene::Traversable::Walker& walker)
1242 scene::Traversable* traversable = Node_getTraversable(root);
1243 if(traversable != 0)
1246 traversable->traverse(ExcludeWalker(walker, SelectionExcluder()));
1248 traversable->traverse(IncludeSelectedWalker(walker));
1253 void Map_ExportSelected(TextOutputStream& out, const MapFormat& format)
1255 format.writeGraph(GlobalSceneGraph().root(), Map_Traverse_Selected, out);
1258 void Map_Traverse(scene::Node& root, const scene::Traversable::Walker& walker)
1260 scene::Traversable* traversable = Node_getTraversable(root);
1261 if(traversable != 0)
1263 traversable->traverse(walker);
1267 class RegionExcluder : public Excluder
1270 bool excluded(scene::Node& node) const
1272 return node.excluded();
1276 void Map_Traverse_Region(scene::Node& root, const scene::Traversable::Walker& walker)
1278 scene::Traversable* traversable = Node_getTraversable(root);
1279 if(traversable != 0)
1281 traversable->traverse(ExcludeWalker(walker, RegionExcluder()));
1285 bool Map_SaveRegion(const char *filename)
1289 bool success = MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Region, filename);
1291 RemoveRegionBrushes();
1297 void Map_RenameAbsolute(const char* absolute)
1299 Resource* resource = GlobalReferenceCache().capture(absolute);
1300 NodeSmartReference clone(NewMapRoot(path_make_relative(absolute, GlobalFileSystem().findRoot(absolute))));
1301 resource->setNode(clone.get_pointer());
1304 //ScopeTimer timer("clone subgraph");
1305 Node_getTraversable(GlobalSceneGraph().root())->traverse(CloneAll(clone));
1308 g_map.m_resource->detach(g_map);
1309 GlobalReferenceCache().release(g_map.m_name.c_str());
1311 g_map.m_resource = resource;
1313 g_map.m_name = absolute;
1314 Map_UpdateTitle(g_map);
1316 g_map.m_resource->attach(g_map);
1319 void Map_Rename(const char* filename)
1321 if(!string_equal(g_map.m_name.c_str(), filename))
1323 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1325 Map_RenameAbsolute(filename);
1327 SceneChangeNotify();
1339 ScopeTimer timer("map save");
1341 return true; // assume success..
1352 //globalOutputStream() << "Map_New\n";
1354 g_map.m_name = "unnamed.map";
1355 Map_UpdateTitle(g_map);
1358 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1359 // ASSERT_MESSAGE(g_map.m_resource->getNode() == 0, "bleh");
1360 g_map.m_resource->attach(g_map);
1362 SceneChangeNotify();
1365 FocusViews(g_vector3_identity, 0);
1367 g_currentMap = &g_map;
1370 extern void ConstructRegionBrushes(scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs);
1372 void ConstructRegionStartpoint(scene::Node* startpoint, const Vector3& region_mins, const Vector3& region_maxs)
1375 \todo we need to make sure that the player start IS inside the region and bail out if it's not
1376 the compiler will refuse to compile a map with a player_start somewhere in empty space..
1377 for now, let's just print an error
1380 Vector3 vOrig(Camera_getOrigin(*g_pParentWnd->GetCamWnd()));
1382 for (int i=0 ; i<3 ; i++)
1384 if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
1386 globalErrorStream() << "Camera is NOT in the region, it's likely that the region won't compile correctly\n";
1391 // write the info_playerstart
1393 sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]);
1394 Node_getEntity(*startpoint)->setKeyValue("origin", sTmp);
1395 sprintf(sTmp, "%d", (int)Camera_getAngles(*g_pParentWnd->GetCamWnd())[CAMERA_YAW]);
1396 Node_getEntity(*startpoint)->setKeyValue("angle", sTmp);
1400 ===========================================================
1404 ===========================================================
1407 Vector3 region_mins(g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord);
1408 Vector3 region_maxs(g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord);
1410 scene::Node* region_sides[6];
1411 scene::Node* region_startpoint = 0;
1416 a regioned map will have temp walls put up at the region boundary
1417 \todo TODO TTimo old implementation of region brushes
1418 we still add them straight in the worldspawn and take them out after the map is saved
1419 with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module
1422 void AddRegionBrushes (void)
1428 region_sides[i] = &GlobalBrushCreator().createBrush();
1429 Node_getTraversable(Map_FindOrInsertWorldspawn(g_map))->insert(NodeSmartReference(*region_sides[i]));
1432 region_startpoint = &GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("info_player_start", false));
1434 ConstructRegionBrushes(region_sides, region_mins, region_maxs);
1435 ConstructRegionStartpoint(region_startpoint, region_mins, region_maxs);
1437 Node_getTraversable(GlobalSceneGraph().root())->insert(NodeSmartReference(*region_startpoint));
1440 void RemoveRegionBrushes (void)
1442 for(std::size_t i=0; i<6; i++)
1444 Node_getTraversable(*Map_GetWorldspawn(g_map))->erase(*region_sides[i]);
1446 Node_getTraversable(GlobalSceneGraph().root())->erase(*region_startpoint);
1449 inline void exclude_node(scene::Node& node, bool exclude)
1452 ? node.enable(scene::Node::eExcluded)
1453 : node.disable(scene::Node::eExcluded);
1456 class ExcludeAllWalker : public scene::Graph::Walker
1460 ExcludeAllWalker(bool exclude)
1461 : m_exclude(exclude)
1464 bool pre(const scene::Path& path, scene::Instance& instance) const
1466 exclude_node(path.top(), m_exclude);
1472 void Scene_Exclude_All(bool exclude)
1474 GlobalSceneGraph().traverse(ExcludeAllWalker(exclude));
1477 bool Instance_isSelected(const scene::Instance& instance)
1479 const Selectable* selectable = Instance_getSelectable(instance);
1480 return selectable != 0 && selectable->isSelected();
1483 class ExcludeSelectedWalker : public scene::Graph::Walker
1487 ExcludeSelectedWalker(bool exclude)
1488 : m_exclude(exclude)
1491 bool pre(const scene::Path& path, scene::Instance& instance) const
1493 exclude_node(path.top(), (instance.isSelected() || instance.childSelected() || instance.parentSelected()) == m_exclude);
1498 void Scene_Exclude_Selected(bool exclude)
1500 GlobalSceneGraph().traverse(ExcludeSelectedWalker(exclude));
1503 class ExcludeRegionedWalker : public scene::Graph::Walker
1507 ExcludeRegionedWalker(bool exclude)
1508 : m_exclude(exclude)
1511 bool pre(const scene::Path& path, scene::Instance& instance) const
1517 aabb_intersects_aabb(
1518 instance.worldAABB(),
1519 aabb_for_minmax(region_mins, region_maxs)
1529 void Scene_Exclude_Region(bool exclude)
1531 GlobalSceneGraph().traverse(ExcludeRegionedWalker(exclude));
1538 Other filtering options may still be on
1541 void Map_RegionOff()
1543 region_active = false;
1545 region_maxs[0] = g_MaxWorldCoord - 64;
1546 region_mins[0] = g_MinWorldCoord + 64;
1547 region_maxs[1] = g_MaxWorldCoord - 64;
1548 region_mins[1] = g_MinWorldCoord + 64;
1549 region_maxs[2] = g_MaxWorldCoord - 64;
1550 region_mins[2] = g_MinWorldCoord + 64;
1552 Scene_Exclude_All(false);
1555 void Map_ApplyRegion (void)
1557 region_active = true;
1559 Scene_Exclude_Region(false);
1564 ========================
1565 Map_RegionSelectedBrushes
1566 ========================
1568 void Map_RegionSelectedBrushes (void)
1572 if(GlobalSelectionSystem().countSelected() != 0
1573 && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
1575 region_active = true;
1576 Select_GetBounds (region_mins, region_maxs);
1578 Scene_Exclude_Selected(false);
1580 GlobalSelectionSystem().setSelectedAll(false);
1590 void Map_RegionXY(float x_min, float y_min, float x_max, float y_max)
1594 region_mins[0] = x_min;
1595 region_maxs[0] = x_max;
1596 region_mins[1] = y_min;
1597 region_maxs[1] = y_max;
1598 region_mins[2] = g_MinWorldCoord + 64;
1599 region_maxs[2] = g_MaxWorldCoord - 64;
1604 void Map_RegionBounds(const AABB& bounds)
1608 region_mins = vector3_subtracted(bounds.origin, bounds.extents);
1609 region_maxs = vector3_added(bounds.origin, bounds.extents);
1621 void Map_RegionBrush (void)
1623 if(GlobalSelectionSystem().countSelected() != 0)
1625 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
1626 Map_RegionBounds(instance.worldAABB());
1635 bool Map_ImportFile(const char* filename)
1637 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1639 bool success = false;
1641 Resource* resource = GlobalReferenceCache().capture(filename);
1642 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1643 if(resource->load())
1645 NodeSmartReference clone(NewMapRoot(""));
1648 //ScopeTimer timer("clone subgraph");
1649 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1652 Map_gatherNamespaced(clone);
1653 Map_mergeClonedNames();
1657 GlobalReferenceCache().release(filename);
1660 SceneChangeNotify();
1670 bool Map_SaveFile(const char* filename)
1672 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1673 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse, filename);
1681 // Saves selected world brushes and whole entities with partial/full selections
1683 bool Map_SaveSelected(const char* filename)
1685 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename);
1689 class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
1691 scene::Node& m_parent;
1693 ParentSelectedBrushesToEntityWalker(scene::Node& parent) : m_parent(parent)
1696 bool pre(const scene::Path& path, scene::Instance& instance) const
1698 if(path.top().get_pointer() != &m_parent
1699 && Node_isPrimitive(path.top()))
1701 Selectable* selectable = Instance_getSelectable(instance);
1703 && selectable->isSelected()
1711 void post(const scene::Path& path, scene::Instance& instance) const
1713 if(path.top().get_pointer() != &m_parent
1714 && Node_isPrimitive(path.top()))
1716 Selectable* selectable = Instance_getSelectable(instance);
1718 && selectable->isSelected()
1721 scene::Node& parent = path.parent();
1722 if(&parent != &m_parent)
1724 NodeSmartReference node(path.top().get());
1725 Node_getTraversable(parent)->erase(node);
1726 Node_getTraversable(m_parent)->insert(node);
1733 void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent)
1735 graph.traverse(ParentSelectedBrushesToEntityWalker(parent));
1738 class CountSelectedBrushes : public scene::Graph::Walker
1740 std::size_t& m_count;
1741 mutable std::size_t m_depth;
1743 CountSelectedBrushes(std::size_t& count) : m_count(count), m_depth(0)
1747 bool pre(const scene::Path& path, scene::Instance& instance) const
1749 if(++m_depth != 1 && path.top().get().isRoot())
1753 Selectable* selectable = Instance_getSelectable(instance);
1755 && selectable->isSelected()
1756 && Node_isPrimitive(path.top()))
1762 void post(const scene::Path& path, scene::Instance& instance) const
1768 std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
1771 graph.traverse(CountSelectedBrushes(count));
1783 const char* nodetype_get_name(ENodeType type)
1785 if(type == eNodeMap)
1787 if(type == eNodeEntity)
1789 if(type == eNodePrimitive)
1794 ENodeType node_get_nodetype(scene::Node& node)
1796 if(Node_isEntity(node))
1800 if(Node_isPrimitive(node))
1802 return eNodePrimitive;
1804 return eNodeUnknown;
1807 bool contains_entity(scene::Node& node)
1809 return Node_getTraversable(node) != 0 && !Node_isBrush(node) && !Node_isPatch(node) && !Node_isEntity(node);
1812 bool contains_primitive(scene::Node& node)
1814 return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
1817 ENodeType node_get_contains(scene::Node& node)
1819 if(contains_entity(node))
1823 if(contains_primitive(node))
1825 return eNodePrimitive;
1827 return eNodeUnknown;
1830 void Path_parent(const scene::Path& parent, const scene::Path& child)
1832 ENodeType contains = node_get_contains(parent.top());
1833 ENodeType type = node_get_nodetype(child.top());
1835 if(contains != eNodeUnknown && contains == type)
1837 NodeSmartReference node(child.top().get());
1838 Path_deleteTop(child);
1839 Node_getTraversable(parent.top())->insert(node);
1840 SceneChangeNotify();
1844 globalErrorStream() << "failed - " << nodetype_get_name(type) << " cannot be parented to " << nodetype_get_name(contains) << " container.\n";
1848 void Scene_parentSelected()
1850 UndoableCommand undo("parentSelected");
1852 if(GlobalSelectionSystem().countSelected() > 1)
1854 class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor
1856 const scene::Path& m_parent;
1858 ParentSelectedBrushesToEntityWalker(const scene::Path& parent) : m_parent(parent)
1861 void visit(scene::Instance& instance) const
1863 if(&m_parent != &instance.path())
1865 Path_parent(m_parent, instance.path());
1870 ParentSelectedBrushesToEntityWalker visitor(GlobalSelectionSystem().ultimateSelected().path());
1871 GlobalSelectionSystem().foreachSelected(visitor);
1875 globalOutputStream() << "failed - did not find two selected nodes.\n";
1883 if (ConfirmModified("New Map"))
1891 CopiedString g_mapsPath;
1893 const char* getMapsPath()
1895 return g_mapsPath.c_str();
1898 const char* map_open(const char* title)
1900 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name(), true, false, false);
1903 const char* map_import(const char* title)
1905 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name(), false, true, false);
1908 const char* map_save(const char* title)
1910 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, getMapsPath(), MapFormat::Name(), false, false, true);
1915 if (!ConfirmModified("Open Map"))
1918 const char* filename = map_open("Open Map");
1922 MRU_AddFile(filename);
1925 Map_LoadFile(filename);
1931 const char* filename = map_import("Import Map");
1935 UndoableCommand undo("mapImport");
1936 Map_ImportFile(filename);
1942 const char* filename = map_save("Save Map");
1946 MRU_AddFile(filename);
1947 Map_Rename(filename);
1960 if(Map_Unnamed(g_map))
1964 else if(Map_Modified(g_map))
1972 const char* filename = map_save("Export Selection");
1976 Map_SaveSelected(filename);
1982 const char* filename = map_save("Export Region");
1986 Map_SaveRegion(filename);
1994 SceneChangeNotify();
2000 g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
2001 g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(),
2002 g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
2003 g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale()
2005 SceneChangeNotify();
2011 SceneChangeNotify();
2014 void RegionSelected()
2016 Map_RegionSelectedBrushes();
2017 SceneChangeNotify();
2024 class BrushFindByIndexWalker : public scene::Traversable::Walker
2026 mutable std::size_t m_index;
2027 scene::Path& m_path;
2029 BrushFindByIndexWalker(std::size_t index, scene::Path& path)
2030 : m_index(index), m_path(path)
2033 bool pre(scene::Node& node) const
2035 if(Node_isPrimitive(node) && m_index-- == 0)
2037 m_path.push(makeReference(node));
2043 class EntityFindByIndexWalker : public scene::Traversable::Walker
2045 mutable std::size_t m_index;
2046 scene::Path& m_path;
2048 EntityFindByIndexWalker(std::size_t index, scene::Path& path)
2049 : m_index(index), m_path(path)
2052 bool pre(scene::Node& node) const
2054 if(Node_isEntity(node) && m_index-- == 0)
2056 m_path.push(makeReference(node));
2062 void Scene_FindEntityBrush(std::size_t entity, std::size_t brush, scene::Path& path)
2064 path.push(makeReference(GlobalSceneGraph().root()));
2066 Node_getTraversable(path.top())->traverse(EntityFindByIndexWalker(entity, path));
2068 if(path.size() == 2)
2070 scene::Traversable* traversable = Node_getTraversable(path.top());
2071 if(traversable != 0)
2073 traversable->traverse(BrushFindByIndexWalker(brush, path));
2078 inline bool Node_hasChildren(scene::Node& node)
2080 scene::Traversable* traversable = Node_getTraversable(node);
2081 return traversable != 0 && !traversable->empty();
2084 void SelectBrush (int entitynum, int brushnum)
2087 Scene_FindEntityBrush(entitynum, brushnum, path);
2088 if(path.size() == 3 || (path.size() == 2 && !Node_hasChildren(path.top())))
2090 scene::Instance* instance = GlobalSceneGraph().find(path);
2091 ASSERT_MESSAGE(instance != 0, "SelectBrush: path not found in scenegraph");
2092 Selectable* selectable = Instance_getSelectable(*instance);
2093 ASSERT_MESSAGE(selectable != 0, "SelectBrush: path not selectable");
2094 selectable->setSelected(true);
2095 g_pParentWnd->GetXYWnd()->PositionView(instance->worldAABB().origin);
2100 class BrushFindIndexWalker : public scene::Graph::Walker
2102 mutable const scene::Node* m_node;
2103 std::size_t& m_count;
2105 BrushFindIndexWalker(const scene::Node& node, std::size_t& count)
2106 : m_node(&node), m_count(count)
2109 bool pre(const scene::Path& path, scene::Instance& instance) const
2111 if(Node_isPrimitive(path.top()))
2113 if(m_node == path.top().get_pointer())
2126 class EntityFindIndexWalker : public scene::Graph::Walker
2128 mutable const scene::Node* m_node;
2129 std::size_t& m_count;
2131 EntityFindIndexWalker(const scene::Node& node, std::size_t& count)
2132 : m_node(&node), m_count(count)
2135 bool pre(const scene::Path& path, scene::Instance& instance) const
2137 if(Node_isEntity(path.top()))
2139 if(m_node == path.top().get_pointer())
2152 static void GetSelectionIndex (int *ent, int *brush)
2154 std::size_t count_brush = 0;
2155 std::size_t count_entity = 0;
2156 if(GlobalSelectionSystem().countSelected() != 0)
2158 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
2160 GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
2161 GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
2163 *brush = int(count_brush);
2164 *ent = int(count_entity);
2173 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
2175 GtkAccelGroup* accel = gtk_accel_group_new();
2176 gtk_window_add_accel_group(window, accel);
2179 GtkVBox* vbox = create_dialog_vbox(4, 4);
2180 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
2182 GtkTable* table = create_dialog_table(2, 2, 4, 4);
2183 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
2185 GtkWidget* label = gtk_label_new ("Entity number");
2186 gtk_widget_show (label);
2187 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2188 (GtkAttachOptions) (0),
2189 (GtkAttachOptions) (0), 0, 0);
2192 GtkWidget* label = gtk_label_new ("Brush number");
2193 gtk_widget_show (label);
2194 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2195 (GtkAttachOptions) (0),
2196 (GtkAttachOptions) (0), 0, 0);
2199 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2200 gtk_widget_show(GTK_WIDGET(entry));
2201 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
2202 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2203 (GtkAttachOptions) (0), 0, 0);
2204 gtk_widget_grab_focus(GTK_WIDGET(entry));
2208 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2209 gtk_widget_show(GTK_WIDGET(entry));
2210 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
2211 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2212 (GtkAttachOptions) (0), 0, 0);
2218 GtkHBox* hbox = create_dialog_hbox(4);
2219 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
2221 GtkButton* button = create_dialog_button("Find", G_CALLBACK(dialog_button_ok), &dialog);
2222 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2223 widget_make_default(GTK_WIDGET(button));
2224 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
2227 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_cancel), &dialog);
2228 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2229 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
2234 // Initialize dialog
2238 GetSelectionIndex (&ent, &br);
2239 sprintf (buf, "%i", ent);
2240 gtk_entry_set_text(entity, buf);
2241 sprintf (buf, "%i", br);
2242 gtk_entry_set_text(brush, buf);
2244 if(modal_dialog_show(window, dialog) == eIDOK)
2246 const char *entstr = gtk_entry_get_text(entity);
2247 const char *brushstr = gtk_entry_get_text(brush);
2248 SelectBrush (atoi(entstr), atoi(brushstr));
2251 gtk_widget_destroy(GTK_WIDGET(window));
2254 void Map_constructPreferences(PreferencesPage& page)
2256 page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
2260 class MapEntityClasses : public ModuleObserver
2262 std::size_t m_unrealised;
2264 MapEntityClasses() : m_unrealised(1)
2269 if(--m_unrealised == 0)
2271 if(g_map.m_resource != 0)
2273 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
2274 g_map.m_resource->realise();
2280 if(++m_unrealised == 1)
2282 if(g_map.m_resource != 0)
2284 g_map.m_resource->flush();
2285 g_map.m_resource->unrealise();
2291 MapEntityClasses g_MapEntityClasses;
2294 class MapModuleObserver : public ModuleObserver
2296 std::size_t m_unrealised;
2298 MapModuleObserver() : m_unrealised(1)
2303 if(--m_unrealised == 0)
2305 ASSERT_MESSAGE(!string_empty(g_qeglobals.m_userGamePath.c_str()), "maps_directory: user-game-path is empty");
2306 StringOutputStream buffer(256);
2307 buffer << g_qeglobals.m_userGamePath.c_str() << "maps/";
2308 Q_mkdir(buffer.c_str());
2309 g_mapsPath = buffer.c_str();
2314 if(++m_unrealised == 1)
2321 MapModuleObserver g_MapModuleObserver;
2323 #include "preferencesystem.h"
2325 CopiedString g_strLastMap;
2326 bool g_bLoadLastMap = false;
2328 void Map_Construct()
2330 GlobalCommands_insert("RegionOff", FreeCaller<RegionOff>());
2331 GlobalCommands_insert("RegionSetXY", FreeCaller<RegionXY>());
2332 GlobalCommands_insert("RegionSetBrush", FreeCaller<RegionBrush>());
2333 GlobalCommands_insert("RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator('R', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
2335 GlobalPreferenceSystem().registerPreference("LastMap", CopiedStringImportStringCaller(g_strLastMap), CopiedStringExportStringCaller(g_strLastMap));
2336 GlobalPreferenceSystem().registerPreference("LoadLastMap", BoolImportStringCaller(g_bLoadLastMap), BoolExportStringCaller(g_bLoadLastMap));
2337 GlobalPreferenceSystem().registerPreference("MapInfoDlg", WindowPositionImportStringCaller(g_posMapInfoWnd), WindowPositionExportStringCaller(g_posMapInfoWnd));
2339 PreferencesDialog_addSettingsPreferences(FreeCaller1<PreferencesPage&, Map_constructPreferences>());
2341 GlobalEntityClassManager().attach(g_MapEntityClasses);
2342 Radiant_attachHomePathsObserver(g_MapModuleObserver);
2347 Radiant_detachHomePathsObserver(g_MapModuleObserver);
2348 GlobalEntityClassManager().detach(g_MapEntityClasses);