diff --git a/doomsday/client/include/map/bsp/hedgeintercept.h b/doomsday/client/include/map/bsp/hedgeintercept.h index 914fdfc60a..9255d365db 100644 --- a/doomsday/client/include/map/bsp/hedgeintercept.h +++ b/doomsday/client/include/map/bsp/hedgeintercept.h @@ -60,7 +60,7 @@ struct HEdgeIntercept static void DebugPrint(HEdgeIntercept const &inst) { LOG_INFO("Vertex #%i [x:%f, y:%f] beforeSector: #%d afterSector: #%d %s") - << inst.vertex->_buildData.index + << (inst.vertex->origIndex() - 1) << inst.vertex->origin()[VX] << inst.vertex->origin()[VY] << (inst.before? inst.before->origIndex() : -1) diff --git a/doomsday/client/include/map/line.h b/doomsday/client/include/map/line.h index 9a1ada6d48..de37ad8829 100644 --- a/doomsday/client/include/map/line.h +++ b/doomsday/client/include/map/line.h @@ -526,8 +526,9 @@ class Line : public de::MapElement public: Line(Vertex &from, Vertex &to, - Sector *frontSector = 0, - Sector *backSector = 0); + int flags = 0, + Sector *frontSector = 0, + Sector *backSector = 0); /** * Returns @c true iff the line is part of some Polyobj. @@ -718,7 +719,7 @@ class Line : public de::MapElement } /** - * Returns the specified edge vertex for the line. + * Returns the specified edge vertex of the line. * * @param to If not @c 0 return the To vertex; otherwise the From vertex. */ @@ -733,8 +734,7 @@ class Line : public de::MapElement * * @see vertex() */ - inline const_pvec2d_t &vertexOrigin(int to) const - { + inline const_pvec2d_t &vertexOrigin(int to) const { return vertex(to).origin(); } @@ -925,6 +925,19 @@ class Line : public de::MapElement return pointOnSide(point); } + /** + * Replace the specified edge vertex of the line. + * + * @attention Should only be called in map edit mode. + * + * @param to If not @c 0 replace the To vertex; otherwise the From vertex. + * @param newVertex The replacement vertex. + */ + void replaceVertex(int to, Vertex &newVertex); + + inline void replaceFrom(Vertex &newVertex) { replaceVertex(FROM, newVertex); } + inline void replaceTo(Vertex &newVertex) { replaceVertex(TO, newVertex); } + /** * Get a property value, selected by DMU_* name. * diff --git a/doomsday/client/include/map/vertex.h b/doomsday/client/include/map/vertex.h index 7592977e7a..1cd9991239 100644 --- a/doomsday/client/include/map/vertex.h +++ b/doomsday/client/include/map/vertex.h @@ -1,4 +1,4 @@ -/** @file vertex.h Map Geometry Vertex +/** @file vertex.h World Map Vertex. * * @authors Copyright © 2003-2013 Jaakko Keränen * @authors Copyright © 2006-2013 Daniel Swanson @@ -18,14 +18,17 @@ * 02110-1301 USA */ -#ifndef LIBDENG_MAP_VERTEX -#define LIBDENG_MAP_VERTEX +#ifndef DENG_WORLD_MAP_VERTEX +#define DENG_WORLD_MAP_VERTEX + +#include +#include /// @todo remove me #include #include -#include /// @todo remove me -#include + #include "resource/r_data.h" + #include "map/p_dmu.h" #include "MapElement" @@ -166,24 +169,8 @@ class Vertex : public de::MapElement LineOwner *_lineOwners; uint _numLineOwners; ///< Total number of line owners. - /// @todo This temporary load-time data does not belong here. -ds - struct { - /// Vertex index. Always valid after loading and pruning of unused - /// vertices has occurred. - int index; - - /// Reference count. When building normal node info, unused vertices - /// will be pruned. - int refCount; - - /// Usually NULL, unless this vertex occupies the same location as a - /// previous vertex. Only used during the pruning phase. - Vertex *equiv; - } _buildData; - public: - Vertex(coord_t x = 0, coord_t y = 0); - Vertex(de::Vector2d const &origin); + Vertex(de::Vector2d const &origin = de::Vector2d(0, 0)); /** * Returns the origin (i.e., location) of the vertex in the map coordinate space. @@ -231,6 +218,18 @@ class Vertex : public de::MapElement */ LineOwner *firstLineOwner() const; + /** + * Returns the original index of the vertex. + */ + uint origIndex() const; + + /** + * Change the original index of the vertex. + * + * @param newIndex New original index. + */ + void setOrigIndex(uint newIndex); + /** * Get a property value, selected by DMU_* name. * @@ -251,4 +250,4 @@ class Vertex : public de::MapElement DENG2_PRIVATE(d) }; -#endif // LIBDENG_MAP_VERTEX +#endif // DENG_WORLD_MAP_VERTEX diff --git a/doomsday/client/src/edit_map.cpp b/doomsday/client/src/edit_map.cpp index 04c07a635e..bbd0ebf6a9 100644 --- a/doomsday/client/src/edit_map.cpp +++ b/doomsday/client/src/edit_map.cpp @@ -24,6 +24,12 @@ #include +#include +#include +#include + +#include + #include "de_base.h" #include "de_console.h" #include "de_play.h" @@ -35,38 +41,11 @@ #ifdef __CLIENT__ # include "render/rend_main.h" #endif -#include #include "audio/s_environ.h" using namespace de; -#if 0 -static int vertexCompare(void const *p1, void const *p2) -{ - Vertex const *a = (Vertex const *) *((void const **) p1); - Vertex const *b = (Vertex const *) *((void const **) p2); - - if(a == b) return 0; - - if(int(a->origin()[VX]) != int(b->origin()[VX])) - return int(a->origin()[VX]) - int(b->origin()[VX]); - - return int(a->origin()[VY]) - int(b->origin()[VY]); -} -#endif - -/** - * @defgroup pruneMapElementFlags Prune Map Element Flags - * Flags for pruneMapElements() - */ -///@{ -#define PRUNE_LINES 0x1 -#define PRUNE_VERTEXES 0x2 -#define PRUNE_SECTORS 0x4 -#define PRUNE_ALL (PRUNE_LINES|PRUNE_VERTEXES|PRUNE_SECTORS) -///@} - /** * Editable map data elements. * @@ -87,20 +66,20 @@ class EditableMap : entityDatabase(0) {} - Vertex *createVertex(coord_t x, coord_t y) + Vertex *createVertex(Vector2d const &origin) { - Vertex *vtx = new Vertex(x, y); + Vertex *vtx = new Vertex(origin); vertexes.append(vtx); - vtx->_buildData.index = vertexes.count(); // 1-based index, 0 = NIL. + vtx->setOrigIndex(vertexes.count()); // 1-based index, 0 = NIL. return vtx; } - Line *createLine(Vertex &v1, Vertex &v2, Sector *frontSector = 0, - Sector *backSector = 0) + Line *createLine(Vertex &v1, Vertex &v2, int flags = 0, + Sector *frontSector = 0, Sector *backSector = 0) { - Line *line = new Line(v1, v2, frontSector, backSector); + Line *line = new Line(v1, v2, flags, frontSector, backSector); lines.append(line); line->setOrigIndex(lines.count()); // 1-based index, 0 = NIL. @@ -148,191 +127,144 @@ class EditableMap polyobjs.clear(); } -#if 0 - void markDuplicateVertexes() + void pruneVertexes() { - Vertex **hits = (Vertex **) M_Malloc(vertexes.count() * sizeof(Vertex *)); - - // Sort array of ptrs. - for(uint i = 0; i < vertexes.count(); ++i) + struct VertexInfo { - hits[i] = vertexes[i]; - } - qsort(hits, vertexes.count(), sizeof(Vertex *), vertexCompare); + /// Vertex for this info. + Vertex *vertex; - // Now mark them off. - for(uint i = 0; i < vertexes.count() - 1; ++i) - { - // A duplicate? - if(vertexCompare(hits + i, hits + i + 1) == 0) - { - // Yes. - Vertex *a = hits[i]; - Vertex *b = hits[i + 1]; + /// Determined equivalent vertex. + Vertex *equiv; - b->_buildData.equiv = (a->_buildData.equiv ? a->_buildData.equiv : a); - } - } + /// Line -> Vertex reference count. + uint refCount; - M_Free(hits); - } + VertexInfo() + : vertex(0), equiv(0), refCount(0) + {} - void findEquivalentVertexes() - { - uint i, newNum; + /// @todo Math here is not correct (rounding directionality). -ds + int compareVertexOrigins(VertexInfo const &other) const + { + DENG_ASSERT(vertex != 0 && other.vertex != 0); - // Scan all lines. - for(i = 0, newNum = 0; i < lines.count(); ++i) - { - Line *l = lines[i]; + if(this == &other) return 0; + if(vertex == other.vertex) return 0; - // Handle duplicated vertices. - while(l->v[0]->_buildData.equiv) - { - l->v[0]->_buildData.refCount--; - l->v[0] = l->v[0]->_buildData.equiv; - l->v[0]->_buildData.refCount++; + // Order is firstly X axis major. + if(int(vertex->origin()[VX]) != int(other.vertex->origin()[VX])) + return int(vertex->origin()[VX]) - int(other.vertex->origin()[VX]); + + // Order is secondly Y axis major. + return int(vertex->origin()[VY]) - int(other.vertex->origin()[VY]); } - while(l->v[1]->_buildData.equiv) - { - l->v[1]->_buildData.refCount--; - l->v[1] = l->v[1]->_buildData.equiv; - l->v[1]->_buildData.refCount++; + bool operator < (VertexInfo const &other) const { + return compareVertexOrigins(other) < 0; } + }; - l->_buildData.index = newNum + 1; - lines[newNum++] = lines[i]; - } - } + /* + * Step 1 - Find equivalent vertexes: + */ - void pruneLines() - { - uint i, newNum, unused = 0; + // Populate the vertex info. + QVector vertexInfo(vertexes.count()); + for(int i = 0; i < vertexes.count(); ++i) + vertexInfo[i].vertex = vertexes[i]; - for(i = 0, newNum = 0; i < lines.count(); ++i) { - Line *l = lines[i]; + // Sort a copy to place near vertexes adjacently. + QVector sortedInfo(vertexInfo); + qSort(sortedInfo.begin(), sortedInfo.end()); - if(!l->hasFrontSections() && !l->hasBackSections()) + // Locate equivalent vertexes in the sorted info. + for(int i = 0; i < sortedInfo.count() - 1; ++i) { - unused++; - - M_Free(l); - continue; + VertexInfo &a = sortedInfo[i]; + VertexInfo &b = sortedInfo[i + 1]; + + // Are these equivalent? + /// @todo fixme: What about polyobjs? They need unique vertexes! -ds + if(a.compareVertexOrigins(b) == 0) + { + b.equiv = (a.equiv? a.equiv : a.vertex); + } } - - l->_buildData.index = newNum + 1; - lines[newNum++] = l; } - if(newNum < lines.count()) - { - if(unused > 0) - Con_Message(" Pruned %d unused lines.", unused); + /* + * Step 2 - Replace line references to equivalent vertexes: + */ - lines.resize(newNum); + // Count line -> vertex references. + foreach(Line *line, lines) + { + vertexInfo[line->from().origIndex() - 1].refCount++; + vertexInfo[ line->to().origIndex() - 1].refCount++; } - } - - void pruneVertices() - { - uint i, newNum, unused = 0; - // Scan all vertices. - for(i = 0, newNum = 0; i < vertexes.count(); ++i) + // Perform the replacement. + foreach(Line *line, lines) { - Vertex *v = vertexes[i]; + while(vertexInfo[line->from().origIndex() - 1].equiv) + { + VertexInfo &info = vertexInfo[line->from().origIndex() - 1]; + + info.refCount--; + line->replaceFrom(*info.equiv); - if(v->_buildData.refCount < 0) - Con_Error("Vertex %d ref_count is %d", i, v->_buildData.refCount); + vertexInfo[line->from().origIndex() - 1].refCount++; + } - if(v->_buildData.refCount == 0) + while(vertexInfo[line->to().origIndex() - 1].equiv) { - if(v->_buildData.equiv == NULL) - unused++; + VertexInfo &info = vertexInfo[line->to().origIndex() - 1]; - M_Free(v); - continue; - } + info.refCount--; + line->replaceTo(*info.equiv); - v->_buildData.index = newNum + 1; - vertexes[newNum++] = v; + vertexInfo[line->to().origIndex() - 1].refCount++; + } } - if(newNum < vertexes.count()) + /* + * Step 3 - Prune vertexes: + */ + uint prunedCount = 0, numUnused = 0; + foreach(VertexInfo const &info, vertexInfo) { - int dupNum = vertexes.count() - newNum - unused; - - if(unused > 0) - Con_Message(" Pruned %d unused vertices.", unused); + Vertex *vertex = info.vertex; - if(dupNum > 0) - Con_Message(" Pruned %d duplicate vertices.", dupNum); - - vertexes.resize(newNum); - } - } + if(info.refCount) + continue; - void pruneUnusedSectors() - { - for(uint i = 0; i < sides.count(); ++i) - { - Side *s = sides[i]; + vertexes.removeOne(vertex); + delete vertex; - if(s->sector) - s->sector->buildData.refCount++; + prunedCount += 1; + if(!info.equiv) numUnused += 1; } - // Scan all sectors. - uint newNum = 0; - for(uint i = 0; i < sectors.count(); ++i) + if(prunedCount) { - Sector* s = sectors[i]; + // Re-index with a contiguous range of indices. + uint idx = 0; + foreach(Vertex *vertex, vertexes) + vertex->setOrigIndex(++idx); // 1-based. - if(s->buildData.refCount == 0) + /// Update lines. @todo Line should handle this itself. + foreach(Line *line, lines) { - M_Free(s); - continue; + line->updateSlopeType(); + line->updateAABox(); } - s->buildData.index = newNum + 1; - sectors[newNum++] = s; + LOG_INFO("Pruned %d vertexes (%d equivalents, %s unused).") + << prunedCount << (prunedCount - numUnused) << numUnused; } - - if(newNum < sectors.count()) - { - Con_Message(" Pruned %d unused sectors.", sectors.count() - newNum); - sectors.resize(newNum); - } - } - - /** - * @param flags @ref pruneMapElementFlags - */ - void pruneMapElements(int /*flags*/) - { - /** - * @todo Pruning cannot be done as game map data object properties - * are currently indexed by their original indices as determined by the - * position in the map data. The same problem occurs within ACS scripts - * and XG line/sector references. - * - * @warning Order here is critical! - */ - - findEquivalentVertexes(); - - if(flags & PRUNE_LINES) - pruneLines(); - - if(flags & PRUNE_VERTEXES) - pruneVertices(); - - if(flags & PRUNE_SECTORS) - pruneUnusedSectors(); } -#endif }; static EditableMap editMap; // singleton @@ -888,6 +820,9 @@ boolean MPE_End() if(!editMapInited) return false; + LOG_DEBUG("New Elements: %d Vertexes, %d Lines, %d Sectors") + << editMap.vertexes.count() << editMap.lines.count() << editMap.sectors.count(); + /* * Log warnings about any issues we encountered during conversion of * the basic map data elements. @@ -898,10 +833,11 @@ boolean MPE_End() GameMap *map = new GameMap; /* - * Perform cleanup on the loaded map data, removing duplicate vertexes, - * pruning unused sectors etc, etc... + * Perform cleanup on the loaded map data. */ + editMap.pruneVertexes(); + /// Ensure one sided lines are flagged as blocking. @todo Refactor away. foreach(Line *line, editMap.lines) { @@ -909,11 +845,6 @@ boolean MPE_End() line->_flags |= DDLF_BLOCKING; } -#if 0 - markDuplicateVertexes(editMap); - pruneMapElements(editMap, PRUNE_ALL); -#endif - buildVertexLineOwnerRings(); /* @@ -1055,14 +986,11 @@ boolean MPE_End() uint MPE_VertexCreate(coord_t x, coord_t y) { if(!editMapInited) return 0; - - Vertex *v = editMap.createVertex(x, y); - - return v->_buildData.index; + return editMap.createVertex(Vector2d(x, y))->origIndex(); } #undef MPE_VertexCreatev -boolean MPE_VertexCreatev(size_t num, coord_t *values, uint *indices) +boolean MPE_VertexCreatev(size_t num, coord_t *values, uint *retIndices) { if(!editMapInited || !num || !values) return false; @@ -1070,10 +998,11 @@ boolean MPE_VertexCreatev(size_t num, coord_t *values, uint *indices) // Create many vertexes. for(uint n = 0; n < num; ++n) { - Vertex *v = editMap.createVertex(values[n * 2], values[n * 2 + 1]); - - if(indices) - indices[n] = v->_buildData.index; + Vertex *vertex = editMap.createVertex(Vector2d(values[n * 2], values[n * 2 + 1])); + if(retIndices) + { + retIndices[n] = vertex->origIndex(); + } } return true; @@ -1096,19 +1025,10 @@ uint MPE_LineCreate(uint v1, uint v2, uint frontSectorIdx, uint backSectorIdx, i Vertex *vtx2 = editMap.vertexes[v2 - 1]; if(!(V2d_Distance(vtx2->origin(), vtx1->origin()) > 0)) return 0; - Sector *frontSector = (frontSectorIdx == 0? NULL: editMap.sectors[frontSectorIdx-1]); - Sector *backSector = (backSectorIdx == 0? NULL: editMap.sectors[backSectorIdx-1]); - - Line *l = editMap.createLine(*vtx1, *vtx2, frontSector, backSector); - - // Determine the default line flags. - l->_flags = flags; - - // Remember the number of unique references. - l->v1()._buildData.refCount++; - l->v2()._buildData.refCount++; + Sector *frontSector = (frontSectorIdx? editMap.sectors[frontSectorIdx - 1] : 0); + Sector *backSector = (backSectorIdx ? editMap.sectors[ backSectorIdx - 1] : 0); - return l->origIndex(); + return editMap.createLine(*vtx1, *vtx2, flags, frontSector, backSector)->origIndex(); } #undef MPE_LineAddSide diff --git a/doomsday/client/src/map/bsp/partitioner.cpp b/doomsday/client/src/map/bsp/partitioner.cpp index ff0f00087a..3dd77f2db3 100644 --- a/doomsday/client/src/map/bsp/partitioner.cpp +++ b/doomsday/client/src/map/bsp/partitioner.cpp @@ -199,7 +199,7 @@ DENG2_PIMPL(Partitioner) */ VertexInfo &vertexInfo(Vertex const &vertex) { - return vertexInfos[vertex._buildData.index - 1]; + return vertexInfos[vertex.origIndex() - 1]; } struct testForWindowEffectParams @@ -2027,7 +2027,7 @@ DENG2_PIMPL(Partitioner) /// @todo We do not have authorization to specify this index. -ds /// (This job should be done post BSP build.) - vtx->_buildData.index = map->vertexCount() + uint(vertexes.size() + 1); // 1-based index, 0 = NIL. + vtx->setOrigIndex(map->vertexCount() + uint(vertexes.size()) + 1); // 1-based index, 0 = NIL. vertexes.push_back(vtx); // There is now one more Vertex. @@ -2161,7 +2161,7 @@ DENG2_PIMPL(Partitioner) { throw Error("Partitioner::openSectorAtAngle", QString("Vertex #%1 has no hedge tips!") - .arg(vtx._buildData.index - 1)); + .arg(vtx.origIndex() - 1)); } // First check whether there's a wall_tip that lies in the exact diff --git a/doomsday/client/src/map/line.cpp b/doomsday/client/src/map/line.cpp index 2d2941570f..53c027a9af 100644 --- a/doomsday/client/src/map/line.cpp +++ b/doomsday/client/src/map/line.cpp @@ -373,11 +373,11 @@ DENG2_PIMPL(Line) } }; -Line::Line(Vertex &from, Vertex &to, Sector *frontSector, Sector *backSector) +Line::Line(Vertex &from, Vertex &to, int flags, Sector *frontSector, Sector *backSector) : MapElement(DMU_LINE), _vo1(0), _vo2(0), - _flags(0), + _flags(flags), _inFlags(0), d(new Instance(this, from, to, frontSector, backSector)) { @@ -431,6 +431,12 @@ Vertex const &Line::vertex(int to) const return to? *d->to : *d->from; } +void Line::replaceVertex(int to, Vertex &newVertex) +{ + if(to) d->to = &newVertex; + else d->from = &newVertex; +} + LineOwner *Line::vertexOwner(int to) const { DENG_ASSERT((to? _vo2 : _vo1) != 0); diff --git a/doomsday/client/src/map/p_data.cpp b/doomsday/client/src/map/p_data.cpp index 14b2eee0d7..e59248488f 100644 --- a/doomsday/client/src/map/p_data.cpp +++ b/doomsday/client/src/map/p_data.cpp @@ -110,6 +110,10 @@ DENG_EXTERN_C boolean P_LoadMap(char const *uriCString) if((theMap = App_MapArchive().loadMap(uri))) { + LOG_INFO("Map Elements: %d Vertexes, %d Lines, %d Sectors, %d BSP Nodes, %d BSP Leafs") + << theMap->vertexCount() << theMap->lineCount() << theMap->sectorCount() + << theMap->bspNodeCount() << theMap->bspLeafCount(); + // Call the game's setup routines. if(gx.SetupForMapData) { diff --git a/doomsday/client/src/map/vertex.cpp b/doomsday/client/src/map/vertex.cpp index 58139a66a5..3c83bca4ee 100644 --- a/doomsday/client/src/map/vertex.cpp +++ b/doomsday/client/src/map/vertex.cpp @@ -1,4 +1,4 @@ -/** @file vertex.cpp Map Geometry Vertex +/** @file vertex.cpp World Map Vertex. * * @authors Copyright © 2003-2013 Jaakko Keränen * @authors Copyright © 2006-2013 Daniel Swanson @@ -18,9 +18,11 @@ * 02110-1301 USA */ -#include "de_base.h" -#include "de_console.h" -#include "de_play.h" +#include /// @todo Remove me. +#include + +#include "dd_share.h" +#include "map/line.h" #include "map/vertex.h" @@ -28,26 +30,22 @@ using namespace de; DENG2_PIMPL(Vertex) { - Instance(Public *i) : Base(i) + /// Original index in the archived map. + uint origIndex; + + Instance(Public *i) + : Base(i), + origIndex(0) {} }; -Vertex::Vertex(coord_t x, coord_t y) : MapElement(DMU_VERTEX) -{ - _origin[VX] = x; - _origin[VY] = y; - _lineOwners = 0; - _numLineOwners = 0; - std::memset(&_buildData, 0, sizeof(_buildData)); -} - -Vertex::Vertex(Vector2d const &origin) : MapElement(DMU_VERTEX) +Vertex::Vertex(Vector2d const &origin) + : MapElement(DMU_VERTEX), d(new Instance(this)) { _origin[VX] = origin.x; _origin[VY] = origin.y; _lineOwners = 0; _numLineOwners = 0; - std::memset(&_buildData, 0, sizeof(_buildData)); } vec2d_t const &Vertex::origin() const @@ -91,6 +89,16 @@ LineOwner *Vertex::firstLineOwner() const return _lineOwners; } +uint Vertex::origIndex() const +{ + return d->origIndex; +} + +void Vertex::setOrigIndex(uint newIndex) +{ + d->origIndex = newIndex; +} + int Vertex::property(setargs_t &args) const { switch(args.prop) diff --git a/doomsday/client/src/resource/maparchive.cpp b/doomsday/client/src/resource/maparchive.cpp index 23923037f6..7e316ebd9d 100644 --- a/doomsday/client/src/resource/maparchive.cpp +++ b/doomsday/client/src/resource/maparchive.cpp @@ -194,6 +194,7 @@ GameMap *MapArchive::Info::convertMap() GameMap *map = MPE_GetLastBuiltMap(); DENG_ASSERT(map != 0); + map->_uri = _uri; // Generate the unique map id.