From 1088c65d97d7cf0b359d0974f17cb1ccd4052353 Mon Sep 17 00:00:00 2001 From: danij Date: Sat, 14 Jun 2014 02:15:33 +0100 Subject: [PATCH] ResourceSystem|CompositeTexture: Dispose of PatchNames once CompositeTextures are initialized, cleanup --- .../include/resource/compositetexture.h | 40 ++--- .../client/src/resource/compositetexture.cpp | 148 ++++++++--------- doomsday/client/src/resource/image.cpp | 4 +- .../client/src/resource/resourcesystem.cpp | 155 +++++++++--------- 4 files changed, 162 insertions(+), 185 deletions(-) diff --git a/doomsday/client/include/resource/compositetexture.h b/doomsday/client/include/resource/compositetexture.h index 67c73c8496..2af4809e21 100644 --- a/doomsday/client/include/resource/compositetexture.h +++ b/doomsday/client/include/resource/compositetexture.h @@ -1,8 +1,7 @@ -/** - * @file compositetexture.h Composite Texture. +/** @file compositetexture.h Composite Texture. * - * @author Copyright © 2003-2013 Jaakko Keränen - * @author Copyright © 2005-2013 Daniel Swanson + * @author Copyright © 2003-2013 Jaakko Keränen + * @author Copyright © 2005-2013 Daniel Swanson * * @par License * GPL: http://www.gnu.org/licenses/gpl.html @@ -48,23 +47,17 @@ class CompositeTexture /** * Flags denoting usage traits. */ - enum Flag - { - Custom = 0x1 /**< The texture does not originate from a definition - of the current game. */ + enum Flag { + Custom = 0x1 ///< The texture does not originate from the current game. }; Q_DECLARE_FLAGS(Flags, Flag) /** * Archived format variants. */ - enum ArchiveFormat - { - /// Original format used by most id-tech 1 games. - DoomFormat, - - /// StrifeFormat differs only slightly from DoomFormat (ommits some unused values). - StrifeFormat + enum ArchiveFormat { + DoomFormat, ///< Format used by most id-tech 1 games. + StrifeFormat ///< Differs slightly from DoomFormat (omits unused values). }; /** @@ -73,7 +66,7 @@ class CompositeTexture struct Component { protected: - explicit Component(int xOrigin = 0, int yOrigin = 0); + explicit Component(Vector2i const &origin = Vector2i()); public: /// Origin of the top left corner of the component (in texture space units). @@ -92,11 +85,8 @@ class CompositeTexture friend class CompositeTexture; private: - /// Origin of the top left corner in the texture coordinate space. - Vector2i origin_; - - /// Index of the lump containing the associated image. - lumpnum_t lumpNum_; + Vector2i _origin; ///< Top left corner in the texture coordinate space. + lumpnum_t _lumpNum; ///< Index of the lump containing the associated image. }; typedef QList Components; @@ -104,8 +94,9 @@ class CompositeTexture /** * Construct a default composite texture. */ - explicit CompositeTexture(String percentEncodedName = "", int logicalWidth = 0, - int logicalHeight = 0, Flags _flags = 0); + explicit CompositeTexture(String const &percentEncodedName = "", + de::Vector2i logicalDimensions = de::Vector2i(), + Flags flags = 0); /** * Construct a composite texture by deserializing an archived id-tech 1 @@ -184,8 +175,7 @@ class CompositeTexture Q_DECLARE_OPERATORS_FOR_FLAGS(CompositeTexture::Flags) -/// A map from String -> CompositeTexture -typedef QMultiMap CompositeTextureMap; +typedef CompositeTexture::Component CompositeTextureComponent; } // namespace de diff --git a/doomsday/client/src/resource/compositetexture.cpp b/doomsday/client/src/resource/compositetexture.cpp index c2615b9426..1dd795ead1 100644 --- a/doomsday/client/src/resource/compositetexture.cpp +++ b/doomsday/client/src/resource/compositetexture.cpp @@ -1,7 +1,7 @@ -/** @file compositetexture.cpp Composite Texture Definition. +/** @file compositetexture.cpp Composite Texture. * - * @authors Copyright © 2003-2013 Jaakko Keränen - * @authors Copyright © 2005-2013 Daniel Swanson + * @authors Copyright © 2003-2014 Jaakko Keränen + * @authors Copyright © 2005-2014 Daniel Swanson * * @par License * GPL: http://www.gnu.org/licenses/gpl.html @@ -18,70 +18,73 @@ * 02110-1301 USA */ -#include "de_platform.h" -#include "de_filesys.h" -#include "resource/patch.h" -#include "resource/patchname.h" +#include "de_base.h" +#include "resource/compositetexture.h" + +#include +#include #include #include #include -#include -#include +#include +#include +#include "resource/patch.h" +#include "resource/patchname.h" -#include "resource/compositetexture.h" +namespace de { +namespace internal { -using namespace de; + static String readAndPercentEncodeRawName(de::Reader &from) + { + /// @attention The raw ASCII name is not necessarily terminated. + char asciiName[9]; + for(int i = 0; i < 8; ++i) { from >> asciiName[i]; } + asciiName[8] = 0; + + // WAD format allows characters not typically permitted in native paths. + // To achieve uniformity we apply a percent encoding to the "raw" names. + return QString(QByteArray(asciiName).toPercentEncoding()); + } -CompositeTexture::Component::Component(int xOrigin, int yOrigin) - : origin_(xOrigin, yOrigin), lumpNum_(-1) +} // namespace internal + +using namespace internal; + +CompositeTexture::Component::Component(Vector2i const &origin) + : _origin (origin) + , _lumpNum(-1) {} Vector2i const &CompositeTexture::Component::origin() const { - return origin_; + return _origin; } lumpnum_t CompositeTexture::Component::lumpNum() const { - return lumpNum_; + return _lumpNum; } -DENG2_PIMPL(CompositeTexture) +DENG2_PIMPL_NOREF(CompositeTexture) { - /// Symbolic name of the texture (percent encoded). - String name; - - /// Flags denoting usage traits. - CompositeTexture::Flags flags; - - /// Logical dimensions of the texture in map coordinate space units. - Vector2i logicalDimensions; - - /// Dimensions of the texture in pixels. - Vector2i dimensions; - - /// Index of this resource determined by the logic of the indexing algorithm - /// used by the original game. - int origIndex; - - /// Set of component images to be composited. - Components components; - - Instance(Public *i, String percentEncodedName, int width, int height, - CompositeTexture::Flags _flags) - : Base(i), - name(percentEncodedName), - flags(_flags), - logicalDimensions(width, height), - dimensions(0, 0), - origIndex(-1) - {} + String name; ///< Symbolic, percent encoded. + Flags flags; ///< Usage traits. + Vector2i logicalDimensions; ///< In map space units. + Vector2i dimensions; ///< In pixels. + int origIndex; ///< Determined by the original game logic. + Components components; ///< Images to be composited. + + Instance() : origIndex(-1) {} }; -CompositeTexture::CompositeTexture(String percentEncodedName, - int width, int height, Flags flags) - : d(new Instance(this, percentEncodedName, width, height, flags)) -{} +CompositeTexture::CompositeTexture(String const &percentEncodedName, + Vector2i logicalDimensions, Flags flags) + : d(new Instance) +{ + d->name = percentEncodedName; + d->flags = flags; + d->logicalDimensions = logicalDimensions; +} String CompositeTexture::percentEncodedName() const { @@ -128,18 +131,6 @@ void CompositeTexture::setOrigIndex(int newIndex) d->origIndex = newIndex; } -static String readAndPercentEncodeRawName(de::Reader &from) -{ - /// @attention The raw ASCII name is not necessarily terminated. - char asciiName[9]; - for(int i = 0; i < 8; ++i) { from >> asciiName[i]; } - asciiName[8] = 0; - - // WAD format allows characters not typically permitted in native paths. - // To achieve uniformity we apply a percent encoding to the "raw" names. - return QString(QByteArray(asciiName).toPercentEncoding()); -} - CompositeTexture *CompositeTexture::constructFrom(de::Reader &reader, QList patchNames, ArchiveFormat format) { @@ -161,10 +152,8 @@ CompositeTexture *CompositeTexture::constructFrom(de::Reader &reader, // We'll initially accept these values as logical dimensions. However // we may need to adjust once we've checked the patch dimensions. - pctex->d->logicalDimensions.x = dimensions[0]; - pctex->d->logicalDimensions.y = dimensions[1]; - - pctex->d->dimensions = pctex->d->logicalDimensions; + pctex->d->logicalDimensions = + pctex->d->dimensions = Vector2i(dimensions[0], dimensions[1]); if(format == DoomFormat) { @@ -187,12 +176,11 @@ CompositeTexture *CompositeTexture::constructFrom(de::Reader &reader, int foundComponentCount = 0; for(dint16 i = 0; i < componentCount; ++i) { - Component patch; + Component comp; dint16 origin16[2]; reader >> origin16[0] >> origin16[1]; - patch.origin_.x = origin16[0]; - patch.origin_.y = origin16[1]; + comp._origin = Vector2i(origin16[0], origin16[1]); dint16 pnamesIndex; reader >> pnamesIndex; @@ -200,18 +188,18 @@ CompositeTexture *CompositeTexture::constructFrom(de::Reader &reader, if(pnamesIndex < 0 || pnamesIndex >= patchNames.count()) { LOG_RES_WARNING("Invalid PNAMES index %i in composite texture \"%s\", ignoring.") - << pnamesIndex << pctex->d->name; + << pnamesIndex << pctex->d->name; } else { - patch.lumpNum_ = patchNames[pnamesIndex].lumpNum(); + comp._lumpNum = patchNames[pnamesIndex].lumpNum(); - if(patch.lumpNum() >= 0) + if(comp.lumpNum() >= 0) { /// There is now one more found component. foundComponentCount += 1; - de::File1 &file = App_FileSystem().nameIndex()[patch.lumpNum_]; + de::File1 &file = App_FileSystem().nameIndex()[comp.lumpNum()]; // If this a "custom" component - the whole texture is. if(file.container().hasCustom()) @@ -226,15 +214,15 @@ CompositeTexture *CompositeTexture::constructFrom(de::Reader &reader, try { Patch::Metadata info = Patch::loadMetadata(fileData); - geom |= QRect(QPoint(patch.origin_.x, patch.origin_.y), + geom |= QRect(QPoint(comp.origin().x, comp.origin().y), QSize(info.dimensions.x, info.dimensions.y)); } catch(IByteArray::OffsetError const &) { LOG_RES_WARNING("Component image \"%s\" (#%i) does not appear to be a valid Patch. " "It may be missing from composite texture \"%s\".") - << patchNames[pnamesIndex].percentEncodedNameRef() << i - << pctex->d->name; + << patchNames[pnamesIndex].percentEncodedNameRef() << i + << pctex->d->name; } } file.unlock(); @@ -242,8 +230,8 @@ CompositeTexture *CompositeTexture::constructFrom(de::Reader &reader, else { LOG_RES_WARNING("Missing component image \"%s\" (#%i) in composite texture \"%s\", ignoring.") - << patchNames[pnamesIndex].percentEncodedNameRef() << i - << pctex->d->name; + << patchNames[pnamesIndex].percentEncodedNameRef() << i + << pctex->d->name; } } @@ -251,19 +239,23 @@ CompositeTexture *CompositeTexture::constructFrom(de::Reader &reader, reader >> unused16 >> unused16; // Add this component. - pctex->d->components.push_back(patch); + pctex->d->components.push_back(comp); } // Clip and apply the final height. if(geom.top() < 0) geom.setTop(0); if(geom.height() > pctex->d->logicalDimensions.y) + { pctex->d->dimensions.y = geom.height(); + } if(!foundComponentCount) { - LOG_RES_WARNING("Zero valid component images in composite texture %s, ignoring.") + LOG_RES_WARNING("Zero valid component images in composite texture %s (will be ignored).") << pctex->d->name; } return pctex; } + +} // namespace de diff --git a/doomsday/client/src/resource/image.cpp b/doomsday/client/src/resource/image.cpp index e92483a4ac..32344e8165 100644 --- a/doomsday/client/src/resource/image.cpp +++ b/doomsday/client/src/resource/image.cpp @@ -655,7 +655,7 @@ static Source loadPatchComposite(image_t &image, Texture const &tex, CompositeTexture const &texDef = *reinterpret_cast(tex.userDataPointer()); DENG2_FOR_EACH_CONST(CompositeTexture::Components, i, texDef.components()) { - de::File1 &file = App_FileSystem().nameIndex()[i->lumpNum()]; + de::File1 &file = App_FileSystem().nameIndex()[i->lumpNum()]; ByteRefArray fileData = ByteRefArray(file.cache(), file.size()); // A DOOM patch? @@ -666,7 +666,7 @@ static Source loadPatchComposite(image_t &image, Texture const &tex, Patch::Flags loadFlags; if(maskZero) loadFlags |= Patch::MaskZero; - Block patchImg = Patch::load(fileData, loadFlags); + Block patchImg = Patch::load(fileData, loadFlags); PatchMetadata info = Patch::loadMetadata(fileData); Vector2i origin = i->origin(); diff --git a/doomsday/client/src/resource/resourcesystem.cpp b/doomsday/client/src/resource/resourcesystem.cpp index 49432ec089..8142c5f18f 100644 --- a/doomsday/client/src/resource/resourcesystem.cpp +++ b/doomsday/client/src/resource/resourcesystem.cpp @@ -88,6 +88,7 @@ using namespace de; typedef QList CompositeTextures; +typedef QList PatchNames; static QList collectPatchCompositeDefinitionFiles(); @@ -212,9 +213,6 @@ DENG2_PIMPL(ResourceSystem) typedef QList AnimGroups; AnimGroups animGroups; - typedef QList PatchNames; - PatchNames patchNames; - typedef QMap ColorPalettes; ColorPalettes colorPalettes; @@ -473,7 +471,7 @@ DENG2_PIMPL(ResourceSystem) self.clearAllColorPalettes(); } - inline de::FS1 &fileSystem() + inline de::FS1 &fileSys() { return App_FileSystem(); } @@ -940,75 +938,75 @@ DENG2_PIMPL(ResourceSystem) } } - void loadPatchNames(String lumpName) + PatchNames loadPatchNames(de::File1 &file) { LOG_AS("loadPatchNames"); + PatchNames names; - // Clear any previously exisiting names. - patchNames.clear(); - - try + if(file.size() < 4) { - lumpnum_t lumpNum = fileSystem().lumpNumForName(lumpName); - de::File1 &file = fileSystem().nameIndex()[lumpNum]; - - if(file.size() < 4) - { - LOG_RES_WARNING("File \"%s\" (#%i) does not appear to be valid PNAMES data") - << NativePath(file.composeUri().asText()).pretty() << lumpNum; - return; - } + LOG_RES_WARNING("File \"%s\" does not appear to be valid PNAMES data") + << NativePath(file.composeUri().asText()).pretty(); + return names; + } - ByteRefArray lumpData = ByteRefArray(file.cache(), file.size()); - de::Reader from = de::Reader(lumpData); + ByteRefArray lumpData(file.cache(), file.size()); + de::Reader from(lumpData); - // The data begins with the total number of patch names. - dint32 numNames; - from >> numNames; + // The data begins with the total number of patch names. + dint32 numNames; + from >> numNames; - // Followed by the names (eight character ASCII strings). - if(numNames > 0) + // Followed by the names (eight character ASCII strings). + if(numNames > 0) + { + if((unsigned) numNames > (file.size() - 4) / 8) { - if((unsigned) numNames > (file.size() - 4) / 8) - { - // The data appears to be truncated. - LOG_RES_WARNING("File \"%s\" (#%i) appears to be truncated (%u bytes, expected %u)") - << NativePath(file.composeUri().asText()).pretty() << lumpNum - << file.size() << (numNames * 8 + 4); - - // We'll only read this many names. - numNames = (file.size() - 4) / 8; - } + // The data appears to be truncated. + LOG_RES_WARNING("File \"%s\" appears to be truncated (%u bytes, expected %u)") + << NativePath(file.composeUri().asText()).pretty() + << file.size() << (numNames * 8 + 4); - // Read the names. - for(int i = 0; i < numNames; ++i) - { - PatchName name; - from >> name; - patchNames.append(name); - } + // We'll only read this many names. + numNames = (file.size() - 4) / 8; } - file.unlock(); - } - catch(LumpIndex::NotFoundError const &er) - { - if(App_GameLoaded()) + // Read the names. + for(int i = 0; i < numNames; ++i) { - LOGDEV_RES_WARNING(er.asText()); + PatchName name; + from >> name; + names.append(name); } } + + file.unlock(); + + return names; } CompositeTextures loadCompositeTextureDefs() { LOG_AS("loadCompositeTextureDefs"); + typedef QMultiMap CompositeTextureMap; + // Load the patch names from the PNAMES lump. - loadPatchNames("PNAMES"); + PatchNames pnames; + try + { + pnames = loadPatchNames(fileSys().nameIndex()[fileSys().lumpNumForName("PNAMES")]); + } + catch(LumpIndex::NotFoundError const &er) + { + if(App_GameLoaded()) + { + LOGDEV_RES_WARNING(er.asText()); + } + } // If no patch names - there is no point continuing further. - if(!patchNames.count()) return CompositeTextures(); + if(!pnames.count()) return CompositeTextures(); // Collate an ordered list of all the definition files we intend to process. QList defFiles = collectPatchCompositeDefinitionFiles(); @@ -1035,18 +1033,15 @@ DENG2_PIMPL(ResourceSystem) << NativePath(file.container().composeUri().asText()).pretty() << NativePath(file.composeUri().asText()).pretty(); - // Buffer the file. - ByteRefArray dataBuffer = ByteRefArray(file.cache(), file.size()); - - // Read the next set of definitions. + // Buffer the file and read the next set of definitions. int archiveCount; - CompositeTextures newDefs = readCompositeTextureDefs(dataBuffer, origIndexBase, archiveCount); + ByteRefArray dataBuffer = ByteRefArray(file.cache(), file.size()); + CompositeTextures newDefs = readCompositeTextureDefs(dataBuffer, pnames, origIndexBase, archiveCount); - // We have now finished with this file. - file.unlock(); + file.unlock(); // We have now finished with this file. // In which set do these belong? - CompositeTextures* existingDefs = + CompositeTextures *existingDefs = (file.container().hasCustom()? &customDefs : &defs); if(!existingDefs->isEmpty()) @@ -1113,8 +1108,8 @@ DENG2_PIMPL(ResourceSystem) // Check the patches. for(int k = 0; k < orig->componentCount(); ++k) { - CompositeTexture::Component const &origP = orig->components()[k]; - CompositeTexture::Component const &customP = custom->components()[k]; + CompositeTextureComponent const &origP = orig->components()[k]; + CompositeTextureComponent const &customP = custom->components()[k]; if(origP.lumpNum() != customP.lumpNum() && origP.xOrigin() != customP.xOrigin() && @@ -1140,8 +1135,8 @@ DENG2_PIMPL(ResourceSystem) } /* - * List 'defs' now contains only those definitions which are not superceeded - * by those in the 'customDefs' list. + * List 'defs' now contains only those definitions which are not + * superceeded by those in the 'customDefs' list. */ // Add definitions from the custom list to the end of the main set. @@ -1161,7 +1156,7 @@ DENG2_PIMPL(ResourceSystem) * number of definitions which are actually read). */ CompositeTextures readCompositeTextureDefs(IByteArray &data, - int origIndexBase, int& archiveCount) + PatchNames const &patchNames, int origIndexBase, int &archiveCount) { LOG_AS("readCompositeTextureDefs"); @@ -1378,16 +1373,16 @@ DENG2_PIMPL(ResourceSystem) // The "first choice" directory is that in which the model file resides. try { - return fileSystem().findPath(de::Uri("Models", modelFilePath.toString().fileNamePath() / skinPath.fileName()), - RLF_DEFAULT, self.resClass(RC_GRAPHIC)); + return fileSys().findPath(de::Uri("Models", modelFilePath.toString().fileNamePath() / skinPath.fileName()), + RLF_DEFAULT, self.resClass(RC_GRAPHIC)); } catch(FS1::NotFoundError const &) {} // Ignore this error. } /// @throws FS1::NotFoundError if no resource was found. - return fileSystem().findPath(de::Uri("Models", skinPath), RLF_DEFAULT, - self.resClass(RC_GRAPHIC)); + return fileSys().findPath(de::Uri("Models", skinPath), RLF_DEFAULT, + self.resClass(RC_GRAPHIC)); } /** @@ -1447,8 +1442,8 @@ DENG2_PIMPL(ResourceSystem) try { - String foundPath = fileSystem().findPath(searchPath, RLF_DEFAULT, - self.resClass(RC_GRAPHIC)); + String foundPath = fileSys().findPath(searchPath, RLF_DEFAULT, + self.resClass(RC_GRAPHIC)); // Ensure the found path is absolute. foundPath = App_BasePath() / foundPath; @@ -1589,8 +1584,8 @@ DENG2_PIMPL(ResourceSystem) try { - String foundPath = fileSystem().findPath(searchPath, RLF_DEFAULT, - self.resClass(RC_MODEL)); + String foundPath = fileSys().findPath(searchPath, RLF_DEFAULT, + self.resClass(RC_MODEL)); // Ensure the found path is absolute. foundPath = App_BasePath() / foundPath; @@ -1600,12 +1595,12 @@ DENG2_PIMPL(ResourceSystem) if(!mdl) { // Attempt to load it in now. - QScopedPointer hndl(&fileSystem().openFile(foundPath, "rb")); + QScopedPointer hndl(&fileSys().openFile(foundPath, "rb")); mdl = Model::loadFromFile(*hndl, modelAspectMod); // We're done with the file. - fileSystem().releaseFile(hndl->file()); + fileSys().releaseFile(hndl->file()); // Loaded? if(mdl) @@ -2236,13 +2231,13 @@ void ResourceSystem::initCompositeTextures() Time begunAt; LOG_AS("ResourceSystem"); - LOG_RES_VERBOSE("Initializing PatchComposite textures..."); + LOG_RES_VERBOSE("Initializing CompositeTextures..."); // Load texture definitions from TEXTURE1/2 lumps. CompositeTextures texs = d->loadCompositeTextureDefs(); d->processCompositeTextureDefs(texs); - DENG_ASSERT(texs.isEmpty()); + DENG2_ASSERT(texs.isEmpty()); LOG_RES_VERBOSE("initCompositeTextures: Completed in %.2f seconds") << begunAt.since(); } @@ -2254,7 +2249,7 @@ void ResourceSystem::initFlatTextures() LOG_AS("ResourceSystem"); LOG_RES_VERBOSE("Initializing Flat textures..."); - LumpIndex const &index = d->fileSystem().nameIndex(); + LumpIndex const &index = d->fileSys().nameIndex(); lumpnum_t firstFlatMarkerLumpNum = index.findFirst(Path("F_START.lmp")); if(firstFlatMarkerLumpNum >= 0) { @@ -2393,7 +2388,7 @@ void ResourceSystem::initSpriteTextures() /// @todo fixme: Order here does not respect id tech1 logic. ddstack_t *stack = Stack_New(); - LumpIndex const &index = d->fileSystem().nameIndex(); + LumpIndex const &index = d->fileSys().nameIndex(); for(int i = 0; i < index.size(); ++i) { de::File1 &file = index[i]; @@ -2563,14 +2558,14 @@ patchid_t ResourceSystem::declarePatch(String encodedName) {} // Ignore this error. Path lumpPath = uri.path() + ".lmp"; - lumpnum_t lumpNum = d->fileSystem().nameIndex().findLast(lumpPath); + lumpnum_t lumpNum = d->fileSys().nameIndex().findLast(lumpPath); if(lumpNum < 0) { LOG_RES_WARNING("Failed to locate lump for \"%s\"") << uri; return 0; } - de::File1 &file = d->fileSystem().nameIndex().toLump(lumpNum); + de::File1 &file = d->fileSys().nameIndex().toLump(lumpNum); Texture::Flags flags; if(file.container().hasCustom()) flags |= Texture::Custom; @@ -3193,7 +3188,7 @@ AbstractFont *ResourceSystem::newFontFromFile(de::Uri const &uri, String filePat { LOG_AS("ResourceSystem::newFontFromFile"); - if(!d->fileSystem().accessFile(de::Uri::fromNativePath(filePath))) + if(!d->fileSys().accessFile(de::Uri::fromNativePath(filePath))) { LOGDEV_RES_WARNING("Ignoring invalid filePath: ") << filePath; return 0;