]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/map.cpp
reorganized about dialog and updated logo. fixed
[xonotic/netradiant.git] / radiant / map.cpp
index f4a23c16d3c57b1c85a74eb421073a7864c53847..078f771977a7126232b63c886b34e2be68cf4e99 100644 (file)
 /*
-Copyright (C) 1999-2006 Id Software, Inc. and contributors.
-For a list of contributors, see the accompanying CONTRIBUTORS file.
-
-This file is part of GtkRadiant.
-
-GtkRadiant is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-GtkRadiant is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GtkRadiant; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
-
-#include "map.h"
-
-#include "debugging/debugging.h"
-
-#include "imap.h"
-#include "iselection.h"
-#include "iundo.h"
-#include "ibrush.h"
-#include "ifilter.h"
-#include "ireference.h"
-#include "ifiletypes.h"
-#include "ieclass.h"
-#include "irender.h"
-#include "ientity.h"
-#include "editable.h"
-#include "ifilesystem.h"
-#include "namespace.h"
-#include "moduleobserver.h"
-
-#include <set>
-
-#include <gtk/gtkmain.h>
-#include <gtk/gtkbox.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtktreemodel.h>
-#include <gtk/gtktreeview.h>
-#include <gtk/gtkliststore.h>
-#include <gtk/gtkcellrenderertext.h>
-
-#include "scenelib.h"
-#include "transformlib.h"
-#include "selectionlib.h"
-#include "instancelib.h"
-#include "traverselib.h"
-#include "maplib.h"
-#include "eclasslib.h"
-#include "cmdlib.h"
-#include "stream/textfilestream.h"
-#include "os/path.h"
-#include "uniquenames.h"
-#include "modulesystem/singletonmodule.h"
-#include "modulesystem/moduleregistry.h"
-#include "stream/stringstream.h"
-
-#include "gtkutil/filechooser.h"
-#include "timer.h"
-#include "select.h"
-#include "plugin.h"
-#include "filetypes.h"
-#include "gtkdlgs.h"
-#include "entityinspector.h"
-#include "points.h"
-#include "qe3.h"
-#include "camwindow.h"
-#include "xywindow.h"
-#include "mainframe.h"
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   GtkRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "stdafx.h"
+#include <string.h>
+#if defined ( __linux__ ) || defined ( __APPLE__ )
+#include <unistd.h>
+#endif
 #include "preferences.h"
-#include "referencecache.h"
-#include "mru.h"
-#include "commands.h"
-#include "autosave.h"
-
-class NameObserver
-{
-  UniqueNames& m_names;
-  CopiedString m_name;
-
-  void construct()
-  {
-    if(!empty())
-    {
-      //globalOutputStream() << "construct " << makeQuoted(c_str()) << "\n";
-      m_names.insert(name_read(c_str()));
-    }
-  }
-  void destroy()
-  {
-    if(!empty())
-    {
-      //globalOutputStream() << "destroy " << makeQuoted(c_str()) << "\n";
-      m_names.erase(name_read(c_str()));
-    }
-  }
-
-  NameObserver& operator=(const NameObserver& other);
-public:
-  NameObserver(UniqueNames& names) : m_names(names)
-  {
-    construct();
-  }
-  NameObserver(const NameObserver& other) : m_names(other.m_names), m_name(other.m_name)
-  {
-    construct();
-  }
-  ~NameObserver()
-  {
-    destroy();
-  }
-  bool empty() const
-  {
-    return string_empty(c_str()); 
-  }
-  const char* c_str() const
-  {
-    return m_name.c_str();
-  }
-  void nameChanged(const char* name)
-  {
-    destroy();
-    m_name = name;
-    construct();
-  }
-  typedef MemberCaller1<NameObserver, const char*, &NameObserver::nameChanged> NameChangedCaller;
-};
-
-class BasicNamespace : public Namespace
-{
-  typedef std::map<NameCallback, NameObserver> Names;
-  Names m_names;
-  UniqueNames m_uniqueNames;
-public:
-  ~BasicNamespace()
-  {
-    ASSERT_MESSAGE(m_names.empty(), "namespace: names still registered at shutdown");
-  }
-  void attach(const NameCallback& setName, const NameCallbackCallback& attachObserver)
-  {
-    std::pair<Names::iterator, bool> result = m_names.insert(Names::value_type(setName, m_uniqueNames));
-    ASSERT_MESSAGE(result.second, "cannot attach name");
-    attachObserver(NameObserver::NameChangedCaller((*result.first).second));
-    //globalOutputStream() << "attach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
-  }
-  void detach(const NameCallback& setName, const NameCallbackCallback& detachObserver)
-  {
-    Names::iterator i = m_names.find(setName);
-    ASSERT_MESSAGE(i != m_names.end(), "cannot detach name");
-    //globalOutputStream() << "detach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
-    detachObserver(NameObserver::NameChangedCaller((*i).second));
-    m_names.erase(i);
-  }
-
-  void makeUnique(const char* name, const NameCallback& setName) const
-  {
-    char buffer[1024];
-    name_write(buffer, m_uniqueNames.make_unique(name_read(name)));
-    setName(buffer);
-  }
-
-  void mergeNames(const BasicNamespace& other) const
-  {
-    typedef std::list<NameCallback> SetNameCallbacks;
-    typedef std::map<CopiedString, SetNameCallbacks> NameGroups;
-    NameGroups groups;
-
-    UniqueNames uniqueNames(other.m_uniqueNames);
-
-    for(Names::const_iterator i = m_names.begin(); i != m_names.end(); ++i)
-    {
-      groups[(*i).second.c_str()].push_back((*i).first);
-    }
-
-    for(NameGroups::iterator i = groups.begin(); i != groups.end(); ++i)
-    {
-      name_t uniqueName(uniqueNames.make_unique(name_read((*i).first.c_str())));
-      uniqueNames.insert(uniqueName);
-
-      char buffer[1024];
-      name_write(buffer, uniqueName);
-
-      //globalOutputStream() << "renaming " << makeQuoted((*i).first.c_str()) << " to " << makeQuoted(buffer) << "\n";
-
-      SetNameCallbacks& setNameCallbacks = (*i).second;
-
-      for(SetNameCallbacks::const_iterator j = setNameCallbacks.begin(); j != setNameCallbacks.end(); ++j)
-      {
-        (*j)(buffer);
-      }
-    }
-  }
-};
-
-BasicNamespace g_defaultNamespace;
-BasicNamespace g_cloneNamespace;
-
-class NamespaceAPI
-{
-  Namespace* m_namespace;
-public:
-  typedef Namespace Type;
-  STRING_CONSTANT(Name, "*");
-
-  NamespaceAPI()
-  {
-    m_namespace = &g_defaultNamespace;
-  }
-  Namespace* getTable()
-  {
-    return m_namespace;
-  }
-};
-
-typedef SingletonModule<NamespaceAPI> NamespaceModule;
-typedef Static<NamespaceModule> StaticNamespaceModule;
-StaticRegisterModule staticRegisterDefaultNamespace(StaticNamespaceModule::instance());
-
-
-std::list<Namespaced*> g_cloned;
-
-inline Namespaced* Node_getNamespaced(scene::Node& node)
-{
-  return NodeTypeCast<Namespaced>::cast(node);
-}
-
-void Node_gatherNamespaced(scene::Node& node)
-{
-  Namespaced* namespaced = Node_getNamespaced(node);
-  if(namespaced != 0)
-  {
-    g_cloned.push_back(namespaced);
-  }
-}
-
-class GatherNamespaced : public scene::Traversable::Walker
-{
-public:
-  bool pre(scene::Node& node) const
-  {
-    Node_gatherNamespaced(node);
-    return true;
-  }
-};
-
-void Map_gatherNamespaced(scene::Node& root)
-{
-  Node_traverseSubgraph(root, GatherNamespaced());
-}
-
-void Map_mergeClonedNames()
-{
-  for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
-  {
-    (*i)->setNamespace(g_cloneNamespace);
-  }
-  g_cloneNamespace.mergeNames(g_defaultNamespace);
-  for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
-  {
-    (*i)->setNamespace(g_defaultNamespace);
-  }
-
-  g_cloned.clear();
-}
-
-class WorldNode
-{
-  scene::Node* m_node;
-public:
-  WorldNode()
-    : m_node(0)
-  {
-  }
-  void set(scene::Node* node)
-  {
-    if(m_node != 0)
-      m_node->DecRef();
-    m_node = node;
-    if(m_node != 0)
-      m_node->IncRef();
-  }
-  scene::Node* get() const
-  {
-    return m_node;
-  }
-};
-
-class Map;
-void Map_SetValid(Map& map, bool valid);
-void Map_UpdateTitle(const Map& map);
-void Map_SetWorldspawn(Map& map, scene::Node* node);
-
-
-class Map : public ModuleObserver
-{
-public:
-  CopiedString m_name;
-  Resource* m_resource;
-  bool m_valid;
-
-  bool m_modified;
-  void (*m_modified_changed)(const Map&);
-
-  typedef std::vector<Callback> MapValidCallbacks;
-  MapValidCallbacks m_mapValidCallbacks;
-
-  WorldNode m_world_node; // "classname" "worldspawn" !
-
-  Map() : m_resource(0), m_valid(false), m_modified_changed(Map_UpdateTitle)
-  {
-  }
-
-  void realise()
-  {
-    if(m_resource != 0)
-    {
-      if(Map_Unnamed(*this))
-      {
-        g_map.m_resource->setNode(NewMapRoot("").get_pointer());
-        MapFile* map = Node_getMapFile(*g_map.m_resource->getNode());
-        if(map != 0)
-        {
-          map->save();
-        }
-      }
-      else
-      {
-        m_resource->load();
-      }
-
-      GlobalSceneGraph().insert_root(*m_resource->getNode());
-
-      AutoSave_clear();
-
-      Map_SetValid(g_map, true);
-    }
-  }
-  void unrealise()
-  {
-    if(m_resource != 0)
-    {
-      Map_SetValid(g_map, false);
-      Map_SetWorldspawn(g_map, 0);
-
-
-      GlobalUndoSystem().clear();
-
-      GlobalSceneGraph().erase_root();
-    }
-  }
-};
-
-Map g_map;
-Map* g_currentMap = 0;
-
-void Map_addValidCallback(Map& map, const Callback& callback)
-{
-  map.m_mapValidCallbacks.push_back(callback);
-}
-
-bool Map_Valid(const Map& map)
-{
-  return map.m_valid;
-}
-
-void Map_SetValid(Map& map, bool valid)
-{
-  map.m_valid = valid;
-  std::for_each(map.m_mapValidCallbacks.begin(), map.m_mapValidCallbacks.end(), CallbackInvoke());
-}
-
-
-const char* Map_Name(const Map& map)
-{
-  return map.m_name.c_str();
-}
-
-bool Map_Unnamed(const Map& map)
-{
-  return string_equal(Map_Name(map), "unnamed.map");
-}
-
-inline const MapFormat& MapFormat_forFile(const char* filename)
-{
-  const char* moduleName = findModuleName(GetFileTypeRegistry(), MapFormat::Name(), path_get_extension(filename));
-  MapFormat* format = Radiant_getMapModules().findModule(moduleName);
-  ASSERT_MESSAGE(format != 0, "map format not found for file " << makeQuoted(filename));
-  return *format;
-}
+#include "mainframe.h"
+#include "gtkmisc.h"
+#include "filters.h"
 
-const MapFormat& Map_getFormat(const Map& map)
-{
-  return MapFormat_forFile(Map_Name(map));
-}
+extern MainFrame* g_pParentWnd;
 
+int modified;   // for quit confirmation (0 = clean, 1 = unsaved,
+// 2 = autosaved, but not regular saved)
 
-bool Map_Modified(const Map& map)
-{
-  return map.m_modified;
-}
+char currentmap[1024];
 
-void Map_SetModified(Map& map, bool modified)
-{
-  if(map.m_modified ^ modified)
-  {
-    map.m_modified = modified;
+brush_t active_brushes;     // brushes currently being displayed
+brush_t selected_brushes;   // highlighted
 
-    map.m_modified_changed(map);
-  }
-}
+face_t  *selected_face;
+brush_t *selected_face_brush;
 
-void Map_UpdateTitle(const Map& map)
-{
-  Sys_SetTitle(map.m_name.c_str(), Map_Modified(map));
-}
+brush_t filtered_brushes;   // brushes that have been filtered or regioned
 
+entity_t entities;          // head/tail of doubly linked list
 
+entity_t    *world_entity = NULL; // "classname" "worldspawn" !
 
-scene::Node* Map_GetWorldspawn(const Map& map)
-{
-  return map.m_world_node.get();
+void Map_Init(){
+       Map_Free();
 }
 
-void Map_SetWorldspawn(Map& map, scene::Node* node)
-{
-  map.m_world_node.set(node);
-}
 
+bool g_bCancel_Map_LoadFile;  // Hydra: moved this here
 
 // TTimo
 // need that in a variable, will have to tweak depending on the game
-float g_MaxWorldCoord = 64*1024;
-float g_MinWorldCoord = -64*1024;
+int g_MaxWorldCoord = 64 * 1024;
+int g_MinWorldCoord = -64 * 1024;
 
-void AddRegionBrushes (void);
-void RemoveRegionBrushes (void);
+// the max size we allow on brushes, this is dependant on world coords too
+// makes more sense to say smaller I think?
+int g_MaxBrushSize = ( g_MaxWorldCoord - 1 ) * 2;
 
+void AddRegionBrushes( void );
+void RemoveRegionBrushes( void );
 
 /*
-================
-Map_Free
-free all map elements, reinitialize the structures that depend on them
-================
-*/
-void Map_Free()
-{
-       Pointfile_Clear();
+   =============================================================
 
-  g_map.m_resource->detach(g_map);
-  GlobalReferenceCache().release(g_map.m_name.c_str());
-  g_map.m_resource = 0;
+   Cross map selection saving
 
-  FlushReferences();
+   this could fuck up if you have only part of a complex entity selected...
+   =============================================================
+ */
 
-  g_currentMap = 0;
-}
+brush_t between_brushes;
+entity_t between_entities;
 
