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
1049 for(i = 1; i < Brush_toggleFormatCount(); ++i)
1052 Brush_toggleFormat(i);
1053 g_map.m_name = filename;
1054 Map_UpdateTitle(g_map);
1055 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1056 g_map.m_resource->attach(g_map);
1060 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
1063 globalOutputStream() << "--- LoadMapFile ---\n";
1064 globalOutputStream() << g_map.m_name.c_str() << "\n";
1066 globalOutputStream() << Unsigned(g_brushCount.get()) << " primitive\n";
1067 globalOutputStream() << Unsigned(g_entityCount.get()) << " entities\n";
1069 //GlobalEntityCreator().printStatistics();
1072 // move the view to a start position
1074 Map_StartPosition();
1076 g_currentMap = &g_map;
1082 virtual bool excluded(scene::Node& node) const = 0;
1085 class ExcludeWalker : public scene::Traversable::Walker
1087 const scene::Traversable::Walker& m_walker;
1088 const Excluder* m_exclude;
1089 mutable bool m_skip;
1091 ExcludeWalker(const scene::Traversable::Walker& walker, const Excluder& exclude)
1092 : m_walker(walker), m_exclude(&exclude), m_skip(false)
1095 bool pre(scene::Node& node) const
1097 if(m_exclude->excluded(node) || node.isRoot())
1108 void post(scene::Node& node) const
1116 m_walker.post(node);
1121 class AnyInstanceSelected : public scene::Instantiable::Visitor
1125 AnyInstanceSelected(bool& selected) : m_selected(selected)
1129 void visit(scene::Instance& instance) const
1131 Selectable* selectable = Instance_getSelectable(instance);
1133 && selectable->isSelected())
1140 bool Node_instanceSelected(scene::Node& node)
1142 scene::Instantiable* instantiable = Node_getInstantiable(node);
1143 ASSERT_NOTNULL(instantiable);
1145 instantiable->forEachInstance(AnyInstanceSelected(selected));
1149 class SelectedDescendantWalker : public scene::Traversable::Walker
1153 SelectedDescendantWalker(bool& selected) : m_selected(selected)
1158 bool pre(scene::Node& node) const
1165 if(Node_instanceSelected(node))
1174 bool Node_selectedDescendant(scene::Node& node)
1177 Node_traverseSubgraph(node, SelectedDescendantWalker(selected));
1181 class SelectionExcluder : public Excluder
1184 bool excluded(scene::Node& node) const
1186 return !Node_selectedDescendant(node);
1190 class IncludeSelectedWalker : public scene::Traversable::Walker
1192 const scene::Traversable::Walker& m_walker;
1193 mutable std::size_t m_selected;
1194 mutable bool m_skip;
1196 bool selectedParent() const
1198 return m_selected != 0;
1201 IncludeSelectedWalker(const scene::Traversable::Walker& walker)
1202 : m_walker(walker), m_selected(0), m_skip(false)
1205 bool pre(scene::Node& node) const
1208 // node is not a 'root' AND ( node is selected OR any child of node is selected OR any parent of node is selected )
1209 if(!node.isRoot() && (Node_selectedDescendant(node) || selectedParent()))
1211 if(Node_instanceSelected(node))
1224 void post(scene::Node& node) const
1232 if(Node_instanceSelected(node))
1236 m_walker.post(node);
1241 void Map_Traverse_Selected(scene::Node& root, const scene::Traversable::Walker& walker)
1243 scene::Traversable* traversable = Node_getTraversable(root);
1244 if(traversable != 0)
1247 traversable->traverse(ExcludeWalker(walker, SelectionExcluder()));
1249 traversable->traverse(IncludeSelectedWalker(walker));
1254 void Map_ExportSelected(TextOutputStream& out, const MapFormat& format)
1256 format.writeGraph(GlobalSceneGraph().root(), Map_Traverse_Selected, out);
1259 void Map_Traverse(scene::Node& root, const scene::Traversable::Walker& walker)
1261 scene::Traversable* traversable = Node_getTraversable(root);
1262 if(traversable != 0)
1264 traversable->traverse(walker);
1268 class RegionExcluder : public Excluder
1271 bool excluded(scene::Node& node) const
1273 return node.excluded();
1277 void Map_Traverse_Region(scene::Node& root, const scene::Traversable::Walker& walker)
1279 scene::Traversable* traversable = Node_getTraversable(root);
1280 if(traversable != 0)
1282 traversable->traverse(ExcludeWalker(walker, RegionExcluder()));
1286 bool Map_SaveRegion(const char *filename)
1290 bool success = MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Region, filename);
1292 RemoveRegionBrushes();
1298 void Map_RenameAbsolute(const char* absolute)
1300 Resource* resource = GlobalReferenceCache().capture(absolute);
1301 NodeSmartReference clone(NewMapRoot(path_make_relative(absolute, GlobalFileSystem().findRoot(absolute))));
1302 resource->setNode(clone.get_pointer());
1305 //ScopeTimer timer("clone subgraph");
1306 Node_getTraversable(GlobalSceneGraph().root())->traverse(CloneAll(clone));
1309 g_map.m_resource->detach(g_map);
1310 GlobalReferenceCache().release(g_map.m_name.c_str());
1312 g_map.m_resource = resource;
1314 g_map.m_name = absolute;
1315 Map_UpdateTitle(g_map);
1317 g_map.m_resource->attach(g_map);
1320 void Map_Rename(const char* filename)
1322 if(!string_equal(g_map.m_name.c_str(), filename))
1324 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1326 Map_RenameAbsolute(filename);
1328 SceneChangeNotify();
1340 ScopeTimer timer("map save");
1342 return true; // assume success..
1353 //globalOutputStream() << "Map_New\n";
1355 g_map.m_name = "unnamed.map";
1356 Map_UpdateTitle(g_map);
1359 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1360 // ASSERT_MESSAGE(g_map.m_resource->getNode() == 0, "bleh");
1361 g_map.m_resource->attach(g_map);
1363 SceneChangeNotify();
1366 FocusViews(g_vector3_identity, 0);
1368 g_currentMap = &g_map;
1371 extern void ConstructRegionBrushes(scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs);
1373 void ConstructRegionStartpoint(scene::Node* startpoint, const Vector3& region_mins, const Vector3& region_maxs)
1376 \todo we need to make sure that the player start IS inside the region and bail out if it's not
1377 the compiler will refuse to compile a map with a player_start somewhere in empty space..
1378 for now, let's just print an error
1381 Vector3 vOrig(Camera_getOrigin(*g_pParentWnd->GetCamWnd()));
1383 for (int i=0 ; i<3 ; i++)
1385 if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
1387 globalErrorStream() << "Camera is NOT in the region, it's likely that the region won't compile correctly\n";
1392 // write the info_playerstart
1394 sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]);
1395 Node_getEntity(*startpoint)->setKeyValue("origin", sTmp);
1396 sprintf(sTmp, "%d", (int)Camera_getAngles(*g_pParentWnd->GetCamWnd())[CAMERA_YAW]);
1397 Node_getEntity(*startpoint)->setKeyValue("angle", sTmp);
1401 ===========================================================
1405 ===========================================================
1408 Vector3 region_mins(g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord);
1409 Vector3 region_maxs(g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord);
1411 scene::Node* region_sides[6];
1412 scene::Node* region_startpoint = 0;
1417 a regioned map will have temp walls put up at the region boundary
1418 \todo TODO TTimo old implementation of region brushes
1419 we still add them straight in the worldspawn and take them out after the map is saved
1420 with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module
1423 void AddRegionBrushes (void)
1429 region_sides[i] = &GlobalBrushCreator().createBrush();
1430 Node_getTraversable(Map_FindOrInsertWorldspawn(g_map))->insert(NodeSmartReference(*region_sides[i]));
1433 region_startpoint = &GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("info_player_start", false));
1435 ConstructRegionBrushes(region_sides, region_mins, region_maxs);
1436 ConstructRegionStartpoint(region_startpoint, region_mins, region_maxs);
1438 Node_getTraversable(GlobalSceneGraph().root())->insert(NodeSmartReference(*region_startpoint));
1441 void RemoveRegionBrushes (void)
1443 for(std::size_t i=0; i<6; i++)
1445 Node_getTraversable(*Map_GetWorldspawn(g_map))->erase(*region_sides[i]);
1447 Node_getTraversable(GlobalSceneGraph().root())->erase(*region_startpoint);
1450 inline void exclude_node(scene::Node& node, bool exclude)
1453 ? node.enable(scene::Node::eExcluded)
1454 : node.disable(scene::Node::eExcluded);
1457 class ExcludeAllWalker : public scene::Graph::Walker
1461 ExcludeAllWalker(bool exclude)
1462 : m_exclude(exclude)
1465 bool pre(const scene::Path& path, scene::Instance& instance) const
1467 exclude_node(path.top(), m_exclude);
1473 void Scene_Exclude_All(bool exclude)
1475 GlobalSceneGraph().traverse(ExcludeAllWalker(exclude));
1478 bool Instance_isSelected(const scene::Instance& instance)
1480 const Selectable* selectable = Instance_getSelectable(instance);
1481 return selectable != 0 && selectable->isSelected();
1484 class ExcludeSelectedWalker : public scene::Graph::Walker
1488 ExcludeSelectedWalker(bool exclude)
1489 : m_exclude(exclude)
1492 bool pre(const scene::Path& path, scene::Instance& instance) const
1494 exclude_node(path.top(), (instance.isSelected() || instance.childSelected() || instance.parentSelected()) == m_exclude);
1499 void Scene_Exclude_Selected(bool exclude)
1501 GlobalSceneGraph().traverse(ExcludeSelectedWalker(exclude));
1504 class ExcludeRegionedWalker : public scene::Graph::Walker
1508 ExcludeRegionedWalker(bool exclude)
1509 : m_exclude(exclude)
1512 bool pre(const scene::Path& path, scene::Instance& instance) const
1518 aabb_intersects_aabb(
1519 instance.worldAABB(),
1520 aabb_for_minmax(region_mins, region_maxs)
1530 void Scene_Exclude_Region(bool exclude)
1532 GlobalSceneGraph().traverse(ExcludeRegionedWalker(exclude));
1539 Other filtering options may still be on
1542 void Map_RegionOff()
1544 region_active = false;
1546 region_maxs[0] = g_MaxWorldCoord - 64;
1547 region_mins[0] = g_MinWorldCoord + 64;
1548 region_maxs[1] = g_MaxWorldCoord - 64;
1549 region_mins[1] = g_MinWorldCoord + 64;
1550 region_maxs[2] = g_MaxWorldCoord - 64;
1551 region_mins[2] = g_MinWorldCoord + 64;
1553 Scene_Exclude_All(false);
1556 void Map_ApplyRegion (void)
1558 region_active = true;
1560 Scene_Exclude_Region(false);
1565 ========================
1566 Map_RegionSelectedBrushes
1567 ========================
1569 void Map_RegionSelectedBrushes (void)
1573 if(GlobalSelectionSystem().countSelected() != 0
1574 && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
1576 region_active = true;
1577 Select_GetBounds (region_mins, region_maxs);
1579 Scene_Exclude_Selected(false);
1581 GlobalSelectionSystem().setSelectedAll(false);
1591 void Map_RegionXY(float x_min, float y_min, float x_max, float y_max)
1595 region_mins[0] = x_min;
1596 region_maxs[0] = x_max;
1597 region_mins[1] = y_min;
1598 region_maxs[1] = y_max;
1599 region_mins[2] = g_MinWorldCoord + 64;
1600 region_maxs[2] = g_MaxWorldCoord - 64;
1605 void Map_RegionBounds(const AABB& bounds)
1609 region_mins = vector3_subtracted(bounds.origin, bounds.extents);
1610 region_maxs = vector3_added(bounds.origin, bounds.extents);
1622 void Map_RegionBrush (void)
1624 if(GlobalSelectionSystem().countSelected() != 0)
1626 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
1627 Map_RegionBounds(instance.worldAABB());
1636 bool Map_ImportFile(const char* filename)
1638 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1640 bool success = false;
1642 Resource* resource = GlobalReferenceCache().capture(filename);
1643 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1644 if(resource->load())
1646 NodeSmartReference clone(NewMapRoot(""));
1649 //ScopeTimer timer("clone subgraph");
1650 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1653 Map_gatherNamespaced(clone);
1654 Map_mergeClonedNames();
1658 GlobalReferenceCache().release(filename);
1661 SceneChangeNotify();
1671 bool Map_SaveFile(const char* filename)
1673 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1674 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse, filename);
1682 // Saves selected world brushes and whole entities with partial/full selections
1684 bool Map_SaveSelected(const char* filename)
1686 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename);
1690 class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
1692 scene::Node& m_parent;
1694 ParentSelectedBrushesToEntityWalker(scene::Node& parent) : m_parent(parent)
1697 bool pre(const scene::Path& path, scene::Instance& instance) const
1699 if(path.top().get_pointer() != &m_parent
1700 && Node_isPrimitive(path.top()))
1702 Selectable* selectable = Instance_getSelectable(instance);
1704 && selectable->isSelected()
1712 void post(const scene::Path& path, scene::Instance& instance) const
1714 if(path.top().get_pointer() != &m_parent
1715 && Node_isPrimitive(path.top()))
1717 Selectable* selectable = Instance_getSelectable(instance);
1719 && selectable->isSelected()
1722 scene::Node& parent = path.parent();
1723 if(&parent != &m_parent)
1725 NodeSmartReference node(path.top().get());
1726 Node_getTraversable(parent)->erase(node);
1727 Node_getTraversable(m_parent)->insert(node);
1734 void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent)
1736 graph.traverse(ParentSelectedBrushesToEntityWalker(parent));
1739 class CountSelectedBrushes : public scene::Graph::Walker
1741 std::size_t& m_count;
1742 mutable std::size_t m_depth;
1744 CountSelectedBrushes(std::size_t& count) : m_count(count), m_depth(0)
1748 bool pre(const scene::Path& path, scene::Instance& instance) const
1750 if(++m_depth != 1 && path.top().get().isRoot())
1754 Selectable* selectable = Instance_getSelectable(instance);
1756 && selectable->isSelected()
1757 && Node_isPrimitive(path.top()))
1763 void post(const scene::Path& path, scene::Instance& instance) const
1769 std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
1772 graph.traverse(CountSelectedBrushes(count));
1784 const char* nodetype_get_name(ENodeType type)
1786 if(type == eNodeMap)
1788 if(type == eNodeEntity)
1790 if(type == eNodePrimitive)
1795 ENodeType node_get_nodetype(scene::Node& node)
1797 if(Node_isEntity(node))
1801 if(Node_isPrimitive(node))
1803 return eNodePrimitive;
1805 return eNodeUnknown;
1808 bool contains_entity(scene::Node& node)
1810 return Node_getTraversable(node) != 0 && !Node_isBrush(node) && !Node_isPatch(node) && !Node_isEntity(node);
1813 bool contains_primitive(scene::Node& node)
1815 return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
1818 ENodeType node_get_contains(scene::Node& node)
1820 if(contains_entity(node))
1824 if(contains_primitive(node))
1826 return eNodePrimitive;
1828 return eNodeUnknown;
1831 void Path_parent(const scene::Path& parent, const scene::Path& child)
1833 ENodeType contains = node_get_contains(parent.top());
1834 ENodeType type = node_get_nodetype(child.top());
1836 if(contains != eNodeUnknown && contains == type)
1838 NodeSmartReference node(child.top().get());
1839 Path_deleteTop(child);
1840 Node_getTraversable(parent.top())->insert(node);
1841 SceneChangeNotify();
1845 globalErrorStream() << "failed - " << nodetype_get_name(type) << " cannot be parented to " << nodetype_get_name(contains) << " container.\n";
1849 void Scene_parentSelected()
1851 UndoableCommand undo("parentSelected");
1853 if(GlobalSelectionSystem().countSelected() > 1)
1855 class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor
1857 const scene::Path& m_parent;
1859 ParentSelectedBrushesToEntityWalker(const scene::Path& parent) : m_parent(parent)
1862 void visit(scene::Instance& instance) const
1864 if(&m_parent != &instance.path())
1866 Path_parent(m_parent, instance.path());
1871 ParentSelectedBrushesToEntityWalker visitor(GlobalSelectionSystem().ultimateSelected().path());
1872 GlobalSelectionSystem().foreachSelected(visitor);
1876 globalOutputStream() << "failed - did not find two selected nodes.\n";
1884 if (ConfirmModified("New Map"))
1892 CopiedString g_mapsPath;
1894 const char* getMapsPath()
1896 return g_mapsPath.c_str();
1899 const char* map_open(const char* title)
1901 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name());
1904 const char* map_save(const char* title)
1906 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, getMapsPath(), MapFormat::Name());
1911 if (!ConfirmModified("Open Map"))
1914 const char* filename = map_open("Open Map");
1918 MRU_AddFile(filename);
1921 Map_LoadFile(filename);
1927 const char* filename = map_open("Import Map");
1931 UndoableCommand undo("mapImport");
1932 Map_ImportFile(filename);
1938 const char* filename = map_save("Save Map");
1942 MRU_AddFile(filename);
1943 Map_Rename(filename);
1956 if(Map_Unnamed(g_map))
1960 else if(Map_Modified(g_map))
1968 const char* filename = map_save("Export Selection");
1972 Map_SaveSelected(filename);
1978 const char* filename = map_save("Export Region");
1982 Map_SaveRegion(filename);
1990 SceneChangeNotify();
1996 g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
1997 g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(),
1998 g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
1999 g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale()
2001 SceneChangeNotify();
2007 SceneChangeNotify();
2010 void RegionSelected()
2012 Map_RegionSelectedBrushes();
2013 SceneChangeNotify();
2020 class BrushFindByIndexWalker : public scene::Traversable::Walker
2022 mutable std::size_t m_index;
2023 scene::Path& m_path;
2025 BrushFindByIndexWalker(std::size_t index, scene::Path& path)
2026 : m_index(index), m_path(path)
2029 bool pre(scene::Node& node) const
2031 if(Node_isPrimitive(node) && m_index-- == 0)
2033 m_path.push(makeReference(node));
2039 class EntityFindByIndexWalker : public scene::Traversable::Walker
2041 mutable std::size_t m_index;
2042 scene::Path& m_path;
2044 EntityFindByIndexWalker(std::size_t index, scene::Path& path)
2045 : m_index(index), m_path(path)
2048 bool pre(scene::Node& node) const
2050 if(Node_isEntity(node) && m_index-- == 0)
2052 m_path.push(makeReference(node));
2058 void Scene_FindEntityBrush(std::size_t entity, std::size_t brush, scene::Path& path)
2060 path.push(makeReference(GlobalSceneGraph().root()));
2062 Node_getTraversable(path.top())->traverse(EntityFindByIndexWalker(entity, path));
2064 if(path.size() == 2)
2066 scene::Traversable* traversable = Node_getTraversable(path.top());
2067 if(traversable != 0)
2069 traversable->traverse(BrushFindByIndexWalker(brush, path));
2074 inline bool Node_hasChildren(scene::Node& node)
2076 scene::Traversable* traversable = Node_getTraversable(node);
2077 return traversable != 0 && !traversable->empty();
2080 void SelectBrush (int entitynum, int brushnum)
2083 Scene_FindEntityBrush(entitynum, brushnum, path);
2084 if(path.size() == 3 || (path.size() == 2 && !Node_hasChildren(path.top())))
2086 scene::Instance* instance = GlobalSceneGraph().find(path);
2087 ASSERT_MESSAGE(instance != 0, "SelectBrush: path not found in scenegraph");
2088 Selectable* selectable = Instance_getSelectable(*instance);
2089 ASSERT_MESSAGE(selectable != 0, "SelectBrush: path not selectable");
2090 selectable->setSelected(true);
2091 g_pParentWnd->GetXYWnd()->PositionView(instance->worldAABB().origin);
2096 class BrushFindIndexWalker : public scene::Graph::Walker
2098 mutable const scene::Node* m_node;
2099 std::size_t& m_count;
2101 BrushFindIndexWalker(const scene::Node& node, std::size_t& count)
2102 : m_node(&node), m_count(count)
2105 bool pre(const scene::Path& path, scene::Instance& instance) const
2107 if(Node_isPrimitive(path.top()))
2109 if(m_node == path.top().get_pointer())
2122 class EntityFindIndexWalker : public scene::Graph::Walker
2124 mutable const scene::Node* m_node;
2125 std::size_t& m_count;
2127 EntityFindIndexWalker(const scene::Node& node, std::size_t& count)
2128 : m_node(&node), m_count(count)
2131 bool pre(const scene::Path& path, scene::Instance& instance) const
2133 if(Node_isEntity(path.top()))
2135 if(m_node == path.top().get_pointer())
2148 static void GetSelectionIndex (int *ent, int *brush)
2150 std::size_t count_brush = 0;
2151 std::size_t count_entity = 0;
2152 if(GlobalSelectionSystem().countSelected() != 0)
2154 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
2156 GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
2157 GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
2159 *brush = int(count_brush);
2160 *ent = int(count_entity);
2169 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
2171 GtkAccelGroup* accel = gtk_accel_group_new();
2172 gtk_window_add_accel_group(window, accel);
2175 GtkVBox* vbox = create_dialog_vbox(4, 4);
2176 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
2178 GtkTable* table = create_dialog_table(2, 2, 4, 4);
2179 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
2181 GtkWidget* label = gtk_label_new ("Entity number");
2182 gtk_widget_show (label);
2183 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2184 (GtkAttachOptions) (0),
2185 (GtkAttachOptions) (0), 0, 0);
2188 GtkWidget* label = gtk_label_new ("Brush number");
2189 gtk_widget_show (label);
2190 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2191 (GtkAttachOptions) (0),
2192 (GtkAttachOptions) (0), 0, 0);
2195 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2196 gtk_widget_show(GTK_WIDGET(entry));
2197 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
2198 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2199 (GtkAttachOptions) (0), 0, 0);
2200 gtk_widget_grab_focus(GTK_WIDGET(entry));
2204 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2205 gtk_widget_show(GTK_WIDGET(entry));
2206 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
2207 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2208 (GtkAttachOptions) (0), 0, 0);
2214 GtkHBox* hbox = create_dialog_hbox(4);
2215 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
2217 GtkButton* button = create_dialog_button("Find", G_CALLBACK(dialog_button_ok), &dialog);
2218 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2219 widget_make_default(GTK_WIDGET(button));
2220 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
2223 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_cancel), &dialog);
2224 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2225 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
2230 // Initialize dialog
2234 GetSelectionIndex (&ent, &br);
2235 sprintf (buf, "%i", ent);
2236 gtk_entry_set_text(entity, buf);
2237 sprintf (buf, "%i", br);
2238 gtk_entry_set_text(brush, buf);
2240 if(modal_dialog_show(window, dialog) == eIDOK)
2242 const char *entstr = gtk_entry_get_text(entity);
2243 const char *brushstr = gtk_entry_get_text(brush);
2244 SelectBrush (atoi(entstr), atoi(brushstr));
2247 gtk_widget_destroy(GTK_WIDGET(window));
2250 void Map_constructPreferences(PreferencesPage& page)
2252 page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
2256 class MapEntityClasses : public ModuleObserver
2258 std::size_t m_unrealised;
2260 MapEntityClasses() : m_unrealised(1)
2265 if(--m_unrealised == 0)
2267 if(g_map.m_resource != 0)
2269 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
2270 g_map.m_resource->realise();
2276 if(++m_unrealised == 1)
2278 if(g_map.m_resource != 0)
2280 g_map.m_resource->flush();
2281 g_map.m_resource->unrealise();
2287 MapEntityClasses g_MapEntityClasses;
2290 class MapModuleObserver : public ModuleObserver
2292 std::size_t m_unrealised;
2294 MapModuleObserver() : m_unrealised(1)
2299 if(--m_unrealised == 0)
2301 ASSERT_MESSAGE(!string_empty(g_qeglobals.m_userGamePath.c_str()), "maps_directory: user-game-path is empty");
2302 StringOutputStream buffer(256);
2303 buffer << g_qeglobals.m_userGamePath.c_str() << "maps/";
2304 Q_mkdir(buffer.c_str());
2305 g_mapsPath = buffer.c_str();
2310 if(++m_unrealised == 1)
2317 MapModuleObserver g_MapModuleObserver;
2319 #include "preferencesystem.h"
2321 CopiedString g_strLastMap;
2322 bool g_bLoadLastMap = false;
2324 void Map_Construct()
2326 GlobalCommands_insert("RegionOff", FreeCaller<RegionOff>());
2327 GlobalCommands_insert("RegionSetXY", FreeCaller<RegionXY>());
2328 GlobalCommands_insert("RegionSetBrush", FreeCaller<RegionBrush>());
2329 GlobalCommands_insert("RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator('R', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
2331 GlobalPreferenceSystem().registerPreference("LastMap", CopiedStringImportStringCaller(g_strLastMap), CopiedStringExportStringCaller(g_strLastMap));
2332 GlobalPreferenceSystem().registerPreference("LoadLastMap", BoolImportStringCaller(g_bLoadLastMap), BoolExportStringCaller(g_bLoadLastMap));
2333 GlobalPreferenceSystem().registerPreference("MapInfoDlg", WindowPositionImportStringCaller(g_posMapInfoWnd), WindowPositionExportStringCaller(g_posMapInfoWnd));
2335 PreferencesDialog_addSettingsPreferences(FreeCaller1<PreferencesPage&, Map_constructPreferences>());
2337 GlobalEntityClassManager().attach(g_MapEntityClasses);
2338 Radiant_attachHomePathsObserver(g_MapModuleObserver);
2343 Radiant_detachHomePathsObserver(g_MapModuleObserver);
2344 GlobalEntityClassManager().detach(g_MapEntityClasses);