diff --git a/doomsday/engine/api/resourceclass.h b/doomsday/engine/api/resourceclass.h index 9f5d52c4bd..3c30b9e18b 100644 --- a/doomsday/engine/api/resourceclass.h +++ b/doomsday/engine/api/resourceclass.h @@ -75,7 +75,7 @@ namespace de struct ResourceClass { public: - typedef QList Types; + typedef QList Types; public: ResourceClass(String _name, String _defaultNamespace) @@ -108,7 +108,7 @@ namespace de * @param rtype Identifier of the resourceType to add. * @return This instance. */ - ResourceClass& addResourceType(resourcetypeid_e rtype) + ResourceClass& addResourceType(ResourceType* rtype) { searchTypeOrder.push_back(rtype); return *this; diff --git a/doomsday/engine/api/resourcetype.h b/doomsday/engine/api/resourcetype.h index f4c11f259c..14435ec5d6 100644 --- a/doomsday/engine/api/resourcetype.h +++ b/doomsday/engine/api/resourcetype.h @@ -26,65 +26,32 @@ #ifndef LIBDENG_RESOURCETYPE_H #define LIBDENG_RESOURCETYPE_H -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Resource Type identifer attributable to resources (e.g., files). - * - * @ingroup core - * - * @todo Refactor away. These identifiers are no longer needed. - */ -typedef enum resourcetypeid_e { - RT_NONE = 0, - RT_FIRST = 1, - RT_ZIP = RT_FIRST, - RT_WAD, - RT_LMP, - RT_DED, - RT_PNG, - RT_JPG, - RT_TGA, - RT_PCX, - RT_DMD, - RT_MD2, - RT_WAV, - RT_OGG, - RT_MP3, - RT_MOD, - RT_MID, - RT_DEH, - RT_DFN, - RT_LAST_INDEX -} resourcetypeid_t; - -#define RESOURCETYPE_COUNT (RT_LAST_INDEX - 1) -#define VALID_RESOURCE_TYPEID(v) ((v) >= RT_FIRST && (v) < RT_LAST_INDEX) - -#ifdef __cplusplus -} // extern "C" -#endif - #ifdef __cplusplus #ifndef DENG2_C_API_ONLY #include +#include +#include #include +#include "filehandle.h" enum resourceclassid_e; namespace de { + struct FileInfo; + /** * Encapsulates the properties and logics belonging to a logical * type of resource (e.g., Zip, PNG, WAV, etc...) * * @ingroup core */ - struct ResourceType + class ResourceType { + public: + typedef de::File1* (*InterpretFunc)(de::FileHandle& hndl, String path, FileInfo const& info); + public: ResourceType(String _name, resourceclassid_e _defaultClass) : name_(_name), defaultClass_(_defaultClass) @@ -104,12 +71,6 @@ namespace de return defaultClass_; } - /// Return the number of known extensions for this type of resource. - int knownExtensionCount() const - { - return knownFileNameExtensions_.count(); - } - /** * Add a new known extension to this resource type. Earlier extensions * have priority. @@ -167,8 +128,9 @@ namespace de * * @ingroup core */ - struct NullResourceType : public ResourceType + class NullResourceType : public ResourceType { + public: NullResourceType() : ResourceType("RT_NONE", RC_UNKNOWN) {} }; @@ -178,6 +140,33 @@ namespace de return !!dynamic_cast(&rtype); } + /** + * Base class for all file resource types. + */ + class FileResourceType : public ResourceType + { + public: + FileResourceType(String name, resourceclassid_t rclassId) + : ResourceType(name, rclassId) + {} + + /** + * Attempt to interpret a file resource of this type. + * + * @param hndl Handle to the file to be interpreted. + * @param path VFS path to associate with the file. + * @param info File metadata info to attach to the file. + * + * @return The interpreted file; otherwise @c 0. + */ + virtual de::File1* interpret(de::FileHandle& /*hndl*/, String /*path*/, FileInfo const& /*info*/) const = 0; + }; + + /// @return @c true= @a rtype is a FileResourceType object. + inline bool isFileResourceType(ResourceType const& rtype) { + return !!dynamic_cast(&rtype); + } + } // namespace de #endif // DENG2_C_API_ONLY #endif // __cplusplus diff --git a/doomsday/engine/include/de_platform.h b/doomsday/engine/include/de_platform.h index dfbb2c6a5b..0563b98099 100644 --- a/doomsday/engine/include/de_platform.h +++ b/doomsday/engine/include/de_platform.h @@ -58,7 +58,7 @@ #define stricmp _stricmp #define strnicmp _strnicmp #define open _open -#define close _close +//#define close _close //#define read _read //#define write _write #define access _access diff --git a/doomsday/engine/include/resource/sys_reslocator.h b/doomsday/engine/include/resource/sys_reslocator.h index 279cfd2417..236b50823a 100644 --- a/doomsday/engine/include/resource/sys_reslocator.h +++ b/doomsday/engine/include/resource/sys_reslocator.h @@ -123,6 +123,8 @@ typedef QList ResourceNamespaces; */ de::ResourceNamespace* F_ResourceNamespaceByName(de::String name); +de::ResourceTypes const& F_ResourceTypes(); + de::ResourceNamespaces const& F_ResourceNamespaces(); /** @@ -133,7 +135,7 @@ de::ResourceNamespaces const& F_ResourceNamespaces(); * @param classId Unique identifier of the class. * @return ResourceClass associated with @a id; otherwise @c 0 (not found). */ -de::ResourceClass const* F_ResourceClassById(resourceclassid_t classId); +de::ResourceClass* F_ResourceClassById(resourceclassid_t classId); /** * Lookup a ResourceClass by symbolic name. @@ -141,17 +143,7 @@ de::ResourceClass const* F_ResourceClassById(resourceclassid_t classId); * @param name Symbolic name of the class. * @return ResourceClass associated with @a name; otherwise @c 0 (not found). */ -de::ResourceClass const& F_ResourceClassByName(de::String name); - -/** - * Lookup a ResourceType by id. - * - * @todo Refactor away. - * - * @param typeId Unique identifier of the type. - * @return ResourceType associated with @a id; otherwise @c 0 (not found). - */ -de::ResourceType const* F_ResourceTypeById(resourcetypeid_t typeId); +de::ResourceClass& F_ResourceClassByName(de::String name); /** * Lookup a ResourceType by symbolic name. @@ -159,7 +151,7 @@ de::ResourceType const* F_ResourceTypeById(resourcetypeid_t typeId); * @param name Symbolic name of the type. * @return ResourceType associated with @a name. May return a null-object. */ -de::ResourceType const& F_ResourceTypeByName(de::String name); +de::ResourceType& F_ResourceTypeByName(de::String name); /** * Attempts to determine which "type" should be attributed to a resource, solely @@ -167,7 +159,7 @@ de::ResourceType const& F_ResourceTypeByName(de::String name); * * @return Type determined for this resource. May return a null-object. */ -de::ResourceType const& F_GuessResourceTypeFromFileName(de::String name); +de::ResourceType& F_GuessResourceTypeFromFileName(de::String name); #endif // __cplusplus diff --git a/doomsday/engine/src/dd_main.cpp b/doomsday/engine/src/dd_main.cpp index 83dbf7a369..646d07b7e4 100644 --- a/doomsday/engine/src/dd_main.cpp +++ b/doomsday/engine/src/dd_main.cpp @@ -58,6 +58,7 @@ #include "texture.h" #include "updater.h" #include "filesys/wad.h" +#include "resource/sys_reslocator.h" using namespace de; diff --git a/doomsday/engine/src/filesys/fs_main.cpp b/doomsday/engine/src/filesys/fs_main.cpp index 566975329d..ef0eb7d747 100644 --- a/doomsday/engine/src/filesys/fs_main.cpp +++ b/doomsday/engine/src/filesys/fs_main.cpp @@ -46,6 +46,7 @@ #include "game.h" #include "lumpindex.h" #include "resourcenamespace.h" +#include "resource/sys_reslocator.h" using namespace de; @@ -1002,63 +1003,33 @@ int FS1::findAllPaths(String searchPattern, int flags, FS1::PathList& found) return found.count() - numFoundSoFar; } -struct FileInterpreter -{ - resourcetypeid_t resourceType; - de::File1* (*interpret)(de::FileHandle& hndl, String path, FileInfo const& info); -}; - -static de::File1* interpretAsZipFile(de::FileHandle& hndl, String path, FileInfo const& info) -{ - if(!Zip::recognise(hndl)) return 0; - LOG_VERBOSE("Interpreted \"") << NativePath(path).pretty() << "\" as a Zip (archive)"; - return new Zip(hndl, path, info); -} - -static de::File1* interpretAsWadFile(de::FileHandle& hndl, String path, FileInfo const& info) -{ - if(!Wad::recognise(hndl)) return 0; - LOG_VERBOSE("Interpreted \"") << NativePath(path).pretty() << "\" as a Wad (archive)"; - return new Wad(hndl, path, info); -} - de::File1& FS1::interpret(de::FileHandle& hndl, String path, FileInfo const& info) { DENG_ASSERT(!path.isEmpty()); - static FileInterpreter interpreters[] = { - { RT_ZIP, interpretAsZipFile }, - { RT_WAD, interpretAsWadFile }, - { RT_NONE, NULL } - }; - de::File1* interpretedFile = 0; // Firstly try interpreter(s) for guessed resource types. ResourceType const& rtypeGuess = F_GuessResourceTypeFromFileName(path); - if(!isNullResourceType(rtypeGuess)) + if(FileResourceType const* fileType = dynamic_cast(&rtypeGuess)) { - for(FileInterpreter* intper = interpreters; intper->interpret; ++intper) - { - // Not applicable for this resource type? - if(F_ResourceTypeById(intper->resourceType) != &rtypeGuess) continue; - - interpretedFile = intper->interpret(hndl, path, info); - if(interpretedFile) break; - } + interpretedFile = fileType->interpret(hndl, path, info); } // If not yet interpreted - try each recognisable format in order. - /// @todo Order here should be determined by the resource locator. if(!interpretedFile) { - for(FileInterpreter* intper = interpreters; intper->interpret; ++intper) + ResourceTypes const& rtypes = F_ResourceTypes(); + DENG2_FOR_EACH_CONST(ResourceTypes, i, rtypes) { - // Already tried this? - if(F_ResourceTypeById(intper->resourceType) == &rtypeGuess) continue; + if(FileResourceType const* fileType = dynamic_cast(*i)) + { + // Already tried this? + if(fileType == &rtypeGuess) continue; - interpretedFile = intper->interpret(hndl, path, info); - if(interpretedFile) break; + interpretedFile = fileType->interpret(hndl, path, info); + if(interpretedFile) break; + } } } diff --git a/doomsday/engine/src/filesys/zip.cpp b/doomsday/engine/src/filesys/zip.cpp index cb9a5f4ebb..6982635786 100644 --- a/doomsday/engine/src/filesys/zip.cpp +++ b/doomsday/engine/src/filesys/zip.cpp @@ -31,6 +31,7 @@ #include "lumpcache.h" #include "pathtree.h" #include "resourcenamespace.h" +#include "sys_reslocator.h" #include #include diff --git a/doomsday/engine/src/m_misc.c b/doomsday/engine/src/m_misc.c index 5e55cbab59..0fd7d57f2a 100644 --- a/doomsday/engine/src/m_misc.c +++ b/doomsday/engine/src/m_misc.c @@ -66,6 +66,7 @@ #define DBITS (FRACBITS-SLOPEBITS) #if defined(WIN32) +#define close _close #define read _read #define write _write #endif diff --git a/doomsday/engine/src/resource/sys_reslocator.cpp b/doomsday/engine/src/resource/sys_reslocator.cpp index 4b8633de57..0df346261f 100644 --- a/doomsday/engine/src/resource/sys_reslocator.cpp +++ b/doomsday/engine/src/resource/sys_reslocator.cpp @@ -42,23 +42,52 @@ using namespace de; +class ZipResourceType : public de::FileResourceType +{ +public: + ZipResourceType() : FileResourceType("RT_ZIP", RC_PACKAGE) + {} + + de::File1* interpret(de::FileHandle& hndl, String path, FileInfo const& info) const + { + if(Zip::recognise(hndl)) + { + LOG_AS("ZipResourceType"); + LOG_VERBOSE("Interpreted \"" + NativePath(path).pretty() + "\"."); + return new Zip(hndl, path, info); + } + return 0; + } +}; + +class WadResourceType : public de::FileResourceType +{ +public: + WadResourceType() : FileResourceType("RT_WAD", RC_PACKAGE) + {} + + de::File1* interpret(de::FileHandle& hndl, String path, FileInfo const& info) const + { + if(Wad::recognise(hndl)) + { + LOG_AS("WadResourceType"); + LOG_VERBOSE("Interpreted \"" + NativePath(path).pretty() + "\"."); + return new Wad(hndl, path, info); + } + return 0; + } +}; + static bool inited = false; -static NullResourceClass const nullClass; -static NullResourceType const nullType; +static NullResourceClass nullClass; +static NullResourceType nullType; static ResourceTypes types; static ResourceClasses classes; static ResourceNamespaces namespaces; -static inline ResourceType const& resourceType(resourcetypeid_t id) -{ - if(id == RT_NONE) return nullType; - if(!VALID_RESOURCE_TYPEID(id)) throw Error("resourceType", String("Invalid id %1").arg(id)); - return *types[uint(id) - 1]; -} - -static inline ResourceClass const& resourceClass(resourceclassid_t id) +static inline ResourceClass& resourceClass(resourceclassid_t id) { if(id == RC_NULL) return nullClass; if(!VALID_RESOURCE_CLASSID(id)) throw Error("resourceClass", String("Invalid id %1").arg(id)); @@ -174,8 +203,7 @@ static bool findResource2(int flags, resourceclassid_t classId, String searchPat DENG2_FOR_EACH_CONST(ResourceClass::Types, typeIt, rclass.resourceTypes()) { - ResourceType const& rtype = resourceType(*typeIt); - DENG2_FOR_EACH_CONST(QStringList, i, rtype.knownFileNameExtensions()) + DENG2_FOR_EACH_CONST(QStringList, i, (*typeIt)->knownFileNameExtensions()) { String const& ext = *i; if(findResource3(rnamespace, de::Uri(path2 + ext, RC_NULL), foundPath)) @@ -360,118 +388,134 @@ static void createResourceNamespaces() static void createResourceClasses() { - ResourceClass* rclass; - - classes.push_back(new ResourceClass("RC_PACKAGE", "Packages")); - rclass = classes.back(); - rclass->addResourceType(RT_ZIP); // Favor ZIP over WAD. - rclass->addResourceType(RT_WAD); - - classes.push_back(new ResourceClass("RC_DEFINITION", "Defs")); - rclass = classes.back(); - rclass->addResourceType(RT_DED); - - classes.push_back(new ResourceClass("RC_GRAPHIC", "Graphics")); - rclass = classes.back(); - rclass->addResourceType(RT_PNG); // Favour quality. - rclass->addResourceType(RT_TGA); - rclass->addResourceType(RT_JPG); - rclass->addResourceType(RT_PCX); - - classes.push_back(new ResourceClass("RC_MODEL", "Models")); - rclass = classes.back(); - rclass->addResourceType(RT_DMD); // Favour DMD over MD2. - rclass->addResourceType(RT_MD2); - - classes.push_back(new ResourceClass("RC_SOUND", "Sfx")); - rclass = classes.back(); - rclass->addResourceType(RT_WAV); - - classes.push_back(new ResourceClass("RC_MUSIC", "Music")); - rclass = classes.back(); - rclass->addResourceType(RT_OGG); // Favour quality. - rclass->addResourceType(RT_MP3); - rclass->addResourceType(RT_WAV); - rclass->addResourceType(RT_MOD); - rclass->addResourceType(RT_MID); - - classes.push_back(new ResourceClass("RC_FONT", "Fonts")); - rclass = classes.back(); - rclass->addResourceType(RT_DFN); + classes.push_back(new ResourceClass("RC_PACKAGE", "Packages")); + classes.push_back(new ResourceClass("RC_DEFINITION", "Defs")); + classes.push_back(new ResourceClass("RC_GRAPHIC", "Graphics")); + classes.push_back(new ResourceClass("RC_MODEL", "Models")); + classes.push_back(new ResourceClass("RC_SOUND", "Sfx")); + classes.push_back(new ResourceClass("RC_MUSIC", "Music")); + classes.push_back(new ResourceClass("RC_FONT", "Fonts")); } static void createResourceTypes() { ResourceType* rtype; - types.push_back(new ResourceType("RT_ZIP", RC_PACKAGE)); + /* + * Packages types: + */ + ResourceClass& packageClass = F_ResourceClassByName("RC_PACKAGE"); + + types.push_back(new ZipResourceType()); rtype = types.back(); rtype->addKnownExtension(".pk3"); rtype->addKnownExtension(".zip"); + packageClass.addResourceType(rtype); - types.push_back(new ResourceType("RT_WAD", RC_PACKAGE)); + types.push_back(new WadResourceType()); rtype = types.back(); rtype->addKnownExtension(".wad"); + packageClass.addResourceType(rtype); types.push_back(new ResourceType("RT_LMP", RC_PACKAGE)); ///< Treat lumps as packages so they are mapped to $App.DataPath. rtype = types.back(); rtype->addKnownExtension(".lmp"); + /* + * Definition types: + */ types.push_back(new ResourceType("RT_DED", RC_DEFINITION)); rtype = types.back(); rtype->addKnownExtension(".ded"); + F_ResourceClassByName("RC_DEFINITION").addResourceType(rtype); + + /* + * Graphic types: + */ + ResourceClass& graphicClass = F_ResourceClassByName("RC_GRAPHIC"); types.push_back(new ResourceType("RT_PNG", RC_GRAPHIC)); rtype = types.back(); rtype->addKnownExtension(".png"); - - types.push_back(new ResourceType("RT_JPG", RC_GRAPHIC)); - rtype = types.back(); - rtype->addKnownExtension(".jpg"); + graphicClass.addResourceType(rtype); types.push_back(new ResourceType("RT_TGA", RC_GRAPHIC)); rtype = types.back(); rtype->addKnownExtension(".tga"); + graphicClass.addResourceType(rtype); + + types.push_back(new ResourceType("RT_JPG", RC_GRAPHIC)); + rtype = types.back(); + rtype->addKnownExtension(".jpg"); + graphicClass.addResourceType(rtype); types.push_back(new ResourceType("RT_PCX", RC_GRAPHIC)); rtype = types.back(); rtype->addKnownExtension(".pcx"); + graphicClass.addResourceType(rtype); + + /* + * Model types: + */ + ResourceClass& modelClass = F_ResourceClassByName("RC_MODEL"); types.push_back(new ResourceType("RT_DMD", RC_MODEL)); rtype = types.back(); rtype->addKnownExtension(".dmd"); + modelClass.addResourceType(rtype); types.push_back(new ResourceType("RT_MD2", RC_MODEL)); rtype = types.back(); rtype->addKnownExtension(".md2"); + modelClass.addResourceType(rtype); + /* + * Sound types: + */ types.push_back(new ResourceType("RT_WAV", RC_SOUND)); rtype = types.back(); rtype->addKnownExtension(".wav"); + F_ResourceClassByName("RC_SOUND").addResourceType(rtype); + + /* + * Music types: + */ + ResourceClass& musicClass = F_ResourceClassByName("RC_MUSIC"); types.push_back(new ResourceType("RT_OGG", RC_MUSIC)); rtype = types.back(); rtype->addKnownExtension(".ogg"); + musicClass.addResourceType(rtype); types.push_back(new ResourceType("RT_MP3", RC_MUSIC)); rtype = types.back(); rtype->addKnownExtension(".mp3"); + musicClass.addResourceType(rtype); types.push_back(new ResourceType("RT_MOD", RC_MUSIC)); rtype = types.back(); rtype->addKnownExtension(".mod"); + musicClass.addResourceType(rtype); types.push_back(new ResourceType("RT_MID", RC_MUSIC)); rtype = types.back(); rtype->addKnownExtension(".mid"); + musicClass.addResourceType(rtype); - types.push_back(new ResourceType("RT_DEH", RC_PACKAGE)); ///< Treat DeHackEd patches as packages so they are mapped to $App.DataPath. - rtype = types.back(); - rtype->addKnownExtension(".deh"); - + /* + * Font types: + */ types.push_back(new ResourceType("RT_DFN", RC_FONT)); rtype = types.back(); rtype->addKnownExtension(".dfn"); + F_ResourceClassByName("RC_FONT").addResourceType(rtype); + + /* + * Misc types: + */ + types.push_back(new ResourceType("RT_DEH", RC_PACKAGE)); ///< Treat DeHackEd patches as packages so they are mapped to $App.DataPath. + rtype = types.back(); + rtype->addKnownExtension(".deh"); } void F_InitResourceLocator() @@ -531,13 +575,13 @@ ResourceNamespace* F_ResourceNamespaceByName(String name) return 0; // Not found. } -ResourceClass const& F_ResourceClassByName(String name) +ResourceClass& F_ResourceClassByName(String name) { if(!name.isEmpty()) { DENG2_FOR_EACH_CONST(ResourceClasses, i, classes) { - ResourceClass const& rclass = **i; + ResourceClass& rclass = **i; if(!rclass.name().compareWithoutCase(name)) return rclass; } @@ -545,13 +589,13 @@ ResourceClass const& F_ResourceClassByName(String name) return nullClass; // Not found. } -ResourceType const& F_ResourceTypeByName(String name) +ResourceType& F_ResourceTypeByName(String name) { if(!name.isEmpty()) { DENG2_FOR_EACH_CONST(ResourceTypes, i, types) { - ResourceType const& rtype = **i; + ResourceType& rtype = **i; if(!rtype.name().compareWithoutCase(name)) return rtype; } @@ -559,13 +603,13 @@ ResourceType const& F_ResourceTypeByName(String name) return nullType; // Not found. } -ResourceType const& F_GuessResourceTypeFromFileName(String path) +ResourceType& F_GuessResourceTypeFromFileName(String path) { if(!path.isEmpty()) { DENG2_FOR_EACH_CONST(ResourceTypes, i, types) { - ResourceType const& rtype = **i; + ResourceType& rtype = **i; if(rtype.fileNameIsKnown(path)) return rtype; } @@ -573,16 +617,16 @@ ResourceType const& F_GuessResourceTypeFromFileName(String path) return nullType; } -ResourceType const* F_ResourceTypeById(resourcetypeid_t id) +ResourceClass* F_ResourceClassById(resourceclassid_t id) { - if(!VALID_RESOURCE_TYPEID(id)) return 0; - return &resourceType(id); + if(!VALID_RESOURCE_CLASSID(id)) return 0; + return &resourceClass(id); } -ResourceClass const* F_ResourceClassById(resourceclassid_t id) +ResourceTypes const& F_ResourceTypes() { - if(!VALID_RESOURCE_CLASSID(id)) return 0; - return &resourceClass(id); + DENG_ASSERT(inited); + return types; } ResourceNamespaces const& F_ResourceNamespaces()