/*
-Copyright (C) 1999-2006 Id Software, Inc. and contributors.
+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.
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"
+#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"
+#include "mainframe.h"
+#include "gtkmisc.h"
+#include "filters.h"
-class NameObserver
-{
- UniqueNames& m_names;
- CopiedString m_name;
+extern MainFrame* g_pParentWnd;
- 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()));
- }
- }
+int modified; // for quit confirmation (0 = clean, 1 = unsaved,
+ // 2 = autosaved, but not regular saved)
- 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;
-};
+char currentmap[1024];
-class BasicNamespace : public Namespace
+brush_t active_brushes; // brushes currently being displayed
+brush_t selected_brushes; // highlighted
+
+face_t *selected_face;
+brush_t *selected_face_brush;
+
+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" !
+
+void Map_Init()
{
- 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);
- }
+ Map_Free();
+}
- 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;
+bool g_bCancel_Map_LoadFile; // Hydra: moved this here
- UniqueNames uniqueNames(other.m_uniqueNames);
+// TTimo
+// need that in a variable, will have to tweak depending on the game
+int g_MaxWorldCoord = 64*1024;
+int g_MinWorldCoord = -64*1024;
- for(Names::const_iterator i = m_names.begin(); i != m_names.end(); ++i)
- {
- groups[(*i).second.c_str()].push_back((*i).first);
- }
+// 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;
- 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);
+void AddRegionBrushes (void);
+void RemoveRegionBrushes (void);
- char buffer[1024];
- name_write(buffer, uniqueName);
+/*
+=============================================================
- //globalOutputStream() << "renaming " << makeQuoted((*i).first.c_str()) << " to " << makeQuoted(buffer) << "\n";
+ Cross map selection saving
- SetNameCallbacks& setNameCallbacks = (*i).second;
+ this could fuck up if you have only part of a complex entity selected...
+=============================================================
+*/
- for(SetNameCallbacks::const_iterator j = setNameCallbacks.begin(); j != setNameCallbacks.end(); ++j)
- {
- (*j)(buffer);
- }
- }
- }
-};
+brush_t between_brushes;
+entity_t between_entities;
-BasicNamespace g_defaultNamespace;
-BasicNamespace g_cloneNamespace;
+bool g_bRestoreBetween = false;
-class NamespaceAPI
+void Map_SaveBetween (void)
{
- Namespace* m_namespace;
-public:
- typedef Namespace Type;
- STRING_CONSTANT(Name, "*");
-
- NamespaceAPI()
- {
- m_namespace = &g_defaultNamespace;
- }
- Namespace* getTable()
+ if (g_pParentWnd->ActiveXY())
{
- return m_namespace;
+ g_bRestoreBetween = true;
+ g_pParentWnd->ActiveXY()->Copy();
}
-};
-
-typedef SingletonModule<NamespaceAPI> NamespaceModule;
-typedef Static<NamespaceModule> StaticNamespaceModule;
-StaticRegisterModule staticRegisterDefaultNamespace(StaticNamespaceModule::instance());
+ return;
+}
+void Map_RestoreBetween (void)
+{
+ if (g_pParentWnd->ActiveXY() && g_bRestoreBetween)
+ g_pParentWnd->ActiveXY()->Paste();
+}
-std::list<Namespaced*> g_cloned;
+//============================================================================
-inline Namespaced* Node_getNamespaced(scene::Node& node)
+bool CheckForTinyBrush(brush_t* b, int n, float fSize)
{
- return NodeTypeCast<Namespaced>::cast(node);
+ 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 Node_gatherNamespaced(scene::Node& node)
+void Map_BuildBrushData(void)
{
- Namespaced* namespaced = Node_getNamespaced(node);
- if(namespaced != 0)
+ brush_t *b, *next;
+
+ if (active_brushes.next == NULL)
+ return;
+
+ Sys_BeginWait (); // this could take a while
+
+ int n = 0;
+ for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next)
{
- g_cloned.push_back(namespaced);
+ 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();
}
-class GatherNamespaced : public scene::Traversable::Walker
+entity_t *Map_FindClass (const char *cname)
{
-public:
- bool pre(scene::Node& node) const
- {
- Node_gatherNamespaced(node);
- return true;
- }
-};
+ entity_t *ent;
-void Map_gatherNamespaced(scene::Node& root)
+ for (ent = entities.next ; ent != &entities ; ent=ent->next)
+ {
+ if (!strcmp(cname, ValueForKey (ent, "classname")))
+ return ent;
+ }
+ return NULL;
+}
+
+/*
+================
+Map_Free
+free all map elements, reinitialize the structures that depend on them
+================
+*/
+void Map_Free (void)
{
- Node_traverseSubgraph(root, GatherNamespaced());
+ 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;
}
-void Map_mergeClonedNames()
+entity_t *AngledEntity()
{
- for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
+ entity_t *ent = Map_FindClass ("info_player_start");
+ if (!ent)
{
- (*i)->setNamespace(g_cloneNamespace);
+ ent = Map_FindClass ("info_player_deathmatch");
}
- g_cloneNamespace.mergeNames(g_defaultNamespace);
- for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
+ if (!ent)
{
- (*i)->setNamespace(g_defaultNamespace);
+ ent = Map_FindClass ("info_player_deathmatch");
}
-
- g_cloned.clear();
+ 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 WorldNode
+//
+// move the view to a start position
+//
+void Map_StartPosition()
{
- scene::Node* m_node;
-public:
- WorldNode()
- : m_node(0)
- {
- }
- void set(scene::Node* node)
+ entity_t *ent = AngledEntity();
+
+ g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0;
+ if (ent)
{
- if(m_node != 0)
- m_node->DecRef();
- m_node = node;
- if(m_node != 0)
- m_node->IncRef();
+ GetVectorForKey (ent, "origin", g_pParentWnd->GetCamWnd()->Camera()->origin);
+ GetVectorForKey (ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin());
+ g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = FloatForKey (ent, "angle");
}
- scene::Node* get() const
+ else
{
- return m_node;
+ g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0;
+ VectorCopy (vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin);
+ VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin());
}
-};
+}
-class Map;
-void Map_SetValid(Map& map, bool valid);
-void Map_UpdateTitle(const Map& map);
-void Map_SetWorldspawn(Map& map, scene::Node* node);
+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();
+}
-class Map : public ModuleObserver
+/*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */
+void Map_ImportEntities(CPtrArray *ents, bool bAddSelected = false)
{
-public:
- CopiedString m_name;
- Resource* m_resource;
- bool m_valid;
+ int num_ents, num_brushes;
+ CPtrArray *brushes;
+ vec3_t mins, maxs;
+ entity_t *e;
+ brush_t *b;
+ face_t *f;
+ int i,j;
- bool m_modified;
- void (*m_modified_changed)(const Map&);
+ GPtrArray *new_ents = g_ptr_array_new();
- typedef std::vector<Callback> MapValidCallbacks;
- MapValidCallbacks m_mapValidCallbacks;
+ g_qeglobals.bPrimitBrushes = false;
- WorldNode m_world_node; // "classname" "worldspawn" !
+ brush_t *pBrushList = (bAddSelected) ? &selected_brushes : &active_brushes;
- Map() : m_resource(0), m_valid(false), m_modified_changed(Map_UpdateTitle)
+ 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;
+ }
+ }
+ }
}
- void realise()
+ // process the entities into the world geometry
+ num_ents = ents->GetSize();
+ for(i=0; i<num_ents; i++)
{
- if(m_resource != 0)
+ 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)
{
- if(Map_Unnamed(*this))
+ for(f = b->brush_faces; f != NULL; f = f->next)
{
- g_map.m_resource->setNode(NewMapRoot("").get_pointer());
- MapFile* map = Node_getMapFile(*g_map.m_resource->getNode());
- if(map != 0)
- {
- map->save();
- }
+ f->pShader = QERApp_Shader_ForName(f->texdef.GetName());
+ f->d_texture = f->pShader->getTexture();
}
- else
+
+ // 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)
{
- m_resource->load();
+ 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
- GlobalSceneGraph().insert_root(*m_resource->getNode());
+#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);
+ }
- AutoSave_clear();
+ for(b = e->brushes.onext; b!=&e->brushes; b=b->onext)
+ Brush_AddToList(b, pBrushList);
- Map_SetValid(g_map, true);
+ 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;
+ }
}
- }
- void unrealise()
- {
- if(m_resource != 0)
+ else if (strcmp(e->eclass->name, "group_info") == 0)
{
- Map_SetValid(g_map, false);
- Map_SetWorldspawn(g_map, 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);
+ }
+ }
- GlobalUndoSystem().clear();
+ // add the entity to the end of the entity list
+ Entity_AddToList(e, &entities);
+ g_qeglobals.d_num_entities++;
- GlobalSceneGraph().erase_root();
+ // 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);
-Map g_map;
-Map* g_currentMap = 0;
+ ents->RemoveAll();
-void Map_addValidCallback(Map& map, const Callback& callback)
-{
- map.m_mapValidCallbacks.push_back(callback);
+ g_qeglobals.bNeedConvert = false;
}
-bool Map_Valid(const Map& map)
+void Map_Import(IDataStream *in, const char *type, bool bAddSelected)
{
- return map.m_valid;
+ CPtrArray ents;
+
+ g_pParentWnd->GetSynapseClient().ImportMap(in, &ents, type);
+ Map_ImportEntities(&ents, bAddSelected);
}
-void Map_SetValid(Map& map, bool valid)
+/*
+================
+Map_LoadFile
+================
+*/
+void Map_LoadFile (const char *filename)
{
- map.m_valid = valid;
- std::for_each(map.m_mapValidCallbacks.begin(), map.m_mapValidCallbacks.end(), CallbackInvoke());
-}
+ 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 );
-const char* Map_Name(const Map& map)
-{
- return map.m_name.c_str();
-}
+ 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;
-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;
-}
+ // 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;
-const MapFormat& Map_getFormat(const Map& map)
-{
- return MapFormat_forFile(Map_Name(map));
-}
+ strcpy (currentmap, filename);
+ g_bScreenUpdates = false; // leo: avoid redraws while loading the map (see fenris:1952)
-bool Map_Modified(const Map& map)
-{
- return map.m_modified;
-}
+ // 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();
-void Map_SetModified(Map& map, bool modified)
-{
- if(map.m_modified ^ modified)
+ g_bScreenUpdates = true;
+
+ if (g_bCancel_Map_LoadFile)
{
- map.m_modified = modified;
+ Sys_Printf("Map_LoadFile canceled\n");
+ Map_New();
+ Sys_EndWait();
+ return;
+ }
- map.m_modified_changed(map);
+ 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;
-void Map_UpdateTitle(const Map& map)
-{
- Sys_SetTitle(map.m_name.c_str(), Map_Modified(map));
-}
+ 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();
-scene::Node* Map_GetWorldspawn(const Map& map)
-{
- return map.m_world_node.get();
-}
+ Map_RestoreBetween ();
-void Map_SetWorldspawn(Map& map, scene::Node* node)
-{
- map.m_world_node.set(node);
-}
+ //
+ // move the view to a start position
+ //
+ Map_StartPosition();
+ Map_RegionOff ();
-// TTimo
-// need that in a variable, will have to tweak depending on the game
-float g_MaxWorldCoord = 64*1024;
-float g_MinWorldCoord = -64*1024;
+ modified = false;
+ Sys_SetTitle (filename);
-void AddRegionBrushes (void);
-void RemoveRegionBrushes (void);
+ Texture_ShowInuse ();
+ QERApp_SortActiveShaders();
+ Sys_UpdateWindows (W_ALL);
+}
-/*
-================
-Map_Free
-free all map elements, reinitialize the structures that depend on them
-================
+/*!
+===========
+Supporting functions for Map_SaveFile, builds a CPtrArray with the filtered / non filtered brushes
+===========
*/
-void Map_Free()
+void CleanFilter(entity_t *ent)
{
- Pointfile_Clear();
-
- g_map.m_resource->detach(g_map);
- GlobalReferenceCache().release(g_map.m_name.c_str());
- g_map.m_resource = 0;
-
- FlushReferences();
-
- g_currentMap = 0;
+ if (ent->pData)
+ {
+ delete static_cast<CPtrArray*>(ent->pData);
+ ent->pData = NULL;
+ }
}
-class EntityFindByClassname : public scene::Graph::Walker
+/*!
+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)
{
- 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(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(m_entity == 0)
+ if(bSelectedOnly && !IsBrushSelected(ent->brushes.onext))
+ return false;
+
+ if(bRegionOnly && region_active)
{
- Entity* entity = Node_getEntity(path.top());
- if(entity != 0
- && string_equal(m_name, entity->getKeyValue("classname")))
- {
- m_entity = entity;
- }
+ 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;
+ }
}
- return true;
}
-};
-
-Entity* Scene_FindEntityByClass(const char* name)
-{
- Entity* entity;
- GlobalSceneGraph().traverse(EntityFindByClassname(name, entity));
- return entity;
-}
-
-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)
+ else
{
- Entity* entity = Scene_FindEntityByClass(*i);
- if(entity != 0)
+ for (brush_t *b = ent->brushes.onext ; b != &ent->brushes ; b=b->onext)
{
- return entity;
+ // 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 0;
+ return true;
}
-//
-// move the view to a start position
-//
+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
-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);
-}
+ 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
-#include "stringio.h"
+ 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?
+ */
-void Map_StartPosition()
-{
- Entity* entity = Scene_FindPlayerStart();
+ FilterChildren(world_entity, bRegionOnly, bSelectedOnly);
+ ents->Add(world_entity);
- if (entity)
+ for (e=entities.next ; e!=&entities ; e=e->next)
{
- Vector3 origin;
- string_parse_vector3(entity->getKeyValue("origin"), origin);
- FocusViews(origin, string_read_float(entity->getKeyValue("angle")));
+ // 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);
}
- else
+
+ if (bRegionOnly && region_active)
{
- FocusViews(g_vector3_identity, 0);
+ for(i=0; i<6; i++)
+ ((CPtrArray*)world_entity->pData)->Add(region_sides[i]);
+
+ ents->Add(region_startpoint);
}
}
-
-inline bool node_is_worldspawn(scene::Node& node)
+void Map_Export(IDataStream *out, const char *type, bool bRegionOnly, bool bSelectedOnly)
{
- Entity* entity = Node_getEntity(node);
- return entity != 0 && string_equal(entity->getKeyValue("classname"), "worldspawn");
-}
+ entity_t *e;
+ CPtrArray ents;
-// 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;
- }
-};
+ if (bRegionOnly && region_active)
+ AddRegionBrushes();
-scene::Node* Map_FindWorldspawn(Map& map)
-{
- Map_SetWorldspawn(map, 0);
+ // create the filters
+ world_entity->pData = new CPtrArray();
+ for(e = entities.next; e != &entities; e = e->next)
+ e->pData = new CPtrArray();
- Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
+ Map_ExportEntities(&ents, bRegionOnly, bSelectedOnly);
- return Map_GetWorldspawn(map);
-}
+ g_pParentWnd->GetSynapseClient().ExportMap(&ents, out, type);
+ // cleanup the filters
+ CleanFilter(world_entity);
+ for (e=entities.next ; e!=&entities ; e=e->next)
+ CleanFilter(e);
-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;
-}
-
-void Map_UpdateWorldspawn(Map& map)
-{
- if(Map_FindWorldspawn(map) == 0)
- {
- Map_SetWorldspawn(map, &createWorldspawn());
- }
-}
-
-scene::Node& Map_FindOrInsertWorldspawn(Map& map)
-{
- Map_UpdateWorldspawn(map);
- return *Map_GetWorldspawn(map);
-}
-
-
-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);
-}
-
-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;
-}
-
-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;
-}
-
-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));
-#endif
- }
-}
-
-void Map_ExportSelected(TextOutputStream& out, const MapFormat& format)
-{
- format.writeGraph(GlobalSceneGraph().root(), Map_Traverse_Selected, out);
-}
-
-void Map_Traverse(scene::Node& root, const scene::Traversable::Walker& walker)
-{
- scene::Traversable* traversable = Node_getTraversable(root);
- if(traversable != 0)
- {
- traversable->traverse(walker);
- }
-}
-
-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()));
- }
-}
-
-bool Map_SaveRegion(const char *filename)
-{
- AddRegionBrushes();
-
- bool success = MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Region, filename);
-
- RemoveRegionBrushes();
-
- return success;
-}
-
-
-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());
-
- {
- //ScopeTimer timer("clone subgraph");
- Node_getTraversable(GlobalSceneGraph().root())->traverse(CloneAll(clone));
- }
-
- g_map.m_resource->detach(g_map);
- GlobalReferenceCache().release(g_map.m_name.c_str());
-
- g_map.m_resource = resource;
-
- g_map.m_name = absolute;
- Map_UpdateTitle(g_map);
-
- g_map.m_resource->attach(g_map);
-}
-
-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();
- }
-}
-
-bool Map_Save()
-{
- Pointfile_Clear();
-
- ScopeTimer timer("map save");
- SaveReferences();
- return true; // assume success..
-}
-
-/*
-===========
-Map_New
-
-===========
-*/
-void Map_New()
-{
- //globalOutputStream() << "Map_New\n";
-
- g_map.m_name = "unnamed.map";
- Map_UpdateTitle(g_map);
-
- {
- 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);
-
- SceneChangeNotify();
- }
-
- FocusViews(g_vector3_identity, 0);
-
- g_currentMap = &g_map;
+ if (bRegionOnly && region_active)
+ RemoveRegionBrushes();
}
-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)
+const char* filename_get_extension(const char* filename)
{
- /*!
- \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);
+ const char* type = strrchr(filename,'.');
+ if(type != NULL)
+ return ++type;
+ return "";
}
-/*
-===========================================================
-
- REGION
-
-===========================================================
-*/
-bool region_active;
-Vector3 region_mins(g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord);
-Vector3 region_maxs(g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord);
-
-scene::Node* region_sides[6];
-scene::Node* region_startpoint = 0;
-
/*
===========
-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
+Map_SaveFile
+\todo FIXME remove the use_region, this is broken .. work with a global flag to set region mode or not
===========
*/
-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);
-}
-
-void RemoveRegionBrushes (void)
+void Map_SaveFile (const char *filename, qboolean use_region )
{
- 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);
-}
-
-inline void exclude_node(scene::Node& node, bool exclude)
-{
- exclude
- ? node.enable(scene::Node::eExcluded)
- : node.disable(scene::Node::eExcluded);
-}
-
-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;
- }
-};
+ clock_t start, finish;
+ double elapsed_time;
+ start = clock();
+ Sys_Printf("Saving map to %s\n",filename);
-void Scene_Exclude_All(bool exclude)
-{
- GlobalSceneGraph().traverse(ExcludeAllWalker(exclude));
-}
+ Pointfile_Clear ();
-bool Instance_isSelected(const scene::Instance& instance)
-{
- const Selectable* selectable = Instance_getSelectable(instance);
- return selectable != 0 && selectable->isSelected();
-}
+ if (!use_region)
+ {
+ char backup[1024];
-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;
- }
-};
+ // rename current to .bak
+ strcpy (backup, filename);
+ StripExtension (backup);
+ strcat (backup, ".bak");
+ unlink (backup);
+ rename (filename, backup);
+ }
-void Scene_Exclude_Selected(bool exclude)
-{
- GlobalSceneGraph().traverse(ExcludeSelectedWalker(exclude));
-}
+ Sys_Printf ("Map_SaveFile: %s\n", filename);
-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
+ // build the out data stream
+ FileStream file;
+ if (!file.Open(filename,"w"))
{
- exclude_node(
- path.top(),
- !(
- (
- aabb_intersects_aabb(
- instance.worldAABB(),
- aabb_for_minmax(region_mins, region_maxs)
- ) != 0
- ) ^ m_exclude
- )
- );
-
- return true;
+ Sys_FPrintf(SYS_ERR, "ERROR: couldn't open %s for write\n", filename);
+ return;
}
-};
-
-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);
-}
-
-void Map_ApplyRegion (void)
-{
- region_active = true;
-
- Scene_Exclude_Region(false);
-}
-
-
-/*
-========================
-Map_RegionSelectedBrushes
-========================
-*/
-void Map_RegionSelectedBrushes (void)
-{
- Map_RegionOff();
-
- if(GlobalSelectionSystem().countSelected() != 0
- && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
- {
- region_active = true;
- Select_GetBounds (region_mins, region_maxs);
- Scene_Exclude_Selected(false);
-
- GlobalSelectionSystem().setSelectedAll(false);
- }
-}
+ // extract filetype
+ Map_Export(&file, filename_get_extension(filename), use_region);
+ file.Close();
-/*
-===========
-Map_RegionXY
-===========
-*/
-void Map_RegionXY(float x_min, float y_min, float x_max, float y_max)
-{
- Map_RegionOff();
+ finish = clock();
+ elapsed_time = (double)(finish - start) / CLOCKS_PER_SEC;
- 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_maxs[2] = g_MaxWorldCoord - 64;
+ Sys_Printf ("Saved in %-.2f second(s).\n",elapsed_time);
+ modified = false;
- Map_ApplyRegion();
-}
+ if ( !strstr( filename, "autosave" ) )
+ Sys_SetTitle (filename);
-void Map_RegionBounds(const AABB& bounds)
-{
- Map_RegionOff();
+ if (!use_region)
+ {
+ time_t timer;
- region_mins = vector3_subtracted(bounds.origin, bounds.extents);
- region_maxs = vector3_added(bounds.origin, bounds.extents);
+ time (&timer);
- deleteSelection();
+ Sys_Beep ();
- Map_ApplyRegion();
+ Sys_Status ("Saved.", 0);
+ }
}
/*
===========
-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_New
-/*
-===========
-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)
+void Map_New (void)
{
- return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename);
-}
+ Sys_Printf ("Map_New\n");
+ Map_Free ();
+ strcpy (currentmap, "unnamed.map");
+ Sys_SetTitle (currentmap);
-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));
-}
+ 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);
-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;
- }
-};
+ 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());
-std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
-{
- std::size_t count;
- graph.traverse(CountSelectedBrushes(count));
- return count;
-}
+ Map_RestoreBetween ();
-enum ENodeType
-{
- eNodeUnknown,
- eNodeMap,
- eNodeEntity,
- eNodePrimitive,
-};
+ Group_Init();
-const char* nodetype_get_name(ENodeType type)
-{
- if(type == eNodeMap)
- return "map";
- if(type == eNodeEntity)
- return "entity";
- if(type == eNodePrimitive)
- return "primitive";
- return "unknown";
+ Sys_UpdateWindows (W_ALL);
+ modified = false;
}
-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);
-}
+ REGION
-bool contains_primitive(scene::Node& node)
-{
- return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
-}
+===========================================================
+*/
+qboolean region_active;
+vec3_t region_mins = {g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord};
+vec3_t region_maxs = {g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord};
-ENodeType node_get_contains(scene::Node& node)
-{
- if(contains_entity(node))
- {
- return eNodeEntity;
- }
- if(contains_primitive(node))
- {
- return eNodePrimitive;
- }
- return eNodeUnknown;
-}
+brush_t *region_sides[6];
-void Path_parent(const scene::Path& parent, const scene::Path& child)
+/*
+===========
+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)
{
- ENodeType contains = node_get_contains(parent.top());
- ENodeType type = node_get_nodetype(child.top());
+ vec3_t mins, maxs;
+ int i;
+ texdef_t td;
- if(contains != eNodeUnknown && contains == type)
+ if (!region_active)
{
- 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";
+#ifdef _DEBUG
+ Sys_FPrintf( SYS_WRN, "Unexpected AddRegionBrushes call.\n");
+#endif
+ return;
}
-}
-void Scene_parentSelected()
-{
- UndoableCommand undo("parentSelected");
+ memset (&td, 0, sizeof(td));
+ td.SetName(SHADER_NOT_FOUND);
- if(GlobalSelectionSystem().countSelected() > 1)
+ // set mins
+ VectorSet(mins, region_mins[0]-32, region_mins[1]-32, region_mins[2]-32);
+
+ // vary maxs
+ for(i=0; i<3; i++)
{
- 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);
+ 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);
}
- else
+
+ // set maxs
+ VectorSet(maxs, region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32);
+
+ // vary mins
+ for(i=0; i<3; i++)
{
- globalOutputStream() << "failed - did not find two selected nodes.\n";
+ 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]);
-void NewMap()
-{
- if (ConfirmModified("New Map"))
+ for (i=0 ; i<3 ; i++)
{
- Map_RegionOff();
- Map_Free();
- Map_New();
+ 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 maps_directory(StringOutputStream& buffer)
+void RemoveRegionBrushes (void)
{
- 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());
+ int i;
+
+ if (!region_active)
+ return;
+ for (i=0 ; i<6 ; i++)
+ Brush_Free (region_sides[i]);
+
+ CleanFilter(region_startpoint);
+ Entity_Free(region_startpoint);
}
-const char* map_open(const char* title)
+qboolean Map_IsBrushFiltered (brush_t *b)
{
- StringOutputStream buf(256);
- maps_directory(buf);
- return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, buf.c_str(), MapFormat::Name());
+ 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;
}
-const char* map_save(const char* title)
+/*
+===========
+Map_RegionOff
+
+Other filtering options may still be on
+===========
+*/
+void Map_RegionOff (void)
{
- StringOutputStream buf(256);
- maps_directory(buf);
- return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, buf.c_str(), MapFormat::Name());
+ brush_t *b, *next;
+ int i;
+
+ 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 OpenMap()
+void Map_ApplyRegion (void)
{
- if (!ConfirmModified("Open Map"))
- return;
+ brush_t *b, *next;
- const char* filename = map_open("Open Map");
+ 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);
+ }
- if (filename != 0)
- {
- MRU_AddFile(filename);
- Map_RegionOff();
- Map_Free();
- Map_LoadFile(filename);
- }
+ Sys_UpdateWindows (W_ALL);
}
-void ImportMap()
+
+/*
+========================
+Map_RegionSelectedBrushes
+========================
+*/
+void Map_RegionSelectedBrushes (void)
{
- const char* filename = map_open("Import Map");
+ Map_RegionOff ();
- if(filename != 0)
+ if (selected_brushes.next == &selected_brushes) // nothing selected
{
- UndoableCommand undo("mapImport");
- Map_ImportFile(filename);
+ Sys_Printf("Tried to region with no selection...\n");
+ return;
}
-}
+ region_active = true;
+ Select_GetBounds (region_mins, region_maxs);
-bool Map_SaveAs()
-{
- const char* filename = map_save("Save Map");
-
- if(filename != 0)
- {
- MRU_AddFile(filename);
- Map_Rename(filename);
- return Map_Save();
- }
- return false;
-}
+#ifdef _DEBUG
+ if (filtered_brushes.next != &filtered_brushes)
+ Sys_Printf("WARNING: filtered_brushes list may not be empty in Map_RegionSelectedBrushes\n");
+#endif
-void SaveMapAs()
-{
- Map_SaveAs();
-}
+ 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;
+ }
-void SaveMap()
-{
- if(Map_Unnamed(g_map))
- {
- SaveMapAs();
- }
- else if(Map_Modified(g_map))
- {
- Map_Save();
- }
-}
+ // 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;
-void ExportMap()
-{
- const char* filename = map_save("Export Selection");
+ // deselect patches
+ for (brush_t *b = active_brushes.next; b != &active_brushes; b = b->next)
+ if (b->patchBrush)
+ b->pPatch->bSelected = false;
- if(filename != 0)
- {
- Map_SaveSelected(filename);
- }
-}
+ // clear selected_brushes
+ selected_brushes.next = selected_brushes.prev = &selected_brushes;
-void SaveRegion()
-{
- const char* filename = map_save("Export Region");
-
- if(filename != 0)
- {
- Map_SaveRegion(filename);
- }
+ Sys_UpdateWindows (W_ALL);
}
-void RegionOff()
+/*
+===========
+Map_RegionXY
+===========
+*/
+void Map_RegionXY (void)
{
- Map_RegionOff();
- SceneChangeNotify();
-}
+ Map_RegionOff ();
-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();
+ 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 RegionBrush()
+/*
+===========
+Map_RegionTallBrush
+===========
+*/
+void Map_RegionTallBrush (void)
{
- Map_RegionBrush();
- SceneChangeNotify();
-}
+ brush_t *b;
-void RegionSelected()
-{
- Map_RegionSelectedBrushes();
- SceneChangeNotify();
-}
+ if (!QE_SingleBrush ())
+ return;
+ b = selected_brushes.next;
+ Map_RegionOff ();
+ VectorCopy (b->mins, region_mins);
+ VectorCopy (b->maxs, region_maxs);
+ region_mins[2] = g_MinWorldCoord+64;
+ region_maxs[2] = g_MaxWorldCoord-64;
+ Undo_Start("delete");
+ Undo_AddBrushList(&selected_brushes);
+ Undo_AddEntity(b->owner);
+ Select_Delete ();
+ Undo_EndBrushList(&selected_brushes);
+ Undo_End();
-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;
- }
-};
+ Map_ApplyRegion ();
+}
-class EntityFindByIndexWalker : public scene::Traversable::Walker
+/*
+===========
+Map_RegionBrush
+===========
+*/
+void Map_RegionBrush (void)
{
- 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;
- }
-};
+ brush_t *b;
-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));
- }
- }
-}
+ if (!QE_SingleBrush ())
+ return;
-inline bool Node_hasChildren(scene::Node& node)
-{
- scene::Traversable* traversable = Node_getTraversable(node);
- return traversable != 0 && !traversable->empty();
-}
+ b = selected_brushes.next;
-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_RegionOff ();
+ VectorCopy (b->mins, region_mins);
+ VectorCopy (b->maxs, region_maxs);
-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;
- }
-};
+ Undo_Start("delete");
+ Undo_AddBrushList(&selected_brushes);
+ Undo_AddEntity(b->owner);
+ Select_Delete ();
+ Undo_EndBrushList(&selected_brushes);
+ Undo_End();
-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;
- }
-};
+ Map_ApplyRegion ();
+}
-static void GetSelectionIndex (int *ent, int *brush)
+GList *find_string(GList *glist, const char *buf)
{
- std::size_t count_brush = 0;
- std::size_t count_entity = 0;
- if(GlobalSelectionSystem().countSelected() != 0)
+ while (glist)
{
- const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
-
- GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
- GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
+ if (strcmp((char *)glist->data, buf) == 0)
+ break; // this name is in our list already
+ glist = glist->next;
}
- *brush = int(count_brush);
- *ent = int(count_entity);
+ return glist;
}
-void DoFind()
+void Map_ImportBuffer(char *buf)
{
- ModalDialog dialog;
- GtkEntry* entity;
- GtkEntry* brush;
+ Select_Deselect();
- GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
+ Undo_Start("import buffer");
- GtkAccelGroup* accel = gtk_accel_group_new();
- gtk_window_add_accel_group(window, accel);
+ MemStream stream;
- {
- 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);
+ stream.Write(buf, strlen(buf));
+ Map_Import(&stream, "xmap");
+ stream.Close();
- 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);
- }
- }
- }
+ Sys_UpdateWindows (W_ALL);
+ Sys_MarkMapModified();
+
+ Undo_End();
+}
- // 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);
+//
+//================
+//Map_ImportFile
+//================
+//
+void Map_ImportFile (const char *filename)
+{
+ FileStream file;
+ Sys_BeginWait ();
- 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));
- }
+ Sys_Printf("Importing map from %s\n",filename);
- 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();
+ Sys_UpdateWindows (W_ALL);
+ modified = true;
+ Sys_EndWait();
+}
-class MapEntityClasses : public ModuleObserver
+//
+//===========
+//Map_SaveSelected
+//===========
+//
+// Saves selected world brushes and whole entities with partial/full selections
+//
+void Map_SaveSelected(const char* filename)
{
- 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();
- }
- }
- }
-};
+ FileStream file;
-MapEntityClasses g_MapEntityClasses;
+ Sys_Printf("Saving selection to %s\n",filename);
+ 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);
+
+ file.Close();
-void Map_constructPreferences(PreferencesPage& page)
-{
- page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
}
-#include "preferencesystem.h"
+//
+//===========
+//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);
+ */
+}
-CopiedString g_strLastMap;
-bool g_bLoadLastMap = false;
-void Map_Construct()
+void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...)
{
- 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)));
-
- 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>());
-
- GlobalEntityClassManager().attach(g_MapEntityClasses);
+ char Buffer[4096];
+ va_list args;
+ va_start (args,pText);
+ vsprintf(Buffer, pText, args);
+ pMemFile->Write(Buffer, strlen(Buffer));
}
-void Map_Destroy()
-{
- GlobalEntityClassManager().detach(g_MapEntityClasses);
+/*!
+==============
+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");
}