diff --git a/doomsday/engine/api/dd_share.h b/doomsday/engine/api/dd_share.h index 72f3ede871..56a2098469 100644 --- a/doomsday/engine/api/dd_share.h +++ b/doomsday/engine/api/dd_share.h @@ -66,12 +66,6 @@ extern "C" { /// Maximum number of players supported by the engine. #define DDMAXPLAYERS 16 -/// Base default paths for data files. -#define DD_BASEPATH_DATA "}data/" - -/// Base default paths for definition files. -#define DD_BASEPATH_DEFS "}defs/" - // The case-independent strcmps have different names. #if WIN32 # define strcasecmp _stricmp diff --git a/doomsday/engine/api/dd_types.h b/doomsday/engine/api/dd_types.h index 62060e1039..b7bd10a983 100644 --- a/doomsday/engine/api/dd_types.h +++ b/doomsday/engine/api/dd_types.h @@ -69,27 +69,6 @@ typedef char filename_t[FILENAME_T_MAXLEN]; typedef void (*con_textfilter_t) (char* text); -/** - * Resource Class. - * - * @ingroup fs - */ -typedef enum { - RC_NULL = -2, ///< Not a real class, used internally during resource locator init. - RC_UNKNOWN = -1, ///< Attempt to guess the class using heuristic evaluation of the path. - RESOURCECLASS_FIRST = 0, - RC_PACKAGE = RESOURCECLASS_FIRST, - RC_DEFINITION, - RC_GRAPHIC, - RC_MODEL, - RC_SOUND, - RC_MUSIC, - RC_FONT, - RESOURCECLASS_COUNT -} resourceclass_t; - -#define VALID_RESOURCE_CLASS(n) ((n) >= RESOURCECLASS_FIRST && (n) < RESOURCECLASS_COUNT) - #define BAMS_BITS 16 #if BAMS_BITS == 32 @@ -121,6 +100,8 @@ struct surface_s; struct material_s; #include +#include "resourceclass.h" +#include "resourcetype.h" #include "uri.h" #endif /* ENGINE_TYPES_H */ diff --git a/doomsday/engine/api/doomsday.h b/doomsday/engine/api/doomsday.h index ddd16877b3..61ca6a3972 100644 --- a/doomsday/engine/api/doomsday.h +++ b/doomsday/engine/api/doomsday.h @@ -160,7 +160,7 @@ gameid_t DD_GameIdForKey(char const* identityKey); * recent. * * @param game Unique identifier/name of the game. - * @param rclass Class of resource being added. + * @param classId Class of resource being added. * @param rflags Resource flags (see @ref resourceFlags). * @param names One or more known potential names, seperated by semicolon * (e.g.,
 "name1;name2" 
). Valid names include @@ -171,7 +171,7 @@ gameid_t DD_GameIdForKey(char const* identityKey); * For package resources this may be C-String containing a * semicolon delimited list of identity keys. */ -void DD_AddGameResource(gameid_t game, resourceclass_t rclass, int rflags, +void DD_AddGameResource(gameid_t game, resourceclassid_t classId, int rflags, const char* names, void* params); /** diff --git a/doomsday/engine/api/resourceclass.h b/doomsday/engine/api/resourceclass.h new file mode 100644 index 0000000000..9323c5d45f --- /dev/null +++ b/doomsday/engine/api/resourceclass.h @@ -0,0 +1,126 @@ +/** + * @file resourceclass.h + * + * Resource Class. + * + * @ingroup base + * + * @author Copyright © 2003-2012 Jaakko Keränen + * @author Copyright © 2006-2012 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef LIBDENG_RESOURCECLASS_H +#define LIBDENG_RESOURCECLASS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Resource Class Identifier. + * + * @ingroup base + */ +typedef enum resourceclassid_e { + RC_NULL = -2, ///< Not a real class, used internally during resource locator init. + RC_UNKNOWN = -1, ///< Attempt to guess the class using heuristic evaluation of the path. + RESOURCECLASS_FIRST = 0, + RC_PACKAGE = RESOURCECLASS_FIRST, + RC_DEFINITION, + RC_GRAPHIC, + RC_MODEL, + RC_SOUND, + RC_MUSIC, + RC_FONT, + RESOURCECLASS_COUNT +} resourceclassid_t; + +#define VALID_RESOURCE_CLASSID(n) ((n) >= RESOURCECLASS_FIRST && (n) < RESOURCECLASS_COUNT) + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus +#ifndef DENG2_C_API_ONLY + +#include +#include + +enum resourcetypeid_e; + +namespace de +{ + /** + * ResourceClass. + * + * @ingroup base + */ + struct ResourceClass + { + public: + typedef QList Types; + + public: + String name_; + + String defaultNamespace_; + + /// Recognized resource types (in order of importance, left to right). + Types searchTypeOrder; + + ResourceClass(String _name, String _defaultNamespace) + : name_(_name), defaultNamespace_(_defaultNamespace) + {} + + virtual ~ResourceClass() {}; + + String const& name() const { + return name_; + } + + String const& defaultNamespace() const { + return defaultNamespace_; + } + + ResourceClass& addResourceType(resourcetypeid_e rtype) { + searchTypeOrder.push_back(rtype); + return *this; + } + }; + + /** + * The special "null" ResourceClass object. + * + * @ingroup core + */ + struct NullResourceClass : public ResourceClass + { + NullResourceClass() : ResourceClass("RC_NULL", "") + {} + }; + + /// @return @c true= @a rtype is a "null-resourceclass" object (not a real resource class). + inline bool isNullResourceClass(ResourceClass const& rclass) { + return !!dynamic_cast(&rclass); + } + +} // namespace de +#endif // DENG2_C_API_ONLY +#endif // __cplusplus + +#endif /* LIBDENG_RESOURCECLASS_H */ diff --git a/doomsday/engine/api/resourcetype.h b/doomsday/engine/api/resourcetype.h new file mode 100644 index 0000000000..aebc2809a2 --- /dev/null +++ b/doomsday/engine/api/resourcetype.h @@ -0,0 +1,144 @@ +/** + * @file resourcetype.h + * + * Resource Type. + * + * @ingroup core + * + * @author Copyright © 2003-2012 Jaakko Keränen + * @author Copyright © 2006-2012 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef LIBDENG_RESOURCETYPE_H +#define LIBDENG_RESOURCETYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Resource Type identifer attributable to resources (e.g., files). + * + * @ingroup core + */ +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 + +enum resourceclassid_e; + +namespace de +{ + /** + * ResourceType. + * + * @ingroup core + */ + struct ResourceType + { + String name_; + + /// Default class attributed to resources of this type. + resourceclassid_e defaultClass_; + + /// List of known extensions for this resource type. + QStringList knownFileNameExtensions; + + ResourceType(String _name, resourceclassid_e _defaultClass) + : name_(_name), defaultClass_(_defaultClass) + {} + + virtual ~ResourceType() {}; + + String const& name() const { + return name_; + } + + resourceclassid_e defaultClass() const { + return defaultClass_; + } + + ResourceType& addKnownExtension(String ext) { + knownFileNameExtensions.push_back(ext); + return *this; + } + + bool fileNameIsKnown(String path) const + { + // We require an extension for this. + String ext = path.fileNameExtension(); + if(!ext.isEmpty()) + { + return knownFileNameExtensions.contains(ext, Qt::CaseInsensitive); + } + return false; + } + }; + + /** + * The special "null" ResourceType object. + * + * @ingroup core + */ + struct NullResourceType : public ResourceType + { + NullResourceType() : ResourceType("RT_NONE", RC_UNKNOWN) + {} + }; + + /// @return @c true= @a rtype is a "null-resourcetype" object (not a real resource type). + inline bool isNullResourceType(ResourceType const& rtype) { + return !!dynamic_cast(&rtype); + } + +} // namespace de +#endif // DENG2_C_API_ONLY +#endif // __cplusplus + +#endif /* LIBDENG_RESOURCETYPE_H */ diff --git a/doomsday/engine/api/uri.h b/doomsday/engine/api/uri.h index 2a2e180b16..b977bae8ec 100644 --- a/doomsday/engine/api/uri.h +++ b/doomsday/engine/api/uri.h @@ -151,7 +151,7 @@ namespace de * is not @c RC_NULL, ask the resource locator whether it knows of an * appropriate default scheme for this class of resource. */ - Uri(String path, resourceclass_t defaultResourceClass = RC_UNKNOWN, QChar delimiter = '/'); + Uri(String path, resourceclassid_t defaultResourceClass = RC_UNKNOWN, QChar delimiter = '/'); /** * Construct a Uri instance by duplicating @a other. @@ -249,7 +249,7 @@ namespace de * this is not @c RC_NULL, ask the resource locator whether it knows * of an appropriate default scheme for this class of resource. */ - Uri& setUri(String newUri, resourceclass_t defaultResourceClass = RC_UNKNOWN, + Uri& setUri(String newUri, resourceclassid_t defaultResourceClass = RC_UNKNOWN, QChar delimiter = '/'); /** @@ -386,7 +386,7 @@ Uri* Uri_New(void); * @param defaultResourceClass If no scheme is defined in @a path and this is not @c RC_NULL, * look for an appropriate default scheme for this class of resource. */ -Uri* Uri_NewWithPath2(char const* path, resourceclass_t defaultResourceClass); +Uri* Uri_NewWithPath2(char const* path, resourceclassid_t defaultResourceClass); Uri* Uri_NewWithPath(char const* path); /** @@ -476,7 +476,7 @@ Uri* Uri_SetPath(Uri* uri, char const* path); * * @return Same as @a uri, for caller convenience. */ -Uri* Uri_SetUri2(Uri* uri, char const* path, resourceclass_t defaultResourceClass); +Uri* Uri_SetUri2(Uri* uri, char const* path, resourceclassid_t defaultResourceClass); Uri* Uri_SetUri(Uri* uri, char const* path/* defaultResourceClass = RC_UNKNOWN*/); Uri* Uri_SetUriStr(Uri* uri, ddstring_t const* path); diff --git a/doomsday/engine/engine.pro b/doomsday/engine/engine.pro index d8495273c9..0dd6085d7b 100644 --- a/doomsday/engine/engine.pro +++ b/doomsday/engine/engine.pro @@ -110,6 +110,8 @@ DENG_API_HEADERS = \ api/doomsday.h \ api/filehandle.h \ api/materialarchive.h \ + api/resourceclass.h \ + api/resourcetype.h \ api/sys_audiod.h \ api/sys_audiod_mus.h \ api/sys_audiod_sfx.h \ diff --git a/doomsday/engine/include/dd_main.h b/doomsday/engine/include/dd_main.h index a9843a48e2..c4c2cd244b 100644 --- a/doomsday/engine/include/dd_main.h +++ b/doomsday/engine/include/dd_main.h @@ -161,7 +161,7 @@ void DD_DestroyGames(void); boolean DD_GameInfo(struct gameinfo_s* info); -void DD_AddGameResource(gameid_t game, resourceclass_t rclass, int rflags, char const* names, void* params); +void DD_AddGameResource(gameid_t game, resourceclassid_t classId, int rflags, char const* names, void* params); gameid_t DD_DefineGame(struct gamedef_s const* def); diff --git a/doomsday/engine/include/game.h b/doomsday/engine/include/game.h index 380e8ef262..378c975729 100644 --- a/doomsday/engine/include/game.h +++ b/doomsday/engine/include/game.h @@ -70,7 +70,7 @@ class GameCollection; class Game { public: - typedef QMultiMap Resources; + typedef QMultiMap Resources; public: /** @@ -116,10 +116,10 @@ class Game * @note Resource registration order defines the order in which resources of each * type are loaded. * - * @param rclass Class of resource being added. + * @param classId Class of resource being added. * @param record ResourceRecord to add. */ - Game& addResource(resourceclass_t rclass, ResourceRecord& record); + Game& addResource(resourceclassid_t classId, ResourceRecord& record); bool allStartupResourcesFound() const; @@ -195,7 +195,7 @@ class NullGame : public Game public: NullGame(); - Game& addResource(resourceclass_t /*rclass*/, struct resourcerecord_s& /*record*/) { + Game& addResource(resourceclassid_t /*classId*/, struct resourcerecord_s& /*record*/) { throw NullObjectError("NullGame::addResource", "Invalid action on null-object"); } @@ -207,7 +207,7 @@ class NullGame : public Game return true; // Always. } - struct resourcerecord_s* const* resources(resourceclass_t /*rclass*/, int* /*count*/) const { + struct resourcerecord_s* const* resources(resourceclassid_t /*classId*/, int* /*count*/) const { return 0; } @@ -239,7 +239,7 @@ void Game_Delete(Game* game); boolean Game_IsNullObject(Game const* game); -struct game_s* Game_AddResource(Game* game, resourceclass_t rclass, struct resourcerecord_s* record); +struct game_s* Game_AddResource(Game* game, resourceclassid_t classId, struct resourcerecord_s* record); boolean Game_AllStartupResourcesFound(Game const* game); diff --git a/doomsday/engine/include/resourcerecord.h b/doomsday/engine/include/resourcerecord.h index 49306795c2..a06640b371 100644 --- a/doomsday/engine/include/resourcerecord.h +++ b/doomsday/engine/include/resourcerecord.h @@ -45,11 +45,11 @@ namespace de * @param rFlags @ref resourceFlags * @param name An expected name for the associated resource. */ - ResourceRecord(resourceclass_t rClass, int rFlags, String* name = 0); + ResourceRecord(resourceclassid_t rClass, int rFlags, String* name = 0); ~ResourceRecord(); /// @return Class of resource. - resourceclass_t resourceClass() const; + resourceclassid_t resourceClass() const; /// @return Flags for this resource. int resourceFlags() const; diff --git a/doomsday/engine/include/sys_reslocator.h b/doomsday/engine/include/sys_reslocator.h index 762545ce31..243ffb0093 100644 --- a/doomsday/engine/include/sys_reslocator.h +++ b/doomsday/engine/include/sys_reslocator.h @@ -41,36 +41,6 @@ extern "C" { #endif -/** - * Resource Type. Unique identifer attributable to resources (e.g., files). - * - * @ingroup core - */ -typedef enum { - RT_NONE = 0, - RT_FIRST = 1, - RT_ZIP = RT_FIRST, - RT_WAD, - 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 -} resourcetype_t; - -#define NUM_RESOURCE_TYPES (RT_LAST_INDEX-1) -#define VALID_RESOURCE_TYPE(v) ((v) >= RT_FIRST && (v) < RT_LAST_INDEX) - /** * @defgroup resourceLocationFlags Resource Location Flags * @@ -88,8 +58,6 @@ typedef enum { /** * @post Initial/default search paths registered, namespaces initialized and * queries may begin. - * - * @note May be called to re-initialize the locator back to default state. */ void F_InitResourceLocator(void); @@ -101,15 +69,13 @@ void F_ShutdownResourceLocator(void); void F_ResetAllResourceNamespaces(void); -void F_CreateResourceNamespaces(void); - /** * Attempt to locate a named resource. * - * @param rclass Class of resource being searched for (if known). + * @param classId Class of resource being searched for (if known). * * @param searchPath Path/name of the resource being searched for. Note that - * the resource class (@a rclass) specified significantly + * the resource class (@a classId) specified significantly * alters search behavior. This allows text replacements of * symbolic escape sequences in the path, allowing access to * the engine's view of the virtual file system. @@ -126,57 +92,82 @@ void F_CreateResourceNamespaces(void); * * @return @c true iff a resource was found. */ -boolean F_FindResource4(resourceclass_t rclass, struct uri_s const* searchPath, ddstring_t* foundPath, int flags, char const* optionalSuffix); -boolean F_FindResource3(resourceclass_t rclass, struct uri_s const* searchPath, ddstring_t* foundPath, int flags/*, optionalSuffix = NULL*/); -boolean F_FindResource2(resourceclass_t rclass, struct uri_s const* searchPath, ddstring_t* foundPath/*, flags = RLF_DEFAULT*/); -boolean F_FindResource(resourceclass_t rclass, struct uri_s const* searchPath/*, foundPath = NULL*/); +boolean F_FindResource4(resourceclassid_t classId, struct uri_s const* searchPath, ddstring_t* foundPath, int flags, char const* optionalSuffix); +boolean F_FindResource3(resourceclassid_t classId, struct uri_s const* searchPath, ddstring_t* foundPath, int flags/*, optionalSuffix = NULL*/); +boolean F_FindResource2(resourceclassid_t classId, struct uri_s const* searchPath, ddstring_t* foundPath/*, flags = RLF_DEFAULT*/); +boolean F_FindResource(resourceclassid_t classId, struct uri_s const* searchPath/*, foundPath = NULL*/); /** * @return If a resource is found, the index + 1 of the path from @a searchPaths * that was used to find it; otherwise @c 0. */ -uint F_FindResourceFromList(resourceclass_t rclass, char const* searchPaths, +uint F_FindResourceFromList(resourceclassid_t classId, char const* searchPaths, ddstring_t* foundPath, int flags, char const* optionalSuffix); -/** - * @return Default class associated with resources of type @a type. - */ -resourceclass_t F_DefaultResourceClassForType(resourcetype_t type); - #ifdef __cplusplus } // extern "C" namespace de { + +typedef QList ResourceClasses; +typedef QList ResourceTypes; typedef QList ResourceNamespaces; + } +/** + * Lookup a ResourceNamespace by symbolic name. + * + * @param name Symbolic name of the namespace. + * @return ResourceNamespace associated with @a name; otherwise @c 0 (not found). + */ +de::ResourceNamespace* F_ResourceNamespaceByName(de::String name); + de::ResourceNamespaces const& F_ResourceNamespaces(); /** - * @return Unique identifier of the default namespace associated with @a rclass. + * Lookup a ResourceClass by id. + * + * @todo Refactor away. + * + * @param classId Unique identifier of the class. + * @return ResourceClass associated with @a id; otherwise @c 0 (not found). */ -de::ResourceNamespace* F_DefaultResourceNamespaceForClass(resourceclass_t rclass); +de::ResourceClass const* F_ResourceClassById(resourceclassid_t classId); /** - * Lookup a ResourceNamespace by symbolic name. + * Lookup a ResourceClass by symbolic name. * - * @param name Symbolic name of the namespace. - * @return ResourceNamespace associated with @a name; otherwise @c 0 (not found). + * @param name Symbolic name of the class. + * @return ResourceClass associated with @a name; otherwise @c 0 (not found). */ -de::ResourceNamespace* F_ResourceNamespaceByName(de::String name); +de::ResourceClass const& F_ResourceClassByName(de::String name); /** - * Attempts to determine which "type" should be attributed to a resource, solely - * by examining the name (e.g., a file name/path). + * Lookup a ResourceType by id. * - * @return Type determined for this resource else @c RT_NONE if not recognizable. + * @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); + +/** + * Lookup a ResourceType by symbolic name. + * + * @param name Symbolic name of the type. + * @return ResourceType associated with @a name. May return a null-object. */ -resourcetype_t F_GuessResourceTypeFromFileName(de::String name); +de::ResourceType const& F_ResourceTypeByName(de::String name); /** - * Convert a resourceclass_t constant into a string for error/debug messages. + * Attempts to determine which "type" should be attributed to a resource, solely + * by examining the name (e.g., a file name/path). + * + * @return Type determined for this resource. May return a null-object. */ -de::String const& F_ResourceClassName(resourceclass_t rclass); +de::ResourceType const& F_GuessResourceTypeFromFileName(de::String name); #endif // __cplusplus diff --git a/doomsday/engine/src/dd_help.c b/doomsday/engine/src/dd_help.c index 3ca31bba0a..9a32d8be40 100644 --- a/doomsday/engine/src/dd_help.c +++ b/doomsday/engine/src/dd_help.c @@ -301,7 +301,7 @@ void DD_InitHelp(void) // Parse the control panel help file. { ddstring_t helpFileName; Str_Init(&helpFileName); - Str_Set(&helpFileName, DD_BASEPATH_DATA"cphelp.txt"); + Str_Set(&helpFileName, "}data/cphelp.txt"); F_ExpandBasePath(&helpFileName, &helpFileName); DH_ReadStrings(Str_Text(&helpFileName)); diff --git a/doomsday/engine/src/dd_main.cpp b/doomsday/engine/src/dd_main.cpp index 650e347e19..cc13b6af7e 100644 --- a/doomsday/engine/src/dd_main.cpp +++ b/doomsday/engine/src/dd_main.cpp @@ -479,14 +479,14 @@ static int DD_LoadGameStartupResourcesWorker(void* parameters) return 0; } -static int addListFiles(ddstring_t*** list, size_t* listSize, resourcetype_t resType) +static int addListFiles(ddstring_t*** list, size_t* listSize, ResourceType const& rtype) { size_t i; int count = 0; if(!list || !listSize) return 0; for(i = 0; i < *listSize; ++i) { - if(resType != F_GuessResourceTypeFromFileName(Str_Text((*list)[i]))) continue; + if(&rtype != &F_GuessResourceTypeFromFileName(Str_Text((*list)[i]))) continue; if(tryLoadFile(Str_Text((*list)[i]))) { count += 1; @@ -665,9 +665,9 @@ static int DD_LoadAddonResourcesWorker(void* parameters) listFilesFromDataGameAuto(&sessionResourceFileList, &numSessionResourceFileList); if(numSessionResourceFileList > 0) { - addListFiles(&sessionResourceFileList, &numSessionResourceFileList, RT_ZIP); + addListFiles(&sessionResourceFileList, &numSessionResourceFileList, F_ResourceTypeByName("RT_ZIP")); - addListFiles(&sessionResourceFileList, &numSessionResourceFileList, RT_WAD); + addListFiles(&sessionResourceFileList, &numSessionResourceFileList, F_ResourceTypeByName("RT_WAD")); } // Final autoload round. @@ -844,18 +844,18 @@ boolean DD_GameInfo(GameInfo* info) } /// @note Part of the Doomsday public API. -void DD_AddGameResource(gameid_t gameId, resourceclass_t rclass, int rflags, +void DD_AddGameResource(gameid_t gameId, resourceclassid_t classId, int rflags, char const* names, void* params) { DENG_ASSERT(games); - if(!VALID_RESOURCE_CLASS(rclass)) Con_Error("DD_AddGameResource: Unknown resource class %i.", (int)rclass); + if(!VALID_RESOURCE_CLASSID(classId)) Con_Error("DD_AddGameResource: Unknown resource class %i.", (int)classId); if(!names || !names[0]) Con_Error("DD_AddGameResource: Invalid name argument."); // Construct and attach the new resource record. de::Game& game = games->byId(gameId); - ResourceRecord* record = new ResourceRecord(rclass, rflags); - game.addResource(rclass, *record); + ResourceRecord* record = new ResourceRecord(classId, rflags); + game.addResource(classId, *record); // Add the name list to the resource record. QStringList nameList = String(names).split(";", QString::SkipEmptyParts); @@ -864,7 +864,7 @@ void DD_AddGameResource(gameid_t gameId, resourceclass_t rclass, int rflags, record->addName(*i); } - if(params && rclass == RC_PACKAGE) + if(params && classId == RC_PACKAGE) { // Add the identityKey list to the resource record. QStringList idKeys = String((char const*) params).split(";", QString::SkipEmptyParts); @@ -1366,8 +1366,7 @@ boolean DD_Init(void) DD_DummyWorker, 0, "Buffering..."); // Add resource paths specified using -iwad on the command line. - ResourceNamespace* rnamespace = F_DefaultResourceNamespaceForClass(RC_PACKAGE); - DENG_ASSERT(rnamespace); + ResourceNamespace* rnamespace = F_ResourceNamespaceByName(F_ResourceClassByName("RC_PACKAGE").defaultNamespace()); for(int p = 0; p < CommandLine_Count(); ++p) { if(!CommandLine_IsMatchingAlias("-iwad", CommandLine_At(p))) @@ -1567,9 +1566,6 @@ static void DD_InitResourceSystem(void) { Con_Message("Initializing Resource subsystem...\n"); - F_InitResourceLocator(); - F_CreateResourceNamespaces(); - initPathMappings(); F_ResetAllResourceNamespaces(); diff --git a/doomsday/engine/src/dd_pinit.c b/doomsday/engine/src/dd_pinit.c index 6f4729f186..709473f982 100644 --- a/doomsday/engine/src/dd_pinit.c +++ b/doomsday/engine/src/dd_pinit.c @@ -188,7 +188,6 @@ void DD_ShutdownAll(void) R_Shutdown(); Materials_Shutdown(); Def_Destroy(); - F_ShutdownResourceLocator(); F_Shutdown(); Libdeng_Shutdown(); Sys_ShutdownWindowManager(); diff --git a/doomsday/engine/src/def_main.cpp b/doomsday/engine/src/def_main.cpp index 92e3b53409..38888d0b48 100644 --- a/doomsday/engine/src/def_main.cpp +++ b/doomsday/engine/src/def_main.cpp @@ -1077,7 +1077,7 @@ void Def_Read(void) { // We've already initialized the definitions once. // Get rid of everything. - de::ResourceNamespace* rnamespace = F_DefaultResourceNamespaceForClass(RC_MODEL); + de::ResourceNamespace* rnamespace = F_ResourceNamespaceByName(F_ResourceClassByName("RC_MODEL").defaultNamespace()); DENG_ASSERT(rnamespace); rnamespace->reset(); diff --git a/doomsday/engine/src/def_read.cpp b/doomsday/engine/src/def_read.cpp index d1737d6c55..a2f0cac3f5 100644 --- a/doomsday/engine/src/def_read.cpp +++ b/doomsday/engine/src/def_read.cpp @@ -815,7 +815,7 @@ static int DED_ReadData(ded_t* ded, const char* buffer, const char* _sourceFile) String modelPath = NativePath(label).withSeparators('/') / "/"; // Ensure it has a terminating separator. de::Uri newSearchPath = de::Uri(modelPath, RC_NULL); - ResourceNamespace* rnamespace = F_DefaultResourceNamespaceForClass(RC_MODEL); + ResourceNamespace* rnamespace = F_ResourceNamespaceByName(F_ResourceClassByName("RC_MODEL").defaultNamespace()); DENG_ASSERT(rnamespace); rnamespace->addSearchPath(ResourceNamespace::ExtraPaths, reinterpret_cast(newSearchPath), 0); } diff --git a/doomsday/engine/src/fs_main.cpp b/doomsday/engine/src/fs_main.cpp index f0ef2d625d..5885676cb2 100644 --- a/doomsday/engine/src/fs_main.cpp +++ b/doomsday/engine/src/fs_main.cpp @@ -995,7 +995,7 @@ int FS1::findAllPaths(String searchPattern, int flags, FS1::PathList& found) struct FileInterpreter { - resourcetype_t resourceType; + resourcetypeid_t resourceType; de::File1* (*interpret)(de::FileHandle& hndl, String path, FileInfo const& info); }; @@ -1017,7 +1017,6 @@ de::File1& FS1::interpret(de::FileHandle& hndl, String path, FileInfo const& inf { DENG_ASSERT(!path.isEmpty()); - /// @todo Order here should be determined by the resource locator. static FileInterpreter interpreters[] = { { RT_ZIP, interpretAsZipFile }, { RT_WAD, interpretAsWadFile }, @@ -1027,13 +1026,13 @@ de::File1& FS1::interpret(de::FileHandle& hndl, String path, FileInfo const& inf de::File1* interpretedFile = 0; // Firstly try interpreter(s) for guessed resource types. - resourcetype_t resTypeGuess = F_GuessResourceTypeFromFileName(path); - if(resTypeGuess != RT_NONE) + ResourceType const& rtypeGuess = F_GuessResourceTypeFromFileName(path); + if(!isNullResourceType(rtypeGuess)) { for(FileInterpreter* intper = interpreters; intper->interpret; ++intper) { // Not applicable for this resource type? - if(intper->resourceType != resTypeGuess) continue; + if(F_ResourceTypeById(intper->resourceType) != &rtypeGuess) continue; interpretedFile = intper->interpret(hndl, path, info); if(interpretedFile) break; @@ -1041,12 +1040,13 @@ de::File1& FS1::interpret(de::FileHandle& hndl, String path, FileInfo const& inf } // 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) { // Already tried this? - if(resTypeGuess && intper->resourceType == resTypeGuess) continue; + if(F_ResourceTypeById(intper->resourceType) == &rtypeGuess) continue; interpretedFile = intper->interpret(hndl, path, info); if(interpretedFile) break; @@ -1330,12 +1330,16 @@ void F_Init(void) { DENG_ASSERT(!fileSystem); fileSystem = new de::FS1(); + + F_InitResourceLocator(); } void F_Shutdown(void) { if(!fileSystem) return; delete fileSystem; fileSystem = 0; + + F_ShutdownResourceLocator(); } void F_EndStartup(void) diff --git a/doomsday/engine/src/game.cpp b/doomsday/engine/src/game.cpp index aaff6152b3..31e366a272 100644 --- a/doomsday/engine/src/game.cpp +++ b/doomsday/engine/src/game.cpp @@ -113,16 +113,16 @@ GameCollection& Game::collection() const return *reinterpret_cast(App_GameCollection()); } -Game& Game::addResource(resourceclass_t rclass, ResourceRecord& record) +Game& Game::addResource(resourceclassid_t classId, ResourceRecord& record) { - if(!VALID_RESOURCE_CLASS(rclass)) - throw de::Error("Game::addResource", QString("Invalid resource class %1").arg(rclass)); + if(!VALID_RESOURCE_CLASSID(classId)) + throw de::Error("Game::addResource", QString("Invalid resource class %1").arg(classId)); // Ensure we don't add duplicates. - Resources::const_iterator found = d->resources.find(rclass, &record); + Resources::const_iterator found = d->resources.find(classId, &record); if(found == d->resources.end()) { - d->resources.insert(rclass, &record); + d->resources.insert(classId, &record); } return *this; } @@ -228,9 +228,9 @@ void Game::printResources(Game const& game, int rflags, bool printStatus) Resources const& resources = game.resources(); for(uint i = 0; i < RESOURCECLASS_COUNT; ++i) { - resourceclass_t const rclass = resourceclass_t(i); - for(Resources::const_iterator i = resources.find(rclass); - i != resources.end() && i.key() == rclass; ++i) + resourceclassid_t const classId = resourceclassid_t(i); + for(Resources::const_iterator i = resources.find(classId); + i != resources.end() && i.key() == classId; ++i) { ResourceRecord& record = **i; if(rflags >= 0 && (rflags & record.resourceFlags())) @@ -331,11 +331,11 @@ boolean Game_IsNullObject(Game const* game) return de::isNullGame(*reinterpret_cast(game)); } -struct game_s* Game_AddResource(struct game_s* game, resourceclass_t rclass, struct resourcerecord_s* record) +struct game_s* Game_AddResource(struct game_s* game, resourceclassid_t classId, struct resourcerecord_s* record) { SELF(game); DENG_ASSERT(record); - self->addResource(rclass, reinterpret_cast(*record)); + self->addResource(classId, reinterpret_cast(*record)); return game; } diff --git a/doomsday/engine/src/resourcerecord.cpp b/doomsday/engine/src/resourcerecord.cpp index 7e40a8a1f9..99ba5be4c0 100644 --- a/doomsday/engine/src/resourcerecord.cpp +++ b/doomsday/engine/src/resourcerecord.cpp @@ -34,7 +34,7 @@ namespace de { struct ResourceRecord::Instance { /// Class of resource. - resourceclass_t rclass; + resourceclassid_t classId; /// @see resourceFlags. int flags; @@ -54,15 +54,15 @@ struct ResourceRecord::Instance /// Set during resource location. String foundPath; - Instance(resourceclass_t _rclass, int rflags) - : rclass(_rclass), flags(rflags & ~RF_FOUND), names(), + Instance(resourceclassid_t _rclass, int rflags) + : classId(_rclass), flags(rflags & ~RF_FOUND), names(), identityKeys(), foundNameIndex(-1), foundPath() {} }; -ResourceRecord::ResourceRecord(resourceclass_t rclass, int rflags, String* name) +ResourceRecord::ResourceRecord(resourceclassid_t classId, int rflags, String* name) { - d = new Instance(rclass, rflags); + d = new Instance(classId, rflags); if(name) addName(*name); } @@ -164,17 +164,17 @@ ResourceRecord& ResourceRecord::locateResource() int nameIndex = 0; for(QStringList::const_iterator i = d->names.constBegin(); i != d->names.constEnd(); ++i, ++nameIndex) { - Uri path = Uri(*i, d->rclass); + Uri path = Uri(*i, d->classId); // Attempt to resolve a path to the named resource. - if(!F_FindResource2(d->rclass, reinterpret_cast(&path), found)) continue; + if(!F_FindResource2(d->classId, reinterpret_cast(&path), found)) continue; // We've found *something*. String foundPath = String(Str_Text(found)); // Perform identity validation. bool validated = false; - if(d->rclass == RC_PACKAGE) + if(d->classId == RC_PACKAGE) { /// @todo The identity configuration should declare the type of resource... validated = recognizeWAD(foundPath, d->identityKeys); @@ -219,9 +219,9 @@ String const& ResourceRecord::resolvedPath(bool tryLocate) return d->foundPath; } -resourceclass_t ResourceRecord::resourceClass() const +resourceclassid_t ResourceRecord::resourceClass() const { - return d->rclass; + return d->classId; } int ResourceRecord::resourceFlags() const diff --git a/doomsday/engine/src/sys_reslocator.cpp b/doomsday/engine/src/sys_reslocator.cpp index c080d128db..b74d441d3d 100644 --- a/doomsday/engine/src/sys_reslocator.cpp +++ b/doomsday/engine/src/sys_reslocator.cpp @@ -29,90 +29,38 @@ #include #include "de_base.h" -#include "de_console.h" #include "de_filesys.h" -#include "resourcerecord.h" +#include "resourceclass.h" #include "resourcenamespace.h" +#include "resourcetype.h" #include #include -#include #include using namespace de; -struct ResourceTypeInfo -{ - static int const max_extensions = 3; - - /// Default class attributed to resources of this type. - resourceclass_t defaultClass; - - /// List of known extensions for this resource type. - String const knownFileNameExtensions[max_extensions]; -}; - static bool inited = false; -static ResourceTypeInfo const typeInfo[NUM_RESOURCE_TYPES] = { - /* RT_ZIP */ { RC_PACKAGE, { ".pk3", ".zip", "" } }, - /* RT_WAD */ { RC_PACKAGE, { ".wad", "" } }, - /* RT_DED */ { RC_DEFINITION, { ".ded", "" } }, - /* RT_PNG */ { RC_GRAPHIC, { ".png", "" } }, - /* RT_JPG */ { RC_GRAPHIC, { ".jpg", "" } }, - /* RT_TGA */ { RC_GRAPHIC, { ".tga", "" } }, - /* RT_PCX */ { RC_GRAPHIC, { ".pcx", "" } }, - /* RT_DMD */ { RC_MODEL, { ".dmd", "" } }, - /* RT_MD2 */ { RC_MODEL, { ".md2", "" } }, - /* RT_WAV */ { RC_SOUND, { ".wav", "" } }, - /* RT_OGG */ { RC_MUSIC, { ".ogg", "" } }, - /* RT_MP3 */ { RC_MUSIC, { ".mp3", "" } }, - /* RT_MOD */ { RC_MUSIC, { ".mod", "" } }, - /* RT_MID */ { RC_MUSIC, { ".mid", "" } }, - /* RT_DEH */ { RC_UNKNOWN, { ".deh", "" } }, - /* RT_DFN */ { RC_FONT, { ".dfn", "" } } -}; - -// Recognized resource types (in order of importance, left to right). -#define MAX_TYPEORDER 6 -static resourcetype_t const searchTypeOrder[RESOURCECLASS_COUNT][MAX_TYPEORDER] = { - /* RC_PACKAGE */ { RT_ZIP, RT_WAD, RT_NONE }, // Favor ZIP over WAD. - /* RC_DEFINITION */ { RT_DED, RT_NONE }, // Only DED files. - /* RC_GRAPHIC */ { RT_PNG, RT_TGA, RT_JPG, RT_PCX, RT_NONE }, // Favour quality. - /* RC_MODEL */ { RT_DMD, RT_MD2, RT_NONE }, // Favour DMD over MD2. - /* RC_SOUND */ { RT_WAV, RT_NONE }, // Only WAV files. - /* RC_MUSIC */ { RT_OGG, RT_MP3, RT_WAV, RT_MOD, RT_MID, RT_NONE }, - /* RC_FONT */ { RT_DFN, RT_NONE } // Only DFN fonts. -}; +static NullResourceClass const nullClass; +static NullResourceType const nullType; +static ResourceTypes types; +static ResourceClasses classes; static ResourceNamespaces namespaces; -static inline ResourceTypeInfo const& resourceTypeInfo(resourcetype_t type) +static inline ResourceType const& resourceType(resourcetypeid_t id) { - if(!VALID_RESOURCE_TYPE(type)) throw Error("resourceTypeInfo", String("Invalid type %1").arg(type)); - return typeInfo[uint(type) - 1]; -} - -static ResourceNamespace* namespaceByName(String name) -{ - if(!name.isEmpty()) - { - for(int i = 0; i < namespaces.count(); ++i) - { - ResourceNamespace& rnamespace = *namespaces[i]; - if(!rnamespace.name().compareWithoutCase(name)) - return &rnamespace; - } - } - return 0; // Not found. + 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 void resetAllNamespaces() +static inline ResourceClass const& resourceClass(resourceclassid_t id) { - DENG2_FOR_EACH(ResourceNamespaces, i, namespaces) - { - (*i)->reset(); - } + if(id == RC_NULL) return nullClass; + if(!VALID_RESOURCE_CLASSID(id)) throw Error("resourceClass", String("Invalid id %1").arg(id)); + return *classes[uint(id)]; } /** @@ -195,7 +143,7 @@ static bool findResource3(ResourceNamespace* rnamespace, de::Uri const& searchPa return findResourceFile(searchPath, foundPath); } -static bool findResource2(int flags, resourceclass_t rclass, String searchPath, +static bool findResource2(int flags, resourceclassid_t classId, String searchPath, ddstring_t* foundPath, ResourceNamespace* rnamespace) { if(searchPath.isEmpty()) return false; @@ -210,7 +158,8 @@ static bool findResource2(int flags, resourceclass_t rclass, String searchPath, if(flags & RLF_MATCH_EXTENSION) return false; } - if(!(VALID_RESOURCE_CLASS(rclass) && searchTypeOrder[rclass][0] != RT_NONE)) return false; + ResourceClass const& rclass = resourceClass(classId); + if(rclass.searchTypeOrder[0] == RT_NONE) return false; /* * Try some different name patterns (i.e., resource types) known to us. @@ -221,12 +170,12 @@ static bool findResource2(int flags, resourceclass_t rclass, String searchPath, path2.reserve(path2.length() + 5 /*max expected extension length*/); - for(resourcetype_t const* type = searchTypeOrder[rclass]; *type != RT_NONE; ++type) + DENG2_FOR_EACH_CONST(ResourceClass::Types, typeIt, rclass.searchTypeOrder) { - ResourceTypeInfo const& typeInfo = resourceTypeInfo(*type); - for(int i = 0; !typeInfo.knownFileNameExtensions[i].isEmpty(); ++i) + ResourceType const& rtype = resourceType(*typeIt); + DENG2_FOR_EACH_CONST(QStringList, i, rtype.knownFileNameExtensions) { - String const& ext = typeInfo.knownFileNameExtensions[i]; + String const& ext = *i; if(findResource3(rnamespace, de::Uri(path2 + ext, RC_NULL), foundPath)) { return true; @@ -237,10 +186,10 @@ static bool findResource2(int flags, resourceclass_t rclass, String searchPath, return false; // Not found. } -static bool findResource(resourceclass_t rclass, de::Uri const& searchPath, +static bool findResource(resourceclassid_t classId, de::Uri const& searchPath, ddstring_t* foundPath, int flags, String optionalSuffix = "") { - DENG_ASSERT(rclass == RC_UNKNOWN || VALID_RESOURCE_CLASS(rclass)); + DENG_ASSERT(classId == RC_UNKNOWN || VALID_RESOURCE_CLASSID(classId)); LOG_AS("findResource"); @@ -251,7 +200,7 @@ static bool findResource(resourceclass_t rclass, de::Uri const& searchPath, String const& resolvedPath = searchPath.resolved(); // Is a namespace specified? - ResourceNamespace* rnamespace = namespaceByName(Str_Text(searchPath.scheme())); + ResourceNamespace* rnamespace = F_ResourceNamespaceByName(Str_Text(searchPath.scheme())); // First try with the optional suffix. if(!optionalSuffix.isEmpty()) @@ -259,12 +208,12 @@ static bool findResource(resourceclass_t rclass, de::Uri const& searchPath, String resolvedPath2 = resolvedPath.fileNamePath() / resolvedPath.fileNameWithoutExtension() + optionalSuffix + resolvedPath.fileNameExtension(); - if(findResource2(flags, rclass, resolvedPath2, foundPath, rnamespace)) + if(findResource2(flags, classId, resolvedPath2, foundPath, rnamespace)) return true; } // Try without a suffix. - return findResource2(flags, rclass, resolvedPath, foundPath, rnamespace); + return findResource2(flags, classId, resolvedPath, foundPath, rnamespace); } catch(de::Uri::ResolveError const& er) { @@ -274,7 +223,7 @@ static bool findResource(resourceclass_t rclass, de::Uri const& searchPath, return false; } -static void createPackagesNamespace(void) +static void createPackagesNamespace() { ResourceNamespace& rnamespace = createResourceNamespace("Packages"); @@ -337,10 +286,9 @@ static void createPackagesNamespace(void) rnamespace.addSearchPath(ResourceNamespace::DefaultPaths, de::Uri("$(App.DataPath)/$(GamePlugin.Name)/", RC_NULL), SPF_NO_DESCEND); } -void F_CreateResourceNamespaces(void) +static void createResourceNamespaces() { -#define NAMESPACEDEF_MAX_SEARCHPATHS 5 - + int const namespacedef_max_searchpaths = 5; struct namespacedef_s { char const* name; char const* optOverridePath; @@ -348,7 +296,7 @@ void F_CreateResourceNamespaces(void) ResourceNamespace::Flags flags; int searchPathFlags; /// @see searchPathFlags /// Priority is right to left. - char const* searchPaths[NAMESPACEDEF_MAX_SEARCHPATHS]; + char const* searchPaths[namespacedef_max_searchpaths]; } defs[] = { { "Defs", NULL, NULL, ResourceNamespace::Flag(0), 0, { "$(App.DefsPath)/", "$(App.DefsPath)/$(GamePlugin.Name)/", "$(App.DefsPath)/$(GamePlugin.Name)/$(Game.IdentityKey)/" } @@ -386,17 +334,16 @@ void F_CreateResourceNamespaces(void) createPackagesNamespace(); // Setup the rest... - for(size_t i = 0; defs[i].name; ++i) + struct namespacedef_s const* def = defs; + for(int i = 0; defs[i].name; ++i, ++def) { - uint j, searchPathCount; - struct namespacedef_s* def = &defs[i]; ResourceNamespace& rnamespace = createResourceNamespace(def->name, def->flags); - searchPathCount = 0; - while(def->searchPaths[searchPathCount] && ++searchPathCount < NAMESPACEDEF_MAX_SEARCHPATHS) + uint searchPathCount = 0; + while(def->searchPaths[searchPathCount] && ++searchPathCount < namespacedef_max_searchpaths) {} - for(j = 0; j < searchPathCount; ++j) + for(uint j = 0; j < searchPathCount; ++j) { de::Uri uri = de::Uri(def->searchPaths[j], RC_NULL); rnamespace.addSearchPath(ResourceNamespace::DefaultPaths, uri, def->searchPathFlags); @@ -416,35 +363,233 @@ void F_CreateResourceNamespaces(void) rnamespace.addSearchPath(ResourceNamespace::FallbackPaths, de::Uri::fromNativeDirPath(path), def->searchPathFlags); } } +} -#undef NAMESPACEDEF_MAX_SEARCHPATHS +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); } -void F_InitResourceLocator(void) +static void createResourceTypes() { - // Allow re-init. + ResourceType* rtype; + + types.push_back(new ResourceType("RT_ZIP", RC_PACKAGE)); + rtype = types.back(); + rtype->addKnownExtension(".pk3"); + rtype->addKnownExtension(".zip"); + + types.push_back(new ResourceType("RT_WAD", RC_PACKAGE)); + rtype = types.back(); + rtype->addKnownExtension(".wad"); + + 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"); + + types.push_back(new ResourceType("RT_DED", RC_DEFINITION)); + rtype = types.back(); + rtype->addKnownExtension(".ded"); + + 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"); + + types.push_back(new ResourceType("RT_TGA", RC_GRAPHIC)); + rtype = types.back(); + rtype->addKnownExtension(".tga"); + + types.push_back(new ResourceType("RT_PCX", RC_GRAPHIC)); + rtype = types.back(); + rtype->addKnownExtension(".pcx"); + + types.push_back(new ResourceType("RT_DMD", RC_MODEL)); + rtype = types.back(); + rtype->addKnownExtension(".dmd"); + + types.push_back(new ResourceType("RT_MD2", RC_MODEL)); + rtype = types.back(); + rtype->addKnownExtension(".md2"); + + types.push_back(new ResourceType("RT_WAV", RC_SOUND)); + rtype = types.back(); + rtype->addKnownExtension(".wav"); + + types.push_back(new ResourceType("RT_OGG", RC_MUSIC)); + rtype = types.back(); + rtype->addKnownExtension(".ogg"); + + types.push_back(new ResourceType("RT_MP3", RC_MUSIC)); + rtype = types.back(); + rtype->addKnownExtension(".mp3"); + + types.push_back(new ResourceType("RT_MOD", RC_MUSIC)); + rtype = types.back(); + rtype->addKnownExtension(".mod"); + + types.push_back(new ResourceType("RT_MID", RC_MUSIC)); + rtype = types.back(); + rtype->addKnownExtension(".mid"); + + 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"); + + types.push_back(new ResourceType("RT_DFN", RC_FONT)); + rtype = types.back(); + rtype->addKnownExtension(".dfn"); +} + +void F_InitResourceLocator() +{ + if(inited) return; + + createResourceClasses(); + createResourceTypes(); + createResourceNamespaces(); inited = true; } -void F_ShutdownResourceLocator(void) +void F_ShutdownResourceLocator() { if(!inited) return; + DENG2_FOR_EACH(ResourceNamespaces, i, namespaces) { delete *i; } namespaces.clear(); + + DENG2_FOR_EACH(ResourceTypes, i, types) + { + delete *i; + } + types.clear(); + + DENG2_FOR_EACH(ResourceClasses, i, classes) + { + delete *i; + } + classes.clear(); + inited = false; } -void F_ResetAllResourceNamespaces(void) +void F_ResetAllResourceNamespaces() { - resetAllNamespaces(); + DENG2_FOR_EACH(ResourceNamespaces, i, namespaces) + { + (*i)->reset(); + } } ResourceNamespace* F_ResourceNamespaceByName(String name) { - return namespaceByName(name); + if(!name.isEmpty()) + { + DENG2_FOR_EACH(ResourceNamespaces, i, namespaces) + { + ResourceNamespace& rnamespace = **i; + if(!rnamespace.name().compareWithoutCase(name)) + return &rnamespace; + } + } + return 0; // Not found. +} + +ResourceClass const& F_ResourceClassByName(String name) +{ + if(!name.isEmpty()) + { + DENG2_FOR_EACH_CONST(ResourceClasses, i, classes) + { + ResourceClass const& rclass = **i; + if(!rclass.name().compareWithoutCase(name)) + return rclass; + } + } + return nullClass; // Not found. +} + +ResourceType const& F_ResourceTypeByName(String name) +{ + if(!name.isEmpty()) + { + DENG2_FOR_EACH_CONST(ResourceTypes, i, types) + { + ResourceType const& rtype = **i; + if(!rtype.name().compareWithoutCase(name)) + return rtype; + } + } + return nullType; // Not found. +} + +ResourceType const& F_GuessResourceTypeFromFileName(String path) +{ + if(!path.isEmpty()) + { + DENG2_FOR_EACH_CONST(ResourceTypes, i, types) + { + ResourceType const& rtype = **i; + if(rtype.fileNameIsKnown(path)) + return rtype; + } + } + return nullType; +} + +ResourceType const* F_ResourceTypeById(resourcetypeid_t id) +{ + if(!VALID_RESOURCE_TYPEID(id)) return 0; + return &resourceType(id); +} + +ResourceClass const* F_ResourceClassById(resourceclassid_t id) +{ + if(!VALID_RESOURCE_CLASSID(id)) return 0; + return &resourceClass(id); } ResourceNamespaces const& F_ResourceNamespaces() @@ -453,31 +598,31 @@ ResourceNamespaces const& F_ResourceNamespaces() return namespaces; } -boolean F_FindResource4(resourceclass_t rclass, uri_s const* searchPath, +boolean F_FindResource4(resourceclassid_t classId, uri_s const* searchPath, ddstring_t* foundPath, int flags, char const* optionalSuffix) { DENG_ASSERT(searchPath); - return findResource(rclass, reinterpret_cast(*searchPath), foundPath, flags, optionalSuffix); + return findResource(classId, reinterpret_cast(*searchPath), foundPath, flags, optionalSuffix); } -boolean F_FindResource3(resourceclass_t rclass, uri_s const* searchPath, +boolean F_FindResource3(resourceclassid_t classId, uri_s const* searchPath, ddstring_t* foundPath, int flags) { - return F_FindResource4(rclass, searchPath, foundPath, flags, NULL); + return F_FindResource4(classId, searchPath, foundPath, flags, NULL); } -boolean F_FindResource2(resourceclass_t rclass, uri_s const* searchPath, +boolean F_FindResource2(resourceclassid_t classId, uri_s const* searchPath, ddstring_t* foundPath) { - return F_FindResource3(rclass, searchPath, foundPath, RLF_DEFAULT); + return F_FindResource3(classId, searchPath, foundPath, RLF_DEFAULT); } -boolean F_FindResource(resourceclass_t rclass, uri_s const* searchPath) +boolean F_FindResource(resourceclassid_t classId, uri_s const* searchPath) { - return F_FindResource2(rclass, searchPath, NULL); + return F_FindResource2(classId, searchPath, NULL); } -uint F_FindResourceFromList(resourceclass_t rclass, char const* searchPaths, +uint F_FindResourceFromList(resourceclassid_t classId, char const* searchPaths, ddstring_t* foundPath, int flags, char const* optionalSuffix) { if(!searchPaths || !searchPaths[0]) return 0; @@ -486,8 +631,8 @@ uint F_FindResourceFromList(resourceclass_t rclass, char const* searchPaths, int pathIndex = 0; for(QStringList::const_iterator i = paths.constBegin(); i != paths.constEnd(); ++i, ++pathIndex) { - de::Uri searchPath = de::Uri(*i, rclass); - if(findResource(rclass, searchPath, foundPath, flags, optionalSuffix)) + de::Uri searchPath = de::Uri(*i, classId); + if(findResource(classId, searchPath, foundPath, flags, optionalSuffix)) { return pathIndex + 1; // 1-based index. } @@ -495,62 +640,3 @@ uint F_FindResourceFromList(resourceclass_t rclass, char const* searchPaths, return 0; // Not found. } - -ResourceNamespace* F_DefaultResourceNamespaceForClass(resourceclass_t rclass) -{ - DENG_ASSERT(VALID_RESOURCE_CLASS(rclass)); - static String const defaultNamespaces[RESOURCECLASS_COUNT] = { - /* RC_PACKAGE */ "Packages", - /* RC_DEFINITION */ "Defs", - /* RC_GRAPHIC */ "Graphics", - /* RC_MODEL */ "Models", - /* RC_SOUND */ "Sfx", - /* RC_MUSIC */ "Music", - /* RC_FONT */ "Fonts" - }; - return namespaceByName(defaultNamespaces[rclass]); -} - -String const& F_ResourceClassName(resourceclass_t rclass) -{ - DENG_ASSERT(VALID_RESOURCE_CLASS(rclass)); - static String const resourceClassNames[RESOURCECLASS_COUNT] = { - "RC_PACKAGE", - "RC_DEFINITION", - "RC_GRAPHIC", - "RC_MODEL", - "RC_SOUND", - "RC_MUSIC", - "RC_FONT" - }; - return resourceClassNames[uint(rclass)]; -} - -resourcetype_t F_GuessResourceTypeFromFileName(String path) -{ - if(path.isEmpty()) return RT_NONE; - - // We require a file extension for this. - String ext = path.fileNameExtension(); - if(ext.isEmpty()) return RT_NONE; - - for(uint i = RT_FIRST; i < NUM_RESOURCE_TYPES; ++i) - { - ResourceTypeInfo const& typeInfo = resourceTypeInfo(resourcetype_t(i)); - for(int j = 0; !typeInfo.knownFileNameExtensions[j].isEmpty(); ++j) - { - if(!ext.compareWithoutCase(typeInfo.knownFileNameExtensions[j])) - { - return resourcetype_t(i); - } - } - } - - return RT_NONE; -} - -resourceclass_t F_DefaultResourceClassForType(resourcetype_t type) -{ - if(type == RT_NONE) return RC_UNKNOWN; - return resourceTypeInfo(type).defaultClass; -} diff --git a/doomsday/engine/src/uri.cpp b/doomsday/engine/src/uri.cpp index 9e9a2b999f..ba03e62bf0 100644 --- a/doomsday/engine/src/uri.cpp +++ b/doomsday/engine/src/uri.cpp @@ -262,7 +262,7 @@ struct Uri::Instance resolvedForGame = 0; } - void parseScheme(resourceclass_t defaultResourceClass) + void parseScheme(resourceclassid_t defaultResourceClass) { LOG_AS("Uri::parseScheme"); @@ -288,11 +288,13 @@ struct Uri::Instance // Attempt to guess the scheme by interpreting the path? if(defaultResourceClass == RC_UNKNOWN) - defaultResourceClass = F_DefaultResourceClassForType(F_GuessResourceTypeFromFileName(Str_Text(&path))); + { + defaultResourceClass = F_GuessResourceTypeFromFileName(Str_Text(&path)).defaultClass(); + } - if(VALID_RESOURCE_CLASS(defaultResourceClass)) + if(VALID_RESOURCE_CLASSID(defaultResourceClass)) { - ResourceNamespace* rnamespace = F_DefaultResourceNamespaceForClass(defaultResourceClass); + ResourceNamespace* rnamespace = F_ResourceNamespaceByName(F_ResourceClassById(defaultResourceClass)->defaultNamespace()); DENG_ASSERT(rnamespace); QByteArray rnamespaceName = rnamespace->name().toUtf8(); Str_Set(&scheme, rnamespaceName.constData()); @@ -393,7 +395,7 @@ struct Uri::Instance } }; -Uri::Uri(String path, resourceclass_t defaultResourceClass, QChar delimiter) +Uri::Uri(String path, resourceclassid_t defaultResourceClass, QChar delimiter) { d = new Instance(); if(!path.isEmpty()) @@ -594,7 +596,7 @@ Uri& Uri::setPath(String newPath, QChar delimiter) return *this; } -Uri& Uri::setUri(String rawUri, resourceclass_t defaultResourceClass, QChar delimiter) +Uri& Uri::setUri(String rawUri, resourceclassid_t defaultResourceClass, QChar delimiter) { LOG_AS("Uri::setUri"); @@ -790,7 +792,7 @@ LIBDENG_RUN_UNITTEST(Uri) DENG2_ASSERT(inst); \ de::Uri const* self = TOINTERNAL_CONST(inst) -Uri* Uri_NewWithPath2(char const* path, resourceclass_t defaultResourceClass) +Uri* Uri_NewWithPath2(char const* path, resourceclassid_t defaultResourceClass) { return reinterpret_cast( new de::Uri(path, defaultResourceClass) ); } @@ -895,7 +897,7 @@ Uri* Uri_SetPath(Uri* uri, char const* path) return reinterpret_cast(&self->setPath(path)); } -Uri* Uri_SetUri2(Uri* uri, char const* path, resourceclass_t defaultResourceClass) +Uri* Uri_SetUri2(Uri* uri, char const* path, resourceclassid_t defaultResourceClass) { SELF(uri); return reinterpret_cast(&self->setUri(path, defaultResourceClass)); diff --git a/doomsday/engine/src/zip.cpp b/doomsday/engine/src/zip.cpp index 2beca53df7..58b04d7dde 100644 --- a/doomsday/engine/src/zip.cpp +++ b/doomsday/engine/src/zip.cpp @@ -973,50 +973,23 @@ static bool applyGamePathMappings(String& path) if(!path.contains('/')) { // No directory separators; i.e., a root file. - resourcetype_t type = F_GuessResourceTypeFromFileName(path.fileName()); - resourceclass_t rclass; + ResourceType const& rtype = F_GuessResourceTypeFromFileName(path.fileName()); - // Certain resource files require special handling. - // Something of a kludge, at this level. - switch(type) - { - case RT_DEH: // Treat DeHackEd patches as packages so they are mapped to Data. - rclass = RC_PACKAGE; - break; - - case RT_NONE: { // *.lmp files must be mapped to Data. - String ext = path.fileNameExtension(); - if(!ext.empty() && !ext.compareWithoutCase(".lmp")) - { - rclass = RC_PACKAGE; - } - else - { - rclass = RC_UNKNOWN; - } - break; } - - default: - rclass = F_DefaultResourceClassForType(type); - break; - } - // Kludge end - - // Mapped to the Data directory? - if(rclass == RC_PACKAGE) + switch(rtype.defaultClass()) { + case RC_PACKAGE: + // Mapped to the Data directory. path = String("$(App.DataPath)/$(GamePlugin.Name)/auto/") / path; return true; - } - // Mapped to the Defs directory? - if(rclass == RC_DEFINITION) - { + case RC_DEFINITION: + // Mapped to the Defs directory? path = String("$(App.DefsPath)/$(GamePlugin.Name)/auto/") / path; return true; - } - return false; + default: + return false; + } } // Key-named directories in the root might be mapped to another location.