-class EntityFindByClassname : public scene::Graph::Walker
-{
-  const char* m_name;
-  Entity*& m_entity;
-public:
-  EntityFindByClassname(const char* name, Entity*& entity) : m_name(name), m_entity(entity)
-  {
-    m_entity = 0;
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    if(m_entity == 0)
-    {
-      Entity* entity = Node_getEntity(path.top());
-      if(entity != 0
-        && string_equal(m_name, entity->getKeyValue("classname")))
-      {
-        m_entity = entity;
-      }
-    }
-    return true;
-  }
-};
-
-Entity* Scene_FindEntityByClass(const char* name)
-{
-  Entity* entity;
-  GlobalSceneGraph().traverse(EntityFindByClassname(name, entity));
-  return entity;
-}
+bool g_bRestoreBetween = false;
 
-Entity *Scene_FindPlayerStart()
-{
-  typedef const char* StaticString;
-  StaticString strings[] = {
-    "info_player_start",
-    "info_player_deathmatch",
-    "team_CTF_redplayer",
-    "team_CTF_blueplayer",
-    "team_CTF_redspawn",
-    "team_CTF_bluespawn",
-  };
-  typedef const StaticString* StaticStringIterator;
-  for(StaticStringIterator i = strings, end = strings+(sizeof(strings)/sizeof(StaticString)); i != end; ++i)
-  {
-    Entity* entity = Scene_FindEntityByClass(*i);
-    if(entity != 0)
-    {
-      return entity;
-    }
-  }
-  return 0;
+void Map_SaveBetween( void ){
+       if ( g_pParentWnd->ActiveXY() ) {
+               g_bRestoreBetween = true;
+               g_pParentWnd->ActiveXY()->Copy();
+       }
+       return;
 }
 
-//
-// move the view to a start position
-//
-
-
-void FocusViews(const Vector3& point, float angle)
-{
-  CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
-  Camera_setOrigin(camwnd, point);
-  Vector3 angles(Camera_getAngles(camwnd));
-  angles[CAMERA_PITCH] = 0;
-  angles[CAMERA_YAW] = angle;
-  Camera_setAngles(camwnd, angles);
-
-  XYWnd* xywnd = g_pParentWnd->GetXYWnd();
-  xywnd->SetOrigin(point);
+void Map_RestoreBetween( void ){
+       if ( g_pParentWnd->ActiveXY() && g_bRestoreBetween ) {
+               g_pParentWnd->ActiveXY()->Paste();
+       }
 }
 
-#include "stringio.h"
-
-void Map_StartPosition()
-{
-  Entity* entity = Scene_FindPlayerStart();
-
-  if (entity)
-  {
-    Vector3 origin;
-    string_parse_vector3(entity->getKeyValue("origin"), origin);
-    FocusViews(origin, string_read_float(entity->getKeyValue("angle")));
-  }
-  else
-  {
-    FocusViews(g_vector3_identity, 0);
-  }
-}
+//============================================================================
 
-
-inline bool node_is_worldspawn(scene::Node& node)
-{
-  Entity* entity = Node_getEntity(node);
-  return entity != 0 && string_equal(entity->getKeyValue("classname"), "worldspawn");
-}
-
-
-// use first worldspawn
-class entity_updateworldspawn : public scene::Traversable::Walker
-{
-public:
-  bool pre(scene::Node& node) const
-  {
-    if(node_is_worldspawn(node))
-    {
-      if(Map_GetWorldspawn(g_map) == 0)
-      {
-        Map_SetWorldspawn(g_map, &node);
-      }
-    }
-    return false;
-  }
-};
-
-scene::Node* Map_FindWorldspawn(Map& map)
-{
-  Map_SetWorldspawn(map, 0);
-
-  Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
-
-  return Map_GetWorldspawn(map);
+bool CheckForTinyBrush( brush_t* b, int n, float fSize ){
+       bool bTiny = false;
+       for ( int i = 0 ; i < 3 ; i++ )
+       {
+               if ( b->maxs[i] - b->mins[i] < fSize ) {
+                       bTiny = true;
+               }
+       }
+       if ( bTiny ) {
+               Sys_Printf( "Possible problem brush (too small) #%i ", n );
+       }
+       return bTiny;
 }
 
+void Map_BuildBrushData( void ){
+       brush_t *b, *next;
 
-class CollectAllWalker : public scene::Traversable::Walker
-{
-  scene::Node& m_root;
-  UnsortedNodeSet& m_nodes;
-public:
-  CollectAllWalker(scene::Node& root, UnsortedNodeSet& nodes) : m_root(root), m_nodes(nodes)
-  {
-  }
-  bool pre(scene::Node& node) const
-  {
-    m_nodes.insert(NodeSmartReference(node));
-    Node_getTraversable(m_root)->erase(node);
-    return false;
-  }
-};
-
-void Node_insertChildFirst(scene::Node& parent, scene::Node& child)
-{
-  UnsortedNodeSet nodes;
-  Node_getTraversable(parent)->traverse(CollectAllWalker(parent, nodes));
-  Node_getTraversable(parent)->insert(child);
-
-  for(UnsortedNodeSet::iterator i = nodes.begin(); i != nodes.end(); ++i)
-  {
-    Node_getTraversable(parent)->insert((*i));
-  }
-}
-
-scene::Node& createWorldspawn()
-{
-  NodeSmartReference worldspawn(GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("worldspawn", true)));
-  Node_insertChildFirst(GlobalSceneGraph().root(), worldspawn);
-  return worldspawn;
-}
+       if ( active_brushes.next == NULL ) {
+               return;
+       }
 
-void Map_UpdateWorldspawn(Map& map)
-{
-  if(Map_FindWorldspawn(map) == 0)
-  {
-    Map_SetWorldspawn(map, &createWorldspawn());
-  }
-}
+       Sys_BeginWait(); // this could take a while
 
-scene::Node& Map_FindOrInsertWorldspawn(Map& map)
-{
-  Map_UpdateWorldspawn(map);
-  return *Map_GetWorldspawn(map);
+       int n = 0;
+       for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b = next )
+       {
+               next = b->next;
+               Brush_Build( b, true, false, false );
+               if ( !b->brush_faces || ( g_PrefsDlg.m_bCleanTiny && CheckForTinyBrush( b, n++, g_PrefsDlg.m_fTinySize ) ) ) {
+                       Brush_Free( b );
+                       Sys_Printf( "Removed degenerate brush\n" );
+               }
+       }
+       Sys_EndWait();
 }
 
+entity_t *Map_FindClass( const char *cname ){
+       entity_t    *ent;
 
-class MapMergeAll : public scene::Traversable::Walker
-{
-  mutable scene::Path m_path;
-public:
-  MapMergeAll(const scene::Path& root)
-    : m_path(root)
-  {
-  }
-  bool pre(scene::Node& node) const
-  {
-    Node_getTraversable(m_path.top())->insert(node);
-    m_path.push(makeReference(node));
-    selectPath(m_path, true);
-    return false;
-  }
-  void post(scene::Node& node) const
-  {
-    m_path.pop();
-  }
-};
-
-class MapMergeEntities : public scene::Traversable::Walker
-{
-  mutable scene::Path m_path;
-public:
-  MapMergeEntities(const scene::Path& root)
-    : m_path(root)
-  {
-  }
-  bool pre(scene::Node& node) const
-  {
-    if(node_is_worldspawn(node))
-    {
-      scene::Node* world_node = Map_FindWorldspawn(g_map);
-      if(world_node == 0)
-      {
-        Map_SetWorldspawn(g_map, &node);
-        Node_getTraversable(m_path.top().get())->insert(node);
-        m_path.push(makeReference(node));
-        Node_getTraversable(node)->traverse(SelectChildren(m_path));
-      }
-      else
-      {
-        m_path.push(makeReference(*world_node));
-        Node_getTraversable(node)->traverse(MapMergeAll(m_path));
-      }
-    }
-    else
-    {
-      Node_getTraversable(m_path.top())->insert(node);
-      m_path.push(makeReference(node));
-      if(node_is_group(node))
-      {
-        Node_getTraversable(node)->traverse(SelectChildren(m_path));
-      }
-      else
-      {
-        selectPath(m_path, true);
-      }
-    }
-    return false;
-  }
-  void post(scene::Node& node) const
-  {
-    m_path.pop();
-  }
-};
-
-class BasicContainer : public scene::Node::Symbiot
-{
-  class TypeCasts
-  {
-    NodeTypeCastTable m_casts;
-  public:
-    TypeCasts()
-    {
-      NodeContainedCast<BasicContainer, scene::Traversable>::install(m_casts);
-    }
-    NodeTypeCastTable& get()
-    {
-      return m_casts;
-    }
-  };
-
-  scene::Node m_node;
-  TraversableNodeSet m_traverse;
-public:
-
-  typedef LazyStatic<TypeCasts> StaticTypeCasts;
-
-  scene::Traversable& get(NullType<scene::Traversable>)
-  {
-    return m_traverse;
-  }
-
-  BasicContainer() : m_node(this, this, StaticTypeCasts::instance().get())
-  {
-  }
-  void release()
-  {
-    delete this;
-  }
-  scene::Node& node()
-  {
-    return m_node;
-  }
-};
-
-/// Merges the map graph rooted at \p node into the global scene-graph.
-void MergeMap(scene::Node& node)
-{
-  Node_getTraversable(node)->traverse(MapMergeEntities(scene::Path(makeReference(GlobalSceneGraph().root()))));
-}
-void Map_ImportSelected(TextInputStream& in, const MapFormat& format)
-{
-  NodeSmartReference node((new BasicContainer)->node());
-  format.readGraph(node, in, GlobalEntityCreator());
-  Map_gatherNamespaced(node);
-  Map_mergeClonedNames();
-  MergeMap(node);
-}
-
-inline scene::Cloneable* Node_getCloneable(scene::Node& node)
-{
-  return NodeTypeCast<scene::Cloneable>::cast(node);
+       for ( ent = entities.next ; ent != &entities ; ent = ent->next )
+       {
+               if ( !strcmp( cname, ValueForKey( ent, "classname" ) ) ) {
+                       return ent;
+               }
+       }
+       return NULL;
 }
 
-inline scene::Node& node_clone(scene::Node& node)
-{
-  scene::Cloneable* cloneable = Node_getCloneable(node);
-  if(cloneable != 0)
-  {
-    return cloneable->clone();
-  }
-  
-  return (new scene::NullNode)->node();
-}
-
-class CloneAll : public scene::Traversable::Walker
-{
-  mutable scene::Path m_path;
-public:
-  CloneAll(scene::Node& root)
-    : m_path(makeReference(root))
-  {
-  }
-  bool pre(scene::Node& node) const
-  {
-    if(node.isRoot())
-    {
-      return false;
-    }
-    
-    m_path.push(makeReference(node_clone(node)));
-    m_path.top().get().IncRef();
-
-    return true;
-  }
-  void post(scene::Node& node) const
-  {
-    if(node.isRoot())
-    {
-      return;
-    }
-
-    Node_getTraversable(m_path.parent())->insert(m_path.top());
-
-    m_path.top().get().DecRef();
-    m_path.pop();
-  }
-};
-
-scene::Node& Node_Clone(scene::Node& node)
-{
-  scene::Node& clone = node_clone(node);
-  scene::Traversable* traversable = Node_getTraversable(node);
-  if(traversable != 0)
-  {
-    traversable->traverse(CloneAll(clone));
-  }
-  return clone;
-}
-
-
-typedef std::map<CopiedString, std::size_t> EntityBreakdown;
-
-class EntityBreakdownWalker : public scene::Graph::Walker
-{
-  EntityBreakdown& m_entitymap;
-public:
-  EntityBreakdownWalker(EntityBreakdown& entitymap)
-    : m_entitymap(entitymap)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    Entity* entity = Node_getEntity(path.top());
-    if(entity != 0)
-    {
-      const EntityClass& eclass = entity->getEntityClass();
-      if(m_entitymap.find(eclass.name()) == m_entitymap.end())
-      {
-        m_entitymap[eclass.name()] = 1;
-      }
-      else ++m_entitymap[eclass.name()];
-    }
-    return true;
-  }
-};
-
-void Scene_EntityBreakdown(EntityBreakdown& entitymap)
-{
-  GlobalSceneGraph().traverse(EntityBreakdownWalker(entitymap));
-}
-
-
-WindowPosition g_posMapInfoWnd(c_default_window_pos);
-
-void DoMapInfo()
-{
-  ModalDialog dialog;
-  GtkEntry* brushes_entry;
-  GtkEntry* entities_entry;
-  GtkListStore* EntityBreakdownWalker;
-
-  GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Map Info", G_CALLBACK(dialog_delete_callback), &dialog);
-
-  window_set_position(window, g_posMapInfoWnd);
-
-  {
-    GtkVBox* vbox = create_dialog_vbox(4, 4);
-    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
-
-    {
-      GtkHBox* hbox = create_dialog_hbox(4);
-      gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, TRUE, 0);
-
-      {
-        GtkTable* table = create_dialog_table(2, 2, 4, 4);
-        gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
-
-        {
-          GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
-          gtk_widget_show(GTK_WIDGET(entry));
-          gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
-                            (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                            (GtkAttachOptions) (0), 0, 0);
-          gtk_entry_set_editable(entry, FALSE);
-
-          brushes_entry = entry;
-        }
-        {
-          GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
-          gtk_widget_show(GTK_WIDGET(entry));
-          gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
-                            (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                            (GtkAttachOptions) (0), 0, 0);
-          gtk_entry_set_editable(entry, FALSE);
-
-          entities_entry = entry;
-        }
-        {
-          GtkWidget* label = gtk_label_new ("Total Brushes");
-          gtk_widget_show (label);
-          gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
-                            (GtkAttachOptions) (GTK_FILL),
-                            (GtkAttachOptions) (0), 0, 0);
-          gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-        }
-        {
-          GtkWidget* label = gtk_label_new ("Total Entities");
-          gtk_widget_show (label);
-          gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
-                            (GtkAttachOptions) (GTK_FILL),
-                            (GtkAttachOptions) (0), 0, 0);
-          gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-        }
-      }
-      {
-        GtkVBox* vbox2 = create_dialog_vbox(4);
-        gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox2), FALSE, FALSE, 0);
-
-        {
-          GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_ok), &dialog);
-          gtk_box_pack_start(GTK_BOX(vbox2), GTK_WIDGET(button), FALSE, FALSE, 0);
-        }
-      }
-    }
-    {
-      GtkWidget* label = gtk_label_new ("Entity breakdown");
-      gtk_widget_show (label);
-      gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, TRUE, 0);
-      gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-    }
-    {
-      GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4);
-      gtk_box_pack_start(GTK_BOX (vbox), GTK_WIDGET(scr), TRUE, TRUE, 0);
-
-      {
-        GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
-
-        GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
-        gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(view), TRUE);
-
-        {
-          GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
-          GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Entity", renderer, "text", 0, 0);
-          gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
-          gtk_tree_view_column_set_sort_column_id(column, 0);
-        }
-
-        {
-          GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
-          GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Count", renderer, "text", 1, 0);
-          gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
-          gtk_tree_view_column_set_sort_column_id(column, 1);
-        }
-
-        gtk_widget_show(view);
-
-        gtk_container_add(GTK_CONTAINER(scr), view);
-        
-        EntityBreakdownWalker = store;
-      }
-    }
-  }
-
-  // Initialize fields
-
-  {
-    EntityBreakdown entitymap;
-    Scene_EntityBreakdown(entitymap);
-
-    for(EntityBreakdown::iterator i=entitymap.begin(); i != entitymap.end(); ++i)
-    {
-      char tmp[16];
-      sprintf (tmp, "%u", Unsigned((*i).second));
-      GtkTreeIter iter;
-      gtk_list_store_append(GTK_LIST_STORE(EntityBreakdownWalker), &iter);
-      gtk_list_store_set(GTK_LIST_STORE(EntityBreakdownWalker), &iter, 0, (*i).first.c_str(), 1, tmp, -1);
-    }
-  }
-
-  g_object_unref(G_OBJECT(EntityBreakdownWalker));
-
-  char tmp[16];
-  sprintf (tmp, "%u", Unsigned(g_brushCount.get()));
-  gtk_entry_set_text (GTK_ENTRY (brushes_entry), tmp);
-  sprintf (tmp, "%u", Unsigned(g_entityCount.get()));
-  gtk_entry_set_text (GTK_ENTRY (entities_entry), tmp);
-
-  modal_dialog_show(window, dialog);
-
-  // save before exit
-  window_get_position(window, g_posMapInfoWnd);
-
-  gtk_widget_destroy(GTK_WIDGET(window));
-}
-
-
-
-class ScopeTimer
-{
-  Timer m_timer;
-  const char* m_message;
-public:
-  ScopeTimer(const char* message)
-    : m_message(message)
-  {
-    m_timer.start();
-  }
-  ~ScopeTimer()
-  {
-    double elapsed_time = m_timer.elapsed_msec() / 1000.f;
-    globalOutputStream() << m_message << " timer: " << FloatFormat(elapsed_time, 5, 2) << " second(s) elapsed\n";
-  }
-};
-
 /*
-================
-Map_LoadFile
-================
-*/
-
-void Map_LoadFile (const char *filename)
-{
-  globalOutputStream() << "Loading map from " << filename << "\n";
-  ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
-
-  g_map.m_name = filename;
-  Map_UpdateTitle(g_map);
-
-  {
-    ScopeTimer timer("map load");
-
-    g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
-    g_map.m_resource->attach(g_map);
-
-    Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
-  }
-
-  globalOutputStream() << "--- LoadMapFile ---\n";
-  globalOutputStream() << g_map.m_name.c_str() << "\n";
-  
-  globalOutputStream() << makeLeftJustified(Unsigned(g_brushCount.get()), 5) << " primitive\n";
-  globalOutputStream() << makeLeftJustified(Unsigned(g_entityCount.get()), 5) << " entities\n";
-  
-  //
-  // move the view to a start position
-  //
-  Map_StartPosition();
-
-  g_currentMap = &g_map;
-}
-
-class Excluder
-{
-public:
-  virtual bool excluded(scene::Node& node) const = 0;
-};
-
-class ExcludeWalker : public scene::Traversable::Walker
-{
-  const scene::Traversable::Walker& m_walker;
-  const Excluder* m_exclude;
-  mutable bool m_skip;
-public:
-  ExcludeWalker(const scene::Traversable::Walker& walker, const Excluder& exclude)
-    : m_walker(walker), m_exclude(&exclude), m_skip(false)
-  {
-  }
-  bool pre(scene::Node& node) const
-  {
-    if(m_exclude->excluded(node) || node.isRoot())
-    {
-      m_skip = true;
-      return false;
-    }
-    else
-    {
-      m_walker.pre(node);
-    }
-    return true;
-  }
-  void post(scene::Node& node) const
-  {
-    if(m_skip)
-    {
-      m_skip = false;
-    }
-    else
-    {
-      m_walker.post(node);
-    }
-  }
-};
-
-class AnyInstanceSelected : public scene::Instantiable::Visitor
-{
-  bool& m_selected;
-public:
-  AnyInstanceSelected(bool& selected) : m_selected(selected)
-  {
-    m_selected = false;
-  }
-  void visit(scene::Instance& instance) const
-  {
-    Selectable* selectable = Instance_getSelectable(instance);
-    if(selectable != 0
-      && selectable->isSelected())
-    {
-      m_selected = true;
-    }
-  }
-};
-
-bool Node_instanceSelected(scene::Node& node)
-{
-  scene::Instantiable* instantiable = Node_getInstantiable(node);
-  ASSERT_NOTNULL(instantiable);
-  bool selected;
-  instantiable->forEachInstance(AnyInstanceSelected(selected));
-  return selected;
+   ================
+   Map_Free
+   free all map elements, reinitialize the structures that depend on them
+   ================
+ */
+void Map_Free( void ){
+       g_bRestoreBetween = false;
+       if ( selected_brushes.next &&
+                ( selected_brushes.next != &selected_brushes ) ) {
+               if ( gtk_MessageBox( g_pParentWnd->m_pWidget, "Copy selection?", " ", MB_YESNO ) == IDYES ) {
+                       Map_SaveBetween();
+               }
+       }
+
+       QERApp_ActiveShaders_SetInUse( false );
+       Pointfile_Clear();
+       g_qeglobals.d_num_entities = 0;
+
+       if ( !active_brushes.next ) {
+               // first map
+               active_brushes.prev = active_brushes.next = &active_brushes;
+               selected_brushes.prev = selected_brushes.next = &selected_brushes;
+               filtered_brushes.prev = filtered_brushes.next = &filtered_brushes;
+               entities.prev = entities.next = &entities;
+       }
+       else
+       {
+               // free selected faces array
+               g_ptrSelectedFaces.RemoveAll();
+               g_ptrSelectedFaceBrushes.RemoveAll();
+               while ( active_brushes.next != &active_brushes )
+                       Brush_Free( active_brushes.next );
+               while ( selected_brushes.next != &selected_brushes )
+                       Brush_Free( selected_brushes.next );
+               while ( filtered_brushes.next != &filtered_brushes )
+                       Brush_Free( filtered_brushes.next );
+               while ( entities.next != &entities )
+                       Entity_Free( entities.next );
+       }
+
+       if ( world_entity ) {
+               Entity_Free( world_entity );
+       }
+       world_entity = NULL;
+}
+
+entity_t *AngledEntity(){
+       entity_t *ent = Map_FindClass( "info_player_start" );
+       if ( !ent ) {
+               ent = Map_FindClass( "info_player_deathmatch" );
+       }
+       if ( !ent ) {
+               ent = Map_FindClass( "info_player_deathmatch" );
+       }
+       if ( !ent ) {
+               ent = Map_FindClass( "team_CTF_redplayer" );
+       }
+       if ( !ent ) {
+               ent = Map_FindClass( "team_CTF_blueplayer" );
+       }
+       if ( !ent ) {
+               ent = Map_FindClass( "team_CTF_redspawn" );
+       }
+       if ( !ent ) {
+               ent = Map_FindClass( "team_CTF_bluespawn" );
+       }
+       return ent;
 }
 
-class SelectedDescendantWalker : public scene::Traversable::Walker
-{
-  bool& m_selected;
-public:
-  SelectedDescendantWalker(bool& selected) : m_selected(selected)
-  {
-    m_selected = false;
-  }
-
-  bool pre(scene::Node& node) const
-  {
-    if(node.isRoot())
-    {
-      return false;
-    }
-
-    if(Node_instanceSelected(node))
-    {
-      m_selected = true;
-    }
-
-    return true;
-  }
-};
-
-bool Node_selectedDescendant(scene::Node& node)
-{
-  bool selected;
-  Node_traverseSubgraph(node, SelectedDescendantWalker(selected));
-  return selected;
-}
+//
+// move the view to a start position
+//
+void Map_StartPosition(){
+       entity_t *ent = AngledEntity();
+
+       g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0;
+       if ( ent ) {
+               GetVectorForKey( ent, "origin", g_pParentWnd->GetCamWnd()->Camera()->origin );
+               GetVectorForKey( ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin() );
+               g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = FloatForKey( ent, "angle" );
+       }
+       else
+       {
+               g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0;
+               VectorCopy( vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin );
+               VectorCopy( vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin() );
+       }
+}
+
+void Map_FreeEntities( CPtrArray *ents ){
+       int i, j, num_ents, num_brushes;
+       entity_t* e;
+       CPtrArray* brushes;
+
+       num_ents = ents->GetSize();
+       for ( i = 0; i < num_ents; i++ )
+       {
+               e = (entity_t*)ents->GetAt( i );
+               brushes = (CPtrArray*)e->pData;
+               num_brushes = brushes->GetSize();
+               for ( j = 0; j < num_brushes; j++ )
+                       Brush_Free( (brush_t*)brushes->GetAt( j ) );
+               brushes->RemoveAll();
+               delete (CPtrArray*)e->pData;
+               e->pData = NULL;
+               Entity_Free( e );
+       }
+       ents->RemoveAll();
+}
+
+/*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */
+void Map_ImportEntities( CPtrArray *ents, bool bAddSelected = false ){
+       int num_ents, num_brushes;
+       CPtrArray *brushes;
+       vec3_t mins, maxs;
+       entity_t *e;
+       brush_t *b;
+       face_t *f;
+       int i,j;
+
+       GPtrArray *new_ents = g_ptr_array_new();
+
+       g_qeglobals.bPrimitBrushes = false;
+
+       brush_t *pBrushList = ( bAddSelected ) ? &selected_brushes : &active_brushes;
+
+       bool bDoneBPCheck = false;
+       g_qeglobals.bNeedConvert = false;
+       // HACK: find out if this map file was a BP one
+       // check the first brush in the file that is NOT a patch
+       // this will not be necessary when we allow both formats in the same file
+       num_ents = ents->GetSize();
+       for ( i = 0; !bDoneBPCheck && i < num_ents; i++ )
+       {
+               e = (entity_t*)ents->GetAt( i );
+               brushes = (CPtrArray*)e->pData;
+               num_brushes = brushes->GetSize();
+               for ( j = 0; !bDoneBPCheck && j < num_brushes; j++ )
+               {
+                       /*!todo Allow mixing texdef formats per-face. */
+                       b = (brush_t *)brushes->GetAt( j );
+                       if ( b->patchBrush ) {
+                               continue;
+                       }
+                       bDoneBPCheck = true;
+                       int BP_param = -1;
+                       if ( b->bBrushDef && !g_qeglobals.m_bBrushPrimitMode ) {
+                               BP_param = 0;
+                       }
+                       else if ( !b->bBrushDef && g_qeglobals.m_bBrushPrimitMode ) {
+                               BP_param = 1;
+                       }
+
+                       if ( BP_param != -1 ) {
+                               switch ( BP_MessageBox( BP_param ) )
+                               {
+                               case 0:
+                                       Map_FreeEntities( ents );
+                                       return;
+                               case 1:
+                                       g_qeglobals.bNeedConvert = true;
+                                       break;
+                               case 2:
+                                       g_qeglobals.bNeedConvert = false;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       // process the entities into the world geometry
+       num_ents = ents->GetSize();
+       for ( i = 0; i < num_ents; i++ )
+       {
+               num_brushes = 0;
+               e = (entity_t*)ents->GetAt( i );
+               brushes = (CPtrArray*)e->pData;
+
+               num_brushes = brushes->GetSize();
+               // link brushes into entity
+               for ( j = 0; j < num_brushes; j++ )
+               {
+                       Entity_LinkBrush( e, (brush_t *)brushes->GetAt( j ) );
+                       g_qeglobals.d_parsed_brushes++;
+               }
+               brushes->RemoveAll();
+               delete brushes;
+               e->pData = NULL;
+
+               // set entity origin
+               GetVectorForKey( e, "origin", e->origin );
+               // set entity eclass
+               /*!\todo Make SetKeyValue check for "classname" change and assign appropriate eclass */
+               e->eclass = Eclass_ForName( ValueForKey( e, "classname" ),
+                                                                       ( e->brushes.onext != &e->brushes ) );
+
+               // go through all parsed brushes and build stuff
+               for ( b = e->brushes.onext; b != &e->brushes; b = b->onext )
+               {
+                       for ( f = b->brush_faces; f != NULL; f = f->next )
+                       {
+                               f->pShader = QERApp_Shader_ForName( f->texdef.GetName() );
+                               f->d_texture = f->pShader->getTexture();
+                       }
+
+                       // when brushes are in final state, build the planes and windings
+                       // NOTE: also converts BP brushes if g_qeglobals.bNeedConvert is true
+                       Brush_Build( b );
+               }
+
+//#define TERRAIN_HACK
+#undef TERRAIN_HACK
+
+#ifdef TERRAIN_HACK
+               if ( ( strcmp( ValueForKey( e, "terrain" ),"1" ) == 0 && strcmp( e->eclass->name,"func_group" ) == 0 ) ) {
+
+                       // two aux pointers to the shaders used in the terrain entity
+                       // we don't keep refcount on them since they are only temporary
+                       // this avoids doing expensive lookups by name for all faces
+                       IShader *pTerrainShader, *pCaulk;
+
+                       pTerrainShader = NULL;
+                       pCaulk = QERApp_Shader_ForName( SHADER_CAULK );
+
+                       for ( b = e->brushes.onext; b != &e->brushes; b = b->onext )
+                       {
+                               if ( pTerrainShader == NULL ) {
+                                       for ( f = b->brush_faces; f != NULL; f = f->next )
+                                               if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) {
+                                                       pTerrainShader = f->pShader;
+                                               }
+                               }
+
+                               if ( pTerrainShader ) {
+                                       for ( f = b->brush_faces; f != NULL; f = f->next )
+                                       {
+                                               if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) { // not caulk
+                                                       Face_SetShader( f, pTerrainShader->getName() );
+                                               }
+                                               else{
+                                                       Face_SetShader( f, pCaulk->getName() );
+                                               }
+                                       }
+                               }
+                               else{
+                                       Sys_Printf( "WARNING: no terrain shader found for brush\n" );
+                               }
+                       }
+               }
+#endif
 
-class SelectionExcluder : public Excluder
-{
-public:
-  bool excluded(scene::Node& node) const
-  {
-    return !Node_selectedDescendant(node);
-  }
-};
-
-class IncludeSelectedWalker : public scene::Traversable::Walker
-{
-  const scene::Traversable::Walker& m_walker;
-  mutable std::size_t m_selected;
-  mutable bool m_skip;
-
-  bool selectedParent() const
-  {
-    return m_selected != 0;
-  }
-public:
-  IncludeSelectedWalker(const scene::Traversable::Walker& walker)
-    : m_walker(walker), m_selected(0), m_skip(false)
-  {
-  }
-  bool pre(scene::Node& node) const
-  {
-    // include node if:
-    // node is not a 'root' AND ( node is selected OR any child of node is selected OR any parent of node is selected )
-    if(!node.isRoot() && (Node_selectedDescendant(node) || selectedParent()))
-    {
-      if(Node_instanceSelected(node))
-      {
-        ++m_selected;
-      }
-      m_walker.pre(node);
-      return true;
-    }
-    else
-    {
-      m_skip = true;
-      return false;
-    }
-  }
-  void post(scene::Node& node) const
-  {
-    if(m_skip)
-    {
-      m_skip = false;
-    }
-    else
-    {
-      if(Node_instanceSelected(node))
-      {
-        --m_selected;
-      }
-      m_walker.post(node);
-    }
-  }
-};
-
-void Map_Traverse_Selected(scene::Node& root, const scene::Traversable::Walker& walker)
-{
-  scene::Traversable* traversable = Node_getTraversable(root);
-  if(traversable != 0)
-  {
-#if 0
-    traversable->traverse(ExcludeWalker(walker, SelectionExcluder()));
-#else
-    traversable->traverse(IncludeSelectedWalker(walker));
+#define PATCH_HACK
+#ifdef PATCH_HACK
+               for ( b = e->brushes.onext; b != &e->brushes; b = b->onext )
+               {
+                       // patch hack, to be removed when dependency on brush_faces is removed
+                       if ( b->patchBrush ) {
+                               Patch_CalcBounds( b->pPatch, mins, maxs );
+                               for ( int i = 0; i < 3; i++ )
+                               {
+                                       if ( (int)mins[i] == (int)maxs[i] ) {
+                                               mins[i] -= 4;
+                                               maxs[i] += 4;
+                                       }
+                               }
+                               Brush_Resize( b, mins, maxs );
+                               Brush_Build( b );
+                       }
+               }
 #endif
-  }
+               // add brush for fixedsize entity
+               if ( e->eclass->fixedsize ) {
+                       vec3_t mins, maxs;
+                       VectorAdd( e->eclass->mins, e->origin, mins );
+                       VectorAdd( e->eclass->maxs, e->origin, maxs );
+                       b = Brush_Create( mins, maxs, &e->eclass->texdef );
+                       Entity_LinkBrush( e, b );
+                       Brush_Build( b );
+               }
+
+               for ( b = e->brushes.onext; b != &e->brushes; b = b->onext )
+                       Brush_AddToList( b, pBrushList );
+
+               if ( strcmp( e->eclass->name, "worldspawn" ) == 0 ) {
+                       if ( world_entity ) {
+                               while ( e->brushes.onext != &e->brushes )
+                               {
+                                       b = e->brushes.onext;
+                                       Entity_UnlinkBrush( b );
+                                       Entity_LinkBrush( world_entity, b );
+                               }
+                               Entity_Free( e );
+                       }
+                       else
+                       {
+                               world_entity = e;
+                       }
+               }
+               else if ( strcmp( e->eclass->name, "group_info" ) == 0 ) {
+                       // it's a group thing!
+                       Group_Add( e );
+                       Entity_Free( e );
+               }
+               else
+               {
+                       // fix target/targetname collisions
+                       if ( ( g_PrefsDlg.m_bDoTargetFix ) && ( strcmp( ValueForKey( e, "target" ), "" ) != 0 ) ) {
+                               GPtrArray *t_ents = g_ptr_array_new();
+                               entity_t *e_target;
+                               const char *target = ValueForKey( e, "target" );
+                               qboolean bCollision = FALSE;
+
+                               // check the current map entities for an actual collision
+                               for ( e_target = entities.next; e_target != &entities; e_target = e_target->next )
+                               {
+                                       if ( !strcmp( target, ValueForKey( e_target, "target" ) ) ) {
+                                               bCollision = TRUE;
+                                               // make sure the collision is not between two imported entities
+                                               for ( j = 0; j < (int)new_ents->len; j++ )
+                                               {
+                                                       if ( e_target == g_ptr_array_index( new_ents, j ) ) {
+                                                               bCollision = FALSE;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // find the matching targeted entity(s)
+                               if ( bCollision ) {
+                                       for ( j = num_ents - 1; j > 0; j-- )
+                                       {
+                                               e_target = (entity_t*)ents->GetAt( j );
+                                               if ( e_target != NULL && e_target != e ) {
+                                                       const char *targetname = ValueForKey( e_target, "targetname" );
+                                                       if ( ( targetname != NULL ) && ( strcmp( target, targetname ) == 0 ) ) {
+                                                               g_ptr_array_add( t_ents, (gpointer)e_target );
+                                                       }
+                                               }
+                                       }
+                                       if ( t_ents->len > 0 ) {
+                                               // link the first to get a unique target/targetname
+                                               Entity_Connect( e, (entity_t*)g_ptr_array_index( t_ents,0 ) );
+                                               // set the targetname of the rest of them manually
+                                               for ( j = 1; j < (int)t_ents->len; j++ )
+                                                       SetKeyValue( (entity_t*)g_ptr_array_index( t_ents, j ), "targetname", ValueForKey( e, "target" ) );
+                                       }
+                                       g_ptr_array_free( t_ents, FALSE );
+                               }
+                       }
+
+                       // add the entity to the end of the entity list
+                       Entity_AddToList( e, &entities );
+                       g_qeglobals.d_num_entities++;
+
+                       // keep a list of ents added to avoid testing collisions against them
+                       g_ptr_array_add( new_ents, (gpointer)e );
+               }
+       }
+       g_ptr_array_free( new_ents, FALSE );
+
+       ents->RemoveAll();
+
+       g_qeglobals.bNeedConvert = false;
+}
+
+void Map_Import( IDataStream *in, const char *type, bool bAddSelected ){
+       CPtrArray ents;
+
+       g_pParentWnd->GetSynapseClient().ImportMap( in, &ents, type );
+       Map_ImportEntities( &ents, bAddSelected );
 }
 
-void Map_ExportSelected(TextOutputStream& out, const MapFormat& format)
-{
-  format.writeGraph(GlobalSceneGraph().root(), Map_Traverse_Selected, out);
-}
+/*
+   ================
+   Map_LoadFile
+   ================
+ */
+void Map_LoadFile( const char *filename ){
+       clock_t start, finish;
+       double elapsed_time;
+       start = clock();
+
+       Sys_BeginWait();
+       Select_Deselect();
+       /*!
+          \todo FIXME TTimo why is this commented out?
+          stability issues maybe? or duplicate feature?
+          forcing to show the console during map load was a good thing IMO
+        */
+       //SetInspectorMode(W_CONSOLE);
+       Sys_Printf( "Loading map from %s\n", filename );
+
+       Map_Free();
+       //++timo FIXME: maybe even easier to have Group_Init called from Map_Free?
+       Group_Init();
+       g_qeglobals.d_num_entities = 0;
+       g_qeglobals.d_parsed_brushes = 0;
+
+
+       // cancel the map loading process
+       // used when conversion between standard map format and BP format is required and the user cancels the process
+       g_bCancel_Map_LoadFile = false;
+
+       strcpy( currentmap, filename );
+
+       g_bScreenUpdates = false; // leo: avoid redraws while loading the map (see fenris:1952)
+
+       // prepare to let the map module do the parsing
+       FileStream file;
+       const char* type = strrchr( filename,'.' );
+       if ( type != NULL ) {
+               type++;
+       }
+       // NOTE TTimo opening has binary doesn't make a lot of sense
+       // but opening as text confuses the scriptlib parser
+       // this may be a problem if we "rb" and use the XML parser, might have an incompatibility
+       if ( file.Open( filename, "rb" ) ) {
+               Map_Import( &file, type );
+       }
+       else{
+               Sys_FPrintf( SYS_ERR, "ERROR: failed to open %s for read\n", filename );
+       }
+       file.Close();
+
+       g_bScreenUpdates = true;
+
+       if ( g_bCancel_Map_LoadFile ) {
+               Sys_Printf( "Map_LoadFile canceled\n" );
+               Map_New();
+               Sys_EndWait();
+               return;
+       }
+
+       if ( !world_entity ) {
+               Sys_Printf( "No worldspawn in map.\n" );
+               Map_New();
+               Sys_EndWait();
+               return;
+       }
+       finish = clock();
+       elapsed_time = (double)( finish - start ) / CLOCKS_PER_SEC;
+
+       Sys_Printf( "--- LoadMapFile ---\n" );
+       Sys_Printf( "%s\n", filename );
+
+       Sys_Printf( "%5i brushes\n",  g_qeglobals.d_parsed_brushes );
+       Sys_Printf( "%5i entities\n", g_qeglobals.d_num_entities );
+       Sys_Printf( "%5.2f second(s) load time\n", elapsed_time );
+
+       Sys_EndWait();
+
+       Map_RestoreBetween();
+
+       //
+       // move the view to a start position
+       //
+       Map_StartPosition();
 
-void Map_Traverse(scene::Node& root, const scene::Traversable::Walker& walker)
-{
-  scene::Traversable* traversable = Node_getTraversable(root);
-  if(traversable != 0)
-  {
-    traversable->traverse(walker);
-  }
-}
+       Map_RegionOff();
 
-class RegionExcluder : public Excluder
-{
-public:
-  bool excluded(scene::Node& node) const
-  {
-    return node.excluded();
-  }
-};
-
-void Map_Traverse_Region(scene::Node& root, const scene::Traversable::Walker& walker)
-{
-  scene::Traversable* traversable = Node_getTraversable(root);
-  if(traversable != 0)
-  {
-    traversable->traverse(ExcludeWalker(walker, RegionExcluder()));
-  }
+       modified = false;
+       Sys_SetTitle( filename );
+
+       Texture_ShowInuse();
+       QERApp_SortActiveShaders();
+
+       Sys_UpdateWindows( W_ALL );
+}
+
+/*!
+   ===========
+   Supporting functions for Map_SaveFile, builds a CPtrArray with the filtered / non filtered brushes
+   ===========
+ */
+void CleanFilter( entity_t *ent ){
+       if ( ent->pData ) {
+               delete static_cast<CPtrArray*>( ent->pData );
+               ent->pData = NULL;
+       }
+}
+
+/*!
+   filters out the region brushes if necessary
+   returns true if this entity as a whole is out of the region
+   (if all brushes are filtered out, then the entity will be completely dropped .. except if it's worldspawn of course)
+ */
+bool FilterChildren( entity_t *ent, bool bRegionOnly = false, bool bSelectedOnly = false ){
+       if ( ent->brushes.onext == &ent->brushes ) {
+               return false;
+       }
+       // entity without a brush, ignore it... this can be caused by Undo
+
+       // filter fixedsize ents by their eclass bounding box
+       // don't add their brushes
+       if ( ent->eclass->fixedsize ) {
+               if ( bSelectedOnly && !IsBrushSelected( ent->brushes.onext ) ) {
+                       return false;
+               }
+
+               if ( bRegionOnly && region_active ) {
+                       for ( int i = 0 ; i < 3 ; i++ )
+                       {
+                               if ( ( ent->origin[i] + ent->eclass->mins[i] ) > region_maxs[i] ) {
+                                       return false;
+                               }
+                               if ( ( ent->origin[i] + ent->eclass->maxs[i] ) < region_mins[i] ) {
+                                       return false;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               for ( brush_t *b = ent->brushes.onext ; b != &ent->brushes ; b = b->onext )
+               {
+                       // set flag to use brushprimit_texdef
+                       if ( g_qeglobals.m_bBrushPrimitMode ) {
+                               b->bBrushDef = true;
+                       }
+                       else{
+                               b->bBrushDef = false;
+                       }
+
+                       // add brush, unless it's excluded by region
+                       if ( !( bRegionOnly && Map_IsBrushFiltered( b ) ) &&
+                                !( bSelectedOnly && !IsBrushSelected( b ) ) ) {
+                               ( (CPtrArray*)ent->pData )->Add( b );
+                       }
+               }
+
+               if ( ( (CPtrArray*)ent->pData )->GetSize() <= 0 ) {
+                       return false;
+               }
+       }
+       return true;
+}
+
+entity_t *region_startpoint = NULL;
+void Map_ExportEntities( CPtrArray* ents, bool bRegionOnly = false, bool bSelectedOnly = false ){
+       int i;
+       entity_t *e;
+
+       /*!
+          \todo the entity_t needs to be reworked and asbtracted some more
+
+          keeping the entity_t as the struct providing access to a list of map objects, a list of epairs and various other info?
+          but separating some more the data that belongs to the entity_t and the 'sons' data
+          on a side note, I don't think that doing that with linked list would be a good thing
+
+          for now, we use the blind void* in entity_t casted to a CPtrArray of brush_t* to hand out a list of the brushes for map write
+          the next step is very likely to be a change of the brush_t* to a more abstract object?
+        */
+
+       FilterChildren( world_entity, bRegionOnly, bSelectedOnly );
+       ents->Add( world_entity );
+
+       for ( e = entities.next ; e != &entities ; e = e->next )
+       {
+               // not sure this still happens, probably safe to leave it in
+               if ( ( !strcmp( ValueForKey( e, "classname" ), "worldspawn" ) ) && ( e != world_entity ) ) {
+                       Sys_FPrintf( SYS_ERR, "Dropping parasite worldspawn entity\n" );
+                       continue;
+               }
+
+               // entities which brushes are completely filtered out by regioning are not printed to the map
+               if ( FilterChildren( e, bRegionOnly, bSelectedOnly ) ) {
+                       ents->Add( e );
+               }
+       }
+
+       if ( bRegionOnly && region_active ) {
+               for ( i = 0; i < 6; i++ )
+                       ( (CPtrArray*)world_entity->pData )->Add( region_sides[i] );
+
+               ents->Add( region_startpoint );
+       }
+}
+
+void Map_Export( IDataStream *out, const char *type, bool bRegionOnly, bool bSelectedOnly ){
+       entity_t  *e;
+
+       CPtrArray ents;
+
+       if ( bRegionOnly && region_active ) {
+               AddRegionBrushes();
+       }
+
+       // create the filters
+       world_entity->pData = new CPtrArray();
+       for ( e = entities.next; e != &entities; e = e->next )
+               e->pData = new CPtrArray();
+
+       Map_ExportEntities( &ents, bRegionOnly, bSelectedOnly );
+
+       g_pParentWnd->GetSynapseClient().ExportMap( &ents, out, type );
+
+       // cleanup the filters
+       CleanFilter( world_entity );
+       for ( e = entities.next ; e != &entities ; e = e->next )
+               CleanFilter( e );
+
+       if ( bRegionOnly && region_active ) {
+               RemoveRegionBrushes();
+       }
+}
+
+const char* filename_get_extension( const char* filename ){
+       const char* type = strrchr( filename,'.' );
+       if ( type != NULL ) {
+               return ++type;
+       }
+       return "";
 }
 
-bool Map_SaveRegion(const char *filename)
-{
-  AddRegionBrushes();
+/*
+   ===========
+   Map_SaveFile
+   \todo FIXME remove the use_region, this is broken .. work with a global flag to set region mode or not
+   ===========
+ */
+void Map_SaveFile( const char *filename, qboolean use_region ){
+       clock_t start, finish;
+       double elapsed_time;
+       start = clock();
+       Sys_Printf( "Saving map to %s\n",filename );
 
-  bool success = MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Region, filename); 
+       Pointfile_Clear();
 
-  RemoveRegionBrushes();
+       if ( !use_region ) {
+               char backup[1024];
 
-  return success;
-}
+               // rename current to .bak
+               strcpy( backup, filename );
+               StripExtension( backup );
+               strcat( backup, ".bak" );
+               unlink( backup );
+               rename( filename, backup );
+       }
 
+       Sys_Printf( "Map_SaveFile: %s\n", filename );
 
-void Map_RenameAbsolute(const char* absolute)
-{
-  Resource* resource = GlobalReferenceCache().capture(absolute);
-  NodeSmartReference clone(NewMapRoot(path_make_relative(absolute, GlobalFileSystem().findRoot(absolute))));
-  resource->setNode(clone.get_pointer());
+       // build the out data stream
+       FileStream file;
+       if ( !file.Open( filename,"w" ) ) {
+               Sys_FPrintf( SYS_ERR, "ERROR: couldn't open %s for write\n", filename );
+               return;
+       }
 
-  {
-    //ScopeTimer timer("clone subgraph");
-    Node_getTraversable(GlobalSceneGraph().root())->traverse(CloneAll(clone));
-  }
+       // extract filetype
+       Map_Export( &file, filename_get_extension( filename ), use_region );
 
-  g_map.m_resource->detach(g_map);
-  GlobalReferenceCache().release(g_map.m_name.c_str());
+       file.Close();
 
-  g_map.m_resource = resource;
+       finish = clock();
+       elapsed_time = (double)( finish - start ) / CLOCKS_PER_SEC;
 
-  g_map.m_name = absolute;
-  Map_UpdateTitle(g_map);
+       Sys_Printf( "Saved in %-.2f second(s).\n",elapsed_time );
+       modified = false;
 
-  g_map.m_resource->attach(g_map);
-}
+       if ( !strstr( filename, "autosave" ) ) {
+               Sys_SetTitle( filename );
+       }
 
-void Map_Rename(const char* filename)
-{
-  if(!string_equal(g_map.m_name.c_str(), filename))
-  {
-    ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
-
-    Map_RenameAbsolute(filename);
-    
-    SceneChangeNotify();
-  }
-  else
-  {
-    SaveReferences();
-  }
-}
+       if ( !use_region ) {
+               time_t timer;
 
-bool Map_Save()
-{
-       Pointfile_Clear();
+               time( &timer );
+
+               Sys_Beep();
 
-  ScopeTimer timer("map save");
-  SaveReferences();
-  return true; // assume success..
+               Sys_Status( "Saved.", 0 );
+       }
 }
 
 /*
-===========
-Map_New
+   ===========
+   Map_New
 
-===========
-*/
-void Map_New()
-{
-       //globalOutputStream() << "Map_New\n";
+   ===========
+ */
+void Map_New( void ){
+       Sys_Printf( "Map_New\n" );
+       Map_Free();
 
-       g_map.m_name = "unnamed.map";
-  Map_UpdateTitle(g_map);
+       strcpy( currentmap, "unnamed.map" );
+       Sys_SetTitle( currentmap );
 
-  {
-    g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
-//    ASSERT_MESSAGE(g_map.m_resource->getNode() == 0, "bleh");
-    g_map.m_resource->attach(g_map);
+       world_entity = (entity_s*)qmalloc( sizeof( *world_entity ) );
+       world_entity->brushes.onext =
+               world_entity->brushes.oprev = &world_entity->brushes;
+       SetKeyValue( world_entity, "classname", "worldspawn" );
+       world_entity->eclass = Eclass_ForName( "worldspawn", true );
 
-    SceneChangeNotify();
-  }
+       g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0;
+       g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0;
+       VectorCopy( vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin );
+       g_pParentWnd->GetCamWnd()->Camera()->origin[2] = 48;
+       VectorCopy( vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin() );
 
-  FocusViews(g_vector3_identity, 0);
+       Map_RestoreBetween();
 
-  g_currentMap = &g_map;
-}
+       Group_Init();
 
-extern void ConstructRegionBrushes(scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs);
-
-void ConstructRegionStartpoint(scene::Node* startpoint, const Vector3& region_mins, const Vector3& region_maxs)
-{
-  /*! 
-  \todo we need to make sure that the player start IS inside the region and bail out if it's not
-  the compiler will refuse to compile a map with a player_start somewhere in empty space..
-  for now, let's just print an error
-  */
-  
-  Vector3 vOrig(Camera_getOrigin(*g_pParentWnd->GetCamWnd()));
-
-  for (int i=0 ; i<3 ; i++)
-  {
-    if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
-    {
-      globalErrorStream() << "Camera is NOT in the region, it's likely that the region won't compile correctly\n";
-      break;
-    }
-  }
-  
-  // write the info_playerstart
-  char sTmp[1024];
-  sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]);
-  Node_getEntity(*startpoint)->setKeyValue("origin", sTmp);
-  sprintf(sTmp, "%d", (int)Camera_getAngles(*g_pParentWnd->GetCamWnd())[CAMERA_YAW]);
-  Node_getEntity(*startpoint)->setKeyValue("angle", sTmp);
+       Sys_UpdateWindows( W_ALL );
+       modified = false;
 }
 
 /*
-===========================================================
+   ===========================================================
 
-  REGION
+   REGION
 
-===========================================================
-*/
-bool   region_active;
-Vector3        region_mins(g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord);
-Vector3        region_maxs(g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord);
+   ===========================================================
+ */
+qboolean region_active;
+vec3_t region_mins = {g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord};
+vec3_t region_maxs = {g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord};
 
-scene::Node* region_sides[6];
-scene::Node* region_startpoint = 0;
+brush_t *region_sides[6];
 
 /*
-===========
-AddRegionBrushes
-a regioned map will have temp walls put up at the region boundary
-\todo TODO TTimo old implementation of region brushes
-  we still add them straight in the worldspawn and take them out after the map is saved
-  with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module
-===========
-*/
-void AddRegionBrushes (void)
-{
-       int             i;
-
-  for(i=0; i<6; i++)
-  {
-    region_sides[i] = &GlobalBrushCreator().createBrush();
-    Node_getTraversable(Map_FindOrInsertWorldspawn(g_map))->insert(*region_sides[i]);
-  }
-
-  region_startpoint = &GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("info_player_start", false));
-
-  ConstructRegionBrushes(region_sides, region_mins, region_maxs);
-  ConstructRegionStartpoint(region_startpoint, region_mins, region_maxs);
-
-  Node_getTraversable(GlobalSceneGraph().root())->insert(*region_startpoint);
+   ===========
+   AddRegionBrushes
+   a regioned map will have temp walls put up at the region boundary
+   \todo TODO TTimo old implementation of region brushes
+   we still add them straight in the worldspawn and take them out after the map is saved
+   with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module
+   ===========
+ */
+void AddRegionBrushes( void ){
+       vec3_t mins, maxs;
+       int i;
+       texdef_t td;
+
+       if ( !region_active ) {
+#ifdef _DEBUG
+               Sys_FPrintf( SYS_WRN, "Unexpected AddRegionBrushes call.\n" );
+#endif
+               return;
+       }
+
+       memset( &td, 0, sizeof( td ) );
+       td.SetName( SHADER_NOT_FOUND );
+
+       // set mins
+       VectorSet( mins, region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 );
+
+       // vary maxs
+       for ( i = 0; i < 3; i++ )
+       {
+               VectorSet( maxs, region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 );
+               maxs[i] = region_mins[i];
+               region_sides[i] = Brush_Create( mins, maxs, &td );
+       }
+
+       // set maxs
+       VectorSet( maxs, region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 );
+
+       // vary mins
+       for ( i = 0; i < 3; i++ )
+       {
+               VectorSet( mins, region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 );
+               mins[i] = region_maxs[i];
+               region_sides[i + 3] = Brush_Create( mins, maxs, &td );
+       }
+
+
+       // this is a safe check, but it should not really happen anymore
+       vec3_t vOrig;
+       VectorSet( vOrig,
+                          (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0],
+                          (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1],
+                          (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2] );
+
+       for ( i = 0 ; i < 3 ; i++ )
+       {
+               if ( vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i] ) {
+                       Sys_FPrintf( SYS_ERR, "Camera is NOT in the region, it's likely that the region won't compile correctly\n" );
+               }
+       }
+
+       // write the info_playerstart
+       region_startpoint = Entity_Alloc();
+       SetKeyValue( region_startpoint, "classname", "info_player_start" );
+       region_startpoint->eclass = Eclass_ForName( "info_player_start", false );
+       char sTmp[1024];
+       sprintf( sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2] );
+       SetKeyValue( region_startpoint, "origin", sTmp );
+       sprintf( sTmp, "%d", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] );
+       SetKeyValue( region_startpoint, "angle", sTmp );
+       // empty array of children
+       region_startpoint->pData = new CPtrArray;
+}
+
+void RemoveRegionBrushes( void ){
+       int i;
+
+       if ( !region_active ) {
+               return;
+       }
+       for ( i = 0 ; i < 6 ; i++ )
+               Brush_Free( region_sides[i] );
+
+       CleanFilter( region_startpoint );
+       Entity_Free( region_startpoint );
+}
+
+qboolean Map_IsBrushFiltered( brush_t *b ){
+       int i;
+
+       for ( i = 0 ; i < 3 ; i++ )
+       {
+               if ( b->mins[i] > region_maxs[i] ) {
+                       return true;
+               }
+               if ( b->maxs[i] < region_mins[i] ) {
+                       return true;
+               }
+       }
+       return false;
 }
 
-void RemoveRegionBrushes (void)
-{
-  for(std::size_t i=0; i<6; i++)
-  {
-    Node_getTraversable(*Map_GetWorldspawn(g_map))->erase(*region_sides[i]);
-  }
-  Node_getTraversable(GlobalSceneGraph().root())->erase(*region_startpoint);
-}
+/*
+   ===========
+   Map_RegionOff
 
-inline void exclude_node(scene::Node& node, bool exclude)
-{
-  exclude
-    ? node.enable(scene::Node::eExcluded)
-    : node.disable(scene::Node::eExcluded);
-}
+   Other filtering options may still be on
+   ===========
+ */
+void Map_RegionOff( void ){
+       brush_t *b, *next;
+       int i;
 
-class ExcludeAllWalker : public scene::Graph::Walker
-{
-  bool m_exclude;
-public:
-  ExcludeAllWalker(bool exclude)
-    : m_exclude(exclude)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    exclude_node(path.top(), m_exclude);
-
-    return true;
-  }
-};
-
-void Scene_Exclude_All(bool exclude)
-{
-  GlobalSceneGraph().traverse(ExcludeAllWalker(exclude));
-}
+       region_active = false;
+       for ( i = 0 ; i < 3 ; i++ )
+       {
+               region_maxs[i] = g_MaxWorldCoord - 64;
+               region_mins[i] = g_MinWorldCoord + 64;
+       }
+
+       for ( b = filtered_brushes.next ; b != &filtered_brushes ; b = next )
+       {
+               next = b->next;
+               if ( Map_IsBrushFiltered( b ) ) {
+                       continue;       // still filtered
+               }
+               Brush_RemoveFromList( b );
+               if ( active_brushes.next == NULL || active_brushes.prev == NULL ) {
+                       active_brushes.next = &active_brushes;
+                       active_brushes.prev = &active_brushes;
+               }
+               Brush_AddToList( b, &active_brushes );
+               b->bFiltered = FilterBrush( b );
+       }
+       Sys_UpdateWindows( W_ALL );
+}
+
+void Map_ApplyRegion( void ){
+       brush_t *b, *next;
 
-bool Instance_isSelected(const scene::Instance& instance)
-{
-  const Selectable* selectable = Instance_getSelectable(instance);
-  return selectable != 0 && selectable->isSelected();
-}
+       region_active = true;
+       for ( b = active_brushes.next ; b != &active_brushes ; b = next )
+       {
+               next = b->next;
+               if ( !Map_IsBrushFiltered( b ) ) {
+                       continue;       // still filtered
+               }
+               Brush_RemoveFromList( b );
+               Brush_AddToList( b, &filtered_brushes );
+       }
 
-class ExcludeSelectedWalker : public scene::Graph::Walker
-{
-  bool m_exclude;
-public:
-  ExcludeSelectedWalker(bool exclude)
-    : m_exclude(exclude)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    exclude_node(path.top(), (instance.isSelected() || instance.childSelected() || instance.parentSelected()) == m_exclude);
-    return true;
-  }
-};
-
-void Scene_Exclude_Selected(bool exclude)
-{
-  GlobalSceneGraph().traverse(ExcludeSelectedWalker(exclude));
+       Sys_UpdateWindows( W_ALL );
 }
 
-class ExcludeRegionedWalker : public scene::Graph::Walker
-{
-  bool m_exclude;
-public:
-  ExcludeRegionedWalker(bool exclude)
-    : m_exclude(exclude)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    exclude_node(
-      path.top(),
-      !(
-        (
-          aabb_intersects_aabb(
-            instance.worldAABB(),
-            aabb_for_minmax(region_mins, region_maxs)
-          ) != 0
-        ) ^ m_exclude
-      )
-    );
-
-    return true;
-  }
-};
-
-void Scene_Exclude_Region(bool exclude)
-{
-  GlobalSceneGraph().traverse(ExcludeRegionedWalker(exclude));
-}
 
 /*
-===========
-Map_RegionOff
-
-Other filtering options may still be on
-===========
-*/
-void Map_RegionOff()
-{
-       region_active = false;
-
-       region_maxs[0] = g_MaxWorldCoord - 64;
-       region_mins[0] = g_MinWorldCoord + 64;
-       region_maxs[1] = g_MaxWorldCoord - 64;
-       region_mins[1] = g_MinWorldCoord + 64;
-       region_maxs[2] = g_MaxWorldCoord - 64;
-       region_mins[2] = g_MinWorldCoord + 64;
-       
-       Scene_Exclude_All(false);
-}
+   ========================
+   Map_RegionSelectedBrushes
+   ========================
+ */
+void Map_RegionSelectedBrushes( void ){
+       Map_RegionOff();
 
-void Map_ApplyRegion (void)
-{
+       if ( selected_brushes.next == &selected_brushes ) { // nothing selected
+               Sys_Printf( "Tried to region with no selection...\n" );
+               return;
+       }
        region_active = true;
+       Select_GetBounds( region_mins, region_maxs );
 
-       Scene_Exclude_Region(false);
-}
+#ifdef _DEBUG
+       if ( filtered_brushes.next != &filtered_brushes ) {
+               Sys_Printf( "WARNING: filtered_brushes list may not be empty in Map_RegionSelectedBrushes\n" );
+       }
+#endif
 
+       if ( active_brushes.next == &active_brushes ) {
+               // just have an empty filtered_brushes list
+               // this happens if you set region after selecting all the brushes in your map (some weird people do that, ask MrE!)
+               filtered_brushes.next = filtered_brushes.prev = &filtered_brushes;
+       }
+       else
+       {
+               // move the entire active_brushes list to filtered_brushes
+               filtered_brushes.next = active_brushes.next;
+               filtered_brushes.prev = active_brushes.prev;
+               filtered_brushes.next->prev = &filtered_brushes;
+               filtered_brushes.prev->next = &filtered_brushes;
+       }
 
-/*
-========================
-Map_RegionSelectedBrushes
-========================
-*/
-void Map_RegionSelectedBrushes (void)
-{
-       Map_RegionOff();
+       // move the entire selected_brushes list to active_brushes
+       active_brushes.next = selected_brushes.next;
+       active_brushes.prev = selected_brushes.prev;
+       active_brushes.next->prev = &active_brushes;
+       active_brushes.prev->next = &active_brushes;
 
-  if(GlobalSelectionSystem().countSelected() != 0
-    && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
-  {
-         region_active = true;
-         Select_GetBounds (region_mins, region_maxs);
+       // deselect patches
+       for ( brush_t *b = active_brushes.next; b != &active_brushes; b = b->next )
+               if ( b->patchBrush ) {
+                       b->pPatch->bSelected = false;
+               }
 
-         Scene_Exclude_Selected(false);
-    
-    GlobalSelectionSystem().setSelectedAll(false);
-  }
+       // clear selected_brushes
+       selected_brushes.next = selected_brushes.prev = &selected_brushes;
+
+       Sys_UpdateWindows( W_ALL );
 }
 
 
 /*
-===========
-Map_RegionXY
-===========
-*/
-void Map_RegionXY(float x_min, float y_min, float x_max, float y_max)
-{
+   ===========
+   Map_RegionXY
+   ===========
+ */
+void Map_RegionXY( void ){
        Map_RegionOff();
 
-       region_mins[0] = x_min;
-  region_maxs[0] = x_max;
-  region_mins[1] = y_min;
-  region_maxs[1] = y_max;
-  region_mins[2] = g_MinWorldCoord + 64;
+       region_mins[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale();
+       region_maxs[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale();
+       region_mins[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale();
+       region_maxs[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale();
+       region_mins[2] = g_MinWorldCoord + 64;
        region_maxs[2] = g_MaxWorldCoord - 64;
-
        Map_ApplyRegion();
 }
 
-void Map_RegionBounds(const AABB& bounds)
-{
-  Map_RegionOff();
-
-  region_mins = vector3_subtracted(bounds.origin, bounds.extents);
-  region_maxs = vector3_added(bounds.origin, bounds.extents);
-
-  deleteSelection();
-
-  Map_ApplyRegion();
-}
-
 /*
-===========
-Map_RegionBrush
-===========
-*/
-void Map_RegionBrush (void)
-{
-  if(GlobalSelectionSystem().countSelected() != 0)
-  {
-    scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
-    Map_RegionBounds(instance.worldAABB());
-  }
-}
-
-//
-//================
-//Map_ImportFile
-//================
-//
-bool Map_ImportFile(const char* filename)
-{
-  ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
-
-  bool success = false;
-  {
-    Resource* resource = GlobalReferenceCache().capture(filename);
-    resource->refresh(); // avoid loading old version if map has changed on disk since last import
-    if(resource->load())
-    {
-      NodeSmartReference clone(NewMapRoot(""));
-
-      {
-        //ScopeTimer timer("clone subgraph");
-        Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
-      }
-
-      Map_gatherNamespaced(clone);
-      Map_mergeClonedNames();
-      MergeMap(clone);
-      success = true;
-    }
-    GlobalReferenceCache().release(filename);
-  }
-
-       SceneChangeNotify();
-
-  return success;
-}
-
-/*
-===========
-Map_SaveFile
-===========
-*/
-bool Map_SaveFile(const char* filename)
-{
-  ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
-  return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse, filename); 
-}
-
-//
-//===========
-//Map_SaveSelected
-//===========
-//
-// Saves selected world brushes and whole entities with partial/full selections
-//
-bool Map_SaveSelected(const char* filename)
-{
-  return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename); 
-}
+   ===========
+   Map_RegionTallBrush
+   ===========
+ */
+void Map_RegionTallBrush( void ){
+       brush_t *b;
 
+       if ( !QE_SingleBrush() ) {
+               return;
+       }
 
-class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
-{
-  scene::Node& m_parent;
-public:
-  ParentSelectedBrushesToEntityWalker(scene::Node& parent) : m_parent(parent)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    if(path.top().get_pointer() != &m_parent
-      && Node_isPrimitive(path.top()))
-    {
-      Selectable* selectable = Instance_getSelectable(instance);
-      if(selectable != 0
-        && selectable->isSelected()
-        && path.size() > 1)
-      {
-        return false;
-      }
-    }
-    return true;
-  }
-  void post(const scene::Path& path, scene::Instance& instance) const
-  {
-    if(path.top().get_pointer() != &m_parent
-      && Node_isPrimitive(path.top()))
-    {
-      Selectable* selectable = Instance_getSelectable(instance);
-      if(selectable != 0
-        && selectable->isSelected()
-        && path.size() > 1)
-      {
-        scene::Node& parent = path.parent();
-        if(&parent != &m_parent)
-        {
-          NodeSmartReference node(path.top().get());
-          Node_getTraversable(parent)->erase(node);
-          Node_getTraversable(m_parent)->insert(node);
-        }
-      }
-    }
-  }
-};
-
-void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent)
-{
-  graph.traverse(ParentSelectedBrushesToEntityWalker(parent));
-}
+       b = selected_brushes.next;
 
-class CountSelectedBrushes : public scene::Graph::Walker
-{
-  std::size_t& m_count;
-  mutable std::size_t m_depth;
-public:
-  CountSelectedBrushes(std::size_t& count) : m_count(count), m_depth(0)
-  {
-    m_count = 0;
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    if(++m_depth != 1 && path.top().get().isRoot())
-    {
-      return false;
-    }
-    Selectable* selectable = Instance_getSelectable(instance);
-    if(selectable != 0
-      && selectable->isSelected()
-      && Node_isPrimitive(path.top()))
-    {
-      ++m_count;
-    }
-    return true;
-  }
-  void post(const scene::Path& path, scene::Instance& instance) const
-  {
-    --m_depth;
-  }
-};
-
-std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
-{
-  std::size_t count;
-  graph.traverse(CountSelectedBrushes(count));
-  return count;
-}
-
-enum ENodeType
-{
-  eNodeUnknown,
-  eNodeMap,
-  eNodeEntity,
-  eNodePrimitive,
-};
-
-const char* nodetype_get_name(ENodeType type)
-{
-  if(type == eNodeMap)
-    return "map";
-  if(type == eNodeEntity)
-    return "entity";
-  if(type == eNodePrimitive)
-    return "primitive";
-  return "unknown";
-}
-
-ENodeType node_get_nodetype(scene::Node& node)
-{
-  if(Node_isEntity(node))
-  {
-    return eNodeEntity;
-  }
-  if(Node_isPrimitive(node))
-  {
-    return eNodePrimitive;
-  }
-  return eNodeUnknown;
-}
-
-bool contains_entity(scene::Node& node)
-{
-  return Node_getTraversable(node) != 0 && !Node_isBrush(node) && !Node_isPatch(node) && !Node_isEntity(node);
-}
-
-bool contains_primitive(scene::Node& node)
-{
-  return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
-}
-
-ENodeType node_get_contains(scene::Node& node)
-{
-  if(contains_entity(node))
-  {
-    return eNodeEntity;
-  }
-  if(contains_primitive(node))
-  {
-    return eNodePrimitive;
-  }
-  return eNodeUnknown;
-}
-
-void Path_parent(const scene::Path& parent, const scene::Path& child)
-{
-  ENodeType contains = node_get_contains(parent.top());
-  ENodeType type = node_get_nodetype(child.top());
-
-  if(contains != eNodeUnknown && contains == type)
-  {
-    NodeSmartReference node(child.top().get());
-    Path_deleteTop(child);
-    Node_getTraversable(parent.top())->insert(node);
-    SceneChangeNotify();
-  }
-  else
-  {
-    globalErrorStream() << "failed - " << nodetype_get_name(type) << " cannot be parented to " << nodetype_get_name(contains) << " container.\n";
-  }
-}
-
-void Scene_parentSelected()
-{
-  UndoableCommand undo("parentSelected");
-
-  if(GlobalSelectionSystem().countSelected() > 1)
-  {
-    class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor
-    {
-      const scene::Path& m_parent;
-    public:
-      ParentSelectedBrushesToEntityWalker(const scene::Path& parent) : m_parent(parent)
-      {
-      }
-      void visit(scene::Instance& instance) const
-      {
-        if(&m_parent != &instance.path())
-        {
-          Path_parent(m_parent, instance.path());
-        }
-      }
-    };
-    
-    ParentSelectedBrushesToEntityWalker visitor(GlobalSelectionSystem().ultimateSelected().path());
-    GlobalSelectionSystem().foreachSelected(visitor);
-  }
-  else
-  {
-    globalOutputStream() << "failed - did not find two selected nodes.\n";
-  }
-}
-
-
-
-void NewMap()
-{
-  if (ConfirmModified("New Map"))
-  {
-    Map_RegionOff();
-         Map_Free();
-    Map_New();
-  }
-}
-
-void maps_directory(StringOutputStream& buffer)
-{
-  ASSERT_MESSAGE(!string_empty(g_qeglobals.m_userGamePath.c_str()), "maps_directory: user-game-path is empty");
-  buffer << g_qeglobals.m_userGamePath.c_str() << "maps/";
-  Q_mkdir(buffer.c_str());
-}
-
-const char* map_open(const char* title)
-{
-       StringOutputStream buf(256);
-  maps_directory(buf);
-  return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, buf.c_str(), MapFormat::Name());
-}
-
-const char* map_save(const char* title)
-{
-       StringOutputStream buf(256);
-  maps_directory(buf);
-  return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, buf.c_str(), MapFormat::Name());
-}
-
-void OpenMap()
-{
-  if (!ConfirmModified("Open Map"))
-    return;
-
-  const char* filename = map_open("Open Map");
-
-  if (filename != 0)
-  {
-    MRU_AddFile(filename);
-    Map_RegionOff();
-    Map_Free();
-    Map_LoadFile(filename);
-  }
-}
-
-void ImportMap()
-{
-  const char* filename = map_open("Import Map");
-
-  if(filename != 0)
-  {
-    UndoableCommand undo("mapImport");
-    Map_ImportFile(filename);
-  }
-}
+       Map_RegionOff();
 
-bool Map_SaveAs()
-{
-  const char* filename = map_save("Save Map");
-  
-  if(filename != 0)
-  {
-    MRU_AddFile(filename);
-    Map_Rename(filename);
-    return Map_Save();
-  }
-  return false;
-}
+       VectorCopy( b->mins, region_mins );
+       VectorCopy( b->maxs, region_maxs );
+       region_mins[2] = g_MinWorldCoord + 64;
+       region_maxs[2] = g_MaxWorldCoord - 64;
 
-void SaveMapAs()
-{
-  Map_SaveAs();
-}
+       Undo_Start( "delete" );
+       Undo_AddBrushList( &selected_brushes );
+       Undo_AddEntity( b->owner );
+       Select_Delete();
+       Undo_EndBrushList( &selected_brushes );
+       Undo_End();
 
-void SaveMap()
-{
-  if(Map_Unnamed(g_map))
-  {
-    SaveMapAs();
-  }
-  else if(Map_Modified(g_map))
-  {
-    Map_Save();
-  }
+       Map_ApplyRegion();
 }
 
-void ExportMap()
-{
-  const char* filename = map_save("Export Selection");
+/*
+   ===========
+   Map_RegionBrush
+   ===========
+ */
+void Map_RegionBrush( void ){
+       brush_t *b;
 
-  if(filename != 0)
-  {
-    Map_SaveSelected(filename);
-  }
-}
+       if ( !QE_SingleBrush() ) {
+               return;
+       }
 
-void SaveRegion()
-{
-  const char* filename = map_save("Export Region");
-  
-  if(filename != 0)
-  {
-    Map_SaveRegion(filename);
-  }
-}
+       b = selected_brushes.next;
 
+       Map_RegionOff();
 
-void RegionOff()
-{
-  Map_RegionOff();
-  SceneChangeNotify();
-}
+       VectorCopy( b->mins, region_mins );
+       VectorCopy( b->maxs, region_maxs );
 
-void RegionXY()
-{
-  Map_RegionXY(
-    g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
-    g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(),
-    g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
-    g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale()
-    );
-  SceneChangeNotify();
-}
+       Undo_Start( "delete" );
+       Undo_AddBrushList( &selected_brushes );
+       Undo_AddEntity( b->owner );
+       Select_Delete();
+       Undo_EndBrushList( &selected_brushes );
+       Undo_End();
 
-void RegionBrush()
-{
-  Map_RegionBrush();
-  SceneChangeNotify();
+       Map_ApplyRegion();
 }
 
-void RegionSelected()
-{
-  Map_RegionSelectedBrushes();
-  SceneChangeNotify();
+GList *find_string( GList *glist, const char *buf ){
+       while ( glist )
+       {
+               if ( strcmp( (char *)glist->data, buf ) == 0 ) {
+                       break; // this name is in our list already
+               }
+               glist = glist->next;
+       }
+       return glist;
 }
 
+void Map_ImportBuffer( char *buf ){
+       Select_Deselect();
 
+       Undo_Start( "import buffer" );
 
+       MemStream stream;
 
+       stream.Write( buf, strlen( buf ) );
+       Map_Import( &stream, "xmap" );
+       stream.Close();
 
-class BrushFindByIndexWalker : public scene::Traversable::Walker
-{
-  mutable std::size_t m_index;
-  scene::Path& m_path;
-public:
-  BrushFindByIndexWalker(std::size_t index, scene::Path& path)
-    : m_index(index), m_path(path)
-  {
-  }
-  bool pre(scene::Node& node) const
-  {
-    if(Node_isPrimitive(node) && m_index-- == 0)
-    {
-      m_path.push(makeReference(node));
-    }
-    return false;
-  }
-};
-
-class EntityFindByIndexWalker : public scene::Traversable::Walker
-{
-  mutable std::size_t m_index;
-  scene::Path& m_path;
-public:
-  EntityFindByIndexWalker(std::size_t index, scene::Path& path)
-    : m_index(index), m_path(path)
-  {
-  }
-  bool pre(scene::Node& node) const
-  {
-    if(Node_isEntity(node) && m_index-- == 0)
-    {
-      m_path.push(makeReference(node));
-    }
-    return false;
-  }
-};
-
-void Scene_FindEntityBrush(std::size_t entity, std::size_t brush, scene::Path& path)
-{
-  path.push(makeReference(GlobalSceneGraph().root()));
-  {
-    Node_getTraversable(path.top())->traverse(EntityFindByIndexWalker(entity, path));
-  }
-  if(path.size() == 2)
-  {
-    scene::Traversable* traversable = Node_getTraversable(path.top());
-    if(traversable != 0)
-    {
-      traversable->traverse(BrushFindByIndexWalker(brush, path));
-    }
-  }
-}
+       Sys_UpdateWindows( W_ALL );
+       Sys_MarkMapModified();
 
-inline bool Node_hasChildren(scene::Node& node)
-{
-  scene::Traversable* traversable = Node_getTraversable(node);
-  return traversable != 0 && !traversable->empty();
+       Undo_End();
 }
 
-void SelectBrush (int entitynum, int brushnum)
-{
-  scene::Path path;
-  Scene_FindEntityBrush(entitynum, brushnum, path);
-  if(path.size() == 3 || (path.size() == 2 && !Node_hasChildren(path.top())))
-  {
-    scene::Instance* instance = GlobalSceneGraph().find(path);
-    ASSERT_MESSAGE(instance != 0, "SelectBrush: path not found in scenegraph");
-    Selectable* selectable = Instance_getSelectable(*instance);
-    ASSERT_MESSAGE(selectable != 0, "SelectBrush: path not selectable");
-    selectable->setSelected(true);
-    g_pParentWnd->GetXYWnd()->PositionView(instance->worldAABB().origin);
-  }
-}
 
+//
+//================
+//Map_ImportFile
+//================
+//
+void Map_ImportFile( const char *filename ){
+       FileStream file;
+       Sys_BeginWait();
 
-class BrushFindIndexWalker : public scene::Graph::Walker
-{
-  mutable const scene::Node* m_node;
-  std::size_t& m_count;
-public:
-  BrushFindIndexWalker(const scene::Node& node, std::size_t& count)
-    : m_node(&node), m_count(count)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    if(Node_isPrimitive(path.top()))
-    {
-      if(m_node == path.top().get_pointer())
-      {
-        m_node = 0;
-      }
-      if(m_node)
-      {
-        ++m_count;
-      }
-    }
-    return true;
-  }
-};
-
-class EntityFindIndexWalker : public scene::Graph::Walker
-{
-  mutable const scene::Node* m_node;
-  std::size_t& m_count;
-public:
-  EntityFindIndexWalker(const scene::Node& node, std::size_t& count)
-    : m_node(&node), m_count(count)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    if(Node_isEntity(path.top()))
-    {
-      if(m_node == path.top().get_pointer())
-      {
-        m_node = 0;
-      }
-      if(m_node)
-      {
-        ++m_count;
-      }
-    }
-    return true;
-  }
-};
-
-static void GetSelectionIndex (int *ent, int *brush)
-{
-  std::size_t count_brush = 0;
-  std::size_t count_entity = 0;
-  if(GlobalSelectionSystem().countSelected() != 0)
-  {
-    const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
-
-    GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
-    GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
-  }
-  *brush = int(count_brush);
-  *ent = int(count_entity);
-}
+       Sys_Printf( "Importing map from %s\n",filename );
 
-void DoFind()
-{
-  ModalDialog dialog;
-  GtkEntry* entity;
-  GtkEntry* brush;
-
-  GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
-
-  GtkAccelGroup* accel = gtk_accel_group_new();
-  gtk_window_add_accel_group(window, accel);
-
-  {
-    GtkVBox* vbox = create_dialog_vbox(4, 4);
-    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
-    {
-      GtkTable* table = create_dialog_table(2, 2, 4, 4);
-      gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
-      {
-        GtkWidget* label = gtk_label_new ("Entity number");
-        gtk_widget_show (label);
-        gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
-                          (GtkAttachOptions) (0),
-                          (GtkAttachOptions) (0), 0, 0);
-      }
-      {
-        GtkWidget* label = gtk_label_new ("Brush number");
-        gtk_widget_show (label);
-        gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
-                          (GtkAttachOptions) (0),
-                          (GtkAttachOptions) (0), 0, 0);
-      }
-      {
-        GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
-        gtk_widget_show(GTK_WIDGET(entry));
-        gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
-                          (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-        gtk_widget_grab_focus(GTK_WIDGET(entry));
-        entity = entry;
-      }
-      {
-        GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
-        gtk_widget_show(GTK_WIDGET(entry));
-        gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
-                          (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-
-        brush = entry;
-      }
-    }
-    {
-      GtkHBox* hbox = create_dialog_hbox(4);
-      gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
-      {
-        GtkButton* button = create_dialog_button("Find", G_CALLBACK(dialog_button_ok), &dialog);
-        gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-        widget_make_default(GTK_WIDGET(button));
-        gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
-      }
-      {
-        GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_cancel), &dialog);
-        gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-        gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
-      }
-    }
-  }
-
-  // Initialize dialog
-  char buf[16];
-  int ent, br;
-
-  GetSelectionIndex (&ent, &br);
-  sprintf (buf, "%i", ent);
-  gtk_entry_set_text(entity, buf);
-  sprintf (buf, "%i", br);
-  gtk_entry_set_text(brush, buf);
-
-  if(modal_dialog_show(window, dialog) == eIDOK)
-  {
-    const char *entstr = gtk_entry_get_text(entity);
-    const char *brushstr = gtk_entry_get_text(brush);
-    SelectBrush (atoi(entstr), atoi(brushstr));
-  }
-
-  gtk_widget_destroy(GTK_WIDGET(window));
-}
+       const char* type = strrchr( filename,'.' );
+       if ( type != NULL ) {
+               type++;
+       }
+       /*!\todo Resolve "r" problem in scriptlib" */
+       if ( file.Open( filename, "rb" ) ) {
+               Map_Import( &file, type, true );
+       }
+       else{
+               Sys_FPrintf( SYS_ERR, "ERROR: couldn't open %s for read\n", filename );
+       }
 
+       file.Close();
 
-class MapEntityClasses : public ModuleObserver
-{
-  std::size_t m_unrealised;
-public:
-  MapEntityClasses() : m_unrealised(1)
-  {
-  }
-  void realise()
-  {
-    if(--m_unrealised == 0)
-    {
-      if(g_map.m_resource != 0)
-      {
-        ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
-             g_map.m_resource->realise();
-      }
-    }
-  }
-  void unrealise()
-  {
-    if(++m_unrealised == 1)
-    {
-      if(g_map.m_resource != 0)
-      {
-        g_map.m_resource->flush();
-             g_map.m_resource->unrealise();
-      }
-    }
-  }
-};
-
-MapEntityClasses g_MapEntityClasses;
-
-
-void Map_constructPreferences(PreferencesPage& page)
-{
-  page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
+       Sys_UpdateWindows( W_ALL );
+       modified = true;
+       Sys_EndWait();
 }
 
-#include "preferencesystem.h"
+//
+//===========
+//Map_SaveSelected
+//===========
+//
+// Saves selected world brushes and whole entities with partial/full selections
+//
+void Map_SaveSelected( const char* filename ){
+       FileStream file;
 
-CopiedString g_strLastMap;
-bool g_bLoadLastMap = false;
+       Sys_Printf( "Saving selection to %s\n",filename );
 
-void Map_Construct()
-{
-  GlobalCommands_insert("RegionOff", FreeCaller<RegionOff>());
-  GlobalCommands_insert("RegionSetXY", FreeCaller<RegionXY>());
-  GlobalCommands_insert("RegionSetBrush", FreeCaller<RegionBrush>());
-  GlobalCommands_insert("RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator('R', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
+       const char* type = strrchr( filename,'.' );
+       if ( type != NULL ) {
+               type++;
+       }
+       if ( file.Open( filename, "w" ) ) {
+               Map_Export( &file, type, false, true );
+       }
+       else{
+               Sys_FPrintf( SYS_ERR, "ERROR: failed to open %s for write\n", filename );
+       }
 
-  GlobalPreferenceSystem().registerPreference("LastMap", CopiedStringImportStringCaller(g_strLastMap), CopiedStringExportStringCaller(g_strLastMap));
-  GlobalPreferenceSystem().registerPreference("LoadLastMap", BoolImportStringCaller(g_bLoadLastMap), BoolExportStringCaller(g_bLoadLastMap));
-  GlobalPreferenceSystem().registerPreference("MapInfoDlg", WindowPositionImportStringCaller(g_posMapInfoWnd), WindowPositionExportStringCaller(g_posMapInfoWnd));
-  
-  PreferencesDialog_addSettingsPreferences(FreeCaller1<PreferencesPage&, Map_constructPreferences>());
+       file.Close();
 
-  GlobalEntityClassManager().attach(g_MapEntityClasses);
 }
 
-void Map_Destroy()
-{
-  GlobalEntityClassManager().detach(g_MapEntityClasses);
+//
+//===========
+//Map_SaveSelected
+//===========
+//
+// Saves selected world brushes and whole entities with partial/full selections
+//
+void Map_SaveSelected( MemStream* pMemFile, MemStream* pPatchFile ){
+       Map_Export( pMemFile, "xmap", false, true );
+
+       /*
+          // write world entity first
+          Entity_WriteSelected(world_entity, pMemFile);
+
+          // then write all other ents
+          count = 1;
+          for (e=entities.next ; e != &entities ; e=next)
+          {
+              MemFile_fprintf(pMemFile, "// entity %i\n", count);
+              count++;
+              Entity_WriteSelected(e, pMemFile);
+              next = e->next;
+          }
+
+          //if (pPatchFile)
+          //  Patch_WriteFile(pPatchFile);
+        */
+}
+
+
+void MemFile_fprintf( MemStream* pMemFile, const char* pText, ... ){
+       char Buffer[4096];
+       va_list args;
+       va_start( args,pText );
+       vsprintf( Buffer, pText, args );
+       pMemFile->Write( Buffer, strlen( Buffer ) );
+}
+
+/*!
+   ==============
+   Region_SpawnPoint
+   push the region spawn point
+   \todo FIXME TTimo this was in the #1 MAP module implementation (in the core)
+   not sure it has any use anymore, should prolly drop it
+   ==============
+ */
+void Region_SpawnPoint( FILE *f ){
+       // write the info_player_start, we use the camera position
+       fprintf( f, "{\n" );
+       fprintf( f, "\"classname\" \"info_player_start\"\n" );
+       fprintf( f, "\"origin\" \"%i %i %i\"\n",
+                        (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0],
+                        (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1],
+                        (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2] );
+       fprintf( f, "\"angle\" \"%i\"\n", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] );
+       fprintf( f, "}\n" );
 }