diff --git a/doomsday/engine/api/dd_share.h b/doomsday/engine/api/dd_share.h index 74b4ebd5d3..09cb4adf6d 100644 --- a/doomsday/engine/api/dd_share.h +++ b/doomsday/engine/api/dd_share.h @@ -1248,35 +1248,6 @@ typedef enum materialschemeid_e { /// @c true= val can be interpreted as a valid material scheme identifier. #define VALID_MATERIALSCHEMEID(val) ((val) >= MATERIALSCHEME_FIRST && (val) <= MATERIALSCHEME_LAST) -/* - * Texture Schemes - */ - -/// Texture scheme identifiers. @ingroup scheme -typedef enum textureschemeid_e { - TS_ANY = -1, - TEXTURESCHEME_FIRST = 2000, - TS_SYSTEM = TEXTURESCHEME_FIRST, - TS_FLATS, - TS_TEXTURES, - TS_SPRITES, - TS_PATCHES, - TS_DETAILS, - TS_REFLECTIONS, - TS_MASKS, - TS_MODELSKINS, - TS_MODELREFLECTIONSKINS, - TS_LIGHTMAPS, - TS_FLAREMAPS, - TEXTURESCHEME_LAST = TS_FLAREMAPS, - TS_INVALID /// Special value used to signify an invalid scheme identifier. -} textureschemeid_t; - -#define TEXTURESCHEME_COUNT (TEXTURESCHEME_LAST - TEXTURESCHEME_FIRST + 1) - -/// @c true= val can be interpreted as a valid texture scheme identifier. -#define VALID_TEXTURESCHEMEID(val) ((val) >= TEXTURESCHEME_FIRST && (val) <= TEXTURESCHEME_LAST) - /* * Font Schemes */ diff --git a/doomsday/engine/api/doomsday.def b/doomsday/engine/api/doomsday.def index 2de35689a0..e7e669173c 100644 --- a/doomsday/engine/api/doomsday.def +++ b/doomsday/engine/api/doomsday.def @@ -21,7 +21,7 @@ EXPORTS DD_GetVariable @43 NONAME DD_GetPlayer @44 NONAME DD_MaterialForTextureUniqueId @234 NONAME - DD_ParseTextureSchemeName @502 NONAME +; DD_ParseTextureSchemeName @502 NONAME DD_ParseMaterialSchemeName @503 NONAME ; Base: Types. @@ -673,8 +673,8 @@ EXPORTS R_ComposePatchUri @247 NONAME R_ComposePatchPath @858 NONAME - R_TextureUniqueId @438 NONAME - R_TextureUniqueId2 @501 NONAME + Textures_UniqueId @438 NONAME + Textures_UniqueId2 @501 NONAME R_CreateAnimGroup @241 NONAME R_AddAnimGroupFrame @242 NONAME diff --git a/doomsday/engine/api/doomsday.h b/doomsday/engine/api/doomsday.h index b82eecd066..d326e56679 100644 --- a/doomsday/engine/api/doomsday.h +++ b/doomsday/engine/api/doomsday.h @@ -196,7 +196,6 @@ boolean DD_GameInfo(GameInfo* info); /// @addtogroup scheme ///@{ -textureschemeid_t DD_ParseTextureSchemeName(const char* str); materialschemeid_t DD_ParseMaterialSchemeName(const char* str); ///@} @@ -205,7 +204,7 @@ materialschemeid_t DD_ParseMaterialSchemeName(const char* str); * @ingroup resource */ ///@{ -materialid_t DD_MaterialForTextureUniqueId(textureschemeid_t texSchemeId, int uniqueId); +materialid_t DD_MaterialForTextureUniqueId(char const *schemeName, int uniqueId); ///@} /// @addtogroup defs @@ -648,8 +647,8 @@ boolean R_GetPatchInfo(patchid_t id, patchinfo_t* info); Uri* R_ComposePatchUri(patchid_t id); AutoStr* R_ComposePatchPath(patchid_t id); -int R_TextureUniqueId2(const Uri* uri, boolean quiet); -int R_TextureUniqueId(const Uri* uri); /*quiet=false*/ +int Textures_UniqueId2(const Uri* uri, boolean quiet); +int Textures_UniqueId(const Uri* uri); /*quiet=false*/ int R_CreateAnimGroup(int flags); void R_AddAnimGroupFrame(int groupNum, const Uri* texture, int tics, int randomTics); diff --git a/doomsday/engine/engine.pro b/doomsday/engine/engine.pro index 693e08c102..0ede3177f5 100644 --- a/doomsday/engine/engine.pro +++ b/doomsday/engine/engine.pro @@ -306,6 +306,7 @@ DENG_HEADERS += \ include/resource/r_data.h \ include/resource/rawtexture.h \ include/resource/texture.h \ + include/resource/texturemetafile.h \ include/resource/textures.h \ include/resource/texturevariant.h \ include/resource/texturevariantspecification.h \ diff --git a/doomsday/engine/include/dd_main.h b/doomsday/engine/include/dd_main.h index 1ca718eb86..7b08ed32a5 100644 --- a/doomsday/engine/include/dd_main.h +++ b/doomsday/engine/include/dd_main.h @@ -200,20 +200,21 @@ de::ResourceClass& DD_ResourceClassById(resourceclassid_t classId); */ de::ResourceClass& DD_ResourceClassByName(de::String name); +/// @return Symbolic name of the material scheme associated with @a textureSchemeName. +ddstring_t const *DD_MaterialSchemeNameForTextureScheme(de::String textureSchemeName); + extern "C" { #endif // __cplusplus -textureschemeid_t DD_ParseTextureSchemeName(const char* str); - materialschemeid_t DD_ParseMaterialSchemeName(const char* str); fontschemeid_t DD_ParseFontSchemeName(const char* str); -/// @return Symbolic name of the material scheme associated with @a schemeId. -const ddstring_t* DD_MaterialSchemeNameForTextureScheme(textureschemeid_t schemeId); +/// @return Symbolic name of the material scheme associated with @a textureSchemeName. +ddstring_t const *DD_MaterialSchemeNameForTextureScheme(ddstring_t const *textureSchemeName); /// @return Unique identifier of the material associated with the identified @a uniqueId texture. -materialid_t DD_MaterialForTextureUniqueId(textureschemeid_t schemeId, int uniqueId); +materialid_t DD_MaterialForTextureUniqueId(char const *schemeName, int uniqueId); const char* value_Str(int val); diff --git a/doomsday/engine/include/de_resource.h b/doomsday/engine/include/de_resource.h index d100c2e0d4..8a918184b1 100644 --- a/doomsday/engine/include/de_resource.h +++ b/doomsday/engine/include/de_resource.h @@ -23,6 +23,7 @@ #define LIBDENG_RESOURCE_SUBSYSTEM_H #include "resource/animgroups.h" +#include "resource/bitmapfont.h" #include "resource/colorpalettes.h" #include "resource/font.h" #include "resource/fonts.h" @@ -36,4 +37,8 @@ #include "resource/wad.h" #include "resource/zip.h" +#ifdef __cplusplus +# include "resource/texturemetafile.h" +#endif + #endif /* LIBDENG_RESOURCE_SUBSYSTEM_H */ diff --git a/doomsday/engine/include/gl/gl_texmanager.h b/doomsday/engine/include/gl/gl_texmanager.h index 96eaa9c4ed..8fd573bb5d 100644 --- a/doomsday/engine/include/gl/gl_texmanager.h +++ b/doomsday/engine/include/gl/gl_texmanager.h @@ -119,21 +119,17 @@ void GL_ReleaseRuntimeTextures(void); void GL_ReleaseSystemTextures(void); /** - * Release all textures in the identified scheme(s). + * Release all textures in the identified scheme. * - * @param schemeId Unique identifier of the scheme to process or @c TS_ANY - * to release all textures in any scheme. + * @param schemeName Symbolic name of the texture scheme to process. */ -void GL_ReleaseTexturesByScheme(textureschemeid_t schemeId); +void GL_ReleaseTexturesByScheme(char const *schemeName); /** * Release all textures associated with the specified @a texture. * @param texture Logical Texture. Can be @c NULL, in which case this is a null-op. - * - * @note Can also be used as an iterator callback. */ -int GL_ReleaseGLTexturesByTexture2(Texture* texture, void* paramaters); -int GL_ReleaseGLTexturesByTexture(Texture* texture); /*paramaters=NULL*/ +void GL_ReleaseGLTexturesByTexture(Texture* texture); /** * Release all textures associated with the specified variant @a texture. @@ -309,8 +305,8 @@ void GL_BindTexture(struct texturevariant_s* tex); DGLuint GL_PrepareExtTexture(const char* name, gfxmode_t mode, int useMipmap, int minFilter, int magFilter, int anisoFilter, int wrapS, int wrapT, int flags); -DGLuint GL_PrepareSysFlareTexture(flaretexid_t flare); -DGLuint GL_PrepareLightMap(const Uri* path); +DGLuint GL_PrepareSysFlaremap(flaretexid_t flare); +DGLuint GL_PrepareLightmap(Uri const *path); DGLuint GL_PrepareLSTexture(lightingtexid_t which); DGLuint GL_PrepareRawTexture(rawtex_t* rawTex); @@ -324,8 +320,10 @@ struct texturevariant_s* GL_PreparePatchTexture(Texture* tex); * * @param name Name of a flare texture or "0" to "4". * @param oldIdx Old method of flare texture selection, by id. + * + * @return @c 0= Use the automatic selection logic. */ -DGLuint GL_PrepareFlareTexture(const Uri* path, int oldIdx); +DGLuint GL_PrepareFlareTexture(Uri const *path, int oldIdx); DGLuint GL_NewTextureWithParams(dgltexformat_t format, int width, int height, const uint8_t* pixels, int flags); @@ -333,12 +331,6 @@ DGLuint GL_NewTextureWithParams2(dgltexformat_t format, int width, int height, const uint8_t* pixels, int flags, int grayMipmap, int minFilter, int magFilter, int anisoFilter, int wrapS, int wrapT); -/** - * @param tex Texture instance to compose the cache name of. - * @return The chosen cache name for this texture. - */ -AutoStr* GL_ComposeCacheNameForTexture(Texture* tex); - /** * Dump the pixel data of @a img to an ARGB32 at @a filePath. * diff --git a/doomsday/engine/include/resource/fonts.h b/doomsday/engine/include/resource/fonts.h index bb2d078630..eb9894c38e 100644 --- a/doomsday/engine/include/resource/fonts.h +++ b/doomsday/engine/include/resource/fonts.h @@ -113,7 +113,7 @@ fontid_t Fonts_Id(struct font_s* font); struct font_s* Fonts_ToFont(fontid_t fontId); /// @return Font associated with the scheme-unique identifier @a index else @c NOFONTID. -textureid_t Fonts_FontForUniqueId(fontschemeid_t schemeId, int uniqueId); +fontid_t Fonts_FontForUniqueId(fontschemeid_t schemeId, int uniqueId); /// @return Scheme-unique identfier associated with the identified @a fontId. int Fonts_UniqueId(fontid_t fontId); diff --git a/doomsday/engine/include/resource/r_data.h b/doomsday/engine/include/resource/r_data.h index f03c69e298..9bca7067d9 100644 --- a/doomsday/engine/include/resource/r_data.h +++ b/doomsday/engine/include/resource/r_data.h @@ -157,25 +157,16 @@ Uri *R_ComposePatchUri(patchid_t id); /// returned if the id is invalid/unknown. AutoStr *R_ComposePatchPath(patchid_t id); -struct texture_s *R_CreateSkinTex(Uri const *filePath, boolean isShinySkin); - -struct texture_s *R_CreateLightMap(Uri const *resourcePath); - -struct texture_s *R_CreateFlareTexture(Uri const *resourcePath); - -struct texture_s *R_CreateReflectionTexture(Uri const *resourcePath); - -struct texture_s *R_CreateMaskTexture(Uri const *resourcePath, Size2Raw const *size); - -/** - * Construct a DetailTexture according to the paramaters of the definition. - * @note May return an existing DetailTexture if it is concluded that the - * definition does not infer a unique DetailTexture. - * - * @param def Definition describing the desired DetailTexture. - * @return DetailTexture inferred from the definition or @c NULL if invalid. +/* + * TODO: Merge/generalize these very similar routines. */ -struct texture_s *R_CreateDetailTextureFromDef(ded_detailtexture_t const *def); + +struct texture_s *R_CreateSkinTex(Uri const *resourceUri, boolean isShinySkin); +struct texture_s *R_CreateLightmap(Uri const *resourceUri); +struct texture_s *R_CreateFlaremap(Uri const *resourceUri); +struct texture_s *R_CreateReflectionTexture(Uri const *resourceUri); +struct texture_s *R_CreateMaskTexture(Uri const *resourceUri, Size2Raw const *dimensions); +struct texture_s *R_CreateDetailTexture(Uri const *resourceUri); #ifdef __cplusplus } // extern "C" diff --git a/doomsday/engine/include/resource/rawtexture.h b/doomsday/engine/include/resource/rawtexture.h index 50169be84d..8378a940a4 100644 --- a/doomsday/engine/include/resource/rawtexture.h +++ b/doomsday/engine/include/resource/rawtexture.h @@ -24,8 +24,6 @@ #include "dd_share.h" // For lumpnum_t -#include - /** * A rawtex is a lump raw graphic that has been prepared for render. */ diff --git a/doomsday/engine/include/resource/texture.h b/doomsday/engine/include/resource/texture.h index 3a02a3bde0..57ffd707f9 100644 --- a/doomsday/engine/include/resource/texture.h +++ b/doomsday/engine/include/resource/texture.h @@ -24,9 +24,10 @@ #define LIBDENG_RESOURCE_TEXTURE_H #include -#include "textures.h" #include "texturevariant.h" +typedef int textureid_t; + #ifdef __cplusplus extern "C" { #endif @@ -53,6 +54,7 @@ typedef enum { #ifdef __cplusplus #include +#include namespace de { @@ -79,7 +81,7 @@ class Texture * for the resultant texture. * @param userData User data to associate with the resultant texture. */ - Texture(textureid_t bindId, void *userData = 0); + Texture(textureid_t bindId, Flags flags = 0, void *userData = 0); /** * @param bindId Unique identifier of the primary binding in the owning @@ -90,7 +92,7 @@ class Texture * image at load time. * @param userData User data to associate with the resultant texture. */ - Texture(textureid_t bindId, Size2Raw const &dimensions, void *userData = 0); + Texture(textureid_t bindId, Size2Raw const &dimensions, Flags flags = 0, void *userData = 0); ~Texture(); @@ -130,10 +132,13 @@ class Texture */ TextureVariant &addVariant(TextureVariant &variant); - /// @return Number of variants for this texture. + /// @return Number of variants for the texture. uint variantCount() const; - /// Destroy all prepared variants owned by this texture. + /// Destroy all analyses for the texture. + void clearAnalyses(); + + /// Destroy all prepared variants for the texture. void clearVariants(); /** diff --git a/doomsday/engine/include/resource/texturemetafile.h b/doomsday/engine/include/resource/texturemetafile.h new file mode 100644 index 0000000000..6a805f91e0 --- /dev/null +++ b/doomsday/engine/include/resource/texturemetafile.h @@ -0,0 +1,149 @@ +/** + * @file texturemetafile.h + * @ingroup resource + * + * @author Copyright © 2010-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_RESOURCE_TEXTUREMETAFILE_H +#define LIBDENG_RESOURCE_TEXTUREMETAFILE_H + +#include +#include +#include +#include "uri.hh" +#include "resource/texture.h" + +namespace de { + +class Textures; + +/** + * Models a texture reference and the associated metadata for a resource + * in the Textures collection. + */ +class TextureMetaFile : public PathTree::Node +{ +public: + TextureMetaFile(PathTree::NodeArgs const &args); + virtual ~TextureMetaFile(); + + /** + * Interpret the TextureMetaFile creating a new logical Texture instance. + * + * @param dimensions Logical dimensions. Components can be @c 0 in which + * case their value will be inherited from the actual + * pixel dimensions of the image at load time. + * @param flags Flags. + * @param userData User data to associate with the resultant texture. + */ + Texture *define(Size2Raw const &dimensions, Texture::Flags flags); + + /** + * @copydoc define() + */ + Texture *define(Texture::Flags flags); + + /** + * Returns the owning scheme of the TextureMetaFile. + */ + Textures::Scheme &scheme() const; + + /** + * Compose a URI of the form "scheme:path" for the TextureMetaFile. + * + * The scheme component of the URI will contain the symbolic name of + * the scheme for the TextureMetaFile. + * + * The path component of the URI will contain the percent-encoded path + * of the TextureMetaFile. + */ + Uri composeUri(QChar sep = '/') const; + + /** + * Compose a URN of the form "urn:scheme:uniqueid" for the texture + * TextureMetaFile. + * + * The scheme component of the URI will contain the identifier 'urn'. + * + * The path component of the URI is a string which contains both the + * symbolic name of the scheme followed by the unique id of the texture + * TextureMetaFile, separated with a colon. + * + * @see uniqueId(), setUniqueId() + */ + Uri composeUrn() const; + + /** + * Returns the URI to the associated resource. May be empty. + */ + Uri const &resourceUri() const; + + /** + * Change the resource URI associated with the metafile. + * + * @return @c true iff @a newUri differed to the existing URI, which + * was subsequently changed. + */ + bool setResourceUri(Uri const &newUri); + + /** + * Returns the logical Texture instance associated with the metafile; + * otherwise @c 0. + */ + Texture *texture() const; + + /** + * Change the logical Texture associated with the metafile. + * + * @param newTexture New logical Texture to associate. + */ + void setTexture(Texture *newTexture); + + /** + * Returns the scheme-unique identifier for the metafile. + */ + int uniqueId() const; + + /** + * Change the unique identifier associated with the metafile. + * + * @return @c true iff @a newUniqueId differed to the existing unique + * identifier, which was subsequently changed. + */ + bool setUniqueId(int newUniqueId); + + /// Returns a reference to the application's texture system. + static Textures &textures(); + + /// @todo Refactor away -ds + textureid_t lookupTextureId() const; + +private: + /// Scheme-unique identifier determined by the owner of the subspace. + int uniqueId_; + + /// Path to the resource containing the loadable data. + Uri resourceUri_; + + /// The associated logical Texture instance (if any). + Texture *texture_; +}; + +} // namespace de + +#endif /// LIBDENG_RESOURCE_TEXTUREMETAFILE_H diff --git a/doomsday/engine/include/resource/textures.h b/doomsday/engine/include/resource/textures.h index ede2883ccb..591f5b11a5 100644 --- a/doomsday/engine/include/resource/textures.h +++ b/doomsday/engine/include/resource/textures.h @@ -1,21 +1,9 @@ /** - * @file textures.h - * Textures collection. @ingroup resource + * @file textures.h Texture Resource Collection. + * @ingroup resource * - * "Clear"ing a Texture is to 'undefine' it - any names bound to it are deleted, - * any GL textures acquired for it are 'released'. The Texture instance record - * used to represent it is also deleted. - * - * "Release"ing a Texture will leave it defined (any names bound to it will - * persist) and any GL textures acquired for it are so too released. Note that - * the Texture instance record used to represent it will NOT be deleted. - * - * Thus there are two general states for textures in the collection: - * - * 1) Declared but not defined. - * 2) Declared and defined. - * - * @authors Copyright © 2010-2012 Daniel Swanson + * @author Copyright © 2010-2012 Daniel Swanson + * @author Copyright © 2010-2012 Jaakko Keränen * * @par License * GPL: http://www.gnu.org/licenses/gpl.html @@ -35,166 +23,362 @@ #ifndef LIBDENG_RESOURCE_TEXTURES_H #define LIBDENG_RESOURCE_TEXTURES_H -#include "dd_share.h" #include "uri.h" -#ifdef __cplusplus -extern "C" { -#endif - /// Unique identifier associated with each texture name in the collection. -typedef uint textureid_t; +typedef int textureid_t; /// Special value used to signify an invalid texture id. -#define NOTEXTUREID 0 - -enum textureschemeid_e; // Defined in dd_share.h -struct texture_s; - -/// Register the console commands, variables, etc..., of this module. -void Textures_Register(void); - -/// Initialize this module. -void Textures_Init(void); - -/// Shutdown this module. -void Textures_Shutdown(void); - -/** - * Try to interpret a texture scheme identifier from @a str. If found to match a known - * scheme name, return the associated identifier. If the reference @a str is not valid - * (i.e., NULL or a zero-length string) then the special identifier @c TS_ANY is returned. - * Otherwise @c TS_INVALID. - */ -textureschemeid_t Textures_ParseSchemeName(const char* str); - -/// @return Name associated with the identified @a schemeId else a zero-length string. -const Str* Textures_SchemeName(textureschemeid_t schemeId); - -/// @return Total number of unique Textures in the collection. -uint Textures_Size(void); - -/// @return Number of unique Textures in the identified @a schemeId. -uint Textures_Count(textureschemeid_t schemeId); - -/// Clear all textures in all schemes (and release any acquired GL-textures). -void Textures_Clear(void); - -/// Clear all textures flagged 'runtime' (and release any acquired GL-textures). -void Textures_ClearRuntime(void); - -/// Clear all textures flagged 'system' (and release any acquired GL-textures). -void Textures_ClearSystem(void); - -/** - * Clear all textures in the identified scheme(s) (and release any acquired GL-textures). - * - * @param schemeId Unique identifier of the scheme to process or - * @c TS_ANY to clear all textures in any scheme. - */ -void Textures_ClearScheme(textureschemeid_t schemeId); - -/// @return Unique identifier of the primary name for @a texture else @c NOTEXTUREID. -textureid_t Textures_Id(struct texture_s* texture); +#define NOTEXTUREID 0 -/// @return Texture associated with unique identifier @a textureId else @c NULL. -struct texture_s* Textures_ToTexture(textureid_t textureId); - -/// @return Texture associated with the scheme-unique identifier @a index else @c NOTEXTUREID. -textureid_t Textures_TextureForUniqueId(textureschemeid_t schemeId, int uniqueId); - -struct texture_s *Textures_TextureForResourcePath(textureschemeid_t schemeId, Uri const *resourcePath); - -/// @return Scheme-unique identfier associated with the identified @a textureId. -int Textures_UniqueId(textureid_t textureId); - -/// @return Declared, percent-encoded path to this data resource, -/// else a "null" Uri (no scheme or path). -const Uri* Textures_ResourcePath(textureid_t textureId); - -/// @return Unique identifier of the scheme this name is in. -textureschemeid_t Textures_Scheme(textureid_t textureId); +#ifdef __cplusplus -/// @return Symbolic, percent-encoded name/path-to this texture as a string. -/// Must be destroyed with Str_Delete(). -AutoStr* Textures_ComposePath(textureid_t textureId); +#include +#include +#include +#include +#include +#include +#include "resource/texture.h" -/// @return URI to this texture, percent-encoded. Must be destroyed with Uri_Delete(). -Uri* Textures_ComposeUri(textureid_t textureId); +namespace de { -/// @return Unique URN to this texture. Must be destroyed with Uri_Delete(). -Uri* Textures_ComposeUrn(textureid_t textureId); +class TextureMetaFile; /** - * Search the Textures collection for a texture associated with @a uri. + * @em Clearing a texture is to 'undefine' it - any names bound to it will be + * deleted and any GL textures acquired for it are 'released'. The logical + * Texture instance used to represent it is also deleted. * - * @param uri Either a path or a URN. - * @return Unique identifier of the found texture else @c NOTEXTUREID. - */ -textureid_t Textures_ResolveUri2(const Uri* uri, boolean quiet); -textureid_t Textures_ResolveUri(const Uri* uri); /*quiet=!(verbose >= 1)*/ - -/// Same as Textures::ResolveUri except @a uri is a C-string. -textureid_t Textures_ResolveUriCString2(const char* uri, boolean quiet); -textureid_t Textures_ResolveUriCString(const char* uri); /*quiet=!(verbose >= 1)*/ - -/** - * Declare a texture in the collection. If a texture with the specified @a uri already - * exists, its unique identifier is returned. If the given @a resourcePath differs from - * that already defined for the pre-existing texture, any associated Texture instance - * is released (and any GL-textures acquired for it). + * @em Releasing a texture will leave it defined (any names bound to it will + * persist) but any GL textures acquired for it are 'released'. Note that the + * logical Texture instance used to represent is NOT be deleted. * - * @param uri Uri representing a path to the texture in the virtual hierarchy. - * @param uniqueId Scheme-unique identifier to associate with the texture. - * @param resourcepath The path to the underlying data resource. + * Thus there are two general states for textures in the collection: * - * @return Unique identifier for this texture unless @a uri is invalid, in which case - * @c NOTEXTUREID is returned. + * A) Declared but not defined. + * B) Declared and defined. */ -textureid_t Textures_Declare(Uri* uri, int uniqueId, Uri const* resourcePath); - -/** - * Create/update a Texture instance in the collection. - * - * @param id Unique identifier of the previously declared Texture. - * @param custom @c true= this is a custom texture. - * @param size Logical size. Components can be @c 0 in which case their value will - * be inherited from the actual pixel size of the texture at load time. - * @param userData User data to associate with the resultant texture. +class Textures +{ +public: + typedef class TextureMetaFile MetaFile; + + class Scheme; // forward declaration + + struct ResourceClass + { + /** + * Interpret a metafile producing a new logical Texture instance.. + * + * @param metafile The file to be interpreted. + * @param dimensions Logical dimensions. Components can be @c 0 in + * which case their value will be inherited from the + * actual pixel dimensions of the image at load time. + * @param flags Texture Flags. + * @param userData User data to associate with the resultant texture. + */ + static Texture *interpret(MetaFile &metafile, Size2Raw const &dimensions, + Texture::Flags flags, void *userData = 0); + + /** + * @copydoc interpret() + */ + static Texture *interpret(MetaFile &metafile, Texture::Flags flags, + void *userData = 0); + }; + + /** + * Scheme defines a texture system subspace. + */ + class Scheme + { + public: + /// Minimum length of a symbolic name. + static int const min_name_length = URI_MINSCHEMELENGTH; + + /// Texture metafiles within the scheme are placed into a tree. + typedef PathTreeT Index; + + public: + /// The requested metafile could not be found in the index. + DENG2_ERROR(NotFoundError); + + public: + /** + * Construct a new (empty) texture subspace scheme. + * + * @param symbolicName Symbolic name of the new subspace scheme. Must + * have at least @ref min_name_length characters. + */ + explicit Scheme(String symbolicName); + + ~Scheme(); + + /// @return Symbolic name of this scheme (e.g., "ModelSkins"). + String const& name() const; + + /// @return Total number of metafiles in the scheme. + int size() const; + + /// @return Total number of metafiles in the scheme. Same as @ref size(). + inline int count() const { + return size(); + } + + /** + * Clear all metafiles in the scheme (any GL textures which have been + * acquired for associated textures will be released). + */ + void clear(); + + /** + * Insert a new metafile at the given @a path into the scheme. + * If a metafile already exists at this path, the existing metafile is + * returned and this is a no-op. + * + * @param path Virtual path for the resultant metafile. + * @return The (possibly newly created) metafile at @a path. + */ + MetaFile &insertMetaFile(Path const &path); + + /** + * Search the scheme for a metafile matching @a path. + * + * @return Found metafile. + */ + MetaFile const &find(Path const &path) const; + + /// @copydoc find() + MetaFile &find(Path const &path); + + /** + * Search the scheme for a metafile whose associated resource + * URI matches @a uri. + * + * @return Found metafile. + */ + MetaFile const &findByResourceUri(Uri const &uri) const; + + /// @copydoc findByResourceUri() + MetaFile &findByResourceUri(Uri const &uri); + + /** + * Search the scheme for a metafile whose associated unique + * identifier matches @a uniqueId. + * + * @return Found metafile. + */ + MetaFile const &findByUniqueId(int uniqueId) const; + + /// @copydoc findByUniqueId() + MetaFile &findByUniqueId(int uniqueId); + + /** + * Provides access to the metafile index for efficient traversal. + */ + Index const &index() const; + + /// @todo Refactor away -ds + void markUniqueIdLutDirty(); + + private: + struct Instance; + Instance *d; + }; + + /// Texture system subspace schemes. + typedef QList Schemes; + +public: + /// An unknown scheme was referenced. @ingroup errors + DENG2_ERROR(UnknownSchemeError); + +public: + /** + * Constructs a new texture resource collection. + */ + Textures(); + + virtual ~Textures(); + + /// Register the console commands, variables, etc..., of this module. + static void consoleRegister(); + + /** + * Lookup a subspace scheme by symbolic name. + * + * @param name Symbolic name of the scheme. + * @return Scheme associated with @a name. + * + * @throws UnknownSchemeError If @a name is unknown. + */ + Scheme &scheme(String name) const; + + /** + * Create a new subspace scheme. + * + * @param name Unique symbolic name of the new scheme. Must be at + * least @c Scheme::min_name_length characters long. + */ + Scheme &createScheme(String name); + + /** + * Returns @c true iff a Scheme exists with the symbolic @a name. + */ + bool knownScheme(String name) const; + + /** + * Returns a list of all the schemes for efficient traversal. + */ + Schemes const &allSchemes() const; + + /** + * Clear all textures in all schemes. + * @see Scheme::clear(). + */ + inline void clearAllSchemes() + { + Schemes schemes = allSchemes(); + DENG2_FOR_EACH(Schemes, i, schemes){ (*i)->clear(); } + } + + /// @return Total number of unique Textures in the collection. + int size() const; + + /// @return Total number of unique Textures in the collection. Same as @ref size() + inline int count() const { + return size(); + } + + /// @return Unique identifier of the primary name for @a texture else @c NOTEXTUREID. + textureid_t id(Texture &texture) const; + + /// @return Unique identifier of the primary name for @a metafile else @c NOTEXTUREID. + textureid_t idForMetaFile(MetaFile const &metafile) const; + + /// @return Texture associated with unique identifier @a textureId else @c 0. + Texture *toTexture(textureid_t textureId) const; + + /// @return Scheme-unique identfier associated with the identified @a textureId. + int uniqueId(textureid_t textureId) const; + + /// @return Declared, percent-encoded path to this data resource, + /// else a "null" Uri (no scheme or path). + Uri const &resourceUri(textureid_t textureId) const; + + /// @return URI to this texture, percent-encoded. + Uri composeUri(textureid_t textureId) const; + + /** + * Find a single declared texture. + * + * @param search The search term. + * @return Found unique identifier; otherwise @c NOTEXTUREID. + */ + MetaFile *find(Uri const &search) const; + + /** + * Declare a texture in the collection. If a texture with the specified + * @a uri already exists, its unique identifier is returned. If the given + * @a resourcePath differs from that already defined for the pre-existing + * texture, any associated Texture instance is released (any GL-textures + * acquired for it). + * + * @param uri Uri representing a path to the texture in the + * virtual hierarchy. + * @param uniqueId Scheme-unique identifier to associate with the + * texture. + * @param resourcepath The path to the underlying data resource. + * + * @return MetaFile for this texture unless @a uri is invalid, in which + * case @c 0 is returned. + */ + MetaFile *declare(Uri const &uri, int uniqueId, Uri const *resourceUri); + + /** + * Removes a file from any indexes. + * + * @param metafile Metafile to remove from the index. + */ + void deindex(MetaFile &metafile); + + /** + * Iterate over defined Textures in the collection making a callback for + * each visited. Iteration ends when all textures have been visited or a + * callback returns non-zero. + * + * @param nameOfScheme If a known symbolic scheme name, only consider + * textures within this scheme. Can be @ zero-length + * string, in which case visit all textures. + * @param callback Callback function ptr. + * @param parameters Passed to the callback. + * + * @return @c 0 iff iteration completed wholly. + */ + int iterate(String nameOfScheme, int (*callback)(Texture &texture, void *parameters), + void *parameters = 0) const; + + /** + * @copydoc iterate() + */ + inline int iterate(int (*callback)(Texture &texture, void *parameters), + void *parameters = 0) const { + return iterate("", callback, parameters); + } + + /** + * Iterate over declared textures in the collection making a callback for + * each visited. Iteration ends when all textures have been visited or a + * callback returns non-zero. + * + * @param nameOfScheme If a known symbolic scheme name, only consider + * textures within this scheme. Can be @ zero-length + * string, in which case visit all textures. + * @param callback Callback function ptr. + * @param parameters Passed to the callback. + * + * @return @c 0 iff iteration completed wholly. + */ + int iterateDeclared(String nameOfScheme, int (*callback)(MetaFile &metafile, void *parameters), + void* parameters = 0) const; + + /** + * @copydoc iterate() + */ + inline int iterateDeclared(int (*callback)(MetaFile &metafile, void *parameters), + void* parameters = 0) const { + return iterateDeclared("", callback, parameters); + } + + +private: + struct Instance; + Instance *d; +}; + +} // namespace de + +de::Textures* App_Textures(); + +#endif __cplusplus + +/* + * C wrapper API */ -struct texture_s* Textures_CreateWithDimensions(textureid_t id, boolean custom, const Size2Raw* size, void* userData); -struct texture_s* Textures_Create(textureid_t id, boolean custom, void* userData); /* width=0, height=0*/ -/** - * Iterate over defined Textures in the collection making a callback for each visited. - * Iteration ends when all textures have been visited or a callback returns non-zero. - * - * @param schemeId If a valid scheme identifier, only consider textures in this - * scheme, otherwise visit all textures. - * @param callback Callback function ptr. - * @param parameters Passed to the callback. - * - * @return @c 0 iff iteration completed wholly. - */ -int Textures_Iterate2(textureschemeid_t schemeId, int (*callback)(struct texture_s* texture, void* parameters), void* parameters); -int Textures_Iterate(textureschemeid_t schemeId, int (*callback)(struct texture_s* texture, void* parameters)); /*parameters=NULL*/ +#ifdef __cplusplus +extern "C" { +#endif -/** - * Iterate over declared textures in the collection making a callback for each visited. - * Iteration ends when all textures have been visited or a callback returns non-zero. - * - * @param schemeId If a valid scheme identifier, only consider textures in this - * scheme, otherwise visit all textures. - * @param callback Callback function ptr. - * @param parameters Passed to the callback. - * - * @return @c 0 iff iteration completed wholly. - */ -int Textures_IterateDeclared2(textureschemeid_t schemeId, int (*callback)(textureid_t textureId, void* parameters), void* parameters); -int Textures_IterateDeclared(textureschemeid_t schemeId, int (*callback)(textureid_t textureId, void* parameters)); /*parameters=NULL*/ +/// Initialize this module. Cannot be re-initialized, must shutdown first. +void Textures_Init(void); + +/// Shutdown this module. +void Textures_Shutdown(void); -int R_TextureUniqueId2(Uri const *uri, boolean quiet); -int R_TextureUniqueId(Uri const *uri/*, quiet = false */); +int Textures_UniqueId2(Uri const *uri, boolean quiet); +int Textures_UniqueId(Uri const *uri/*, quiet = false */); #ifdef __cplusplus } // extern "C" diff --git a/doomsday/engine/include/uri.hh b/doomsday/engine/include/uri.hh index 4c954548dc..2cd3942aaf 100644 --- a/doomsday/engine/include/uri.hh +++ b/doomsday/engine/include/uri.hh @@ -282,6 +282,9 @@ public: * @param sep Character to use to replace path segment separators. * * @return Plain-text String representation. + * + * @todo Should define a set of flags to determine which components of the + * URI to include in the string, like @ref debugPrint() -ds */ String compose(QChar sep = '/') const; diff --git a/doomsday/engine/src/dd_main.cpp b/doomsday/engine/src/dd_main.cpp index 730028e092..f0f9ccd18f 100644 --- a/doomsday/engine/src/dd_main.cpp +++ b/doomsday/engine/src/dd_main.cpp @@ -515,6 +515,54 @@ void DD_CreateFileSystemSchemes() } } +void DD_CreateTextureSchemes() +{ + LOG_VERBOSE("Initializing Textures subsystem..."); + + Textures &textures = *App_Textures(); + textures.createScheme("System"); + textures.createScheme("Flats"); + textures.createScheme("Textures"); + textures.createScheme("Sprites"); + textures.createScheme("Patches"); + textures.createScheme("Details"); + textures.createScheme("Reflections"); + textures.createScheme("Masks"); + textures.createScheme("ModelSkins"); + textures.createScheme("ModelReflectionSkins"); + textures.createScheme("Lightmaps"); + textures.createScheme("Flaremaps"); +} + +void DD_ClearRuntimeTextureSchemes() +{ + Textures &textures = *App_Textures(); + if(!textures.count()) return; + + textures.scheme("Flats").clear(); + textures.scheme("Textures").clear(); + textures.scheme("Patches").clear(); + textures.scheme("Sprites").clear(); + textures.scheme("Details").clear(); + textures.scheme("Reflections").clear(); + textures.scheme("Masks").clear(); + textures.scheme("ModelSkins").clear(); + textures.scheme("ModelReflectionSkins").clear(); + textures.scheme("Lightmaps").clear(); + textures.scheme("Flaremaps").clear(); + + GL_PruneTextureVariantSpecifications(); +} + +void DD_ClearSystemTextureSchemes() +{ + Textures &textures = *App_Textures(); + if(!textures.count()) return; + + textures.scheme("System").clear(); + GL_PruneTextureVariantSpecifications(); +} + /** * Register the engine commands and variables. */ @@ -1368,7 +1416,7 @@ bool DD_ChangeGame(de::Game& game, bool allowReload = false) R_DestroyColorPalettes(); Fonts_ClearRuntime(); - Textures_ClearRuntime(); + DD_ClearRuntimeTextureSchemes(); Sfx_InitLogical(); @@ -2007,9 +2055,13 @@ static int DD_StartupWorker(void* parm) // Execute the startup script (Startup.cfg). Con_ParseCommands("startup.cfg"); - // Get the material manager up and running. Con_SetProgress(90); GL_EarlyInitTextureManager(); + + Textures_Init(); + DD_CreateTextureSchemes(); + + // Get the material manager up and running. Materials_Init(); Con_SetProgress(140); @@ -2505,60 +2557,71 @@ void DD_SetVariable(int ddvalue, void *parm) } /// @note Part of the Doomsday public API. -materialschemeid_t DD_ParseMaterialSchemeName(const char* str) +materialschemeid_t DD_ParseMaterialSchemeName(char const *str) { return Materials_ParseSchemeName(str); } -/// @note Part of the Doomsday public API. -textureschemeid_t DD_ParseTextureSchemeName(const char* str) -{ - return Textures_ParseSchemeName(str); -} - /// @note Part of the Doomsday public API. fontschemeid_t DD_ParseFontSchemeName(const char* str) { return Fonts_ParseScheme(str); } -const ddstring_t* DD_MaterialSchemeNameForTextureScheme(textureschemeid_t texSchemeId) +ddstring_t const *DD_MaterialSchemeNameForTextureScheme(String textureSchemeName) { - static const materialschemeid_t schemeIds[TEXTURESCHEME_COUNT] = { - /* TS_SYSTEM */ MS_SYSTEM, - /* TS_FLATS */ MS_FLATS, - /* TS_TEXTURES */ MS_TEXTURES, - /* TS_SPRITES */ MS_SPRITES, - /* TS_PATCHES */ MS_ANY, // No materials for these yet. - - // -- No Materials for these -- - /* TS_DETAILS */ MS_INVALID, - /* TS_REFLECTIONS */ MS_INVALID, - /* TS_MASKS */ MS_INVALID, - /* TS_MODELSKINS */ MS_INVALID, - /* TS_MODELREFLECTIONSKINS */ MS_INVALID, - /* TS_LIGHTMAPS */ MS_INVALID, - /* TS_FLAREMAPS */ MS_INVALID - }; materialschemeid_t schemeId = MS_INVALID; // Unknown. - if(VALID_TEXTURESCHEMEID(texSchemeId)) - schemeId = schemeIds[texSchemeId-TEXTURESCHEME_FIRST]; + + if(!textureSchemeName.compareWithoutCase("Textures")) + { + schemeId = MS_TEXTURES; + } + else if(!textureSchemeName.compareWithoutCase("Flats")) + { + schemeId = MS_FLATS; + } + else if(!textureSchemeName.compareWithoutCase("Sprites")) + { + schemeId = MS_SPRITES; + } + else if(!textureSchemeName.compareWithoutCase("Patches")) + { + schemeId = MS_ANY; // No materials for these yet. + } + else if(!textureSchemeName.compareWithoutCase("System")) + { + schemeId = MS_SYSTEM; + } + return Materials_SchemeName(schemeId); } -materialid_t DD_MaterialForTextureUniqueId(textureschemeid_t schemeId, int uniqueId) +ddstring_t const *DD_MaterialSchemeNameForTextureScheme(ddstring_t const *textureSchemeName) { - textureid_t texId = Textures_TextureForUniqueId(schemeId, uniqueId); - - if(texId == NOTEXTUREID) return NOMATERIALID; - - de::Uri* uri = reinterpret_cast(Textures_ComposeUri(texId)); - if(!uri) return NOMATERIALID; + if(!textureSchemeName) return Materials_SchemeName(MS_INVALID); + return DD_MaterialSchemeNameForTextureScheme(Str_Text(textureSchemeName)); +} - uri->setScheme(Str_Text(DD_MaterialSchemeNameForTextureScheme(schemeId))); - materialid_t matId = Materials_ResolveUri2(reinterpret_cast(uri), true/*quiet please*/); - delete uri; - return matId; +/// @todo Replace with a version accepting a URN -ds +materialid_t DD_MaterialForTextureUniqueId(char const *schemeName, int uniqueId) +{ + try + { + de::Uri uri = App_Textures()->scheme(schemeName).findByUniqueId(uniqueId).composeUri(); + uri.setScheme(Str_Text(DD_MaterialSchemeNameForTextureScheme(uri.scheme()))); + return Materials_ResolveUri2(reinterpret_cast(&uri), true/*quiet please*/); + } + catch(Textures::UnknownSchemeError const &er) + { + // Log but otherwise ignore this error. + LOG_WARNING(er.asText() + ", ignoring."); + } + catch(Textures::Scheme::NotFoundError const &er) + { + // Log but otherwise ignore this error. + LOG_WARNING(er.asText() + ", ignoring."); + } + return NOMATERIALID; } /** diff --git a/doomsday/engine/src/def_main.cpp b/doomsday/engine/src/def_main.cpp index be30a51b47..df81d036b2 100644 --- a/doomsday/engine/src/def_main.cpp +++ b/doomsday/engine/src/def_main.cpp @@ -922,12 +922,14 @@ void Def_GenerateGroupsFromAnims(void) int groupCount = R_AnimGroupCount(), i; if(!groupCount) return; + de::Textures &textures = *App_Textures(); + // Group ids are 1-based. for(i = 1; i < groupCount+1; ++i) { - const animgroup_t* anim = R_ToAnimGroup(i); - ded_group_member_t* gmbr; - ded_group_t* grp; + animgroup_t const *anim = R_ToAnimGroup(i); + ded_group_member_t *gmbr; + ded_group_t *grp; int idx, j; idx = DED_AddGroup(&defs); @@ -937,129 +939,104 @@ void Def_GenerateGroupsFromAnims(void) for(j = 0; j < anim->count; ++j) { - const animframe_t* frame = &anim->frames[j]; + animframe_t const *frame = &anim->frames[j]; idx = DED_AddGroupMember(grp); gmbr = &grp->members[idx]; gmbr->tics = frame->tics; gmbr->randomTics = frame->randomTics; - gmbr->material = Textures_ComposeUri(frame->texture); - Uri_SetScheme(gmbr->material, Str_Text(DD_MaterialSchemeNameForTextureScheme(Textures_Scheme(frame->texture)))); + de::Uri textureUri = textures.composeUri(frame->texture); + gmbr->material = reinterpret_cast(new de::Uri(Str_Text(DD_MaterialSchemeNameForTextureScheme(textureUri.scheme())), textureUri.path())); } } } -static int generateMaterialDefForCompositeTexture(textureid_t texId, void* /*parameters*/) +static int generateMaterialDefForCompositeTexture(de::TextureMetaFile &metafile, void * /*parameters*/) { LOG_AS("generateMaterialDefForCompositeTexture"); - Uri* texUri = Textures_ComposeUri(texId); - ded_material_layer_stage_t* st; - ded_material_t* mat; - int stage, idx; - Texture* tex; + de::Uri texUri = metafile.composeUri(); - idx = DED_AddMaterial(&defs, NULL); - mat = &defs.materials[idx]; + int matIdx = DED_AddMaterial(&defs, 0); + ded_material_t *mat = &defs.materials[matIdx]; mat->autoGenerated = true; + mat->uri = reinterpret_cast(new de::Uri("Textures", texUri.path())); - mat->uri = Uri_Dup(texUri); - Uri_SetScheme(mat->uri, "Textures"); - - tex = Textures_ToTexture(texId); - if(tex) + if(de::Texture *tex = metafile.texture()) { - de::CompositeTexture* pcTex = reinterpret_cast(Texture_UserDataPointer(tex)); + de::CompositeTexture* pcTex = reinterpret_cast(tex->userDataPointer()); DENG_ASSERT(pcTex); - mat->width = Texture_Width(tex); - mat->height = Texture_Height(tex); + mat->width = tex->width(); + mat->height = tex->height(); mat->flags = (pcTex->flags().testFlag(de::CompositeTexture::NoDraw)? MATF_NO_DRAW : 0); } #if _DEBUG else { - AutoStr* path = Uri_ToString(texUri); - LOG_WARNING("Texture \"%s\" yet defined, resultant Material will inherit dimensions.") - << Str_Text(path); + LOG_DEBUG("Texture \"%s\" yet defined, resultant Material will inherit dimensions.") << texUri; } #endif - stage = DED_AddMaterialLayerStage(&mat->layers[0]); - st = &mat->layers[0].stages[stage]; - st->texture = texUri; + int stage = DED_AddMaterialLayerStage(&mat->layers[0]); + ded_material_layer_stage_t *st = &mat->layers[0].stages[stage]; + st->texture = reinterpret_cast(new de::Uri(texUri)); return 0; // Continue iteration. } -static int generateMaterialDefForFlatTexture(textureid_t texId, void* parameters) +static int generateMaterialDefForFlatTexture(de::TextureMetaFile &metafile, void * /*parameters*/) { - DENG_UNUSED(parameters); + LOG_AS("generateMaterialDefForFlatTexture"); - Uri* texUri = Textures_ComposeUri(texId); - ded_material_layer_stage_t* st; - ded_material_t* mat; - int stage, idx; - Texture* tex; + de::Uri texUri = metafile.composeUri(); - idx = DED_AddMaterial(&defs, NULL); - mat = &defs.materials[idx]; + int matIdx = DED_AddMaterial(&defs, 0); + ded_material_t *mat = &defs.materials[matIdx]; mat->autoGenerated = true; + mat->uri = reinterpret_cast(new de::Uri("Flats", texUri.path())); - mat->uri = Uri_Dup(texUri); - Uri_SetScheme(mat->uri, "Flats"); - - stage = DED_AddMaterialLayerStage(&mat->layers[0]); - st = &mat->layers[0].stages[stage]; - st->texture = texUri; + int stage = DED_AddMaterialLayerStage(&mat->layers[0]); + ded_material_layer_stage_t *st = &mat->layers[0].stages[stage]; + st->texture = reinterpret_cast(new de::Uri(texUri)); - tex = Textures_ToTexture(texId); - if(tex) + if(de::Texture *tex = metafile.texture()) { - mat->width = Texture_Width(tex); - mat->height = Texture_Height(tex); + mat->width = tex->width(); + mat->height = tex->height(); } #if _DEBUG else { - AutoStr* path = Uri_ToString(texUri); - Con_Message("Warning:generateMaterialDefForFlatTexture: Texture \"%s\" has not yet been defined, resultant Material will inherit dimensions.\n", Str_Text(path)); + LOG_DEBUG("Texture \"%s\" not yet defined, resultant Material will inherit dimensions.") << texUri; } #endif return 0; // Continue iteration. } -static int generateMaterialDefForSpriteTexture(textureid_t texId, void* parameters) +static int generateMaterialDefForSpriteTexture(de::TextureMetaFile &metafile, void * /*parameters*/) { - DENG_UNUSED(parameters); + LOG_AS("generateMaterialDefForSpriteTexture"); - Uri* texUri = Textures_ComposeUri(texId); - ded_material_layer_stage_t* st; - ded_material_t* mat; - int stage, idx; - Texture* tex; + de::Uri texUri = metafile.composeUri(); - idx = DED_AddMaterial(&defs, NULL); - mat = &defs.materials[idx]; + int matIdx = DED_AddMaterial(&defs, 0); + ded_material_t *mat = &defs.materials[matIdx]; mat->autoGenerated = true; + mat->uri = reinterpret_cast(new de::Uri("Sprites", texUri.path())); - mat->uri = Uri_Dup(texUri); - Uri_SetScheme(mat->uri, "Sprites"); + int stage = DED_AddMaterialLayerStage(&mat->layers[0]); + ded_material_layer_stage_t *st = &mat->layers[0].stages[stage]; + st->texture = reinterpret_cast(new de::Uri(texUri)); - stage = DED_AddMaterialLayerStage(&mat->layers[0]); - st = &mat->layers[0].stages[stage]; - st->texture = texUri; - - tex = Textures_ToTexture(texId); - if(tex) + if(de::Texture *tex = metafile.texture()) { - mat->width = Texture_Width(tex); - mat->height = Texture_Height(tex); + mat->width = tex->width(); + mat->height = tex->height(); } #if _DEBUG else { - AutoStr* path = Uri_ToString(texUri); - Con_Message("Warning:generateMaterialDefForSpriteTexture: Texture \"%s\" has not yet been defined, resultant Material will inherit dimensions.\n", Str_Text(path)); + LOG_DEBUG("Texture \"%s\" not yet defined, resultant Material will inherit dimensions.") << texUri; } #endif @@ -1068,9 +1045,10 @@ static int generateMaterialDefForSpriteTexture(textureid_t texId, void* paramete void Def_GenerateAutoMaterials(void) { - Textures_IterateDeclared(TS_TEXTURES, generateMaterialDefForCompositeTexture); - Textures_IterateDeclared(TS_FLATS, generateMaterialDefForFlatTexture); - Textures_IterateDeclared(TS_SPRITES, generateMaterialDefForSpriteTexture); + de::Textures &textures = *App_Textures(); + textures.iterateDeclared("Textures", generateMaterialDefForCompositeTexture); + textures.iterateDeclared("Flats", generateMaterialDefForFlatTexture); + textures.iterateDeclared("Sprites", generateMaterialDefForSpriteTexture); } void Def_Read(void) @@ -1081,7 +1059,7 @@ void Def_Read(void) { // We've already initialized the definitions once. // Get rid of everything. - de::FS1::Scheme& scheme = App_FileSystem()->scheme(DD_ResourceClassByName("RC_MODEL").defaultScheme()); + de::FS1::Scheme &scheme = App_FileSystem()->scheme(DD_ResourceClassByName("RC_MODEL").defaultScheme()); scheme.reset(); Materials_ClearDefinitionLinks(); @@ -1462,24 +1440,27 @@ void Def_PostInit(void) } // Detail textures. - Textures_ClearScheme(TS_DETAILS); + App_Textures()->scheme("Details").clear(); for(int i = 0; i < defs.count.details.num; ++i) { - R_CreateDetailTextureFromDef(&defs.details[i]); + ded_detailtexture_t *dtl = &defs.details[i]; + if(!dtl->detailTex) continue; + + R_CreateDetailTexture(dtl->detailTex); } - // Lightmaps and flare textures. - Textures_ClearScheme(TS_LIGHTMAPS); - Textures_ClearScheme(TS_FLAREMAPS); + // Lights. + App_Textures()->scheme("Lightmaps").clear(); + App_Textures()->scheme("Flaremaps").clear(); for(int i = 0; i < defs.count.lights.num; ++i) { ded_light_t* lig = &defs.lights[i]; - R_CreateLightMap(lig->up); - R_CreateLightMap(lig->down); - R_CreateLightMap(lig->sides); + R_CreateLightmap(lig->up); + R_CreateLightmap(lig->down); + R_CreateLightmap(lig->sides); - R_CreateFlareTexture(lig->flare); + R_CreateFlaremap(lig->flare); } for(int i = 0; i < defs.count.decorations.num; ++i) @@ -1492,17 +1473,17 @@ void Def_PostInit(void) if(!R_IsValidLightDecoration(lig)) break; - R_CreateLightMap(lig->up); - R_CreateLightMap(lig->down); - R_CreateLightMap(lig->sides); + R_CreateLightmap(lig->up); + R_CreateLightmap(lig->down); + R_CreateLightmap(lig->sides); - R_CreateFlareTexture(lig->flare); + R_CreateFlaremap(lig->flare); } } // Surface reflections. - Textures_ClearScheme(TS_REFLECTIONS); - Textures_ClearScheme(TS_MASKS); + App_Textures()->scheme("Reflections").clear(); + App_Textures()->scheme("Masks").clear(); for(int i = 0; i < defs.count.reflections.num; ++i) { ded_reflection_t* ref = &defs.reflections[i]; diff --git a/doomsday/engine/src/filesys/filehandle.cpp b/doomsday/engine/src/filesys/filehandle.cpp index 1fcb94657a..e056e52ccf 100644 --- a/doomsday/engine/src/filesys/filehandle.cpp +++ b/doomsday/engine/src/filesys/filehandle.cpp @@ -124,6 +124,8 @@ void FileHandleBuilder::shutdown(void) FileHandle* FileHandleBuilder::fromLump(File1& lump, bool dontBuffer) { + LOG_AS("FileHandle::fromLump"); + de::FileHandle* hndl = new de::FileHandle(); // Init and load in the lump data. hndl->d->file = &lump; @@ -135,7 +137,7 @@ FileHandle* FileHandleBuilder::fromLump(File1& lump, bool dontBuffer) if(!hndl->d->data) Con_Error("FileHandleBuilder::fromFileLump: Failed on allocation of %lu bytes for data buffer.", (unsigned long) hndl->d->size); #if _DEBUG - LOG_VERBOSE("FileHandle [%p] buffering \"%s:%s\"...") + LOG_VERBOSE("[%p] Buffering \"%s:%s\"...") << dintptr(hndl) << NativePath(lump.container().composePath()).pretty() << NativePath(lump.composePath()).pretty(); #endif lump.read((uint8_t*)hndl->d->data, 0, lump.size()); diff --git a/doomsday/engine/src/filesys/fs_main.cpp b/doomsday/engine/src/filesys/fs_main.cpp index 276873041b..bbb50e0621 100644 --- a/doomsday/engine/src/filesys/fs_main.cpp +++ b/doomsday/engine/src/filesys/fs_main.cpp @@ -690,7 +690,8 @@ bool FS1::checkFileId(de::Uri const& path) if(place != d->fileIds.end() && *place == fileId) return false; #ifdef _DEBUG - LOG_DEBUG("Added FileId %s - \"%s\"") << fileId << fileId.path(); /* path() is debug-only */ + LOG_AS("FS1::addFileId") + LOG_DEBUG("\"%s\" => %s") << fileId.path() << fileId; /* path() is debug-only */ #endif d->fileIds.insert(place, fileId); diff --git a/doomsday/engine/src/filesys/fs_scheme.cpp b/doomsday/engine/src/filesys/fs_scheme.cpp index 155bc52f67..73289b83da 100644 --- a/doomsday/engine/src/filesys/fs_scheme.cpp +++ b/doomsday/engine/src/filesys/fs_scheme.cpp @@ -458,8 +458,8 @@ bool FS1::Scheme::addSearchPath(SearchPath const& search, FS1::PathGroup group) // Prepend to the path list - newer paths have priority. d->searchPaths.insert(group, search); - LOG_DEBUG("'%s' path \"%s\" added to scheme '%s'.") - << nameForPathGroup(group) << search << name(); + LOG_DEBUG("\"%s\" added to scheme '%s' (group:%s).") + << search << name() << nameForPathGroup(group); return true; } diff --git a/doomsday/engine/src/gl/dgl_common.cpp b/doomsday/engine/src/gl/dgl_common.cpp index b01daa83ad..eac6b7479a 100644 --- a/doomsday/engine/src/gl/dgl_common.cpp +++ b/doomsday/engine/src/gl/dgl_common.cpp @@ -28,6 +28,7 @@ #include "de_graphics.h" #include "de_misc.h" #include "de_filesys.h" +#include "de_resource.h" #include "gl/sys_opengl.h" @@ -720,9 +721,18 @@ void DGL_SetMaterialUI(material_t *mat, DGLint wrapS, DGLint wrapT) void DGL_SetPatch(patchid_t id, DGLint wrapS, DGLint wrapT) { - Texture *tex = Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, id)); - if(!tex) return; - GL_BindTexture(GL_PreparePatchTexture2(tex, DGL_ToGLWrapCap(wrapS), DGL_ToGLWrapCap(wrapT))); + try + { + Texture *tex = reinterpret_cast(App_Textures()->scheme("Patches").findByUniqueId(id).texture()); + if(!tex) return; + + GL_BindTexture(GL_PreparePatchTexture2(tex, DGL_ToGLWrapCap(wrapS), DGL_ToGLWrapCap(wrapT))); + } + catch(de::Textures::Scheme::NotFoundError const &er) + { + // Log but otherwise ignore this error. + LOG_WARNING(er.asText() + ", ignoring."); + } } void DGL_SetPSprite(material_t *mat) diff --git a/doomsday/engine/src/gl/gl_main.cpp b/doomsday/engine/src/gl/gl_main.cpp index 5af3dd5b57..b6a95d1b25 100644 --- a/doomsday/engine/src/gl/gl_main.cpp +++ b/doomsday/engine/src/gl/gl_main.cpp @@ -364,7 +364,6 @@ void GL_InitRefresh() void GL_ShutdownRefresh() { - Textures_Shutdown(); R_DestroyColorPalettes(); GL_ShutdownTextureManager(); @@ -397,6 +396,7 @@ void GL_Shutdown() Rend_ModelShutdown(); Sky_Shutdown(); Rend_Reset(); + Textures_Shutdown(); GL_ShutdownRefresh(); // Shutdown OpenGL. diff --git a/doomsday/engine/src/gl/gl_texmanager.cpp b/doomsday/engine/src/gl/gl_texmanager.cpp index 3f07db661b..aa2f87a70e 100644 --- a/doomsday/engine/src/gl/gl_texmanager.cpp +++ b/doomsday/engine/src/gl/gl_texmanager.cpp @@ -169,7 +169,7 @@ void GL_TexRegister() C_CMD_FLAGS ("mipmap", "i", MipMap, CMDF_NO_DEDICATED); C_CMD_FLAGS ("texreset", "", TexReset, CMDF_NO_DEDICATED); - Textures_Register(); + Textures::consoleRegister(); } static inline GLint glMinFilterForVariantSpec(variantspecification_t const *spec) @@ -512,15 +512,15 @@ static void emptyVariantSpecificationList(variantspecificationlist_t *list) } } -static int findTextureUsingVariantSpecificationWorker(texture_s *tex, void *parameters) +static int findTextureUsingVariantSpecificationWorker(de::Texture &tex, void *parameters) { texturevariantspecification_t *spec = (texturevariantspecification_t *)parameters; - de::Texture::Variants variants = reinterpret_cast(tex)->variantList(); + de::Texture::Variants variants = tex.variantList(); DENG2_FOR_EACH_CONST(de::Texture::Variants, i, variants) { if((*i)->spec() == spec) { - return Textures_Id(tex); + return App_Textures()->id(tex); } } return 0; // Continue iteration. @@ -533,7 +533,7 @@ static int pruneUnusedVariantSpecificationsInList(variantspecificationlist_t *li while(node) { texturevariantspecificationlist_node_t *next = node->next; - if(!Textures_Iterate2(TS_ANY, findTextureUsingVariantSpecificationWorker, (void *)node->spec)) + if(!App_Textures()->iterate(findTextureUsingVariantSpecificationWorker, (void *)node->spec)) { destroyVariantSpecification(node->spec); ++numPruned; @@ -588,11 +588,11 @@ typedef enum { METHOD_FUZZY } choosevariantmethod_t; -static de::TextureVariant *chooseVariant(choosevariantmethod_t method, de::Texture *tex, +static de::TextureVariant *chooseVariant(choosevariantmethod_t method, de::Texture &tex, texturevariantspecification_t const *spec) { - DENG_ASSERT(initedOk && tex && spec); - DENG2_FOR_EACH_CONST(de::Texture::Variants, i, tex->variantList()) + DENG_ASSERT(initedOk && spec); + DENG2_FOR_EACH_CONST(de::Texture::Variants, i, tex.variantList()) { de::TextureVariant *variant = *i; texturevariantspecification_t const *cand = variant->spec(); @@ -670,7 +670,7 @@ static void uploadContentUnmanaged(uploadcontentmethod_t uploadMethod, if(METHOD_IMMEDIATE == uploadMethod) { #ifdef _DEBUG - LOG_VERBOSE("Uploading unmanaged texture (%i:%ix%i) while not busy! Should be precached in busy mode?") + LOG_VERBOSE("Uploading texture (%i:%ix%i) while not busy! Should be precached in busy mode?") << content->name << content->width << content->height; #endif } @@ -684,28 +684,27 @@ static TexSource loadSourceImage(de::Texture &tex, texturevariantspecification_t TexSource source = TEXS_NONE; spec = TS_GENERAL(&baseSpec); - textureid_t texId = Textures_Id(reinterpret_cast(&tex)); - switch(Textures_Scheme(texId)) + Textures &textures = *App_Textures(); + textureid_t texId = textures.id(tex); + de::Uri uri = textures.composeUri(texId); + if(!uri.scheme().compareWithoutCase("Flats")) { - case TS_FLATS: // Attempt to load an external replacement for this flat? if(!noHighResTex && (loadExtAlways || highResWithPWAD || !tex.isCustom())) { - String path = String(Str_Text(Textures_ComposePath(texId))); - // First try the flats scheme. - source = loadExternalTexture(image, "Flats:" + path, "-ck"); + source = loadExternalTexture(image, uri.compose(), "-ck"); if(!source) { // How about the old-fashioned "flat-name" in the textures scheme? - source = loadExternalTexture(image, "Textures:flat-" + path, "-ck"); + source = loadExternalTexture(image, "Textures:flat-" + uri.path().toStringRef(), "-ck"); } } if(source == TEXS_NONE) { - de::Uri const &resourceUri = reinterpret_cast(*Textures_ResourcePath(texId)); + de::Uri const &resourceUri = textures.resourceUri(texId); lumpnum_t lumpNum = -1; if(!resourceUri.scheme().compareWithoutCase("Lumps")) @@ -730,9 +729,9 @@ static TexSource loadSourceImage(de::Texture &tex, texturevariantspecification_t catch(LumpIndex::NotFoundError const&) {} // Ignore this error. } - break; - - case TS_PATCHES: { + } + else if(!uri.scheme().compareWithoutCase("Patches")) + { int tclass = 0, tmap = 0; if(spec->flags & TSF_HAS_COLORPALETTE_XLAT) { @@ -744,13 +743,12 @@ static TexSource loadSourceImage(de::Texture &tex, texturevariantspecification_t // Attempt to load an external replacement for this patch? if(!noHighResTex && (loadExtAlways || highResWithPWAD || !tex.isCustom())) { - String path = String(Str_Text(Textures_ComposePath(texId))); - source = loadExternalTexture(image, "Patches:" + path, "-ck"); + source = loadExternalTexture(image, uri.compose(), "-ck"); } if(source == TEXS_NONE) { - de::Uri const &resourceUri = reinterpret_cast(*Textures_ResourcePath(texId)); + de::Uri const &resourceUri = textures.resourceUri(texId); if(!resourceUri.scheme().compareWithoutCase("Lumps")) { lumpnum_t lumpNum = App_FileSystem()->lumpNumForName(resourceUri.path()); @@ -770,9 +768,9 @@ static TexSource loadSourceImage(de::Texture &tex, texturevariantspecification_t {} // Ignore this error. } } - break; } - - case TS_SPRITES: { + } + else if(!uri.scheme().compareWithoutCase("Sprites")) + { int tclass = 0, tmap = 0; if(spec->flags & TSF_HAS_COLORPALETTE_XLAT) { @@ -784,27 +782,25 @@ static TexSource loadSourceImage(de::Texture &tex, texturevariantspecification_t // Attempt to load an external replacement for this sprite? if(!noHighResPatches) { - String path = String(Str_Text(Textures_ComposePath(texId))); - // Prefer psprite or translated versions if available. if(TC_PSPRITE_DIFFUSE == spec->context) { - source = loadExternalTexture(image, "Patches:" + path + "-hud", "-ck"); + source = loadExternalTexture(image, "Patches:" + uri.path() + "-hud", "-ck"); } else if(tclass || tmap) { - source = loadExternalTexture(image, "Patches:" + path + String("-table%1%2").arg(tclass).arg(tmap), "-ck"); + source = loadExternalTexture(image, "Patches:" + uri.path() + String("-table%1%2").arg(tclass).arg(tmap), "-ck"); } if(!source) { - source = loadExternalTexture(image, "Patches:" + path, "-ck"); + source = loadExternalTexture(image, "Patches:" + uri.path(), "-ck"); } } if(source == TEXS_NONE) { - de::Uri const &resourceUri = reinterpret_cast(*Textures_ResourcePath(texId)); + de::Uri const &resourceUri = textures.resourceUri(texId); if(!resourceUri.scheme().compareWithoutCase("Lumps")) { lumpnum_t lumpNum = App_FileSystem()->lumpNumForName(resourceUri.path()); @@ -824,10 +820,10 @@ static TexSource loadSourceImage(de::Texture &tex, texturevariantspecification_t {} // Ignore this error. } } - break; } - - case TS_DETAILS: { - de::Uri const &resourceUri = reinterpret_cast(*Textures_ResourcePath(texId)); + } + else if(!uri.scheme().compareWithoutCase("Details")) + { + de::Uri const &resourceUri = textures.resourceUri(texId); if(resourceUri.scheme().compareWithoutCase("Lumps")) { source = loadExternalTexture(image, resourceUri.compose()); @@ -848,22 +844,11 @@ static TexSource loadSourceImage(de::Texture &tex, texturevariantspecification_t catch(LumpIndex::NotFoundError const&) {} // Ignore this error. } - break; } - - case TS_SYSTEM: - case TS_REFLECTIONS: - case TS_MASKS: - case TS_LIGHTMAPS: - case TS_FLAREMAPS: - case TS_MODELSKINS: - case TS_MODELREFLECTIONSKINS: { - de::Uri const &resourcePath = reinterpret_cast(*Textures_ResourcePath(texId)); - source = loadExternalTexture(image, resourcePath.compose()); - break; } - - default: - Con_Error("Textures::loadSourceImage: Unknown texture scheme %i.", (int) Textures_Scheme(texId)); - exit(1); // Unreachable. + } + else + { + de::Uri const &resourceUri = textures.resourceUri(texId); + source = loadExternalTexture(image, resourceUri.compose()); } return source; } @@ -1082,10 +1067,10 @@ static uploadcontentmethod_t prepareDetailVariantFromImage(de::TextureVariant *t grayMipmapFactor = (uint8_t)(255 * MINMAX_OF(0, spec->contrast / 255.f - shift, 1)); // Announce the normalization. - de::Uri &uri = reinterpret_cast(*Textures_ComposeUri(Textures_Id(reinterpret_cast(tex->generalCase())))); + Textures &textures = *App_Textures(); + de::Uri uri = textures.composeUri(textures.id(reinterpret_cast(*tex->generalCase()))); LOG_VERBOSE("Normalized detail texture \"%s\" (balance: %g, high amp: %g, low amp: %g).") << uri << baMul << hiMul << loMul; - delete &uri; } // Disable compression? @@ -1123,8 +1108,6 @@ void GL_EarlyInitTextureManager() variantSpecs = NULL; memset(detailVariantSpecs, 0, sizeof(detailVariantSpecs)); - - Textures_Init(); } void GL_InitTextureManager() @@ -1327,12 +1310,12 @@ void GL_LoadSystemTextures() GL_PrepareLSTexture(LST_GRADIENT); GL_PrepareLSTexture(LST_CAMERA_VIGNETTE); - GL_PrepareSysFlareTexture(FXT_ROUND); - GL_PrepareSysFlareTexture(FXT_FLARE); + GL_PrepareSysFlaremap(FXT_ROUND); + GL_PrepareSysFlaremap(FXT_FLARE); if(!haloRealistic) { - GL_PrepareSysFlareTexture(FXT_BRFLARE); - GL_PrepareSysFlareTexture(FXT_BIGFLARE); + GL_PrepareSysFlaremap(FXT_BRFLARE); + GL_PrepareSysFlaremap(FXT_BIGFLARE); } Rend_ParticleLoadSystemTextures(); @@ -1360,7 +1343,7 @@ void GL_ReleaseSystemTextures() } memset(sysFlareTextures, 0, sizeof(sysFlareTextures)); - GL_ReleaseTexturesByScheme(TS_SYSTEM); + GL_ReleaseTexturesByScheme("System"); UI_ReleaseTextures(); Rend_ParticleReleaseSystemTextures(); @@ -1380,17 +1363,17 @@ void GL_ReleaseRuntimeTextures() RL_DeleteLists(); // texture-wrapped GL textures; textures, flats, sprites... - GL_ReleaseTexturesByScheme(TS_FLATS); - GL_ReleaseTexturesByScheme(TS_TEXTURES); - GL_ReleaseTexturesByScheme(TS_PATCHES); - GL_ReleaseTexturesByScheme(TS_SPRITES); - GL_ReleaseTexturesByScheme(TS_DETAILS); - GL_ReleaseTexturesByScheme(TS_REFLECTIONS); - GL_ReleaseTexturesByScheme(TS_MASKS); - GL_ReleaseTexturesByScheme(TS_MODELSKINS); - GL_ReleaseTexturesByScheme(TS_MODELREFLECTIONSKINS); - GL_ReleaseTexturesByScheme(TS_LIGHTMAPS); - GL_ReleaseTexturesByScheme(TS_FLAREMAPS); + GL_ReleaseTexturesByScheme("Flats"); + GL_ReleaseTexturesByScheme("Textures"); + GL_ReleaseTexturesByScheme("Patches"); + GL_ReleaseTexturesByScheme("Sprites"); + GL_ReleaseTexturesByScheme("Details"); + GL_ReleaseTexturesByScheme("Reflections"); + GL_ReleaseTexturesByScheme("Masks"); + GL_ReleaseTexturesByScheme("ModelSkins"); + GL_ReleaseTexturesByScheme("ModelReflectionSkins"); + GL_ReleaseTexturesByScheme("Lightmaps"); + GL_ReleaseTexturesByScheme("Flaremaps"); GL_ReleaseTexturesForRawImages(); Rend_ParticleReleaseExtraTextures(); @@ -2159,7 +2142,7 @@ DGLuint GL_PrepareLSTexture(lightingtexid_t which) return lightingTextures[which].tex; } -DGLuint GL_PrepareSysFlareTexture(flaretexid_t flare) +DGLuint GL_PrepareSysFlaremap(flaretexid_t flare) { if(novideo || flare < 0 || flare >= NUM_SYSFLARE_TEXTURES) return 0; @@ -2537,17 +2520,19 @@ DGLuint GL_PrepareExtTexture(const char* name, gfxmode_t mode, int useMipmap, return texture; } -TexSource GL_LoadPatchComposite(image_t *image, texture_s *tex) +TexSource GL_LoadPatchComposite(image_t *image, texture_s *_tex) { - DENG_ASSERT(image && tex); + DENG_ASSERT(image && _tex); + de::Texture &tex = reinterpret_cast(*_tex); LOG_AS("GL_LoadPatchComposite"); + Textures &textures = *App_Textures(); #if _DEBUG - if(Textures_Scheme(Textures_Id(tex)) != TS_TEXTURES) - Con_Error("GL_LoadPatchComposite: Internal error, texture [%p id:%i] is not a PatchCompositeTex!", (void *)tex, Textures_Id(tex)); + if(textures.composeUri(textures.id(tex)).scheme().compareWithoutCase("Textures")) + Con_Error("GL_LoadPatchComposite: Internal error, texture [%p id:%i] is not a PatchCompositeTex!", (void *)&tex, textures.id(tex)); #endif - CompositeTexture *texDef = reinterpret_cast(Texture_UserDataPointer(tex)); + CompositeTexture *texDef = reinterpret_cast(tex.userDataPointer()); DENG_ASSERT(texDef); Image_Init(image); @@ -2561,7 +2546,7 @@ TexSource GL_LoadPatchComposite(image_t *image, texture_s *tex) DENG2_FOR_EACH_CONST(CompositeTexture::Components, i, texDef->components()) { - de::File1& file = App_FileSystem()->nameIndex().lump(i->lumpNum()); + de::File1 &file = App_FileSystem()->nameIndex().lump(i->lumpNum()); uint8_t const *dataBuffer = file.cache(); if(validatePatch(*dataBuffer, file.size())) @@ -2572,12 +2557,11 @@ TexSource GL_LoadPatchComposite(image_t *image, texture_s *tex) } else { - de::Uri *uri = reinterpret_cast(Textures_ComposeUri(Textures_Id(tex))); + de::Uri uri = textures.composeUri(textures.id(tex)); LOG_WARNING("File \"%s:%s\" (#%u) does not appear to be a valid Patch. It will be missing from texture \"%s\".") << NativePath(file.container().composePath()).pretty() << NativePath(file.composePath()).pretty() - << i->lumpNum() << *uri; - delete uri; + << i->lumpNum() << uri; } file.unlock(); @@ -2592,17 +2576,19 @@ TexSource GL_LoadPatchComposite(image_t *image, texture_s *tex) return TEXS_ORIGINAL; } -TexSource GL_LoadPatchCompositeAsSky(image_t *image, texture_s *tex, boolean zeroMask) +TexSource GL_LoadPatchCompositeAsSky(image_t *image, texture_s *_tex, boolean zeroMask) { - DENG_ASSERT(image && tex); + DENG_ASSERT(image && _tex); + de::Texture &tex = reinterpret_cast(*_tex); LOG_AS("GL_LoadPatchCompositeAsSky"); + Textures &textures = *App_Textures(); #if _DEBUG - if(Textures_Scheme(Textures_Id(tex)) != TS_TEXTURES) - Con_Error("GL_LoadPatchCompositeAsSky: Internal error, texture [%p id:%i] is not a PatchCompositeTex!", (void*)tex, Textures_Id(tex)); + if(textures.composeUri(textures.id(tex)).scheme().compareWithoutCase("Textures")) + Con_Error("GL_LoadPatchCompositeAsSky: Internal error, texture [%p id:%i] is not a PatchCompositeTex!", (void *)&tex, textures.id(tex)); #endif - CompositeTexture* texDef = reinterpret_cast(Texture_UserDataPointer(tex)); + CompositeTexture *texDef = reinterpret_cast(tex.userDataPointer()); DENG_ASSERT(texDef); /** @@ -2615,7 +2601,7 @@ TexSource GL_LoadPatchCompositeAsSky(image_t *image, texture_s *tex, boolean zer if(texDef->componentCount() == 1) { - de::File1& file = App_FileSystem()->nameIndex().lump(texDef->components()[0].lumpNum()); + de::File1 &file = App_FileSystem()->nameIndex().lump(texDef->components()[0].lumpNum()); uint8_t const *dataBuffer = file.cache(); doompatch_header_t const &hdr = reinterpret_cast(*dataBuffer); @@ -2636,12 +2622,12 @@ TexSource GL_LoadPatchCompositeAsSky(image_t *image, texture_s *tex, boolean zer image->size.height = height; image->paletteId = defaultColorPalette; - image->pixels = (uint8_t*) M_Calloc(2 * image->size.width * image->size.height); + image->pixels = (uint8_t *) M_Calloc(2 * image->size.width * image->size.height); if(!image->pixels) Con_Error("GL_LoadPatchCompositeAsSky: Failed on allocation of %lu bytes for new Image pixel data.", (unsigned long) (2 * image->size.width * image->size.height)); DENG2_FOR_EACH_CONST(CompositeTexture::Components, i, texDef->components()) { - de::File1& file = App_FileSystem()->nameIndex().lump(i->lumpNum()); + de::File1 &file = App_FileSystem()->nameIndex().lump(i->lumpNum()); uint8_t const *dataBuffer = file.cache(); if(validatePatch(*dataBuffer, file.size())) @@ -2654,12 +2640,11 @@ TexSource GL_LoadPatchCompositeAsSky(image_t *image, texture_s *tex, boolean zer } else { - de::Uri *uri = reinterpret_cast(Textures_ComposeUri(Textures_Id(tex))); + de::Uri uri = textures.composeUri(textures.id(tex)); LOG_WARNING("File \"%s:%s\" (#%u) does not appear to be a valid Patch. It will be missing from texture \"%s\".") << NativePath(file.container().composePath()).pretty() << NativePath(file.composePath()).pretty() - << i->lumpNum() << *uri; - delete uri; + << i->lumpNum() << uri; } file.unlock(); @@ -2673,17 +2658,17 @@ TexSource GL_LoadPatchCompositeAsSky(image_t *image, texture_s *tex, boolean zer return TEXS_ORIGINAL; } -TexSource GL_LoadRawTex(image_t* image, const rawtex_t* r) +TexSource GL_LoadRawTex(image_t *image, rawtex_t const *r) { DENG_ASSERT(image); -{ - AutoStr* foundPath = AutoStr_NewStd(); + + AutoStr *foundPath = AutoStr_NewStd(); TexSource source = TEXS_NONE; // First try to find an external resource. - uri_s *searchPath = Uri_NewWithPath(Str_Text(Str_Appendf(AutoStr_NewStd(), "Patches:%s", Str_Text(&r->name)))); + de::Uri searchPath("Patches", Path(Str_Text(&r->name))); - if(F_FindPath(RC_GRAPHIC, searchPath, foundPath) && + if(F_FindPath(RC_GRAPHIC, reinterpret_cast(&searchPath), foundPath) && GL_LoadImage(image, Str_Text(foundPath))) { // "External" image loaded. @@ -2691,7 +2676,7 @@ TexSource GL_LoadRawTex(image_t* image, const rawtex_t* r) } else if(r->lumpNum >= 0) { - filehandle_s* file = F_OpenLump(r->lumpNum); + filehandle_s *file = F_OpenLump(r->lumpNum); if(file) { if(Image_LoadFromFile(image, file)) @@ -2707,14 +2692,14 @@ TexSource GL_LoadRawTex(image_t* image, const rawtex_t* r) size_t bufSize = 3 * RAW_WIDTH * RAW_HEIGHT; Image_Init(image); - image->pixels = (uint8_t*) M_Malloc(bufSize); + image->pixels = (uint8_t *) M_Malloc(bufSize); if(fileLength < bufSize) - memset(image->pixels, 0, bufSize); + std::memset(image->pixels, 0, bufSize); // Load the raw image data. FileHandle_Read(file, image->pixels, fileLength); image->size.width = RAW_WIDTH; - image->size.height = (int) (fileLength / image->size.width); + image->size.height = int(fileLength / image->size.width); image->pixelSize = 1; source = TEXS_ORIGINAL; @@ -2725,11 +2710,10 @@ TexSource GL_LoadRawTex(image_t* image, const rawtex_t* r) } } - Uri_Delete(searchPath); return source; -}} +} -DGLuint GL_PrepareRawTexture(rawtex_t* raw) +DGLuint GL_PrepareRawTexture(rawtex_t *raw) { if(!raw) return 0; if(raw->lumpNum < 0 || raw->lumpNum >= F_LumpCount()) return 0; @@ -2737,9 +2721,7 @@ DGLuint GL_PrepareRawTexture(rawtex_t* raw) if(!raw->tex) { image_t image; - - // Clear any old values. - memset(&image, 0, sizeof(image)); + Image_Init(&image); if(GL_LoadRawTex(&image, raw) == TEXS_EXTERNAL) { @@ -2769,78 +2751,103 @@ DGLuint GL_PrepareRawTexture(rawtex_t* raw) return raw->tex; } -DGLuint GL_PrepareLightMap(const uri_s *filePath) +DGLuint GL_PrepareLightmap(uri_s const *_resourceUri) { - if(filePath) + if(_resourceUri) { - texture_s* tex; - if(!Str_CompareIgnoreCase(Uri_Path(filePath), "-")) return 0; + de::Uri const &resourceUri = reinterpret_cast(*_resourceUri); + if(resourceUri.isEmpty()) return 0; + if(!resourceUri.path().toStringRef().compareWithoutCase("-")) return 0; - tex = Textures_TextureForResourcePath(TS_LIGHTMAPS, filePath); - if(tex) + try { - texturevariantspecification_t* texSpec = - GL_TextureVariantSpecificationForContext(TC_MAPSURFACE_LIGHTMAP, - 0, 0, 0, 0, GL_CLAMP, GL_CLAMP, 1, -1, -1, false, false, false, true); - return GL_PrepareTexture(tex, texSpec); + TextureMetaFile &metafile = App_Textures()->scheme("Lightmaps").findByResourceUri(resourceUri); + if(de::Texture *tex = metafile.texture()) + { + /// @todo fixme: Render context texture specs should be defined only once. + texturevariantspecification_t *texSpec = + GL_TextureVariantSpecificationForContext(TC_MAPSURFACE_LIGHTMAP, + 0, 0, 0, 0, GL_CLAMP, GL_CLAMP, 1, -1, -1, false, false, false, true); + return GL_PrepareTexture(reinterpret_cast(tex), texSpec); + } } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. } // Return the default texture name. return GL_PrepareLSTexture(LST_DYNAMIC); } -DGLuint GL_PrepareFlareTexture(const uri_s *uri, int oldIdx) +DGLuint GL_PrepareFlareTexture(uri_s const *_resourceUri, int oldIdx) { - if(uri) + if(_resourceUri) { - const ddstring_t* path = Uri_Path(uri); - texture_s* tex; + de::Uri const &resourceUri = reinterpret_cast(*_resourceUri); - if(Str_At(path, 0) == '-' || (Str_At(path, 0) == '0' && !Str_At(path, 1))) - return 0; // Use the automatic selection logic. + if(resourceUri.isEmpty()) return 0; // automatic - if(Str_At(path, 0) >= '1' && Str_At(path, 0) <= '4' && !Str_At(path, 1)) + if(resourceUri.path().length() == 1) { - return GL_PrepareSysFlareTexture(flaretexid_t(Str_At(path, 0) - '1')); + QChar first = resourceUri.path().toStringRef().first(); + if(first == '-') return 0; // automatic + + // Select a system flare by numeric identifier? + int number = first.digitValue(); + if(number == 0) return 0; // automatic + if(number >= 1 && number <= 4) + { + return GL_PrepareSysFlaremap(flaretexid_t(number - 1)); + } } - tex = Textures_TextureForResourcePath(TS_FLAREMAPS, uri); - if(tex) + try { - texturevariantspecification_t* texSpec = - GL_TextureVariantSpecificationForContext(TC_HALO_LUMINANCE, - TSF_NO_COMPRESSION, 0, 0, 0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, - 1, 1, 0, false, false, false, true); - return GL_PrepareTexture(tex, texSpec); + TextureMetaFile &metafile = App_Textures()->scheme("Flaremaps").findByResourceUri(resourceUri); + if(de::Texture *tex = metafile.texture()) + { + texturevariantspecification_t *texSpec = + GL_TextureVariantSpecificationForContext(TC_HALO_LUMINANCE, + TSF_NO_COMPRESSION, 0, 0, 0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, + 1, 1, 0, false, false, false, true); + return GL_PrepareTexture(reinterpret_cast(tex), texSpec); + } } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. } else if(oldIdx > 0 && oldIdx < NUM_SYSFLARE_TEXTURES) { - return GL_PrepareSysFlareTexture(flaretexid_t(oldIdx - 1)); + return GL_PrepareSysFlaremap(flaretexid_t(oldIdx - 1)); } return 0; // Use the automatic selection logic. } -texturevariant_s* GL_PreparePatchTexture2(texture_s* tex, int wrapS, int wrapT) +texturevariant_s* GL_PreparePatchTexture2(texture_s* _tex, int wrapS, int wrapT) { - texturevariantspecification_t* texSpec; - patchtex_t* pTex; - if(novideo || !tex) return 0; - if(Textures_Scheme(Textures_Id(tex)) != TS_PATCHES) + if(!_tex) return 0; + if(novideo) return 0; + + de::Texture &tex = reinterpret_cast(*_tex); + + Textures &textures = *App_Textures(); + if(textures.composeUri(textures.id(tex)).scheme().compareWithoutCase("Patches")) { #if _DEBUG - Con_Message("Warning:GL_PreparePatchTexture: Attempted to prepare non-patch [%p].\n", (void*)tex); + LOG_AS("GL_PreparePatchTexture"); + LOG_WARNING("Attempted to prepare non-patch [%p].") << de::dintptr(&tex); #endif return 0; } - pTex = (patchtex_t*)Texture_UserDataPointer(tex); + + patchtex_t* pTex = reinterpret_cast(tex.userDataPointer()); DENG_ASSERT(pTex); - texSpec = GL_TextureVariantSpecificationForContext(TC_UI, + texturevariantspecification_t* texSpec + = GL_TextureVariantSpecificationForContext(TC_UI, 0 | ((pTex->flags & PF_MONOCHROME) ? TSF_MONOCHROME : 0) | ((pTex->flags & PF_UPSCALE_AND_SHARPEN)? TSF_UPSCALE_AND_SHARPEN : 0), 0, 0, 0, wrapS, wrapT, 0, -3, 0, false, false, false, false); - return GL_PrepareTextureVariant(tex, texSpec); + return GL_PrepareTextureVariant(reinterpret_cast(&tex), texSpec); } texturevariant_s* GL_PreparePatchTexture(texture_s* tex) @@ -3014,7 +3021,7 @@ void GL_DoTexReset() void GL_DoResetDetailTextures() { - GL_ReleaseTexturesByScheme(TS_DETAILS); + GL_ReleaseTexturesByScheme("Details"); } void GL_ReleaseTexturesForRawImages() @@ -3060,11 +3067,11 @@ void GL_SetAllTexturesMinFilter(int /*minFilter*/) int localMinFilter = minFilter; /// @todo This is no longer correct logic. Changing the global minification /// filter should not modify the uploaded texture content. - Textures_Iterate2(TS_ANY, setVariantMinFilterWorker, (void*)&localMinFilter); + Textures::iterate(TS_ANY, setVariantMinFilterWorker, (void*)&localMinFilter); #endif } -static void performImageAnalyses(de::Texture *tex, image_t const *image, +static void performImageAnalyses(de::Texture &tex, image_t const *image, texturevariantspecification_t const *spec, bool forceUpdate) { DENG_ASSERT(spec && image); @@ -3072,14 +3079,14 @@ static void performImageAnalyses(de::Texture *tex, image_t const *image, // Do we need color palette info? if(TST_GENERAL == spec->type && image->paletteId != 0) { - colorpalette_analysis_t *cp = reinterpret_cast(tex->analysisDataPointer(TA_COLORPALETTE)); + colorpalette_analysis_t *cp = reinterpret_cast(tex.analysisDataPointer(TA_COLORPALETTE)); bool firstInit = (!cp); if(firstInit) { cp = (colorpalette_analysis_t*) M_Malloc(sizeof(*cp)); if(!cp) Con_Error("Textures::performImageAnalyses: Failed on allocation of %lu bytes for new ColorPaletteAnalysis.", (unsigned long) sizeof(*cp)); - tex->setAnalysisDataPointer(TA_COLORPALETTE, cp); + tex.setAnalysisDataPointer(TA_COLORPALETTE, cp); } if(firstInit || forceUpdate) @@ -3089,14 +3096,14 @@ static void performImageAnalyses(de::Texture *tex, image_t const *image, // Calculate a point light source for Dynlight and/or Halo? if(TST_GENERAL == spec->type && TC_SPRITE_DIFFUSE == TS_GENERAL(spec)->context) { - pointlight_analysis_t *pl = reinterpret_cast(tex->analysisDataPointer(TA_SPRITE_AUTOLIGHT)); + pointlight_analysis_t *pl = reinterpret_cast(tex.analysisDataPointer(TA_SPRITE_AUTOLIGHT)); bool firstInit = (!pl); if(firstInit) { pl = (pointlight_analysis_t*) M_Malloc(sizeof *pl); if(!pl) Con_Error("Textures::performImageAnalyses: Failed on allocation of %lu bytes for new PointLightAnalysis.", (unsigned long) sizeof(*pl)); - tex->setAnalysisDataPointer(TA_SPRITE_AUTOLIGHT, pl); + tex.setAnalysisDataPointer(TA_SPRITE_AUTOLIGHT, pl); } if(firstInit || forceUpdate) @@ -3110,14 +3117,14 @@ static void performImageAnalyses(de::Texture *tex, image_t const *image, (TS_GENERAL(spec)->context == TC_SPRITE_DIFFUSE || TS_GENERAL(spec)->context == TC_UI)) { - averagealpha_analysis_t *aa = reinterpret_cast(tex->analysisDataPointer(TA_ALPHA)); + averagealpha_analysis_t *aa = reinterpret_cast(tex.analysisDataPointer(TA_ALPHA)); bool firstInit = (!aa); if(firstInit) { aa = (averagealpha_analysis_t*) M_Malloc(sizeof(*aa)); if(!aa) Con_Error("Textures::performImageAnalyses: Failed on allocation of %lu bytes for new AverageAlphaAnalysis.", (unsigned long) sizeof(*aa)); - tex->setAnalysisDataPointer(TA_ALPHA, aa); + tex.setAnalysisDataPointer(TA_ALPHA, aa); } if(firstInit || forceUpdate) @@ -3147,14 +3154,14 @@ static void performImageAnalyses(de::Texture *tex, image_t const *image, // Average color for sky ambient color? if(TST_GENERAL == spec->type && TC_SKYSPHERE_DIFFUSE == TS_GENERAL(spec)->context) { - averagecolor_analysis_t *ac = reinterpret_cast(tex->analysisDataPointer(TA_COLOR)); + averagecolor_analysis_t *ac = reinterpret_cast(tex.analysisDataPointer(TA_COLOR)); bool firstInit = (!ac); if(firstInit) { ac = (averagecolor_analysis_t*) M_Malloc(sizeof(*ac)); if(!ac) Con_Error("Textures::performImageAnalyses: Failed on allocation of %lu bytes for new AverageColorAnalysis.", (unsigned long) sizeof(*ac)); - tex->setAnalysisDataPointer(TA_COLOR, ac); + tex.setAnalysisDataPointer(TA_COLOR, ac); } if(firstInit || forceUpdate) @@ -3175,14 +3182,14 @@ static void performImageAnalyses(de::Texture *tex, image_t const *image, // Amplified average color for plane glow? if(TST_GENERAL == spec->type && TC_MAPSURFACE_DIFFUSE == TS_GENERAL(spec)->context) { - averagecolor_analysis_t *ac = reinterpret_cast(tex->analysisDataPointer(TA_COLOR_AMPLIFIED)); + averagecolor_analysis_t *ac = reinterpret_cast(tex.analysisDataPointer(TA_COLOR_AMPLIFIED)); bool firstInit = (!ac); if(firstInit) { ac = (averagecolor_analysis_t*) M_Malloc(sizeof(*ac)); if(!ac) Con_Error("Textures::performImageAnalyses: Failed on allocation of %lu bytes for new AverageColorAnalysis.", (unsigned long) sizeof(*ac)); - tex->setAnalysisDataPointer(TA_COLOR_AMPLIFIED, ac); + tex.setAnalysisDataPointer(TA_COLOR_AMPLIFIED, ac); } if(firstInit || forceUpdate) @@ -3204,14 +3211,14 @@ static void performImageAnalyses(de::Texture *tex, image_t const *image, // Average top line color for sky sphere fadeout? if(TST_GENERAL == spec->type && TC_SKYSPHERE_DIFFUSE == TS_GENERAL(spec)->context) { - averagecolor_analysis_t *ac = reinterpret_cast(tex->analysisDataPointer(TA_LINE_TOP_COLOR)); + averagecolor_analysis_t *ac = reinterpret_cast(tex.analysisDataPointer(TA_LINE_TOP_COLOR)); bool firstInit = (!ac); if(firstInit) { ac = (averagecolor_analysis_t*) M_Malloc(sizeof(*ac)); if(!ac) Con_Error("Textures::performImageAnalyses: Failed on allocation of %lu bytes for new AverageColorAnalysis.", (unsigned long) sizeof(*ac)); - tex->setAnalysisDataPointer(TA_LINE_TOP_COLOR, ac); + tex.setAnalysisDataPointer(TA_LINE_TOP_COLOR, ac); } if(firstInit || forceUpdate) @@ -3232,14 +3239,14 @@ static void performImageAnalyses(de::Texture *tex, image_t const *image, // Average bottom line color for sky sphere fadeout? if(TST_GENERAL == spec->type && TC_SKYSPHERE_DIFFUSE == TS_GENERAL(spec)->context) { - averagecolor_analysis_t *ac = reinterpret_cast(tex->analysisDataPointer(TA_LINE_BOTTOM_COLOR)); + averagecolor_analysis_t *ac = reinterpret_cast(tex.analysisDataPointer(TA_LINE_BOTTOM_COLOR)); bool firstInit = (!ac); if(firstInit) { ac = (averagecolor_analysis_t*) M_Malloc(sizeof(*ac)); if(!ac) Con_Error("Textures::performImageAnalyses: Failed on allocation of %lu bytes for new AverageColorAnalysis.", (unsigned long) sizeof(*ac)); - tex->setAnalysisDataPointer(TA_LINE_BOTTOM_COLOR, ac); + tex.setAnalysisDataPointer(TA_LINE_BOTTOM_COLOR, ac); } if(firstInit || forceUpdate) @@ -3259,23 +3266,23 @@ static void performImageAnalyses(de::Texture *tex, image_t const *image, } } -static bool tryLoadImageAndPrepareVariant(de::Texture *tex, +static bool tryLoadImageAndPrepareVariant(de::Texture &tex, texturevariantspecification_t *spec, de::TextureVariant **variant) { DENG_ASSERT(initedOk && spec); LOG_AS("tryLoadImageAndPrepareVariant"); - uploadcontentmethod_t uploadMethod; - TexSource source = TEXS_NONE; - image_t image; + Textures &textures = *App_Textures(); // Load the source image data. - if(TS_TEXTURES == Textures_Scheme(Textures_Id(reinterpret_cast(tex)))) + TexSource source = TEXS_NONE; + image_t image; + if(!textures.composeUri(textures.id(tex)).scheme().compareWithoutCase("Textures")) { // Try to load a replacement version of this texture? - if(!noHighResTex && (loadExtAlways || highResWithPWAD || !tex->isCustom())) + if(!noHighResTex && (loadExtAlways || highResWithPWAD || !tex.isCustom())) { - CompositeTexture *texDef = reinterpret_cast(tex->userDataPointer()); + CompositeTexture *texDef = reinterpret_cast(tex.userDataPointer()); DENG_ASSERT(texDef); source = loadExternalTexture(image, "Textures:" + texDef->percentEncodedNameRef(), "-ck"); @@ -3285,18 +3292,18 @@ static bool tryLoadImageAndPrepareVariant(de::Texture *tex, { if(TC_SKYSPHERE_DIFFUSE != TS_GENERAL(spec)->context) { - source = GL_LoadPatchComposite(&image, reinterpret_cast(tex)); + source = GL_LoadPatchComposite(&image, reinterpret_cast(&tex)); } else { bool const zeroMask = !!(TS_GENERAL(spec)->flags & TSF_ZEROMASK); - source = GL_LoadPatchCompositeAsSky(&image, reinterpret_cast(tex), zeroMask); + source = GL_LoadPatchCompositeAsSky(&image, reinterpret_cast(&tex), zeroMask); } } } else { - source = loadSourceImage(*tex, *spec, image); + source = loadSourceImage(tex, *spec, image); } if(source == TEXS_NONE) @@ -3307,16 +3314,14 @@ static bool tryLoadImageAndPrepareVariant(de::Texture *tex, } // Are we setting the logical dimensions to the actual pixel dimensions? - if(0 == tex->width() || 0 == tex->height()) + if(0 == tex.width() || 0 == tex.height()) { #if _DEBUG - uri_s *uri = Textures_ComposeUri(Textures_Id(reinterpret_cast(tex))); - AutoStr *path = Uri_ToString(uri); - LOG_VERBOSE("Logical dimensions for \"%s\" taken from image pixels [%ix%i].") - << Str_Text(path) << image.size.width << image.size.height; - Uri_Delete(uri); + de::Uri uri = textures.composeUri(textures.id(tex)); + LOG_VERBOSE("Logical dimensions for \"%s\" taken from image pixels (%ix%i).") + << NativePath(uri.asText()).pretty() << image.size.width << image.size.height; #endif - tex->setDimensions(image.size); + tex.setDimensions(image.size); } performImageAnalyses(tex, &image, spec, true /*Always update*/); @@ -3325,9 +3330,9 @@ static bool tryLoadImageAndPrepareVariant(de::Texture *tex, if(!*variant) { DGLuint newGLName = GL_GetReservedTextureName(); - *variant = new de::TextureVariant(*reinterpret_cast(tex), *spec, source); + *variant = new de::TextureVariant(*reinterpret_cast(&tex), *spec, source); (*variant)->setGLName(newGLName); - tex->addVariant(**variant); + tex.addVariant(**variant); } // Are we re-preparing a released texture? else if(0 == (*variant)->glName()) @@ -3338,6 +3343,7 @@ static bool tryLoadImageAndPrepareVariant(de::Texture *tex, } // (Re)Prepare the variant according to specification. + uploadcontentmethod_t uploadMethod; switch(spec->type) { case TST_GENERAL: uploadMethod = prepareVariantFromImage(*variant, &image); break; @@ -3351,16 +3357,15 @@ static bool tryLoadImageAndPrepareVariant(de::Texture *tex, Image_Destroy(&image); #ifdef _DEBUG - de::Uri &uri = reinterpret_cast(*Textures_ComposeUri(Textures_Id(reinterpret_cast(tex)))); - LOG_VERBOSE("Prepared TextureVariant (name:\"%s\" glName:%u)%s") + de::Uri uri = textures.composeUri(textures.id(tex)); + LOG_VERBOSE("Prepared \"%s\" variant (glName:%u)%s") << uri << uint((*variant)->glName()) << (METHOD_IMMEDIATE == uploadMethod? " while not busy!" : ""); - delete &uri; VERBOSE2( Con_Printf(" Content: "); Image_PrintMetadata(&image); - Con_Printf(" Specification: "); + Con_Printf(" Specification [%p]: ", de::dintptr(spec)); GL_PrintTextureVariantSpecification(spec); ) #endif @@ -3368,7 +3373,7 @@ static bool tryLoadImageAndPrepareVariant(de::Texture *tex, return true; } -static de::TextureVariant *findVariantForSpec(de::Texture *tex, +static de::TextureVariant *findVariantForSpec(de::Texture &tex, texturevariantspecification_t const *spec) { // Look for an exact match. @@ -3389,11 +3394,14 @@ static de::TextureVariant *findVariantForSpec(de::Texture *tex, return variant; } -texturevariant_s *GL_PrepareTextureVariant2(texture_s *tex, texturevariantspecification_t *spec, +texturevariant_s *GL_PrepareTextureVariant2(texture_s *_tex, texturevariantspecification_t *spec, preparetextureresult_t *outcome) { + DENG_ASSERT(_tex); + de::Texture &tex = reinterpret_cast(*_tex); + // Have we already prepared something suitable? - de::TextureVariant *variant = findVariantForSpec(reinterpret_cast(tex), spec); + de::TextureVariant *variant = findVariantForSpec(tex, spec); if(variant && variant->isPrepared()) { @@ -3402,7 +3410,7 @@ texturevariant_s *GL_PrepareTextureVariant2(texture_s *tex, texturevariantspecif } // Suffer the cache miss and attempt to (re)prepare a variant. - bool loadedOk = tryLoadImageAndPrepareVariant(reinterpret_cast(tex), spec, &variant); + bool loadedOk = tryLoadImageAndPrepareVariant(tex, spec, &variant); if(outcome) { if(loadedOk) @@ -3458,7 +3466,7 @@ void GL_BindTexture(texturevariant_s *tex) if(!variant->isPrepared()) { de::TextureVariant **hndl = &variant; - if(!tryLoadImageAndPrepareVariant(reinterpret_cast(variant->generalCase()), spec, hndl)) + if(!tryLoadImageAndPrepareVariant(reinterpret_cast(*variant->generalCase()), spec, hndl)) { tex = 0; } @@ -3493,28 +3501,25 @@ void GL_BindTexture(texturevariant_s *tex) } } -int GL_ReleaseGLTexturesByTexture2(texture_s *tex, void *parameters) +void GL_ReleaseGLTexturesByTexture(texture_s *tex) { - DENG_UNUSED(parameters); - if(tex) + if(!tex) return; + de::Texture::Variants const &variants = reinterpret_cast(tex)->variantList(); + DENG2_FOR_EACH_CONST(de::Texture::Variants, i, variants) { - de::Texture::Variants const &variants = reinterpret_cast(tex)->variantList(); - DENG2_FOR_EACH_CONST(de::Texture::Variants, i, variants) - { - releaseVariantGLTexture(*i); - } + releaseVariantGLTexture(*i); } - return 0; // Continue iteration. -} - -int GL_ReleaseGLTexturesByTexture(texture_s *tex) -{ - return GL_ReleaseGLTexturesByTexture2(tex, NULL); } -void GL_ReleaseTexturesByScheme(textureschemeid_t schemeId) +void GL_ReleaseTexturesByScheme(char const *schemeName) { - Textures_Iterate(schemeId, GL_ReleaseGLTexturesByTexture2); + if(!schemeName) return; + PathTreeIterator iter(App_Textures()->scheme(schemeName).index().leafNodes()); + while(iter.hasNext()) + { + TextureMetaFile &metafile = static_cast(iter.next()); + GL_ReleaseGLTexturesByTexture(reinterpret_cast(metafile.texture())); + } } void GL_ReleaseVariantTexturesBySpec(texture_s *tex, texturevariantspecification_t *spec) @@ -3533,22 +3538,22 @@ void GL_ReleaseVariantTexture(texturevariant_s *tex) releaseVariantGLTexture(reinterpret_cast(tex)); } -static int releaseGLTexturesByColorPaletteWorker(texture_s *tex, void *parameters) +static int releaseGLTexturesByColorPaletteWorker(de::Texture &tex, void *parameters) { - colorpalette_analysis_t* cp = reinterpret_cast(Texture_AnalysisDataPointer(tex, TA_COLORPALETTE)); + colorpalette_analysis_t* cp = reinterpret_cast(tex.analysisDataPointer(TA_COLORPALETTE)); colorpaletteid_t paletteId = *(colorpaletteid_t *)parameters; - DENG_ASSERT(tex && parameters); + DENG_ASSERT(parameters); if(cp && cp->paletteId == paletteId) { - GL_ReleaseGLTexturesByTexture(tex); + GL_ReleaseGLTexturesByTexture(reinterpret_cast(&tex)); } return 0; // Continue iteration. } void GL_ReleaseTexturesByColorPalette(colorpaletteid_t paletteId) { - Textures_Iterate2(TS_ANY, releaseGLTexturesByColorPaletteWorker, (void *)&paletteId); + App_Textures()->iterate(releaseGLTexturesByColorPaletteWorker, (void *)&paletteId); } void GL_InitTextureContent(texturecontent_t *content) @@ -3571,22 +3576,18 @@ void GL_InitTextureContent(texturecontent_t *content) texturecontent_t *GL_ConstructTextureContentCopy(texturecontent_t const *other) { - texturecontent_t *c; - uint8_t *pixels; - int bytesPerPixel; - size_t bufferSize; DENG_ASSERT(other); - c = (texturecontent_t*) M_Malloc(sizeof(*c)); + texturecontent_t *c = (texturecontent_t*) M_Malloc(sizeof(*c)); if(!c) Con_Error("GL_ConstructTextureContentCopy: Failed on allocation of %lu bytes for new TextureContent.", (unsigned long) sizeof(*c)); memcpy(c, other, sizeof(*c)); // Duplicate the image buffer. - bytesPerPixel = BytesPerPixelFmt(other->format); - bufferSize = bytesPerPixel * other->width * other->height; - pixels = (uint8_t*) M_Malloc(bufferSize); - memcpy(pixels, other->pixels, bufferSize); + int bytesPerPixel = BytesPerPixelFmt(other->format); + size_t bufferSize = bytesPerPixel * other->width * other->height; + uint8_t *pixels = (uint8_t*) M_Malloc(bufferSize); + std::memcpy(pixels, other->pixels, bufferSize); c->pixels = pixels; return c; } @@ -3639,13 +3640,15 @@ DGLuint GL_NewTextureWithParams2(dgltexformat_t format, int width, int height, return c.name; } -AutoStr *GL_ComposeCacheNameForTexture(texture_s *tex) +/** + * @param tex Texture instance to compose the cache name of. + * @return The chosen cache name for this texture. + */ +Path GL_ComposeCachePathForTexture(de::Texture &tex) { - textureid_t texId = Textures_Id(tex); - AutoStr* path = Textures_ComposePath(texId); - AutoStr* cacheName = Str_Appendf(AutoStr_NewStd(), "texcache/%s/%s.png", - Str_Text(Textures_SchemeName(Textures_Scheme(texId))), Str_Text(path)); - return cacheName; + Textures &textures = *App_Textures(); + de::Uri uri = textures.composeUri(textures.id(tex)); + return String("texcache") / uri.scheme() / uri.path() + ".png"; } boolean GL_DumpImage(image_t const *origImg, char const *filePath) @@ -3704,7 +3707,7 @@ D_CMD(MipMap) { DENG_UNUSED(src); DENG_UNUSED(argc); - int newMipMode = strtol(argv[1], NULL, 0); + int newMipMode = String(argv[1]).toInt(); if(newMipMode < 0 || newMipMode > 5) { Con_Message("Invalid mipmapping mode %i specified. Valid range is [0..5).\n", newMipMode); diff --git a/doomsday/engine/src/render/lumobj.cpp b/doomsday/engine/src/render/lumobj.cpp index 608e7a149b..bb54de4a7c 100644 --- a/doomsday/engine/src/render/lumobj.cpp +++ b/doomsday/engine/src/render/lumobj.cpp @@ -750,7 +750,7 @@ static void addLuminous(mobj_t *mo) if(!MSU_texture(ms, MTU_PRIMARY)) return; // An invalid sprite texture. pl = (pointlight_analysis_t const *) Texture_AnalysisDataPointer(MSU_texture(ms, MTU_PRIMARY), TA_SPRITE_AUTOLIGHT); - if(!pl) Con_Error("addLuminous: Texture id:%u has no TA_SPRITE_AUTOLIGHT analysis.", Textures_Id(MSU_texture(ms, MTU_PRIMARY))); + if(!pl) Con_Error("addLuminous: Texture id:%u has no TA_SPRITE_AUTOLIGHT analysis.", App_Textures()->id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))); size = pl->brightMul; yOffset = ms->size.height * pl->originY; @@ -764,11 +764,12 @@ static void addLuminous(mobj_t *mo) } #if _DEBUG - if(Textures_Scheme(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TS_SPRITES) + de::Textures &textures = *App_Textures(); + if(textures.composeUri(textures.id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))).scheme().compareWithoutCase("Sprites")) Con_Error("LO_AddLuminous: Internal error, material snapshot's primary texture is not a SpriteTex!"); #endif - pTex = (patchtex_t *) Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY)); + pTex = reinterpret_cast(Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY))); DENG_ASSERT(pTex); center = -pTex->offY - mo->floorClip - R_GetBobOffset(mo) - yOffset; @@ -860,9 +861,9 @@ static void addLuminous(mobj_t *mo) if(def) { - LUM_OMNI(l)->tex = GL_PrepareLightMap(def->sides); - LUM_OMNI(l)->ceilTex = GL_PrepareLightMap(def->up); - LUM_OMNI(l)->floorTex = GL_PrepareLightMap(def->down); + LUM_OMNI(l)->tex = GL_PrepareLightmap(def->sides); + LUM_OMNI(l)->ceilTex = GL_PrepareLightmap(def->up); + LUM_OMNI(l)->floorTex = GL_PrepareLightmap(def->down); } else { @@ -972,7 +973,7 @@ static boolean createGlowLightForSurface(Surface *suf, void * /*paramaters*/) if(!(ms->glowing > .001f)) return true; // Continue iteration. averagecolor_analysis_t const *avgColorAmplified = (averagecolor_analysis_t const *) Texture_AnalysisDataPointer(MSU_texture(ms, MTU_PRIMARY), TA_COLOR_AMPLIFIED); - if(!avgColorAmplified) Con_Error("createGlowLightForSurface: Texture id:%u has no TA_COLOR_AMPLIFIED analysis.", Textures_Id(MSU_texture(ms, MTU_PRIMARY))); + if(!avgColorAmplified) Con_Error("createGlowLightForSurface: Texture id:%u has no TA_COLOR_AMPLIFIED analysis.", App_Textures()->id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))); // @note Plane lights do not spread so simply link to all BspLeafs of this sector. lumobj_t *lum = createLuminous(LT_PLANE, sec->bspLeafs[0]); diff --git a/doomsday/engine/src/render/r_draw.cpp b/doomsday/engine/src/render/r_draw.cpp index dd07a31014..f91cf4b44b 100644 --- a/doomsday/engine/src/render/r_draw.cpp +++ b/doomsday/engine/src/render/r_draw.cpp @@ -24,12 +24,10 @@ #include "de_console.h" #include "de_graphics.h" #include "de_play.h" +#include "de_resource.h" #include "render/r_draw.h" #include "gl/sys_opengl.h" -#include "resource/texture.h" -#include "resource/texturevariant.h" -#include "resource/materialvariant.h" // A logical ordering (twice around). enum { @@ -47,6 +45,8 @@ enum { static bool inited = false; static int borderSize; static Uri *borderGraphicsNames[9]; + +/// @todo Declare the patches with URNs to avoid unnecessary duplication here -ds static patchid_t borderPatches[9]; static void loadViewBorderPatches() @@ -130,7 +130,8 @@ void R_DrawPatch3(Texture *tex, int x, int y, int w, int h, boolean useOffsets) { if(!tex) return; - if(Textures_Scheme(Textures_Id(tex)) != TS_PATCHES) + de::Textures &textures = *App_Textures(); + if(textures.composeUri(textures.id(reinterpret_cast(*tex))).scheme().compareWithoutCase("Patches")) { #if _DEBUG LOG_AS("R_DrawPatch3"); @@ -224,10 +225,11 @@ void R_DrawViewBorder(void) if(border != 0) { - R_DrawPatchTiled(Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, borderPatches[BG_TOP])), vd->window.origin.x, vd->window.origin.y - border, vd->window.size.width, border, GL_REPEAT, GL_CLAMP_TO_EDGE); - R_DrawPatchTiled(Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, borderPatches[BG_BOTTOM])), vd->window.origin.x, vd->window.origin.y + vd->window.size.height , vd->window.size.width, border, GL_REPEAT, GL_CLAMP_TO_EDGE); - R_DrawPatchTiled(Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, borderPatches[BG_LEFT])), vd->window.origin.x - border, vd->window.origin.y, border, vd->window.size.height, GL_CLAMP_TO_EDGE, GL_REPEAT); - R_DrawPatchTiled(Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, borderPatches[BG_RIGHT])), vd->window.origin.x + vd->window.size.width, vd->window.origin.y, border, vd->window.size.height, GL_CLAMP_TO_EDGE, GL_REPEAT); + de::Textures &textures = *App_Textures(); + R_DrawPatchTiled(reinterpret_cast(textures.scheme("Patches").findByUniqueId(borderPatches[BG_TOP]).texture()), vd->window.origin.x, vd->window.origin.y - border, vd->window.size.width, border, GL_REPEAT, GL_CLAMP_TO_EDGE); + R_DrawPatchTiled(reinterpret_cast(textures.scheme("Patches").findByUniqueId(borderPatches[BG_BOTTOM]).texture()), vd->window.origin.x, vd->window.origin.y + vd->window.size.height , vd->window.size.width, border, GL_REPEAT, GL_CLAMP_TO_EDGE); + R_DrawPatchTiled(reinterpret_cast(textures.scheme("Patches").findByUniqueId(borderPatches[BG_LEFT]).texture()), vd->window.origin.x - border, vd->window.origin.y, border, vd->window.size.height, GL_CLAMP_TO_EDGE, GL_REPEAT); + R_DrawPatchTiled(reinterpret_cast(textures.scheme("Patches").findByUniqueId(borderPatches[BG_RIGHT]).texture()), vd->window.origin.x + vd->window.size.width, vd->window.origin.y, border, vd->window.size.height, GL_CLAMP_TO_EDGE, GL_REPEAT); } glMatrixMode(GL_TEXTURE); @@ -235,10 +237,11 @@ void R_DrawViewBorder(void) if(border != 0) { - R_DrawPatch3(Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, borderPatches[BG_TOPLEFT])), vd->window.origin.x - border, vd->window.origin.y - border, border, border, false); - R_DrawPatch3(Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, borderPatches[BG_TOPRIGHT])), vd->window.origin.x + vd->window.size.width, vd->window.origin.y - border, border, border, false); - R_DrawPatch3(Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, borderPatches[BG_BOTTOMRIGHT])), vd->window.origin.x + vd->window.size.width, vd->window.origin.y + vd->window.size.height, border, border, false); - R_DrawPatch3(Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, borderPatches[BG_BOTTOMLEFT])), vd->window.origin.x - border, vd->window.origin.y + vd->window.size.height, border, border, false); + de::Textures &textures = *App_Textures(); + R_DrawPatch3(reinterpret_cast(textures.scheme("Patches").findByUniqueId(borderPatches[BG_TOPLEFT]).texture()), vd->window.origin.x - border, vd->window.origin.y - border, border, border, false); + R_DrawPatch3(reinterpret_cast(textures.scheme("Patches").findByUniqueId(borderPatches[BG_TOPRIGHT]).texture()), vd->window.origin.x + vd->window.size.width, vd->window.origin.y - border, border, border, false); + R_DrawPatch3(reinterpret_cast(textures.scheme("Patches").findByUniqueId(borderPatches[BG_BOTTOMRIGHT]).texture()), vd->window.origin.x + vd->window.size.width, vd->window.origin.y + vd->window.size.height, border, border, false); + R_DrawPatch3(reinterpret_cast(textures.scheme("Patches").findByUniqueId(borderPatches[BG_BOTTOMLEFT]).texture()), vd->window.origin.x - border, vd->window.origin.y + vd->window.size.height, border, border, false); } glDisable(GL_TEXTURE_2D); diff --git a/doomsday/engine/src/render/r_things.cpp b/doomsday/engine/src/render/r_things.cpp index 0f5968d1b9..8c3feca9e0 100644 --- a/doomsday/engine/src/render/r_things.cpp +++ b/doomsday/engine/src/render/r_things.cpp @@ -34,12 +34,10 @@ #include "de_render.h" #include "de_graphics.h" #include "de_misc.h" +#include "de_resource.h" #include "def_main.h" #include "m_stack.h" -#include "resource/texture.h" -#include "resource/texturevariant.h" -#include "resource/materialvariant.h" #include @@ -138,13 +136,13 @@ static void installSpriteLump(spriteframe_t* sprTemp, int* maxFrame, sprTemp[frame].flip[rotation] = (byte) flipped; } -static spriterecord_t* findSpriteRecordForName(const ddstring_t* name) +static spriterecord_t* findSpriteRecordForName(char const *name) { spriterecord_t* rec = NULL; - if(name && !Str_IsEmpty(name) && spriteRecords) + if(name && name[0] && spriteRecords) { rec = spriteRecords; - while(strnicmp(rec->name, Str_Text(name), 4) && (rec = rec->next)) {} + while(strnicmp(rec->name, name, 4) && (rec = rec->next)) {} } return rec; } @@ -171,16 +169,18 @@ static spriterecord_t* findSpriteRecordForName(const ddstring_t* name) * turn CLOCKWISE around the axis. This is not the same as the angle, * which increases counter clockwise (protractor). */ -static int buildSpriteRotationsWorker(textureid_t texId, void * /*parameters*/) +static void buildSprite(de::TextureMetaFile &metafile) { // Have we already encountered this name? - AutoStr *path = Textures_ComposePath(texId); - spriterecord_t *rec = findSpriteRecordForName(path); + de::String decodedPath = QString(QByteArray::fromPercentEncoding(metafile.path().toUtf8())); + QByteArray decodedPathUtf8 = decodedPath.toUtf8(); + + spriterecord_t *rec = findSpriteRecordForName(decodedPathUtf8.constData()); if(!rec) { // An entirely new sprite. rec = (spriterecord_t *) BlockSet_Allocate(spriteRecordBlockSet); - strncpy(rec->name, Str_Text(path), 4); + strncpy(rec->name, decodedPathUtf8.constData(), 4); rec->name[4] = '\0'; rec->numFrames = 0; rec->frames = NULL; @@ -191,15 +191,15 @@ static int buildSpriteRotationsWorker(textureid_t texId, void * /*parameters*/) } // Add the frame(s). - Str decodedPath; Str_InitStd(&decodedPath); - Str_PercentDecode(Str_Set(&decodedPath, Str_Text(path))); + int const frameNumber = decodedPath.at(4).toUpper().unicode() - QChar('A').unicode() + 1; + int const rotationNumber = decodedPath.at(5).digitValue(); - boolean link = false; + bool link = false; spriterecord_frame_t *frame = rec->frames; if(rec->frames) { - while(!(frame->frame[0] == toupper(Str_At(&decodedPath, 4)) - 'A' + 1 && - frame->rotation[0] == toupper(Str_At(&decodedPath, 5)) - '0') && + while(!(frame->frame[0] == frameNumber && + frame->rotation[0] == rotationNumber) && (frame = frame->next)) {} } @@ -210,21 +210,21 @@ static int buildSpriteRotationsWorker(textureid_t texId, void * /*parameters*/) link = true; } - Uri* uri = Uri_NewWithPath2("Sprites:", RC_NULL); - Uri_SetPath(uri, Str_Text(path)); - frame->mat = Materials_ToMaterial(Materials_ResolveUri(uri)); - Uri_Delete(uri); + de::Uri uri = de::Uri("Sprites", metafile.path()); + frame->mat = Materials_ToMaterial(Materials_ResolveUri(reinterpret_cast(&uri))); + + frame->frame[0] = frameNumber; + frame->rotation[0] = rotationNumber; - frame->frame[0] = toupper(Str_At(&decodedPath, 4)) - 'A' + 1; - frame->rotation[0] = toupper(Str_At(&decodedPath, 5)) - '0'; - if(Str_At(&decodedPath, 6)) + // Not mirrored? + if(decodedPath.length() >= 8) { - frame->frame[1] = toupper(Str_At(&decodedPath, 6)) - 'A' + 1; - frame->rotation[1] = toupper(Str_At(&decodedPath, 7)) - '0'; + frame->frame[1] = decodedPath.at(6).toUpper().unicode() - QChar('A').unicode() + 1; + frame->rotation[1] = decodedPath.at(7).digitValue(); } else { - frame->frame[1] = 0; + frame->frame[1] = 0; frame->rotation[1] = 0; } @@ -233,23 +233,24 @@ static int buildSpriteRotationsWorker(textureid_t texId, void * /*parameters*/) frame->next = rec->frames; rec->frames = frame; } - - Str_Free(&decodedPath); - return 0; // Continue iteration. } -static void buildSpriteRotations() +static void buildSprites() { - uint startTime = (verbose >= 2? Timer_RealMilliseconds() : 0); + de::Time begunAt; numSpriteRecords = 0; spriteRecords = 0; spriteRecordBlockSet = BlockSet_New(sizeof(spriterecord_t), 64), spriteRecordFrameBlockSet = BlockSet_New(sizeof(spriterecord_frame_t), 256); - Textures_IterateDeclared(TS_SPRITES, buildSpriteRotationsWorker); + de::PathTreeIterator iter(App_Textures()->scheme("Sprites").index().leafNodes()); + while(iter.hasNext()) + { + buildSprite(static_cast(iter.next())); + } - VERBOSE2( Con_Message("buildSpriteRotations: Done in %.2f seconds.\n", (Timer_RealMilliseconds() - startTime) / 1000.0f) ) + LOG_INFO(de::String("buildSprites: Done in %1 seconds.").arg(begunAt.since(), 0, 'g', 2)); } /** @@ -354,11 +355,10 @@ static void initSpriteDefs(spriterecord_t *const *sprRecords, int num) void R_InitSprites() { - uint startTime = (verbose >= 2? Timer_RealMilliseconds() : 0); - - VERBOSE( Con_Message("Initializing Sprites...\n") ) + de::Time begunAt; - buildSpriteRotations(); + LOG_VERBOSE("Building Sprites..."); + buildSprites(); /** * @attention Kludge: @@ -402,7 +402,7 @@ void R_InitSprites() BlockSet_Delete(spriteRecordFrameBlockSet); spriteRecordFrameBlockSet = 0; numSpriteRecords = 0; - VERBOSE2( Con_Message("R_InitSprites: Done in %.2f seconds.\n", (Timer_RealMilliseconds() - startTime) / 1000.0f) ); + LOG_INFO(de::String("R_InitSprites: Done in %1 seconds.").arg(begunAt.since(), 0, 'g', 2)); } void R_ShutdownSprites() @@ -461,7 +461,8 @@ boolean R_GetSpriteInfo(int sprite, int frame, spriteinfo_t *info) materialsnapshot_t const *ms = Materials_Prepare(mat, spec, false); #if _DEBUG - if(Textures_Scheme(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TS_SPRITES) + de::Textures &textures = *App_Textures(); + if(textures.composeUri(textures.id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))).scheme().compareWithoutCase("Sprites")) Con_Error("R_GetSpriteInfo: Internal error, material snapshot's primary texture is not a SpriteTex!"); #endif @@ -551,7 +552,7 @@ float R_ShadowStrength(mobj_t *mo) materialsnapshot_t const *ms = Materials_Prepare(mat, Sprite_MaterialSpec(0/*tclass*/, 0/*tmap*/), true); averagealpha_analysis_t const *aa = (averagealpha_analysis_t const *) Texture_AnalysisDataPointer(MSU_texture(ms, MTU_PRIMARY), TA_ALPHA); float weightedSpriteAlpha; - if(!aa) Con_Error("R_ShadowStrength: Texture id:%u has no TA_ALPHA analysis.", Textures_Id(MSU_texture(ms, MTU_PRIMARY))); + if(!aa) Con_Error("R_ShadowStrength: Texture id:%u has no TA_ALPHA analysis.", App_Textures()->id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))); // We use an average which factors in the coverage ratio // of alpha:non-alpha pixels. @@ -1045,9 +1046,10 @@ void R_ProjectSprite(mobj_t *mo) ms = Materials_Prepare(mat, spec, true); // An invalid sprite texture? - if(Textures_Scheme(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TS_SPRITES) return; + de::Textures &textures = *App_Textures(); + if(textures.composeUri(textures.id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))).scheme().compareWithoutCase("Sprites")) return; - pTex = (patchtex_t*) Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY)); + pTex = reinterpret_cast(Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY))); DENG_ASSERT(pTex); // Align to the view plane? @@ -1305,7 +1307,7 @@ void R_ProjectSprite(mobj_t *mo) pl = (const pointlight_analysis_t*) Texture_AnalysisDataPointer(MSU_texture(ms, MTU_PRIMARY), TA_SPRITE_AUTOLIGHT); if(!pl) - Con_Error("R_ProjectSprite: Texture id:%u has no TA_SPRITE_AUTOLIGHT analysis.", Textures_Id(MSU_texture(ms, MTU_PRIMARY))); + Con_Error("R_ProjectSprite: Texture id:%u has no TA_SPRITE_AUTOLIGHT analysis.", App_Textures()->id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))); lum = LO_GetLuminous(mo->lumIdx); def = (mo->state? stateLights[mo->state - states] : 0); diff --git a/doomsday/engine/src/render/rend_decor.c b/doomsday/engine/src/render/rend_decor.c index d77e9d1ec3..9f8c9899ba 100644 --- a/doomsday/engine/src/render/rend_decor.c +++ b/doomsday/engine/src/render/rend_decor.c @@ -255,9 +255,9 @@ static void addLuminousDecoration(decorsource_t* src) l->decorSource = src; LUM_OMNI(l)->zOff = 0; - LUM_OMNI(l)->tex = GL_PrepareLightMap(def->sides); - LUM_OMNI(l)->ceilTex = GL_PrepareLightMap(def->up); - LUM_OMNI(l)->floorTex = GL_PrepareLightMap(def->down); + LUM_OMNI(l)->tex = GL_PrepareLightmap(def->sides); + LUM_OMNI(l)->ceilTex = GL_PrepareLightmap(def->up); + LUM_OMNI(l)->floorTex = GL_PrepareLightmap(def->down); // These are the same rules as in DL_MobjRadius(). LUM_OMNI(l)->radius = def->radius * 40 * loRadiusFactor; diff --git a/doomsday/engine/src/render/rend_halo.c b/doomsday/engine/src/render/rend_halo.c index ff9d66de0f..1ed8821351 100644 --- a/doomsday/engine/src/render/rend_halo.c +++ b/doomsday/engine/src/render/rend_halo.c @@ -308,7 +308,7 @@ boolean H_RenderHalo(coord_t x, coord_t y, coord_t z, float size, DGLuint tex, // The 'realistic' halos just use the blurry round // texture unless custom. if(!tex) - tex = GL_PrepareSysFlareTexture(FXT_ROUND); + tex = GL_PrepareSysFlaremap(FXT_ROUND); } else { @@ -319,16 +319,16 @@ boolean H_RenderHalo(coord_t x, coord_t y, coord_t z, float size, DGLuint tex, // The "Very Bright" condition. radius *= .65f; if(!i) - tex = GL_PrepareSysFlareTexture(FXT_BIGFLARE); + tex = GL_PrepareSysFlaremap(FXT_BIGFLARE); else - tex = GL_PrepareSysFlareTexture(fl->texture); + tex = GL_PrepareSysFlaremap(fl->texture); } else { if(!i) - tex = GL_PrepareSysFlareTexture(FXT_ROUND); + tex = GL_PrepareSysFlaremap(FXT_ROUND); else - tex = GL_PrepareSysFlareTexture(fl->texture); + tex = GL_PrepareSysFlaremap(fl->texture); } } } diff --git a/doomsday/engine/src/render/sky.cpp b/doomsday/engine/src/render/sky.cpp index 99831f90c3..89650b6040 100644 --- a/doomsday/engine/src/render/sky.cpp +++ b/doomsday/engine/src/render/sky.cpp @@ -213,18 +213,18 @@ static void calculateSkyAmbientColor() { averagecolor_analysis_t const *avgColor = (averagecolor_analysis_t const *) Texture_AnalysisDataPointer(MSU_texture(ms, MTU_PRIMARY), TA_COLOR); - if(!avgColor) Con_Error("calculateSkyAmbientColor: Texture id:%u has no TA_COLOR analysis.", Textures_Id(MSU_texture(ms, MTU_PRIMARY))); + if(!avgColor) Con_Error("calculateSkyAmbientColor: Texture id:%u has no TA_COLOR analysis.", App_Textures()->id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))); if(i == firstSkyLayer) { Texture const *tex = MSU_texture(ms, MTU_PRIMARY); averagecolor_analysis_t const *avgLineColor = (averagecolor_analysis_t const *) Texture_AnalysisDataPointer(tex, TA_LINE_TOP_COLOR); - if(!avgLineColor) Con_Error("calculateSkyAmbientColor: Texture id:%u has no TA_LINE_TOP_COLOR analysis.", Textures_Id(MSU_texture(ms, MTU_PRIMARY))); + if(!avgLineColor) Con_Error("calculateSkyAmbientColor: Texture id:%u has no TA_LINE_TOP_COLOR analysis.", App_Textures()->id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))); V3f_Copy(topCapColor.rgb, avgLineColor->color.rgb); avgLineColor = (averagecolor_analysis_t const *) Texture_AnalysisDataPointer(tex, TA_LINE_BOTTOM_COLOR); - if(!avgLineColor) Con_Error("calculateSkyAmbientColor: Texture id:%u has no TA_LINE_BOTTOM_COLOR analysis.", Textures_Id(MSU_texture(ms, MTU_PRIMARY))); + if(!avgLineColor) Con_Error("calculateSkyAmbientColor: Texture id:%u has no TA_LINE_BOTTOM_COLOR analysis.", App_Textures()->id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))); V3f_Copy(bottomCapColor.rgb, avgLineColor->color.rgb); } @@ -823,7 +823,7 @@ static void configureRenderHemisphereStateForLayer(int layer, hemispherecap_t se Texture_AnalysisDataPointer(MSU_texture(ms, MTU_PRIMARY), (setupCap == HC_TOP? TA_LINE_TOP_COLOR : TA_LINE_BOTTOM_COLOR)); float const fadeoutLimit = Sky_LayerFadeoutLimit(layer); - if(!avgLineColor) Con_Error("configureRenderHemisphereStateForLayer: Texture id:%u has no %s analysis.", Textures_Id(MSU_texture(ms, MTU_PRIMARY)), (setupCap == HC_TOP? "TA_LINE_TOP_COLOR" : "TA_LINE_BOTTOM_COLOR")); + if(!avgLineColor) Con_Error("configureRenderHemisphereStateForLayer: Texture id:%u has no %s analysis.", App_Textures()->id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY))), (setupCap == HC_TOP? "TA_LINE_TOP_COLOR" : "TA_LINE_BOTTOM_COLOR")); V3f_Copy(rs.capColor.rgb, avgLineColor->color.rgb); // Is the colored fadeout in use? diff --git a/doomsday/engine/src/render/sprite.cpp b/doomsday/engine/src/render/sprite.cpp index 7a72857f27..82e0ecbdd4 100644 --- a/doomsday/engine/src/render/sprite.cpp +++ b/doomsday/engine/src/render/sprite.cpp @@ -318,14 +318,15 @@ static void setupPSpriteParams(rendpspriteparams_t *params, vispsprite_t *spr) ms = Materials_Prepare(sprFrame->mats[0], spec, true); #if _DEBUG - if(Textures_Scheme(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TS_SPRITES) + de::Textures &textures = *App_Textures(); + if(textures.composeUri(textures.id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))).scheme().compareWithoutCase("Sprites")) Con_Error("setupPSpriteParams: Internal error, material snapshot's primary texture is not a SpriteTex!"); #endif - pTex = (patchtex_t *)Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY)); - assert(pTex); + pTex = reinterpret_cast(Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY))); + DENG_ASSERT(pTex); texSpec = TS_GENERAL(MSU_texturespec(ms, MTU_PRIMARY)); - assert(spec); + DENG_ASSERT(spec); params->pos[VX] = psp->pos[VX] - -pTex->offX + pspOffset[VX] + -texSpec->border; params->pos[VY] = offScaleY * (psp->pos[VY] - -pTex->offY) + pspOffset[VY] + -texSpec->border; @@ -932,10 +933,11 @@ void Rend_RenderSprite(rendspriteparams_t const *params) TextureVariant_Coords(MST(ms, MTU_PRIMARY), &s, &t); - if(Textures_Scheme(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) == TS_SPRITES) + de::Textures &textures = *App_Textures(); + if(!textures.composeUri(textures.id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))).scheme().compareWithoutCase("Sprites")) { - pTex = (patchtex_t *) Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY)); - assert(pTex); + pTex = reinterpret_cast(Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY))); + DENG_ASSERT(pTex); viewOffset.x += (float) -pTex->offX; } } diff --git a/doomsday/engine/src/resource/animgroups.cpp b/doomsday/engine/src/resource/animgroups.cpp index 9da185c2b5..0f433b720b 100644 --- a/doomsday/engine/src/resource/animgroups.cpp +++ b/doomsday/engine/src/resource/animgroups.cpp @@ -21,10 +21,9 @@ #include "de_base.h" #include "de_console.h" +#include "de_resource.h" #include -#include "resource/animgroups.h" - static int numgroups; static animgroup_t *groups; @@ -92,10 +91,12 @@ int R_CreateAnimGroup(int flags) } /// @note Part of the Doomsday public API. -void R_AddAnimGroupFrame(int groupNum, Uri const *texture, int tics, int randomTics) +void R_AddAnimGroupFrame(int groupNum, Uri const *textureUri, int tics, int randomTics) { LOG_AS("R_AddAnimGroupFrame"); + if(!textureUri) return; + animgroup_t *group = getAnimGroup(groupNum); if(!group) { @@ -103,11 +104,10 @@ void R_AddAnimGroupFrame(int groupNum, Uri const *texture, int tics, int randomT return; } - textureid_t texId = Textures_ResolveUri2(texture, true/*quiet please*/); - if(texId == NOTEXTUREID) + de::TextureMetaFile *metafile = App_Textures()->find(reinterpret_cast(*textureUri)); + if(!metafile) { - AutoStr *path = Uri_ToString(texture); - LOG_DEBUG("Invalid texture uri \"%s\", ignoring.") << Str_Text(path); + LOG_DEBUG("Invalid texture uri \"%s\", ignoring.") << reinterpret_cast(*textureUri); return; } @@ -116,14 +116,17 @@ void R_AddAnimGroupFrame(int groupNum, Uri const *texture, int tics, int randomT if(!group->frames) Con_Error("R_AddAnimGroupFrame: Failed on (re)allocation of %lu bytes enlarging AnimFrame list for group #%i.", (unsigned long) sizeof(*group->frames) * group->count, groupNum); animframe_t *frame = &group->frames[group->count - 1]; - frame->texture = texId; + frame->texture = metafile->lookupTextureId(); frame->tics = tics; frame->randomTics = randomTics; } boolean R_IsTextureInAnimGroup(Uri const *texture, int groupNum) { + if(!texture) return false; animgroup_t *group = getAnimGroup(groupNum); if(!group) return false; - return isInAnimGroup(group, Textures_ResolveUri2(texture, true/*quiet please*/)); + de::TextureMetaFile *metafile = App_Textures()->find(reinterpret_cast(*texture)); + if(!metafile) return false; + return isInAnimGroup(group, metafile->lookupTextureId()); } diff --git a/doomsday/engine/src/resource/bitmapfont.cpp b/doomsday/engine/src/resource/bitmapfont.cpp index fe65e62bde..66fc86d86e 100644 --- a/doomsday/engine/src/resource/bitmapfont.cpp +++ b/doomsday/engine/src/resource/bitmapfont.cpp @@ -26,13 +26,10 @@ #include "de_render.h" #include "de_system.h" #include "de_filesys.h" +#include "de_resource.h" -#include "resource/fonts.h" -#include "resource/texturevariant.h" #include "m_misc.h" // For M_CeilPow2() -#include "resource/bitmapfont.h" - #include void Font_Init(font_t *font, fonttype_t type, fontid_t bindId) @@ -546,7 +543,6 @@ void BitmapCompositeFont_Prepare(font_t *font) { bitmapcompositefont_char_t *ch = &cf->_chars[i]; patchid_t patch = ch->patch; - textureid_t texId; patchinfo_t info; if(0 == patch) continue; @@ -560,8 +556,8 @@ void BitmapCompositeFont_Prepare(font_t *font) ch->geometry.size.height += font->_marginHeight * 2; ch->border = 0; - texId = Textures_TextureForUniqueId(TS_PATCHES, patch); - ch->tex = GL_PrepareTextureVariant(Textures_ToTexture(texId), BitmapCompositeFont_CharSpec()); + de::Texture *tex = App_Textures()->scheme("Patches").findByUniqueId(patch).texture(); + ch->tex = GL_PrepareTextureVariant(reinterpret_cast(tex), BitmapCompositeFont_CharSpec()); if(ch->tex && TextureVariant_Source(ch->tex) == TEXS_ORIGINAL) { // Upscale & Sharpen will have been applied. diff --git a/doomsday/engine/src/resource/fonts.cpp b/doomsday/engine/src/resource/fonts.cpp index 99515a4773..4ae14a271e 100644 --- a/doomsday/engine/src/resource/fonts.cpp +++ b/doomsday/engine/src/resource/fonts.cpp @@ -498,7 +498,7 @@ void Fonts_ClearRuntime(void) void Fonts_ClearSystem(void) { - if(!Textures_Size()) return; + if(!App_Textures()->count()) return; Fonts_ClearScheme(FS_SYSTEM); GL_PruneTextureVariantSpecifications(); diff --git a/doomsday/engine/src/resource/material.cpp b/doomsday/engine/src/resource/material.cpp index 6e1c8f944b..a4df5231db 100644 --- a/doomsday/engine/src/resource/material.cpp +++ b/doomsday/engine/src/resource/material.cpp @@ -22,11 +22,9 @@ #include "de_base.h" #include "de_console.h" #include "de_play.h" +#include "de_resource.h" #include "m_misc.h" -#include "resource/texture.h" -#include "resource/materialvariant.h" -#include "resource/material.h" #include "audio/s_environ.h" #include @@ -109,10 +107,13 @@ void Material_SetDefinition(material_t* mat, struct ded_material_s* def) mat->_isCustom = false; if(def->layers[0].stageCount.num > 0 && def->layers[0].stages[0].texture) { - textureid_t texId = Textures_ResolveUri2(def->layers[0].stages[0].texture, true/*quiet please*/); - if(texId != NOTEXTUREID) + de::Uri *texUri = reinterpret_cast(def->layers[0].stages[0].texture); + if(de::TextureMetaFile *metafile = App_Textures()->find(*texUri)) { - mat->_isCustom = Texture_IsCustom(Textures_ToTexture(texId)); + if(de::Texture *tex = metafile->texture()) + { + mat->_isCustom = tex->isCustom(); + } } } } diff --git a/doomsday/engine/src/resource/materials.cpp b/doomsday/engine/src/resource/materials.cpp index 4bab14b1f1..3da15e4071 100644 --- a/doomsday/engine/src/resource/materials.cpp +++ b/doomsday/engine/src/resource/materials.cpp @@ -29,10 +29,9 @@ #include "de_graphics.h" #include "de_misc.h" #include "de_audio.h" // For texture, environmental audio properties. +#include "de_resource.h" -#include "resource/texture.h" -#include "resource/texturevariant.h" -#include "resource/materialvariant.h" +#include "resource/materials.h" #include #include @@ -932,14 +931,14 @@ material_t* Materials_CreateFromDef(ded_material_t* def) LOG_AS("Materials::createFromDef"); - if(!initedOk || !def->uri) return NULL; + if(!initedOk || !def->uri) return 0; de::Uri& uri = reinterpret_cast(*def->uri); // We require a properly formed uri. if(!validateMaterialUri(uri, 0, (verbose >= 1))) { LOG_WARNING("Failed creating Material \"%s\" from definition %p, ignoring.") << uri << de::dintptr(def); - return NULL; + return 0; } // Have we already created a material for this? @@ -950,29 +949,36 @@ material_t* Materials_CreateFromDef(ded_material_t* def) return bind->material(); } + de::Textures &textures = *App_Textures(); + // Ensure the primary layer has a valid texture reference. - textureid_t texId = NOTEXTUREID; + de::Texture *tex = 0; if(def->layers[0].stageCount.num > 0) { ded_material_layer_t const& layer = def->layers[0]; - if(layer.stages[0].texture) // Not unused. + de::Uri *texUri = reinterpret_cast(layer.stages[0].texture); + if(texUri) // Not unused. { - texId = Textures_ResolveUri2(layer.stages[0].texture, true/*quiet please*/); - if(texId == NOTEXTUREID) + if(de::TextureMetaFile *metafile = textures.find(*texUri)) { - LOG_WARNING("Unknown texture \"%s\" in Material \"%s\" (layer %i stage %i).") - << reinterpret_cast(layer.stages[0].texture) - << reinterpret_cast(def->uri) - << 0 << 0; + tex = metafile->texture(); + if(!tex) + { + LOG_WARNING("Unknown texture \"%s\" in Material \"%s\" (layer %i stage %i).") + << reinterpret_cast(layer.stages[0].texture) + << reinterpret_cast(def->uri) + << 0 << 0; + } } } } - if(texId == NOTEXTUREID) return NULL; + + if(!tex) return 0; // A new Material. material_t* mat = linkMaterialToGlobalList(allocMaterial()); mat->_flags = def->flags; - mat->_isCustom = Texture_IsCustom(Textures_ToTexture(texId)); + mat->_isCustom = tex->isCustom(); mat->_def = def; Size2_SetWidthHeight(mat->_size, MAX_OF(0, def->width), MAX_OF(0, def->height)); mat->_envClass = S_MaterialEnvClassForUri(reinterpret_cast(&uri)); @@ -1059,19 +1065,34 @@ void Materials_Ticker(timespan_t time) } } -static inline Texture *findDetailTextureForDef(ded_detailtexture_t const &def) +static de::Texture *findTextureByResourceUri(de::String nameOfScheme, de::Uri const &resourceUri) +{ + if(resourceUri.isEmpty()) return 0; + try + { + return App_Textures()->scheme(nameOfScheme).findByResourceUri(resourceUri).texture(); + } + catch(de::Textures::Scheme::NotFoundError const &) + {} // Ignore this error. + return 0; +} + +static de::Texture *findDetailTextureForDef(ded_detailtexture_t const &def) { - return Textures_TextureForResourcePath(TS_DETAILS, def.detailTex); + if(!def.detailTex) return 0; + return findTextureByResourceUri("Details", reinterpret_cast(*def.detailTex)); } -static inline Texture *findShinyTextureForDef(ded_reflection_t const &def) +static de::Texture *findShinyTextureForDef(ded_reflection_t const &def) { - return Textures_TextureForResourcePath(TS_REFLECTIONS, def.shinyMap); + if(!def.shinyMap) return 0; + return findTextureByResourceUri("Reflections", reinterpret_cast(*def.shinyMap)); } -static inline Texture *findShinyMaskTextureForDef(ded_reflection_t const &def) +static de::Texture *findShinyMaskTextureForDef(ded_reflection_t const &def) { - return Textures_TextureForResourcePath(TS_MASKS, def.maskMap); + if(!def.maskMap) return 0; + return findTextureByResourceUri("Masks", reinterpret_cast(*def.maskMap)); } static void updateMaterialTextureLinks(MaterialBind &mb) @@ -1084,13 +1105,13 @@ static void updateMaterialTextureLinks(MaterialBind &mb) if(!mat) return; ded_detailtexture_t const *dtlDef = mb.detailTextureDef(); - Material_SetDetailTexture(mat, (dtlDef? findDetailTextureForDef(*dtlDef) : NULL)); + Material_SetDetailTexture(mat, reinterpret_cast(dtlDef? findDetailTextureForDef(*dtlDef) : NULL)); Material_SetDetailStrength(mat, (dtlDef? dtlDef->strength : 0)); Material_SetDetailScale(mat, (dtlDef? dtlDef->scale : 0)); ded_reflection_t const *refDef = mb.reflectionDef(); - Material_SetShinyTexture(mat, (refDef? findShinyTextureForDef(*refDef) : NULL)); - Material_SetShinyMaskTexture(mat, (refDef? findShinyMaskTextureForDef(*refDef) : NULL)); + Material_SetShinyTexture(mat, reinterpret_cast(refDef? findShinyTextureForDef(*refDef) : NULL)); + Material_SetShinyMaskTexture(mat, reinterpret_cast(refDef? findShinyMaskTextureForDef(*refDef) : NULL)); Material_SetShinyBlendmode(mat, (refDef? refDef->blendMode : BM_ADD)); float const black[3] = { 0, 0, 0 }; Material_SetShinyMinColor(mat, (refDef? refDef->minColor : black)); @@ -1429,19 +1450,19 @@ static int printVariantInfo(MaterialVariant* variant, void* parameters) Uri_Delete(nextUri); } + de::Textures &textures = *App_Textures(); + // Print layer info: for(i = 0; i < layers; ++i) { - const materialvariant_layer_t* l = MaterialVariant_Layer(variant, i); - Uri* uri = Textures_ComposeUri(Textures_Id(l->texture)); - AutoStr* path = Uri_ToString(uri); + materialvariant_layer_t const *l = MaterialVariant_Layer(variant, i); + de::Uri uri = textures.composeUri(textures.id(reinterpret_cast(*l->texture))); + QByteArray path = de::NativePath(uri.asText()).pretty().toUtf8(); Con_Printf(" #%i: Stage:%i Tics:%i Texture:(\"%s\" uid:%u)" "\n Offset: %.2f x %.2f Glow:%.2f\n", - i, l->stage, (int)l->tics, F_PrettyPath(Str_Text(path)), Textures_Id(l->texture), + i, l->stage, (int)l->tics, path.constData(), textures.id(reinterpret_cast(*l->texture)), l->texOrigin[0], l->texOrigin[1], l->glow); - - Uri_Delete(uri); } ++(*variantIdx); @@ -1843,7 +1864,8 @@ void Materials_AnimateAnimGroup(MaterialAnim* group) /*{ ded_material_t* def = Material_Definition(mat); if(def && def->layers[0].stageCount.num > 1) { - if(Textures_ResolveUri(def->layers[0].stages[0].texture)) + de::Uri *texUri = reinterpret_cast(def->layers[0].stages[0].texture) + if(texUri && de::Textures::resolveUri(*texUri)) continue; // Animated elsewhere. }}*/ diff --git a/doomsday/engine/src/resource/materialvariant.cpp b/doomsday/engine/src/resource/materialvariant.cpp index 9dbb9b3ade..c3f4056adc 100644 --- a/doomsday/engine/src/resource/materialvariant.cpp +++ b/doomsday/engine/src/resource/materialvariant.cpp @@ -21,44 +21,53 @@ #include "de_base.h" #include "de_console.h" +#include "de_resource.h" #include "m_misc.h" -#include "resource/materialvariant.h" -#include "resource/texture.h" #include "render/r_main.h" #include #include #include #include -de::MaterialVariant::MaterialVariant(material_t& generalCase, - const materialvariantspecification_t& spec, const ded_material_t& def) +namespace de { + +MaterialVariant::MaterialVariant(material_t &generalCase, + materialvariantspecification_t const &spec, ded_material_t const &def) : material(&generalCase), hasTranslation(false), current(0), next(0), inter(0), varSpec(&spec), snapshot_(0), snapshotPrepareFrame_(0) { // Initialize layers. - const int layerCount = Material_LayerCount(material); + int const layerCount = Material_LayerCount(material); for(int i = 0; i < layerCount; ++i) { layers[i].stage = 0; layers[i].tics = def.layers[i].stages[0].tics; layers[i].glow = def.layers[i].stages[0].glow; - layers[i].texture = Textures_ToTexture(Textures_ResolveUri2(def.layers[i].stages[0].texture, true/*quiet please*/)); + layers[i].texture = 0; + de::Uri *texUri = reinterpret_cast(def.layers[i].stages[0].texture); + if(texUri) + { + if(TextureMetaFile *metafile = App_Textures()->find(*texUri)) + { + layers[i].texture = reinterpret_cast(metafile->texture()); + } + } layers[i].texOrigin[0] = def.layers[i].stages[0].texOrigin[0]; layers[i].texOrigin[1] = def.layers[i].stages[0].texOrigin[1]; } } -de::MaterialVariant::~MaterialVariant() +MaterialVariant::~MaterialVariant() { if(snapshot_) M_Free(snapshot_); } -void de::MaterialVariant::ticker(timespan_t /*time*/) +void MaterialVariant::ticker(timespan_t /*time*/) { - const ded_material_t* def = Material_Definition(material); + ded_material_t const *def = Material_Definition(material); if(!def) { // Material is no longer valid. We can't yet purge them because @@ -68,12 +77,12 @@ void de::MaterialVariant::ticker(timespan_t /*time*/) } // Update layers. - const int layerCount = Material_LayerCount(material); + int const layerCount = Material_LayerCount(material); for(int i = 0; i < layerCount; ++i) { - const ded_material_layer_t* lDef = &def->layers[i]; - const ded_material_layer_stage_t* lsDef, *lsDefNext; - materialvariant_layer_t* layer = &layers[i]; + ded_material_layer_t const *lDef = &def->layers[i]; + ded_material_layer_stage_t const *lsDef, *lsDefNext; + materialvariant_layer_t *layer = &layers[i]; float inter; if(!(lDef->stageCount.num > 1)) continue; @@ -101,8 +110,9 @@ void de::MaterialVariant::ticker(timespan_t /*time*/) inter = 1.0f - (layer->tics - frameTimePos) / (float) lsDef->tics; } - /*const Texture* glTex; - if((glTex = Textures_ResolveUri(lsDef->texture))) + /* Texture const *glTex; + de::Uri *texUri = reinterpret_cast(lsDef->texture); + if(texUri && (glTex = Textures::resolveUri(*texUri))) { layer->tex = Texture_Id(glTex); setTranslationPoint(inter); @@ -131,66 +141,66 @@ void de::MaterialVariant::ticker(timespan_t /*time*/) } } -void de::MaterialVariant::resetAnim() +void MaterialVariant::resetAnim() { - const int layerCount = Material_LayerCount(material); + int const layerCount = Material_LayerCount(material); for(int i = 0; i < layerCount; ++i) { - materialvariant_layer_t* ml = &layers[i]; + materialvariant_layer_t *ml = &layers[i]; if(ml->stage == -1) break; ml->stage = 0; } } -const materialvariant_layer_t* de::MaterialVariant::layer(int layer) +materialvariant_layer_t const *MaterialVariant::layer(int layer) { if(layer >= 0 && layer < Material_LayerCount(material)) return &layers[layer]; return 0; } -materialsnapshot_t& de::MaterialVariant::attachSnapshot(materialsnapshot_t& newSnapshot) +materialsnapshot_t &MaterialVariant::attachSnapshot(materialsnapshot_t &newSnapshot) { if(snapshot_) { LOG_AS("MaterialVariant::AttachSnapshot"); - LOG_WARNING("A snapshot is already attached to %p, it will be replaced.") << (void*) this; + LOG_WARNING("A snapshot is already attached to %p, it will be replaced.") << (void *) this; M_Free(snapshot_); } snapshot_ = &newSnapshot; return newSnapshot; } -materialsnapshot_t* de::MaterialVariant::detachSnapshot() +materialsnapshot_t *MaterialVariant::detachSnapshot() { - materialsnapshot_t* detachedSnapshot = snapshot_; + materialsnapshot_t *detachedSnapshot = snapshot_; snapshot_ = 0; return detachedSnapshot; } -void de::MaterialVariant::setSnapshotPrepareFrame(int frame) +void MaterialVariant::setSnapshotPrepareFrame(int frame) { snapshotPrepareFrame_ = frame; } -de::MaterialVariant* de::MaterialVariant::translationNext() +MaterialVariant *MaterialVariant::translationNext() { if(!hasTranslation) return this; return next; } -de::MaterialVariant* de::MaterialVariant::translationCurrent() +MaterialVariant* MaterialVariant::translationCurrent() { if(!hasTranslation) return this; return current; } -float de::MaterialVariant::translationPoint() +float MaterialVariant::translationPoint() { return inter; } -void de::MaterialVariant::setTranslation(MaterialVariant* newCurrent, MaterialVariant* newNext) +void MaterialVariant::setTranslation(MaterialVariant *newCurrent, MaterialVariant *newNext) { if(newCurrent && newNext && (newCurrent != this || newNext != this)) { @@ -206,34 +216,36 @@ void de::MaterialVariant::setTranslation(MaterialVariant* newCurrent, MaterialVa inter = 0; } -void de::MaterialVariant::setTranslationPoint(float newInter) +void MaterialVariant::setTranslationPoint(float newInter) { inter = newInter; } -/** +} // namespace de + +/* * C wrapper API - **/ + */ #define TOINTERNAL(inst) \ - (inst) != 0? reinterpret_cast(inst) : NULL + (inst) != 0? reinterpret_cast(inst) : NULL #define TOINTERNAL_CONST(inst) \ - (inst) != 0? reinterpret_cast(inst) : NULL + (inst) != 0? reinterpret_cast(inst) : NULL #define TOPUBLIC(inst) \ - (inst) != 0? reinterpret_cast(inst) : NULL + (inst) != 0? reinterpret_cast(inst) : NULL #define TOPUBLIC_CONST(inst) \ - (inst) != 0? reinterpret_cast(inst) : NULL + (inst) != 0? reinterpret_cast(inst) : NULL #define SELF(inst) \ DENG2_ASSERT(inst); \ - de::MaterialVariant* self = TOINTERNAL(inst) + de::MaterialVariant *self = TOINTERNAL(inst) #define SELF_CONST(inst) \ DENG2_ASSERT(inst); \ - const de::MaterialVariant* self = TOINTERNAL_CONST(inst) + de::MaterialVariant const *self = TOINTERNAL_CONST(inst) MaterialVariant* MaterialVariant_New(struct material_s* generalCase, const materialvariantspecification_t* spec) diff --git a/doomsday/engine/src/resource/models.cpp b/doomsday/engine/src/resource/models.cpp index 29213605a3..7c1ec270d9 100644 --- a/doomsday/engine/src/resource/models.cpp +++ b/doomsday/engine/src/resource/models.cpp @@ -958,7 +958,8 @@ static void scaleModelToSprite(modeldef_t& mf, int sprite, int frame) materialsnapshot_t const* ms = Materials_Prepare(spr.spriteFrames[frame].mats[0], spec, true); #if _DEBUG - if(Textures_Scheme(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TS_SPRITES) + Textures &textures = *App_Textures(); + if(textures.composeUri(textures.id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))).scheme().compareWithoutCase("Sprites")) throw Error("scaleModelToSprite", "Material snapshot primary texture is not a SpriteTex"); #endif diff --git a/doomsday/engine/src/resource/r_data.cpp b/doomsday/engine/src/resource/r_data.cpp index 6e52fad5b2..14510a70f1 100644 --- a/doomsday/engine/src/resource/r_data.cpp +++ b/doomsday/engine/src/resource/r_data.cpp @@ -57,22 +57,23 @@ void R_InitSystemTextures() { "unknown", "missing", "bbox", "gray", "" }; LOG_VERBOSE("Initializing System textures..."); + Textures &textures = *App_Textures(); + for(uint i = 0; !names[i].isEmpty(); ++i) { Path path = names[i]; de::Uri uri("System", path); de::Uri resourcePath("Graphics", path); - textureid_t texId = Textures_Declare(reinterpret_cast(&uri), i + 1/*1-based index*/, - reinterpret_cast(&resourcePath)); - if(texId == NOTEXTUREID) continue; // Invalid uri? + TextureMetaFile *metafile = textures.declare(uri, i + 1/*1-based index*/, &resourcePath); + if(!metafile) continue; // Invalid uri? // Have we defined this yet? - de::Texture *tex = reinterpret_cast(Textures_ToTexture(texId)); - if(!tex && !Textures_Create(texId, true/*is-custom*/, 0)) + if(metafile->texture()) continue; + + if(!metafile->define(de::Texture::Custom)) { - LOG_WARNING("Failed to define Texture for system texture \"%s\".") - << NativePath(uri.asText()).pretty(); + LOG_WARNING("Failed to define Texture for system texture \"%s\".") << uri; } } } @@ -80,15 +81,33 @@ void R_InitSystemTextures() /// @note Part of the Doomsday public API. AutoStr *R_ComposePatchPath(patchid_t id) { - textureid_t texId = Textures_TextureForUniqueId(TS_PATCHES, id); - if(texId == NOTEXTUREID) return AutoStr_NewStd(); - return Textures_ComposePath(texId); + try + { + TextureMetaFile &metafile = App_Textures()->scheme("Patches").findByUniqueId(id); + return AutoStr_FromTextStd(metafile.path().toUtf8().constData()); + } + catch(Textures::Scheme::NotFoundError const &er) + { + // Log but otherwise ignore this error. + LOG_WARNING(er.asText() + ", ignoring."); + } + return AutoStr_NewStd(); } /// @note Part of the Doomsday public API. uri_s *R_ComposePatchUri(patchid_t id) { - return Textures_ComposeUri(Textures_TextureForUniqueId(TS_PATCHES, id)); + try + { + TextureMetaFile &metafile = App_Textures()->scheme("Patches").findByUniqueId(id); + return reinterpret_cast(new de::Uri(metafile.composeUri())); + } + catch(Textures::Scheme::NotFoundError const &er) + { + // Log but otherwise ignore this error. + LOG_WARNING(er.asText() + ", ignoring."); + } + return reinterpret_cast(new de::Uri()); } /// @note Part of the Doomsday public API. @@ -102,38 +121,37 @@ patchid_t R_DeclarePatch(char const *name) return 0; } + Textures &textures = *App_Textures(); + // WAD format allows characters not normally permitted in native paths. // To achieve uniformity we apply a percent encoding to the "raw" names. de::Uri uri("Patches", Path(QString(QByteArray(name, qstrlen(name)).toPercentEncoding()))); // Already defined as a patch? - textureid_t texId = Textures_ResolveUri2(reinterpret_cast(&uri), true/*quiet please*/); - if(texId) + if(TextureMetaFile *metafile = textures.find(uri)) { /// @todo We should instead define Materials from patches and return the material id. - return patchid_t( Textures_UniqueId(texId) ); + return patchid_t( metafile->uniqueId() ); } Path lumpPath = uri.path() + ".lmp"; lumpnum_t lumpNum = App_FileSystem()->nameIndex().lastIndexForPath(lumpPath); if(lumpNum < 0) { - LOG_WARNING("Failed to locate lump for \"%s\", ignoring.") - << NativePath(uri.asText()).pretty(); + LOG_WARNING("Failed to locate lump for \"%s\", ignoring.") << uri; return 0; } // Compose the path to the data resource. - de::File1& file = App_FileSystem()->nameIndex().lump(lumpNum); + de::File1 &file = App_FileSystem()->nameIndex().lump(lumpNum); de::Uri resourceUri("Lumps", Path(file.name())); - int uniqueId = Textures_Count(TS_PATCHES) + 1; // 1-based index. - texId = Textures_Declare(reinterpret_cast(&uri), uniqueId, - reinterpret_cast(&resourceUri)); - if(texId == NOTEXTUREID) return 0; // Invalid uri? + int uniqueId = textures.scheme("Patches").count() + 1; // 1-based index. + TextureMetaFile *metafile = textures.declare(uri, uniqueId, &resourceUri); + if(!metafile) return 0; // Invalid uri? // Generate a new patch. - patchtex_t *p = (patchtex_t*) M_Malloc(sizeof(*p)); + patchtex_t *p = (patchtex_t *) M_Malloc(sizeof(*p)); if(!p) Con_Error("R_DeclarePatch: Failed on allocation of %u bytes for new PatchTex.", (unsigned long) sizeof(*p)); // Take a copy of the current patch loading state so that future texture @@ -151,34 +169,36 @@ patchid_t R_DeclarePatch(char const *name) PatchHeader patchHdr; from >> patchHdr; + file.unlock(); + p->offX = -patchHdr.origin.x; p->offY = -patchHdr.origin.y; - de::Texture *tex = reinterpret_cast(Textures_ToTexture(texId)); + de::Texture *tex = metafile->texture(); + de::Texture::Flags flags; + if(file.container().hasCustom()) flags |= de::Texture::Custom; + if(!tex) { - tex = reinterpret_cast(Textures_CreateWithDimensions(texId, file.container().hasCustom(), &patchHdr.dimensions, (void *)p)); - file.unlock(); - + tex = metafile->define(patchHdr.dimensions, flags); if(!tex) { - LOG_WARNING("Failed defining Texture for Patch texture \"%s\".") - << NativePath(uri.asText()).pretty(); + LOG_WARNING("Failed defining Texture for Patch texture \"%s\".") << uri; M_Free(p); return 0; } + + tex->setUserDataPointer((void *)p); } else { patchtex_t *oldPatch = reinterpret_cast(tex->userDataPointer()); - tex->flagCustom(file.container().hasCustom()); + tex->flagCustom(!!(flags & de::Texture::Custom)); tex->setDimensions(patchHdr.dimensions); tex->setUserDataPointer((void *)p); M_Free(oldPatch); - - file.unlock(); } return uniqueId; @@ -191,9 +211,13 @@ boolean R_GetPatchInfo(patchid_t id, patchinfo_t *info) memset(info, 0, sizeof(patchinfo_t)); - de::Texture *tex = reinterpret_cast(Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, id))); - if(tex) + if(!id) return false; + + try { + de::Texture *tex = App_Textures()->scheme("Patches").findByUniqueId(id).texture(); + if(!tex) return false; + patchtex_t const *pTex = reinterpret_cast(tex->userDataPointer()); DENG_ASSERT(pTex); @@ -215,10 +239,10 @@ boolean R_GetPatchInfo(patchid_t id, patchinfo_t *info) // Kludge end. return true; } - - if(id != 0) + catch(de::Textures::Scheme::NotFoundError const &er) { - LOG_DEBUG("Invalid Patch id #%i, returning false.") << id; + // Log but otherwise ignore this error. + LOG_WARNING(er.asText() + ", ignoring."); } return false; } @@ -238,7 +262,7 @@ static void loadPatchNames(String lumpName) if(file.size() < 4) { LOG_WARNING("File \"%s\" (#%i) does not appear to be valid PNAMES data.") - << de::NativePath(file.composeUri().asText()).pretty() << lumpNum; + << NativePath(file.composeUri().asText()).pretty() << lumpNum; return; } @@ -560,14 +584,16 @@ static CompositeTextures loadCompositeTextureDefs() static void processCompositeTextureDefs(CompositeTextures &defs) { LOG_AS("processCompositeTextureDefs"); + Textures &textures = *App_Textures(); + bool isFirst = true; while(!defs.isEmpty()) { CompositeTexture &def = *defs.takeFirst(); - de::Uri uri("Textures", Path(def.percentEncodedName())); - textureid_t texId = Textures_Declare(reinterpret_cast(&uri), def.origIndex(), 0); - if(texId != NOTEXTUREID) + + TextureMetaFile *metafile = textures.declare(uri, def.origIndex(), 0); + if(metafile) { /* * Vanilla DOOM's implementation of the texture collection has a flaw @@ -580,32 +606,36 @@ static void processCompositeTextureDefs(CompositeTextures &defs) isFirst = false; } + de::Texture::Flags flags; + if(def.flags().testFlag(CompositeTexture::Custom)) flags |= de::Texture::Custom; + // Are we redefining an existing texture? - if(de::Texture *tex = reinterpret_cast( - Textures_ToTexture(texId))) + if(de::Texture *tex = metafile->texture()) { // Yes. Destroy the existing definition (*should* exist). CompositeTexture *oldDef = reinterpret_cast(tex->userDataPointer()); - if(oldDef) delete oldDef; + if(oldDef) + { + tex->setUserDataPointer(0); + delete oldDef; + } // Reconfigure and attach the new definition. - tex->flagCustom(def.flags().testFlag(CompositeTexture::Custom)); + tex->flagCustom(!!(flags & de::Texture::Custom)); tex->setDimensions(def.dimensions()); tex->setUserDataPointer((void *)&def); + continue; } - // A new texture. - if(Textures_CreateWithDimensions(texId, def.flags().testFlag(CompositeTexture::Custom), - &def.dimensions(), (void *)&def)) + else if(de::Texture *tex = metafile->define(def.dimensions(), flags)) { + tex->setUserDataPointer((void *)&def); continue; } } - LOG_WARNING("Failed defining Texture for patch composite \"%s\", ignoring.") - << NativePath(uri.asText()).pretty(); - + LOG_WARNING("Failed defining Texture for patch composite \"%s\", ignoring.") << uri; delete &def; } } @@ -622,7 +652,7 @@ void R_InitCompositeTextures() DENG_ASSERT(texs.isEmpty()); - LOG_INFO(String("R_InitPatchComposites: Done in %1 seconds.").arg(begunAt.since(), 0, 'g', 2)); + LOG_INFO(String("R_InitCompositeTextures: Done in %1 seconds.").arg(begunAt.since(), 0, 'g', 2)); } static inline de::Uri composeFlatUri(String percentEncodedPath) @@ -647,37 +677,37 @@ void R_InitFlatTextures() de::Time begunAt; LOG_VERBOSE("Initializing Flat textures..."); + Textures &textures = *App_Textures(); LumpIndex const &index = App_FileSystem()->nameIndex(); lumpnum_t firstFlatMarkerLumpNum = index.firstIndexForPath(Path("F_START.lmp")); if(firstFlatMarkerLumpNum >= 0) { lumpnum_t lumpNum; - de::File1 *blockFile = 0; + de::File1 *blockContainer = 0; for(lumpNum = index.size(); lumpNum --> firstFlatMarkerLumpNum + 1;) { - de::File1 &lump = index.lump(lumpNum); - String percentEncodedName = lump.name().fileNameWithoutExtension(); - de::File1 *containerFile = &lump.container(); + de::File1 &file = index.lump(lumpNum); + String percentEncodedName = file.name().fileNameWithoutExtension(); - if(blockFile && blockFile != containerFile) + if(blockContainer && blockContainer != &file.container()) { - blockFile = 0; + blockContainer = 0; } - if(!blockFile) + if(!blockContainer) { if(!percentEncodedName.compareWithoutCase("F_END") || !percentEncodedName.compareWithoutCase("FF_END")) { - blockFile = containerFile; + blockContainer = &file.container(); } continue; } if(!percentEncodedName.compareWithoutCase("F_START")) { - blockFile = 0; + blockContainer = 0; continue; } @@ -687,7 +717,7 @@ void R_InitFlatTextures() !percentEncodedName.compareWithoutCase("FF_END")) continue; de::Uri uri = composeFlatUri(percentEncodedName); - if(Textures_ResolveUri2(reinterpret_cast(&uri), true/*quiet please*/) == NOTEXTUREID) // A new flat? + if(!textures.find(uri)) // A new flat? { /** * Kludge Assume 64x64 else when the flat is loaded it will inherit the @@ -696,15 +726,17 @@ void R_InitFlatTextures() * * @todo Always determine size from the lowres original. */ - Size2Raw const size = Size2Raw(64, 64); + Size2Raw const dimensions(64, 64); int const uniqueId = lumpNum - (firstFlatMarkerLumpNum + 1); de::Uri resourcePath = composeFlatResourceUrn(lumpNum); - textureid_t texId = Textures_Declare(reinterpret_cast(&uri), uniqueId, - reinterpret_cast(&resourcePath)); - if(!Textures_CreateWithDimensions(texId, lump.hasCustom(), &size, NULL)) + TextureMetaFile *metafile = textures.declare(uri, uniqueId, &resourcePath); + + de::Texture::Flags flags; + if(file.container().hasCustom()) flags |= de::Texture::Custom; + + if(metafile && !metafile->define(dimensions, flags)) { - LOG_WARNING("Failed defining Texture for new flat \"%s\", ignoring.") - << NativePath(uri.asText()).pretty(); + LOG_WARNING("Failed defining Texture for new flat \"%s\", ignoring.") << uri; } } } @@ -713,37 +745,35 @@ void R_InitFlatTextures() LOG_INFO(String("R_InitFlatTetxures: Done in %1 seconds.").arg(begunAt.since(), 0, 'g', 2)); } -void R_DefineSpriteTexture(textureid_t texId) +void R_DefineSpriteTexture(TextureMetaFile &metafile) { LOG_AS("R_DefineSpriteTexture"); - // Have we already encountered this name? - de::Texture *tex = reinterpret_cast(Textures_ToTexture(texId)); + // Have we already defined this texture? + de::Texture *tex = metafile.texture(); if(!tex) { // A new sprite texture. - patchtex_t *pTex = (patchtex_t *) M_Malloc(sizeof(*pTex)); - if(!pTex) Con_Error("R_InitSpriteTextures: Failed on allocation of %lu bytes for new PatchTex.", (unsigned long) sizeof(*pTex)); - pTex->offX = pTex->offY = 0; // Deferred until texture load time. - - tex = reinterpret_cast(Textures_Create(texId, 0, (void *)pTex)); + tex = metafile.define(0); if(!tex) { - M_Free(pTex); - - de::Uri *uri = reinterpret_cast(Textures_ComposeUri(texId)); LOG_WARNING("Failed to define Texture for sprite \"%s\", ignoring.") - << NativePath(uri->asText()).pretty(); - delete uri; + << metafile.composeUri(); } + + patchtex_t *pTex = (patchtex_t *) M_Malloc(sizeof(*pTex)); + if(!pTex) Con_Error("R_InitSpriteTextures: Failed on allocation of %lu bytes for new PatchTex.", (unsigned long) sizeof(*pTex)); + pTex->offX = pTex->offY = 0; // Deferred until texture load time. + tex->setUserDataPointer((void *)pTex); } - de::Uri const *resourceUri = reinterpret_cast(Textures_ResourcePath(texId)); - if(!tex || !resourceUri) return; + if(!tex) return; + de::Uri const &resourceUri = metafile.resourceUri(); + if(resourceUri.isEmpty()) return; try { - String const &resourcePath = resourceUri->resolvedRef(); + String const &resourcePath = resourceUri.resolvedRef(); lumpnum_t lumpNum = App_FileSystem()->nameIndex().lastIndexForPath(resourcePath); de::File1& file = App_FileSystem()->nameIndex().lump(lumpNum); @@ -761,16 +791,16 @@ void R_DefineSpriteTexture(textureid_t texId) {} // Ignore this error. } -static int defineSpriteTextureWorker(textureid_t texId, void *) +static int defineSpriteTextureWorker(TextureMetaFile &metafile, void * /*parameters*/) { - R_DefineSpriteTexture(texId); + R_DefineSpriteTexture(metafile); return 0; // Continue iteration. } /// @todo Defer until necessary (sprite is first de-referenced). static void defineAllSpriteTextures() { - Textures_IterateDeclared(TS_SPRITES, defineSpriteTextureWorker); + App_Textures()->iterateDeclared("Sprites", defineSpriteTextureWorker); } /// Returns @c true iff @a name is a well-formed sprite name. @@ -821,7 +851,6 @@ void R_InitSpriteTextures() { de::File1 &file = index.lump(i); String fileName = file.name().fileNameWithoutExtension(); - textureid_t texId; if(fileName.beginsWith('S', Qt::CaseInsensitive) && fileName.length() >= 5) { @@ -849,16 +878,11 @@ void R_InitSpriteTextures() continue; } - // Compose the resource name. - de::Uri uri("Sprites", Path(fileName)); - // Compose the data resource path. - //de::Uri resourcePath = composeSpriteResourceUrn(i); - de::Uri resourcePath("Lumps", Path(fileName)); + //de::Uri resourceUri = composeSpriteResourceUrn(i); + de::Uri resourceUri("Lumps", Path(fileName)); - texId = Textures_Declare(reinterpret_cast(&uri), uniqueId, - reinterpret_cast(&resourcePath)); - if(texId == NOTEXTUREID) + if(!App_Textures()->declare(de::Uri("Sprites", Path(fileName)), uniqueId, &resourceUri)) { continue; // Invalid uri? } @@ -877,140 +901,178 @@ void R_InitSpriteTextures() LOG_INFO(String("R_InitSpriteTextures: Done in %1 seconds.").arg(begunAt.since(), 0, 'g', 2)); } -texture_s *R_CreateSkinTex(uri_s const *filePath, boolean isShinySkin) +texture_s *R_CreateSkinTex(uri_s const *_resourceUri, boolean isShinySkin) { - if(!filePath || Str_IsEmpty(Uri_Path(filePath))) return 0; - LOG_AS("R_CreateSkinTex"); + if(!_resourceUri) return 0; + de::Uri const &resourceUri = reinterpret_cast(*_resourceUri); + + if(resourceUri.isEmpty()) return 0; + + Textures &textures = *App_Textures(); + Textures::Scheme &scheme = textures.scheme(isShinySkin? "ModelReflectionSkins" : "ModelSkins"); + // Have we already created one for this? - texture_s *tex; - if(!isShinySkin) - { - tex = Textures_TextureForResourcePath(TS_MODELSKINS, filePath); - } - else + try { - tex = Textures_TextureForResourcePath(TS_MODELREFLECTIONSKINS, filePath); + de::Texture *tex = scheme.findByResourceUri(resourceUri).texture(); + if(tex) return reinterpret_cast(tex); } - if(tex) return tex; + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. - int uniqueId = Textures_Count(isShinySkin? TS_MODELREFLECTIONSKINS : TS_MODELSKINS)+1; + int uniqueId = scheme.count() + 1; // 1-based index if(M_NumDigits(uniqueId) > 8) { - LOG_WARNING("Failed to create ModelSkin (max:%i), ignoring.") << DDMAXINT; + LOG_WARNING("Failed declaring new model skin (max:%i), ignoring.") << DDMAXINT; return 0; } - de::Uri uri(Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); - uri.setScheme((isShinySkin? "ModelReflectionSkins" : "ModelSkins")); + de::Uri uri(scheme.name(), Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); - textureid_t texId = Textures_Declare(reinterpret_cast(&uri), uniqueId, filePath); - if(texId == NOTEXTUREID) return 0; // Invalid uri? + TextureMetaFile *metafile = textures.declare(uri, uniqueId, &resourceUri); + if(!metafile) return 0; // Invalid uri? - tex = Textures_ToTexture(texId); + de::Texture *tex = metafile->texture(); if(!tex) { // Create a texture for it. - tex = Textures_Create(texId, true/*is-custom*/, NULL); + tex = metafile->define(de::Texture::Custom); if(!tex) { - LOG_WARNING("Failed defining Texture for ModelSkin \"%s\", ignoring.") - << NativePath(uri.asText()).pretty(); - return 0; + LOG_WARNING("Failed defining Texture for URI \"%s\", ignoring.") << uri; } } - return tex; + return reinterpret_cast(tex); } -texture_s *R_CreateDetailTextureFromDef(ded_detailtexture_t const *def) +texture_s *R_CreateDetailTexture(uri_s const *_resourceUri) { - LOG_AS("R_CreateDetailTextureFromDef"); + LOG_AS("R_CreateDetailTexture"); + + if(!_resourceUri) return 0; + de::Uri const &resourceUri = reinterpret_cast(*_resourceUri); - if(!def->detailTex || Uri_IsEmpty(def->detailTex)) return 0; + if(resourceUri.isEmpty()) return 0; + + Textures &textures = *App_Textures(); + Textures::Scheme &scheme = textures.scheme("Details"); // Have we already created one for this? - texture_s *tex = Textures_TextureForResourcePath(TS_DETAILS, def->detailTex); - if(tex) return tex; + try + { + de::Texture *tex = scheme.findByResourceUri(resourceUri).texture(); + if(tex) return reinterpret_cast(tex); + } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. - int uniqueId = Textures_Count(TS_DETAILS) + 1; // 1-based index. + int uniqueId = scheme.count() + 1; // 1-based index. if(M_NumDigits(uniqueId) > 8) { - LOG_WARNING("Failed creating new detail texture (max:%i).") << DDMAXINT; + LOG_WARNING("Failed declaring new detail texture (max:%i).") << DDMAXINT; return 0; } - de::Uri uri("Details", Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); - textureid_t texId = Textures_Declare(reinterpret_cast(&uri), uniqueId, def->detailTex); - if(texId == NOTEXTUREID) return 0; // Invalid URI? + de::Uri uri(scheme.name(), Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); + TextureMetaFile *metafile = textures.declare(uri, uniqueId, &resourceUri); + if(!metafile) return 0; // Invalid URI? - tex = Textures_ToTexture(texId); - if(!tex && !Textures_Create(texId, true/*is-custom*/, 0)) + de::Texture *tex = metafile->texture(); + if(!tex) { - LOG_WARNING("Failed defining Texture for detail texture \"%s\", ignoring.") - << NativePath(uri.asText()).pretty(); - return 0; + // Create a texture for it. + tex = metafile->define(de::Texture::Custom); + if(!tex) + { + LOG_WARNING("Failed defining Texture for URI \"%s\", ignoring.") << uri; + } } - return tex; + return reinterpret_cast(tex); } -texture_s *R_CreateLightMap(uri_s const *resourcePath) +texture_s *R_CreateLightmap(uri_s const *_resourceUri) { - LOG_AS("R_CreateLightMap"); + LOG_AS("R_CreateLightmap"); + + if(!_resourceUri) return 0; + de::Uri const &resourceUri = reinterpret_cast(*_resourceUri); - if(!resourcePath || Uri_IsEmpty(resourcePath)) return 0; - if(!Str_CompareIgnoreCase(Uri_Path(resourcePath), "-")) return 0; + if(resourceUri.isEmpty()) return 0; + if(!resourceUri.path().toStringRef().compareWithoutCase("-")) return 0; + + Textures &textures = *App_Textures(); + Textures::Scheme &scheme = textures.scheme("Lightmaps"); // Have we already created one for this? - texture_s *tex = Textures_TextureForResourcePath(TS_LIGHTMAPS, resourcePath); - if(tex) return tex; + try + { + de::Texture *tex = scheme.findByResourceUri(resourceUri).texture(); + if(tex) return reinterpret_cast(tex); + } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. + - int uniqueId = Textures_Count(TS_LIGHTMAPS) + 1; // 1-based index. + int uniqueId = scheme.count() + 1; // 1-based index. if(M_NumDigits(uniqueId) > 8) { LOG_WARNING("Failed declaring new lightmap (max:%i), ignoring.") << DDMAXINT; return 0; } - de::Uri uri("Lightmaps", Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); - textureid_t texId = Textures_Declare(reinterpret_cast(&uri), uniqueId, resourcePath); - if(texId == NOTEXTUREID) return 0; // Invalid URI? + de::Uri uri(scheme.name(), Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); + + TextureMetaFile *metafile = textures.declare(uri, uniqueId, &resourceUri); + if(!metafile) return 0; // Invalid URI? - tex = Textures_ToTexture(texId); + de::Texture *tex = metafile->texture(); if(!tex) { // Create a texture for it. - tex = Textures_Create(texId, true/*is-custom*/, 0); + tex = metafile->define(de::Texture::Custom); if(!tex) { - LOG_WARNING("Failed defining Texture for lightmap \"%s\", ignoring.") - << NativePath(uri.asText()).pretty(); - return 0; + LOG_WARNING("Failed defining Texture for URI \"%s\", ignoring.") << uri; } } - return tex; + + return reinterpret_cast(tex); } -texture_s *R_CreateFlareTexture(uri_s const *resourcePath) +texture_s *R_CreateFlaremap(uri_s const *_resourceUri) { - LOG_AS("R_CreateFlareTexture"); + LOG_AS("R_CreateFlaremap"); - if(!resourcePath || Uri_IsEmpty(resourcePath)) return 0; - if(!Str_CompareIgnoreCase(Uri_Path(resourcePath), "-")) return 0; + if(!_resourceUri) return 0; + de::Uri const &resourceUri = reinterpret_cast(*_resourceUri); + + if(resourceUri.isEmpty()) return 0; + if(!resourceUri.path().toStringRef().compareWithoutCase("-")) return 0; // Perhaps a "built-in" flare texture id? // Try to convert the id to a system flare tex constant idx - if(Str_At(Uri_Path(resourcePath), 0) >= '0' && Str_At(Uri_Path(resourcePath), 0) <= '4' && - !Str_At(Uri_Path(resourcePath), 1)) + String const &resourcePathStr = resourceUri.path().toStringRef(); + if(resourcePathStr.length() == 1 && + resourcePathStr.first() >= '0' && resourcePathStr.first() <= '4') return 0; + Textures &textures = *App_Textures(); + Textures::Scheme &scheme = textures.scheme("Flaremaps"); + // Have we already created one for this? - texture_s *tex = Textures_TextureForResourcePath(TS_FLAREMAPS, resourcePath); - if(tex) return tex; + try + { + de::Texture *tex = scheme.findByResourceUri(resourceUri).texture(); + if(tex) return reinterpret_cast(tex); + } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. - int uniqueId = Textures_Count(TS_FLAREMAPS) + 1; // 1-based index. + int uniqueId = scheme.count() + 1; // 1-based index. if(M_NumDigits(uniqueId) > 8) { LOG_WARNING("Failed declaring new flare texture (max:%i), ignoring.") << DDMAXINT; @@ -1018,98 +1080,120 @@ texture_s *R_CreateFlareTexture(uri_s const *resourcePath) } // Create a texture for it. - de::Uri uri("Flaremaps", Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); - textureid_t texId = Textures_Declare(reinterpret_cast(&uri), uniqueId, resourcePath); - if(texId == NOTEXTUREID) return 0; // Invalid URI? + de::Uri uri(scheme.name(), Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); + + TextureMetaFile *metafile = textures.declare(uri, uniqueId, &resourceUri); + if(!metafile) return 0; // Invalid URI? - tex = Textures_ToTexture(texId); + de::Texture *tex = metafile->texture(); if(!tex) { - tex = Textures_Create(texId, true/*is-custom*/, 0); + tex = metafile->define(de::Texture::Custom); if(!tex) { - LOG_WARNING("Failed defining Texture for flare texture \"%s\", ignoring.") - << NativePath(uri.asText()).pretty(); - return 0; + LOG_WARNING("Failed defining Texture for URI \"%s\", ignoring.") << uri; } } - return tex; + + return reinterpret_cast(tex); } -texture_s *R_CreateReflectionTexture(uri_s const *resourcePath) +texture_s *R_CreateReflectionTexture(uri_s const *_resourceUri) { LOG_AS("R_CreateReflectionTexture"); - if(!resourcePath || Uri_IsEmpty(resourcePath)) return 0; + if(!_resourceUri) return 0; + de::Uri const &resourceUri = reinterpret_cast(*_resourceUri); + + if(resourceUri.isEmpty()) return 0; + + Textures &textures = *App_Textures(); + Textures::Scheme &scheme = textures.scheme("Reflections"); // Have we already created one for this? - texture_s *tex = Textures_TextureForResourcePath(TS_REFLECTIONS, resourcePath); - if(tex) return tex; + try + { + de::Texture *tex = scheme.findByResourceUri(resourceUri).texture(); + if(tex) return reinterpret_cast(tex); + } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. - int uniqueId = Textures_Count(TS_REFLECTIONS) + 1; // 1-based index. + int uniqueId = scheme.count() + 1; // 1-based index. if(M_NumDigits(uniqueId) > 8) { LOG_WARNING("Failed declaring new shiny texture (max:%i), ignoring.") << DDMAXINT; return 0; } - de::Uri uri("Reflections", Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); - textureid_t texId = Textures_Declare(reinterpret_cast(&uri), uniqueId, resourcePath); - if(texId == NOTEXTUREID) return 0; // Invalid URI? + de::Uri uri(scheme.name(), Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); + + TextureMetaFile *metafile = textures.declare(uri, uniqueId, &resourceUri); + if(!metafile) return 0; // Invalid URI? - tex = Textures_ToTexture(texId); + de::Texture *tex = metafile->texture(); if(!tex) { // Create a texture for it. - tex = Textures_Create(texId, true/*is-custom*/, 0); + tex = metafile->define(de::Texture::Custom); if(!tex) { - LOG_WARNING("Failed defining Texture for shiny texture \"%s\", ignoring.") - << NativePath(uri.asText()).pretty(); - return 0; + LOG_WARNING("Failed defining Texture for URI \"%s\", ignoring.") << uri; } } - return tex; + return reinterpret_cast(tex); } -texture_s *R_CreateMaskTexture(uri_s const *resourcePath, Size2Raw const *size) +texture_s *R_CreateMaskTexture(uri_s const *_resourceUri, Size2Raw const *dimensions) { + DENG_ASSERT(dimensions); LOG_AS("R_CreateMaskTexture"); - if(!resourcePath || Uri_IsEmpty(resourcePath)) return 0; + if(!_resourceUri) return 0; + de::Uri const &resourceUri = reinterpret_cast(*_resourceUri); + + if(resourceUri.isEmpty()) return 0; + + Textures &textures = *App_Textures(); + Textures::Scheme &scheme = textures.scheme("Masks"); // Have we already created one for this? - texture_s *tex = Textures_TextureForResourcePath(TS_MASKS, resourcePath); - if(tex) return tex; + if(resourceUri.isEmpty()) return 0; + try + { + de::Texture *tex = scheme.findByResourceUri(resourceUri).texture(); + if(tex) return reinterpret_cast(tex); + } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. - int uniqueId = Textures_Count(TS_MASKS) + 1; // 1-based index. + int uniqueId = scheme.count() + 1; // 1-based index. if(M_NumDigits(uniqueId) > 8) { LOG_WARNING("Failed declaring mask texture (max:%i), ignoring.") << DDMAXINT; return 0; } - de::Uri uri("Masks", Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); - textureid_t texId = Textures_Declare(reinterpret_cast(&uri), uniqueId, resourcePath); - if(texId == NOTEXTUREID) return 0; // Invalid URI? + de::Uri uri(scheme.name(), Path(String("%1").arg(uniqueId, 8, 10, QChar('0')))); + + TextureMetaFile *metafile = textures.declare(uri, uniqueId, &resourceUri); + if(!metafile) return 0; // Invalid URI? - tex = Textures_ToTexture(texId); + de::Texture *tex = metafile->texture(); if(tex) { - Texture_SetDimensions(tex, size); + tex->setDimensions(*dimensions); } else { // Create a texture for it. - tex = Textures_CreateWithDimensions(texId, true/*is-custom*/, size, 0); + tex = metafile->define(*dimensions, de::Texture::Custom); if(!tex) { - LOG_WARNING("Failed defining Texture for mask texture \"%s\", ignoring.") - << NativePath(uri.asText()).pretty(); - return 0; + LOG_WARNING("Failed defining Texture for URI \"%s\", ignoring.") << uri; } } - return tex; + return reinterpret_cast(tex); } diff --git a/doomsday/engine/src/resource/texture.cpp b/doomsday/engine/src/resource/texture.cpp index d8e33ec3b9..6426fe3d81 100644 --- a/doomsday/engine/src/resource/texture.cpp +++ b/doomsday/engine/src/resource/texture.cpp @@ -20,13 +20,14 @@ * 02110-1301 USA */ -#include +#include #include #include "de_base.h" #if _DEBUG # include "gl/gl_texmanager.h" // For GL_PrintTextureVariantSpecification() #endif +#include "resource/compositetexture.h" #include "resource/texturevariant.h" #include "resource/texture.h" @@ -35,39 +36,74 @@ #include #include -de::Texture::Texture(textureid_t bindId, void* _userData) - : flags(), primaryBindId(bindId), variants(), userData(_userData), dimensions_() +namespace de { + +Texture::Texture(textureid_t bindId, Flags _flags, void *_userData) + : flags(_flags), primaryBindId(bindId), variants(), userData(_userData), dimensions_() { memset(analyses, 0, sizeof(analyses)); } -de::Texture::Texture(textureid_t bindId, const Size2Raw& size, void* _userData) - : flags(), primaryBindId(bindId), variants(), userData(_userData), dimensions_() +Texture::Texture(textureid_t bindId, Size2Raw const &size, Flags _flags, void *_userData) + : flags(_flags), primaryBindId(bindId), variants(), userData(_userData), dimensions_() { - memset(analyses, 0, sizeof(analyses)); + std::memset(analyses, 0, sizeof(analyses)); setDimensions(size); } -de::Texture::~Texture() +Texture::~Texture() { + GL_ReleaseGLTexturesByTexture(reinterpret_cast(this)); + + /// @todo Texture should employ polymorphism. + Textures &textures = *App_Textures(); + de::Uri uri = textures.composeUri(textures.id(*this)); + if(!uri.scheme().compareWithoutCase("Textures")) + { + CompositeTexture* pcTex = reinterpret_cast(userDataPointer()); + if(pcTex) delete pcTex; + } + else if(!uri.scheme().compareWithoutCase("Sprites")) + { + patchtex_t* pTex = reinterpret_cast(userDataPointer()); + if(pTex) M_Free(pTex); + } + else if(!uri.scheme().compareWithoutCase("Patches")) + { + patchtex_t* pTex = reinterpret_cast(userDataPointer()); + if(pTex) M_Free(pTex); + } + + clearAnalyses(); clearVariants(); } -void de::Texture::clearVariants() +void Texture::clearAnalyses() +{ + for(uint i = uint(TEXTURE_ANALYSIS_FIRST); i < uint(TEXTURE_ANALYSIS_COUNT); ++i) + { + texture_analysisid_t analysis = texture_analysisid_t(i); + void* data = analysisDataPointer(analysis); + if(data) M_Free(data); + setAnalysisDataPointer(analysis, 0); + } +} + +void Texture::clearVariants() { DENG2_FOR_EACH(Variants, i, variants) { #if _DEBUG - unsigned int glName = (*i)->glName(); + uint glName = (*i)->glName(); if(glName) { - textureid_t textureId = Textures_Id(reinterpret_cast(this)); - de::Uri* uri = reinterpret_cast(Textures_ComposeUri(textureId)); + Textures &textures = *App_Textures(); + textureid_t texId = textures.id(*this); + Uri uri = textures.composeUri(texId); LOG_AS("Texture::clearVariants") LOG_WARNING("GLName (%i) still set for a variant of \"%s\" [%p id:%i]. Perhaps it wasn't released?") - << glName << uri << (void*)this << int(textureId); + << glName << uri << (void *)this << int(texId); GL_PrintTextureVariantSpecification((*i)->spec()); - delete uri; } #endif delete *i; @@ -75,128 +111,130 @@ void de::Texture::clearVariants() variants.clear(); } -void de::Texture::setPrimaryBind(textureid_t bindId) +void Texture::setPrimaryBind(textureid_t bindId) { primaryBindId = bindId; } -void de::Texture::setUserDataPointer(void* newUserData) +void Texture::setUserDataPointer(void *newUserData) { - if(userData) + if(userData && newUserData) { - textureid_t textureId = Textures_Id(reinterpret_cast(this)); + textureid_t textureId = App_Textures()->id(*this); LOG_AS("Texture::setUserDataPointer"); - LOG_DEBUG("User data is already present for [%p id:%i], it will be replaced.") - << (void*)this << int(textureId); + LOG_DEBUG("User data already present for [%p id:%i], will be replaced.") + << (void *)this << int(textureId); } userData = newUserData; } -void* de::Texture::userDataPointer() const +void *Texture::userDataPointer() const { return userData; } -uint de::Texture::variantCount() const +uint Texture::variantCount() const { return uint(variants.size()); } -de::TextureVariant& de::Texture::addVariant(de::TextureVariant& variant) +TextureVariant &Texture::addVariant(TextureVariant &variant) { variants.push_back(&variant); return *variants.back(); } -void de::Texture::flagCustom(bool yes) +void Texture::flagCustom(bool yes) { if(yes) flags |= Custom; else flags &= ~Custom; /// @todo Update any Materials (and thus Surfaces) which reference this. } -int de::Texture::width() const +int Texture::width() const { return dimensions_.width; } -void de::Texture::setWidth(int newWidth) +void Texture::setWidth(int newWidth) { dimensions_.width = newWidth; /// @todo Update any Materials (and thus Surfaces) which reference this. } -int de::Texture::height() const +int Texture::height() const { return dimensions_.height; } -void de::Texture::setHeight(int newHeight) +void Texture::setHeight(int newHeight) { dimensions_.height = newHeight; /// @todo Update any Materials (and thus Surfaces) which reference this. } -void de::Texture::setDimensions(const Size2Raw& newSize) +void Texture::setDimensions(Size2Raw const &newSize) { dimensions_.width = newSize.width; dimensions_.height = newSize.height; /// @todo Update any Materials (and thus Surfaces) which reference this. } -void* de::Texture::analysisDataPointer(texture_analysisid_t analysisId) const +void *Texture::analysisDataPointer(texture_analysisid_t analysisId) const { DENG2_ASSERT(VALID_TEXTURE_ANALYSISID(analysisId)); return analyses[analysisId]; } -void de::Texture::setAnalysisDataPointer(texture_analysisid_t analysisId, void* data) +void Texture::setAnalysisDataPointer(texture_analysisid_t analysisId, void *data) { DENG2_ASSERT(VALID_TEXTURE_ANALYSISID(analysisId)); - if(analyses[analysisId]) + if(analyses[analysisId] && data) { #if _DEBUG - textureid_t textureId = Textures_Id(reinterpret_cast(this)); - de::Uri* uri = reinterpret_cast(Textures_ComposeUri(textureId)); + Textures &textures = *App_Textures(); + textureid_t texId = textures.id(*this); + Uri uri = textures.composeUri(texId); LOG_AS("Texture::attachAnalysis"); LOG_DEBUG("Image analysis (id:%i) already present for \"%s\" (replaced).") - << int(analysisId) << *uri; - delete uri; + << int(analysisId) << uri; #endif } analyses[analysisId] = data; } +} // namespace de + /** * C Wrapper API: */ #define TOINTERNAL(inst) \ - (inst) != 0? reinterpret_cast(inst) : NULL + (inst) != 0? reinterpret_cast(inst) : NULL #define TOINTERNAL_CONST(inst) \ - (inst) != 0? reinterpret_cast(inst) : NULL + (inst) != 0? reinterpret_cast(inst) : NULL #define SELF(inst) \ DENG2_ASSERT(inst); \ - de::Texture* self = TOINTERNAL(inst) + de::Texture *self = TOINTERNAL(inst) #define SELF_CONST(inst) \ DENG2_ASSERT(inst); \ - const de::Texture* self = TOINTERNAL_CONST(inst) + de::Texture const *self = TOINTERNAL_CONST(inst) -Texture* Texture_NewWithSize(textureid_t bindId, const Size2Raw* size, void* userData) +Texture *Texture_NewWithSize(textureid_t bindId, Size2Raw const *size, void *userData) { if(!size) LegacyCore_FatalError("Texture_NewWithSize: Attempted with invalid size argument (=NULL)."); - return reinterpret_cast(new de::Texture(bindId, *size, userData)); + return reinterpret_cast(new de::Texture(bindId, *size, 0, userData)); } -Texture* Texture_New(textureid_t bindId, void* userData) +Texture *Texture_New(textureid_t bindId, void *userData) { - return reinterpret_cast(new de::Texture(bindId, userData)); + return reinterpret_cast(new de::Texture(bindId, 0, userData)); } -void Texture_Delete(Texture* tex) +void Texture_Delete(Texture *tex) { if(tex) { @@ -205,43 +243,43 @@ void Texture_Delete(Texture* tex) } } -textureid_t Texture_PrimaryBind(const Texture* tex) +textureid_t Texture_PrimaryBind(Texture const *tex) { SELF_CONST(tex); return self->primaryBind(); } -void Texture_SetPrimaryBind(Texture* tex, textureid_t bindId) +void Texture_SetPrimaryBind(Texture *tex, textureid_t bindId) { SELF(tex); self->setPrimaryBind(bindId); } -void* Texture_UserDataPointer(const Texture* tex) +void *Texture_UserDataPointer(Texture const *tex) { SELF_CONST(tex); return self->userDataPointer(); } -void Texture_SetUserDataPointer(Texture* tex, void* newUserData) +void Texture_SetUserDataPointer(Texture *tex, void *newUserData) { SELF(tex); self->setUserDataPointer(newUserData); } -void Texture_ClearVariants(Texture* tex) +void Texture_ClearVariants(Texture *tex) { SELF(tex); self->clearVariants(); } -uint Texture_VariantCount(const Texture* tex) +uint Texture_VariantCount(Texture const *tex) { SELF_CONST(tex); return self->variantCount(); } -TextureVariant* Texture_AddVariant(Texture* tex, TextureVariant* variant) +TextureVariant *Texture_AddVariant(Texture *tex, TextureVariant *variant) { SELF(tex); if(!variant) @@ -250,11 +288,11 @@ TextureVariant* Texture_AddVariant(Texture* tex, TextureVariant* variant) LOG_WARNING("Invalid variant argument, ignoring."); return variant; } - self->addVariant(*reinterpret_cast(variant)); + self->addVariant(*reinterpret_cast(variant)); return variant; } -void* Texture_AnalysisDataPointer(const Texture* tex, texture_analysisid_t analysisId) +void *Texture_AnalysisDataPointer(Texture const *tex, texture_analysisid_t analysisId) { SELF_CONST(tex); return self->analysisDataPointer(analysisId); diff --git a/doomsday/engine/src/resource/textures.cpp b/doomsday/engine/src/resource/textures.cpp index 6972847f0e..0ebad61a02 100644 --- a/doomsday/engine/src/resource/textures.cpp +++ b/doomsday/engine/src/resource/textures.cpp @@ -20,55 +20,28 @@ */ #include -#include -#include #include "de_base.h" #include "de_console.h" - -#include "m_misc.h" // for M_NumDigits -#include "map/r_world.h" // for ddMapSetup -#include "filesys/fs_util.h" // for F_PrettyPath #include "gl/gl_texmanager.h" -#include "resource/compositetexture.h" -#include "resource/texturevariant.h" -#include "resource/textures.h" +#include "m_misc.h" // for M_NumDigits +#include +#include #include #include #include -#include -#include - -typedef de::UserDataPathTree TextureRepository; - -/** - * POD object. Contains metadata for a unique Texture in the collection. - */ -struct TextureRecord -{ - /// Scheme-unique identifier chosen by the owner of the collection. - int uniqueId; - /// Path to the data resource which contains/wraps the loadable texture data. - de::Uri* resourcePath; - - /// The defined texture instance (if any). - Texture* texture; -}; +#include "resource/compositetexture.h" +#include "resource/texturemetafile.h" +#include "resource/textures.h" -struct TextureScheme +char const *TexSource_Name(TexSource source) { - /// The texture directory contains the mappings between names and unique texture records. - TextureRepository* directory; - - /// LUT which translates scheme-unique-ids to their associated textureid_t (if any). - /// Index with uniqueId - uniqueIdBase. - bool uniqueIdMapDirty; - int uniqueIdBase; - uint uniqueIdMapSize; - textureid_t* uniqueIdMap; -}; + if(source == TEXS_ORIGINAL) return "original"; + if(source == TEXS_EXTERNAL) return "external"; + return "none"; +} D_CMD(ListTextures); D_CMD(InspectTexture); @@ -76,812 +49,690 @@ D_CMD(InspectTexture); D_CMD(PrintTextureStats); #endif -static de::Uri* emptyUri; - -// LUT which translates textureid_t to TextureRepository::Node*. Index with textureid_t-1 -static uint textureIdMapSize; -static TextureRepository::Node** textureIdMap; +namespace de { -// Texture schemes contain mappings between names and TextureRecord instances. -static TextureScheme schemes[TEXTURESCHEME_COUNT]; +static Uri emptyUri; -void Textures_Register(void) +Texture *Textures::ResourceClass::interpret(TextureMetaFile &metafile, Size2Raw const &dimensions, + Texture::Flags flags, void *userData) { - C_CMD("inspecttexture", NULL, InspectTexture) - C_CMD("listtextures", NULL, ListTextures) -#if _DEBUG - C_CMD("texturestats", NULL, PrintTextureStats) -#endif + LOG_AS("Textures::ResourceClass::interpret"); + return new Texture(metafile.lookupTextureId(), dimensions, flags, userData); } -const char* TexSource_Name(TexSource source) +Texture *Textures::ResourceClass::interpret(TextureMetaFile &metafile, Texture::Flags flags, + void *userData) { - if(source == TEXS_ORIGINAL) return "original"; - if(source == TEXS_EXTERNAL) return "external"; - return "none"; + return interpret(metafile, Size2Raw(0, 0), flags, userData); } -static inline TextureRepository& schemeById(textureschemeid_t id) -{ - DENG2_ASSERT(VALID_TEXTURESCHEMEID(id)); - DENG2_ASSERT(schemes[id-TEXTURESCHEME_FIRST].directory); - return *schemes[id-TEXTURESCHEME_FIRST].directory; -} +TextureMetaFile::TextureMetaFile(PathTree::NodeArgs const &args) : Node(args), + uniqueId_(0), resourceUri_(), texture_(0) +{} -static textureschemeid_t schemeIdForDirectory(de::PathTree const &directory) +TextureMetaFile::~TextureMetaFile() { - for(uint i = uint(TEXTURESCHEME_FIRST); i <= uint(TEXTURESCHEME_LAST); ++i) + LOG_AS("~TextureMetaFile"); + if(texture_) { - uint idx = i - TEXTURESCHEME_FIRST; - if(schemes[idx].directory == &directory) return textureschemeid_t(i); +#if _DEBUG + LOG_WARNING("\"%s\" still has an associated texture!") + << composeUri(); +#endif + delete texture_; } - // Only reachable if attempting to find the id for a Texture that is not - // in the collection, or the collection has not yet been initialized. - throw de::Error("Textures::schemeIdForDirectory", - de::String().sprintf("Failed to determine id for directory %p.", (void*)&directory)); -} - -static inline bool validTextureId(textureid_t id) -{ - return (id != NOTEXTUREID && id <= textureIdMapSize); + textures().deindex(*this); } -static TextureRepository::Node* directoryNodeForBindId(textureid_t id) +Textures &TextureMetaFile::textures() { - if(!validTextureId(id)) return NULL; - return textureIdMap[id-1/*1-based index*/]; + return *App_Textures(); } -static textureid_t findBindIdForDirectoryNode(TextureRepository::Node const& node) +Texture *TextureMetaFile::define(Size2Raw const &dimensions, Texture::Flags flags) { - /// @todo Optimize: (Low priority) do not use a linear search. - for(uint i = 0; i < textureIdMapSize; ++i) + if(Texture *tex = texture()) { - if(textureIdMap[i] == &node) - return textureid_t(i+1); // 1-based index. +#if _DEBUG + LOG_WARNING("A Texture with uri \"%s\" already exists, returning existing.") + << composeUri(); +#endif + tex->setDimensions(dimensions); + tex->flagCustom(!!(flags & Texture::Custom)); + + /// @todo Materials and Surfaces should be notified of this! + return tex; } - return NOTEXTUREID; // Not linked. + + Texture *tex = Textures::ResourceClass::interpret(*this, dimensions, flags); + if(!texture()) setTexture(tex); + return tex; } -static inline textureschemeid_t schemeIdForDirectoryNode(TextureRepository::Node const& node) +Texture *TextureMetaFile::define(Texture::Flags flags) { - return schemeIdForDirectory(node.tree()); + return define(Size2Raw(0, 0), flags); } -/// @return Newly composed Uri for @a node. Must be delete'd when no longer needed. -static de::Uri composeUriForDirectoryNode(TextureRepository::Node const& node) +Textures::Scheme &TextureMetaFile::scheme() const { - Str const* schemeName = Textures_SchemeName(schemeIdForDirectoryNode(node)); - return de::Uri(Str_Text(schemeName), node.path()); + LOG_AS("TextureMetaFile::scheme"); + /// @todo Optimize: TextureMetaFile should contain a link to the owning Textures::Scheme. + Textures::Schemes const &schemes = textures().allSchemes(); + DENG2_FOR_EACH_CONST(Textures::Schemes, i, schemes) + { + Textures::Scheme &scheme = **i; + if(&scheme.index() == &tree()) return scheme; + } + + // This should never happen... + /// @throw Error Failed to determine the scheme of the metafile. + throw Error("TextureMetaFile::scheme", String("Failed to determine scheme for metafile [%p].").arg(de::dintptr(this))); } -/// @pre textureIdMap has been initialized and is large enough! -static void unlinkDirectoryNodeFromBindIdMap(TextureRepository::Node const& node) +Uri TextureMetaFile::composeUri(QChar sep) const { - textureid_t id = findBindIdForDirectoryNode(node); - if(!validTextureId(id)) return; // Not linked. - textureIdMap[id - 1/*1-based index*/] = NULL; + return Uri(scheme().name(), path(sep)); } -/// @pre uniqueIdMap has been initialized and is large enough! -static void linkRecordInUniqueIdMap(TextureRecord const* record, TextureScheme* tn, - textureid_t textureId) +Uri TextureMetaFile::composeUrn() const { - DENG2_ASSERT(record && tn); - DENG2_ASSERT(record->uniqueId - tn->uniqueIdBase >= 0 && (unsigned)(record->uniqueId - tn->uniqueIdBase) < tn->uniqueIdMapSize); - tn->uniqueIdMap[record->uniqueId - tn->uniqueIdBase] = textureId; + return Uri("urn", String("%1:%2").arg(scheme().name()).arg(uniqueId_, 0, 10)); } -/// @pre uniqueIdMap is large enough if initialized! -static void unlinkRecordInUniqueIdMap(TextureRecord const* record, TextureScheme* tn) +Uri const &TextureMetaFile::resourceUri() const { - DENG2_ASSERT(record && tn); - // If the map is already considered 'dirty' do not unlink. - if(tn->uniqueIdMap && !tn->uniqueIdMapDirty) - { - DENG2_ASSERT(record->uniqueId - tn->uniqueIdBase >= 0 && (unsigned)(record->uniqueId - tn->uniqueIdBase) < tn->uniqueIdMapSize); - tn->uniqueIdMap[record->uniqueId - tn->uniqueIdBase] = NOTEXTUREID; - } + return resourceUri_; } -/** - * @defgroup validateTextureUriFlags Validate Texture Uri Flags - * @ingroup flags - */ -///@{ -#define VTUF_ALLOW_ANY_SCHEME 0x1 ///< The scheme of the URI may be of zero-length; signifying "any scheme". -#define VTUF_NO_URN 0x2 ///< Do not accept a URN. -///@} - -/** - * @param uri Uri to be validated. - * @param flags @ref validateTextureUriFlags - * @param quiet @c true= Do not output validation remarks to the log. - * - * @return @c true if @a Uri passes validation. - */ -static bool validateTextureUri(de::Uri const& uri, int flags, bool quiet = false) +bool TextureMetaFile::setResourceUri(Uri const &newUri) { - LOG_AS("validateTextureUri"); - - if(uri.isEmpty()) - { - if(!quiet) - { - LOG_MSG("Invalid path in texture URI \"%s\".") << uri; - } - return false; - } - - // If this is a URN we extract the scheme from the path. - de::String schemeString; - if(!uri.scheme().compareWithoutCase("urn")) - { - if(flags & VTUF_NO_URN) return false; - schemeString = uri.path(); - } - else + // Avoid resolving; compare as text. + if(resourceUri_.asText() != newUri.asText()) { - schemeString = uri.scheme(); + resourceUri_ = newUri; + return true; } + return false; +} - textureschemeid_t schemeId = Textures_ParseSchemeName(schemeString.toUtf8().constData()); - if(!((flags & VTUF_ALLOW_ANY_SCHEME) && schemeId == TS_ANY) && - !VALID_TEXTURESCHEMEID(schemeId)) +textureid_t TextureMetaFile::lookupTextureId() const +{ + // If we have bound a texture it can provide the id. + if(texture_) { - if(!quiet) - { - LOG_MSG("Unknown scheme in texture URI \"%s\".") << uri; - } - return false; + textureid_t texId = texture_->primaryBind(); + if(texId != NOTEXTUREID) return texId; } - return true; + // Otherwise look it up. + return textures().idForMetaFile(*this); } -/** - * Given a directory and path, search the Textures collection for a match. - * - * @param directory Scheme-specific TextureRepository to search in. - * @param path Path of the texture to search for. - * - * @return Found DirectoryNode else @c NULL - */ -static TextureRepository::Node* findDirectoryNodeForPath(TextureRepository& texDirectory, de::String path) +Texture *TextureMetaFile::texture() const { - try - { - TextureRepository::Node &node = texDirectory.find(path, de::PathTree::NoBranch | de::PathTree::MatchFull); - return &node; - } - catch(TextureRepository::NotFoundError const&) - {} // Ignore this error. - return 0; + return texture_; } -/// @pre @a uri has already been validated and is well-formed. -static TextureRepository::Node* findDirectoryNodeForUri(de::Uri const& uri) +void TextureMetaFile::setTexture(Texture *newTexture) { - if(!uri.scheme().compareWithoutCase("urn")) - { - // This is a URN of the form; urn:schemename:uniqueid - textureschemeid_t schemeId = Textures_ParseSchemeName(uri.pathCStr()); - int uidPos = uri.path().toStringRef().indexOf(':'); - if(uidPos >= 0) - { - int uid = uri.path().toString().mid(uidPos + 1 /*skip scheme delimiter*/).toInt(); - textureid_t id = Textures_TextureForUniqueId(schemeId, uid); - if(id != NOTEXTUREID) - { - return directoryNodeForBindId(id); - } - } - return NULL; - } - - // This is a URI. - textureschemeid_t schemeId = Textures_ParseSchemeName(uri.schemeCStr()); - de::String const& path = uri.path(); - - TextureRepository::Node* node = NULL; - if(schemeId != TS_ANY) - { - // Caller wants a texture in a specific scheme. - node = findDirectoryNodeForPath(schemeById(schemeId), path); - } - else - { - // Caller does not care which scheme. - // Check for the texture in these schemes in priority order. - static const textureschemeid_t order[] = { - TS_SPRITES, - TS_TEXTURES, - TS_FLATS, - TS_PATCHES, - TS_SYSTEM, - TS_DETAILS, - TS_REFLECTIONS, - TS_MASKS, - TS_MODELSKINS, - TS_MODELREFLECTIONSKINS, - TS_LIGHTMAPS, - TS_FLAREMAPS, - TS_ANY - }; - int n = 0; - do - { - node = findDirectoryNodeForPath(schemeById(order[n]), path); - } while(!node && order[++n] != TS_ANY); - } - return node; + texture_ = newTexture; } -static void clearTextureAnalyses(Texture* tex) +int TextureMetaFile::uniqueId() const { - DENG2_ASSERT(tex); - for(uint i = uint(TEXTURE_ANALYSIS_FIRST); i < uint(TEXTURE_ANALYSIS_COUNT); ++i) - { - texture_analysisid_t analysis = texture_analysisid_t(i); - void* data = Texture_AnalysisDataPointer(tex, analysis); - if(data) M_Free(data); - Texture_SetAnalysisDataPointer(tex, analysis, 0); - } + return uniqueId_; } -static void destroyTexture(Texture* tex) +bool TextureMetaFile::setUniqueId(int newUniqueId) { - DENG2_ASSERT(tex); + if(uniqueId_ == newUniqueId) return false; - GL_ReleaseGLTexturesByTexture(tex); - switch(Textures_Scheme(Textures_Id(tex))) - { - case TS_SYSTEM: - case TS_DETAILS: - case TS_REFLECTIONS: - case TS_MASKS: - case TS_MODELSKINS: - case TS_MODELREFLECTIONSKINS: - case TS_LIGHTMAPS: - case TS_FLAREMAPS: - case TS_FLATS: break; - - case TS_TEXTURES: { - de::CompositeTexture* pcTex = reinterpret_cast(Texture_UserDataPointer(tex)); - if(pcTex) delete pcTex; - break; } - - case TS_SPRITES: { - patchtex_t* pTex = reinterpret_cast(Texture_UserDataPointer(tex)); - if(pTex) M_Free(pTex); - break; } - - case TS_PATCHES: { - patchtex_t* pTex = reinterpret_cast(Texture_UserDataPointer(tex)); - if(pTex) M_Free(pTex); - break; } - - default: - throw de::Error("Textures::destroyTexture", - de::String("Internal error, invalid scheme id %1.") - .arg((int)Textures_Scheme(Textures_Id(tex)))); - } - - clearTextureAnalyses(tex); - Texture_Delete(tex); + uniqueId_ = newUniqueId; + // We'll need to rebuild the id map too. + scheme().markUniqueIdLutDirty(); + return true; } -static void destroyBoundTexture(TextureRepository::Node& node) +struct Textures::Scheme::Instance { - TextureRecord* record = reinterpret_cast(node.userPointer()); - if(record && record->texture) - { - destroyTexture(record->texture); record->texture = NULL; - } -} + /// Symbolic name of the scheme. + String name; -static void destroyRecord(TextureRepository::Node& node) -{ - TextureRecord* record = reinterpret_cast(node.userPointer()); + /// Mappings from paths to metafiles. + Textures::Scheme::Index *index_; - LOG_AS("Textures::destroyRecord"); + /// LUT which translates scheme-unique-ids to their associated metafile (if any). + /// Index with uniqueId - uniqueIdBase. + QList uniqueIdLut; + bool uniqueIdLutDirty; + int uniqueIdBase; - if(record) - { - if(record->texture) - { -#if _DEBUG - de::Uri uri = composeUriForDirectoryNode(node); - LOG_WARNING("Record for \"%s\" still has Texture data!") << uri; -#endif - destroyTexture(record->texture); - } + Instance(String symbolicName) + : name(symbolicName), index_(new Textures::Scheme::Index()), + uniqueIdLut(), uniqueIdLutDirty(false), uniqueIdBase(0) + {} - if(record->resourcePath) + ~Instance() + { + if(index_) { - delete record->resourcePath; record->resourcePath = 0; + PathTreeIterator iter(index_->leafNodes()); + while(iter.hasNext()) + { + TextureMetaFile &metafile = static_cast(iter.next()); + deindex(metafile); + } + delete index_; } - - unlinkDirectoryNodeFromBindIdMap(node); - - textureschemeid_t const schemeId = schemeIdForDirectoryNode(node); - TextureScheme* tn = &schemes[schemeId - TEXTURESCHEME_FIRST]; - unlinkRecordInUniqueIdMap(record, tn); - - // Detach our user data from this node. - node.setUserPointer(0); - M_Free(record); } -} - -void Textures_Init(void) -{ - LOG_VERBOSE("Initializing Textures collection..."); - - emptyUri = new de::Uri(); - textureIdMap = NULL; - textureIdMapSize = 0; - - for(uint i = 0; i < TEXTURESCHEME_COUNT; ++i) + bool inline uniqueIdInLutRange(int uniqueId) const { - TextureScheme* tn = &schemes[i]; - tn->directory = new TextureRepository(); - tn->uniqueIdBase = 0; - tn->uniqueIdMapSize = 0; - tn->uniqueIdMap = NULL; - tn->uniqueIdMapDirty = false; + return (uniqueId - uniqueIdBase >= 0 && (uniqueId - uniqueIdBase) < uniqueIdLut.size()); } -} - -void Textures_Shutdown(void) -{ - Textures_Clear(); - for(uint i = 0; i < TEXTURESCHEME_COUNT; ++i) + void findUniqueIdRange(int *minId, int *maxId) { - TextureScheme* tn = &schemes[i]; + if(!minId && !maxId) return; - if(tn->directory) + if(!index_) { - de::PathTreeIterator iter(tn->directory->leafNodes()); - while(iter.hasNext()) - { - destroyRecord(iter.next()); - } - delete tn->directory; tn->directory = 0; + if(minId) *minId = 0; + if(maxId) *maxId = 0; + return; } - if(!tn->uniqueIdMap) continue; - M_Free(tn->uniqueIdMap); tn->uniqueIdMap = 0; + if(minId) *minId = DDMAXINT; + if(maxId) *maxId = DDMININT; - tn->uniqueIdBase = 0; - tn->uniqueIdMapSize = 0; - tn->uniqueIdMapDirty = false; + PathTreeIterator iter(index_->leafNodes()); + while(iter.hasNext()) + { + TextureMetaFile &metafile = static_cast(iter.next()); + int const uniqueId = metafile.uniqueId(); + if(minId && uniqueId < *minId) *minId = uniqueId; + if(maxId && uniqueId > *maxId) *maxId = uniqueId; + } } - // Clear the bindId to TextureRepository::Node LUT. - if(textureIdMap) + void deindex(TextureMetaFile &metafile) { - M_Free(textureIdMap); textureIdMap = 0; + /// @todo Only destroy the texture if this is the last remaining reference. + Texture *texture = metafile.texture(); + if(texture) + { + delete texture; + metafile.setTexture(0); + } + + unlinkInUniqueIdLut(metafile); } - textureIdMapSize = 0; - if(emptyUri) + /// @pre uniqueIdLut is large enough if initialized! + void unlinkInUniqueIdLut(TextureMetaFile &metafile) { - delete emptyUri; emptyUri = 0; + // If the lut is already considered 'dirty' do not unlink. + if(!uniqueIdLutDirty) + { + int uniqueId = metafile.uniqueId(); + DENG_ASSERT(uniqueIdInLutRange(uniqueId)); + uniqueIdLut[uniqueId - uniqueIdBase] = 0; + } } -} -textureschemeid_t Textures_ParseSchemeName(const char* str) -{ - static const struct scheme_s { - const char* name; - size_t nameLen; - textureschemeid_t id; - } schemeNameIdMap[TEXTURESCHEME_COUNT+1] = { - // Ordered according to a best guess of occurance frequency. - { "Textures", sizeof("Textures")-1, TS_TEXTURES }, - { "Flats", sizeof("Flats")-1, TS_FLATS }, - { "Sprites", sizeof("Sprites")-1, TS_SPRITES }, - { "Patches", sizeof("Patches")-1, TS_PATCHES }, - { "System", sizeof("System")-1, TS_SYSTEM }, - { "Details", sizeof("Details")-1, TS_DETAILS }, - { "Reflections", sizeof("Reflections")-1, TS_REFLECTIONS }, - { "Masks", sizeof("Masks")-1, TS_MASKS }, - { "ModelSkins", sizeof("ModelSkins")-1, TS_MODELSKINS }, - { "ModelReflectionSkins", sizeof("ModelReflectionSkins")-1, TS_MODELREFLECTIONSKINS }, - { "Lightmaps", sizeof("Lightmaps")-1, TS_LIGHTMAPS }, - { "Flaremaps", sizeof("Flaremaps")-1, TS_FLAREMAPS }, - { NULL, 0, TS_INVALID } - }; - - // Special case: zero-length string means "any scheme". - size_t len; - if(!str || 0 == (len = strlen(str))) return TS_ANY; - - // Stop comparing characters at the first occurance of ':' - const char* end = strchr(str, ':'); - if(end) len = end - str; - - for(size_t n = 0; schemeNameIdMap[n].name; ++n) + /// @pre uniqueIdLut has been initialized and is large enough! + void linkInUniqueIdLut(TextureMetaFile &metafile) { - if(len < schemeNameIdMap[n].nameLen) continue; - if(strnicmp(str, schemeNameIdMap[n].name, len)) continue; - return schemeNameIdMap[n].id; + int uniqueId = metafile.uniqueId(); + DENG_ASSERT(uniqueIdInLutRange(uniqueId)); + uniqueIdLut[uniqueId - uniqueIdBase] = &metafile; } - return TS_INVALID; // Unknown. -} - -const Str* Textures_SchemeName(textureschemeid_t id) -{ - static const de::Str names[1+TEXTURESCHEME_COUNT] = { - /* No scheme name */ "", - /* TS_SYSTEM */ "System", - /* TS_FLATS */ "Flats", - /* TS_TEXTURES */ "Textures", - /* TS_SPRITES */ "Sprites", - /* TS_PATCHES */ "Patches", - /* TS_DETAILS */ "Details", - /* TS_REFLECTIONS */ "Reflections", - /* TS_MASKS */ "Masks", - /* TS_MODELSKINS */ "ModelSkins", - /* TS_MODELREFLECTIONSKINS */ "ModelReflectionSkins", - /* TS_LIGHTMAPS */ "Lightmaps", - /* TS_FLAREMAPS */ "Flaremaps" - }; - if(VALID_TEXTURESCHEMEID(id)) + void rebuildUniqueIdLut() { - return names[1 + (id - TEXTURESCHEME_FIRST)]; + // Is a rebuild necessary? + if(!uniqueIdLutDirty) return; + + // Determine the size of the LUT. + int minId, maxId; + findUniqueIdRange(&minId, &maxId); + + int lutSize = 0; + if(minId > maxId) // None found? + { + uniqueIdBase = 0; + } + else + { + uniqueIdBase = minId; + lutSize = maxId - minId + 1; + } + + // Fill the LUT with initial values. + uniqueIdLut.reserve(lutSize); + int i = 0; + for(; i < uniqueIdLut.size(); ++i) + { + uniqueIdLut[i] = 0; + } + for(; i < lutSize; ++i) + { + uniqueIdLut.push_back(0); + } + + if(lutSize) + { + // Populate the LUT. + PathTreeIterator iter(index_->leafNodes()); + while(iter.hasNext()) + { + linkInUniqueIdLut(static_cast(iter.next())); + } + } + + uniqueIdLutDirty = false; } - return names[0]; -} +}; -uint Textures_Size(void) +Textures::Scheme::Scheme(String symbolicName) { - return textureIdMapSize; + d = new Instance(symbolicName); } -uint Textures_Count(textureschemeid_t schemeId) +Textures::Scheme::~Scheme() { - if(!VALID_TEXTURESCHEMEID(schemeId) || !Textures_Size()) return 0; - return schemeById(schemeId).size(); + delete d; } -void Textures_Clear(void) +void Textures::Scheme::clear() { - if(!Textures_Size()) return; - - Textures_ClearScheme(TS_ANY); - GL_PruneTextureVariantSpecifications(); + if(d->index_) + { + PathTreeIterator iter(d->index_->leafNodes()); + while(iter.hasNext()) + { + TextureMetaFile &metafile = static_cast(iter.next()); + d->deindex(metafile); + } + d->index_->clear(); + d->uniqueIdLutDirty = true; + } } -void Textures_ClearRuntime(void) +String const &Textures::Scheme::name() const { - if(!Textures_Size()) return; - - Textures_ClearScheme(TS_FLATS); - Textures_ClearScheme(TS_TEXTURES); - Textures_ClearScheme(TS_PATCHES); - Textures_ClearScheme(TS_SPRITES); - Textures_ClearScheme(TS_DETAILS); - Textures_ClearScheme(TS_REFLECTIONS); - Textures_ClearScheme(TS_MASKS); - Textures_ClearScheme(TS_MODELSKINS); - Textures_ClearScheme(TS_MODELREFLECTIONSKINS); - Textures_ClearScheme(TS_LIGHTMAPS); - Textures_ClearScheme(TS_FLAREMAPS); - - GL_PruneTextureVariantSpecifications(); + return d->name; } -void Textures_ClearSystem(void) +int Textures::Scheme::size() const { - if(!Textures_Size()) return; - - Textures_ClearScheme(TS_SYSTEM); - GL_PruneTextureVariantSpecifications(); + return d->index_->size(); } -void Textures_ClearScheme(textureschemeid_t schemeId) +TextureMetaFile &Textures::Scheme::insertMetaFile(Path const &path) { - if(!Textures_Size()) return; - - textureschemeid_t from, to; - if(schemeId == TS_ANY) + int sizeBefore = d->index_->size(); + TextureMetaFile &metafile = d->index_->insert(path); + if(d->index_->size() != sizeBefore) { - from = TEXTURESCHEME_FIRST; - to = TEXTURESCHEME_LAST; + // We'll need to rebuild the unique id LUT after this. + d->uniqueIdLutDirty = true; } - else if(VALID_TEXTURESCHEMEID(schemeId)) + return metafile; +} + +TextureMetaFile const &Textures::Scheme::find(Path const &path) const +{ + try { - from = to = schemeId; + return d->index_->find(path, PathTree::NoBranch | PathTree::MatchFull); } - else + catch(Scheme::Index::NotFoundError const &er) { - Con_Error("Textures::ClearScheme: Invalid texture scheme %i.", (int) schemeId); - exit(1); // Unreachable. + throw NotFoundError("Textures::Scheme::find", er.asText()); } +} - for(uint i = uint(from); i <= uint(to); ++i) - { - textureschemeid_t iter = textureschemeid_t(i); - TextureScheme* tn = &schemes[iter - TEXTURESCHEME_FIRST]; +TextureMetaFile &Textures::Scheme::find(Path const &path) +{ + TextureMetaFile const &found = const_cast(this)->find(path); + return const_cast(found); +} - de::PathTreeIterator it(tn->directory->leafNodes()); - while(it.hasNext()) +TextureMetaFile const &Textures::Scheme::findByResourceUri(Uri const &uri) const +{ + if(!uri.isEmpty()) + { + PathTreeIterator iter(d->index_->leafNodes()); + while(iter.hasNext()) { - TextureRepository::Node& node = it.next(); - destroyBoundTexture(node); - destroyRecord(node); + TextureMetaFile &metafile = static_cast(iter.next()); + if(metafile.resourceUri() == uri) + { + return metafile; + } } - tn->directory->clear(); - tn->uniqueIdMapDirty = true; } + /// @throw NotFoundError No metafile was found with a matching resource URI. + throw NotFoundError("Textures::Scheme::findByResourceUri", "No metafile found with a resource URI matching \"" + uri + "\""); } -void Textures_Release(Texture* tex) +TextureMetaFile &Textures::Scheme::findByResourceUri(Uri const &uri) { - /// Stub. - GL_ReleaseGLTexturesByTexture(tex); - /// @todo Update any Materials (and thus Surfaces) which reference this. + TextureMetaFile const &found = const_cast(this)->findByResourceUri(uri); + return const_cast(found); } -Texture* Textures_ToTexture(textureid_t id) +TextureMetaFile const &Textures::Scheme::findByUniqueId(int uniqueId) const { - TextureRepository::Node* node = directoryNodeForBindId(id); - TextureRecord* record = (node? reinterpret_cast(node->userPointer()) : NULL); - if(record) - { - return record->texture; - } -#if _DEBUG - else if(id != NOTEXTUREID) + d->rebuildUniqueIdLut(); + + if(d->uniqueIdInLutRange(uniqueId)) { - Con_Message("Warning:Textures::ToTexture: Failed to locate texture for id #%i, returning NULL.\n", id); + TextureMetaFile *metafile = d->uniqueIdLut[uniqueId - d->uniqueIdBase]; + if(metafile) return *metafile; } -#endif - return NULL; + /// @throw NotFoundError No metafile was found with a matching resource URI. + throw NotFoundError("Textures::Scheme::findByUniqueId", "No metafile found with a unique ID matching \"" + QString("%1").arg(uniqueId) + "\""); } -static void findUniqueIdBounds(TextureScheme* tn, int* minId, int* maxId) +TextureMetaFile &Textures::Scheme::findByUniqueId(int uniqueId) { - DENG2_ASSERT(tn); - if(!minId && !maxId) return; - - if(!tn->directory) - { - if(minId) *minId = 0; - if(maxId) *maxId = 0; - return; - } - - if(minId) *minId = DDMAXINT; - if(maxId) *maxId = DDMININT; + TextureMetaFile const &found = const_cast(this)->findByUniqueId(uniqueId); + return const_cast(found); +} - de::PathTreeIterator iter(tn->directory->leafNodes()); - while(iter.hasNext()) - { - TextureRecord const* record = reinterpret_cast(iter.next().userPointer()); - if(!record) continue; +Textures::Scheme::Index const &Textures::Scheme::index() const +{ + return *d->index_; +} - if(minId && record->uniqueId < *minId) *minId = record->uniqueId; - if(maxId && record->uniqueId > *maxId) *maxId = record->uniqueId; - } +void Textures::Scheme::markUniqueIdLutDirty() +{ + d->uniqueIdLutDirty = true; } -static void rebuildUniqueIdMap(textureschemeid_t schemeId) +enum ValidateUriFlag +{ + AnyScheme = 0x1, ///< The scheme of the URI may be of zero-length; signifying "any scheme". + NotUrn = 0x2 ///< Do not accept a URN. +}; +Q_DECLARE_FLAGS(ValidateUriFlags, ValidateUriFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(ValidateUriFlags) + +struct Textures::Instance { - DENG2_ASSERT(VALID_TEXTURESCHEMEID(schemeId)); + Textures& self; - TextureScheme* tn = &schemes[schemeId - TEXTURESCHEME_FIRST]; + // LUT which translates textureid_t => TextureMetaFile*. Index with textureid_t-1 + QList textureIdLut; - // Is a rebuild necessary? - if(!tn->uniqueIdMapDirty) return; + /// System subspace schemes containing the textures. + Textures::Schemes schemes; - // Determine the size of the LUT. - int minId, maxId; - findUniqueIdBounds(tn, &minId, &maxId); + Instance(Textures *d) : self(*d) + {} - if(minId > maxId) + ~Instance() { - // None found. - tn->uniqueIdBase = 0; - tn->uniqueIdMapSize = 0; + DENG2_FOR_EACH(Textures::Schemes, i, schemes) + { + delete *i; + } + schemes.clear(); } - else + + inline bool validTextureId(textureid_t id) const { - tn->uniqueIdBase = minId; - tn->uniqueIdMapSize = maxId - minId + 1; + return (id != NOTEXTUREID && id <= textureIdLut.size()); } - // Allocate and (re)populate the LUT. - tn->uniqueIdMap = static_cast(M_Realloc(tn->uniqueIdMap, sizeof(*tn->uniqueIdMap) * tn->uniqueIdMapSize)); - if(!tn->uniqueIdMap && tn->uniqueIdMapSize) + /// @pre textureIdLut has been initialized and is large enough! + void unlinkFromTextureIdLut(TextureMetaFile &metafile) { - throw de::Error("Textures::rebuildUniqueIdMap", - de::String("Failed on (re)allocation of %1 bytes resizing the map.") - .arg(sizeof(*tn->uniqueIdMap) * tn->uniqueIdMapSize)); + textureid_t texId = metafile.lookupTextureId(); + if(!validTextureId(texId)) return; // Not linked. + textureIdLut[texId - 1/*1-based index*/] = 0; } - if(tn->uniqueIdMapSize) + + TextureMetaFile *metafileByTextureId(textureid_t id) { - memset(tn->uniqueIdMap, NOTEXTUREID, sizeof(*tn->uniqueIdMap) * tn->uniqueIdMapSize); + if(!validTextureId(id)) return 0; + return textureIdLut[id - 1/*1-based index*/]; + } - de::PathTreeIterator iter(tn->directory->leafNodes()); - while(iter.hasNext()) + TextureMetaFile *metafileByUri(Uri const &validatedUri) + { + // Is this a URN? (of the form "urn:schemename:uniqueid") + if(!validatedUri.scheme().compareWithoutCase("urn")) { - TextureRepository::Node& node = iter.next(); - TextureRecord const* record = reinterpret_cast(node.userPointer()); - if(!record) continue; - linkRecordInUniqueIdMap(record, tn, findBindIdForDirectoryNode(node)); + String const &pathStr = validatedUri.path().toStringRef(); + int uIdPos = pathStr.indexOf(':'); + if(uIdPos > 0) + { + String schemeName = pathStr.left(uIdPos); + int uniqueId = pathStr.mid(uIdPos + 1 /*skip delimiter*/).toInt(); + + try + { + return &self.scheme(schemeName).findByUniqueId(uniqueId); + } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. + } + return 0; // Not found. } - } - tn->uniqueIdMapDirty = false; -} + // No, this is a URI. + String const &path = validatedUri.path(); -textureid_t Textures_TextureForUniqueId(textureschemeid_t schemeId, int uniqueId) -{ - if(VALID_TEXTURESCHEMEID(schemeId)) - { - TextureScheme* tn = &schemes[schemeId - TEXTURESCHEME_FIRST]; + // Does the user want a metafile in a specific scheme? + if(!validatedUri.scheme().isEmpty()) + { + try + { + return &self.scheme(validatedUri.scheme()).find(path); + } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. + return 0; + } - rebuildUniqueIdMap(schemeId); - if(tn->uniqueIdMap && uniqueId >= tn->uniqueIdBase && - (unsigned)(uniqueId - tn->uniqueIdBase) <= tn->uniqueIdMapSize) + // No, check in each of these schemes (in priority order). + /// @todo This priorty order should be defined by the user. + static String const order[] = { + "Sprites", + "Textures", + "Flats", + "Patches", + "System", + "Details", + "Reflections", + "Masks", + "ModelSkins", + "ModelReflectionSkins", + "Lightmaps", + "Flaremaps", + "" + }; + for(int i = 0; !order[i].isEmpty(); ++i) { - return tn->uniqueIdMap[uniqueId - tn->uniqueIdBase]; + try + { + return &self.scheme(order[i]).find(path); + } + catch(Textures::Scheme::NotFoundError const &) + {} // Ignore this error. } + return 0; // Not found. } - return NOTEXTUREID; // Not found. -} -Texture *Textures_TextureForResourcePath(textureschemeid_t schemeId, Uri const *path) -{ - if(!VALID_TEXTURESCHEMEID(schemeId)) return 0; - if(!path || Uri_IsEmpty(path)) return 0; - - TextureRepository& directory = schemeById(schemeId); - - de::PathTreeIterator iter(directory.leafNodes()); - while(iter.hasNext()) + /** + * @param uri Uri to be validated. + * @param flags Validation flags. + * @param quiet @c true= Do not output validation remarks to the log. + * + * @return @c true if @a Uri passes validation. + */ + bool validateUri(Uri const &uri, ValidateUriFlags flags, bool quiet = false) { - TextureRepository::Node& node = iter.next(); - TextureRecord* record = reinterpret_cast(node.userPointer()); - if(!record) continue; + LOG_AS("validateUri"); + bool const isUrn = !uri.scheme().compareWithoutCase("urn"); - // If we have bound a texture it can provide the id. - textureid_t textureId = NOTEXTUREID; - if(record->texture) - textureId = Texture_PrimaryBind(record->texture); + if(uri.isEmpty()) + { + if(!quiet) LOG_MSG("Empty path in texture %s \"%s\".") << uri << (isUrn? "URN" : "URI"); + return false; + } - // Otherwise look it up. - if(!validTextureId(textureId)) - textureId = findBindIdForDirectoryNode(node); + // If this is a URN we extract the scheme from the path. + String schemeString; + if(isUrn) + { + if(flags.testFlag(NotUrn)) + { + if(!quiet) LOG_MSG("Texture URN \"%s\" supplied, URI required.") << uri; + return false; + } - // Sanity check. - DENG2_ASSERT(validTextureId(textureId)); + String const &pathStr = uri.path().toStringRef(); + int const uIdPos = pathStr.indexOf(':'); + if(uIdPos > 0) + { + schemeString = pathStr.left(uIdPos); + } + } + else + { + schemeString = uri.scheme(); + } - de::Uri const *resourcePath = reinterpret_cast(Textures_ResourcePath(textureId)); - if(*resourcePath == *(de::Uri const *)path) + if(schemeString.isEmpty()) + { + if(!flags.testFlag(AnyScheme)) + { + if(!quiet) LOG_MSG("Missing scheme in texture %s \"%s\".") << uri << (isUrn? "URN" : "URI"); + return false; + } + } + else if(!self.knownScheme(schemeString)) { - return Textures_ToTexture(textureId); + if(!quiet) LOG_MSG("Unknown scheme in texture %s \"%s\".") << uri << (isUrn? "URN" : "URI"); + return false; } + + return true; } +}; - return 0; +void Textures::consoleRegister() +{ + C_CMD("inspecttexture", "ss", InspectTexture) + C_CMD("inspecttexture", "s", InspectTexture) + C_CMD("listtextures", "ss", ListTextures) + C_CMD("listtextures", "s", ListTextures) + C_CMD("listtextures", "", ListTextures) +#if _DEBUG + C_CMD("texturestats", NULL, PrintTextureStats) +#endif } -textureid_t Textures_ResolveUri2(Uri const* _uri, boolean quiet) +Textures::Textures() { - LOG_AS("Textures::resolveUri"); + d = new Instance(this); +} - if(!_uri || !Textures_Size()) return NOTEXTUREID; +Textures::~Textures() +{ + clearAllSchemes(); + delete d; +} - de::Uri const& uri = reinterpret_cast(*_uri); - if(!validateTextureUri(uri, VTUF_ALLOW_ANY_SCHEME, true /*quiet please*/)) - { -#if _DEBUG - LOG_WARNING("Uri \"%s\" failed validation, returning NOTEXTUREID.") << uri; -#endif - return NOTEXTUREID; - } +Textures::Scheme& Textures::createScheme(String name) +{ + DENG_ASSERT(name.length() >= Scheme::min_name_length); - // Perform the search. - TextureRepository::Node* node = findDirectoryNodeForUri(uri); - if(node) - { - // If we have bound a texture - it can provide the id. - TextureRecord* record = reinterpret_cast(node->userPointer()); - DENG2_ASSERT(record); - if(record->texture) - { - textureid_t id = Texture_PrimaryBind(record->texture); - if(validTextureId(id)) return id; - } - // Oh well, look it up then. - return findBindIdForDirectoryNode(*node); - } + // Ensure this is a unique name. + if(knownScheme(name)) return scheme(name); - // Not found. - if(!quiet && !ddMapSetup) // Do not announce during map setup. - { - LOG_DEBUG("\"%s\" not found!") << uri; - } - return NOTEXTUREID; + // Create a new scheme. + Scheme* newScheme = new Scheme(name); + d->schemes.push_back(newScheme); + return *newScheme; } -textureid_t Textures_ResolveUri(Uri const* uri) +int Textures::size() const { - return Textures_ResolveUri2(uri, !(verbose >= 1)/*log warnings if verbose*/); + return d->textureIdLut.size(); } -textureid_t Textures_ResolveUriCString2(char const* path, boolean quiet) +static void release(Texture *tex) { - if(path && path[0]) + /// Stub. + GL_ReleaseGLTexturesByTexture(reinterpret_cast(tex)); + /// @todo Update any Materials (and thus Surfaces) which reference this. +} + +Texture *Textures::toTexture(textureid_t id) const +{ + LOG_AS("Textures::toTexture"); + if(TextureMetaFile *metafile = d->metafileByTextureId(id)) { - de::Uri uri = de::Uri(path, RC_NULL); - return Textures_ResolveUri2(reinterpret_cast(&uri), quiet); + return metafile->texture(); } - return NOTEXTUREID; + +#if _DEBUG + if(id != NOTEXTUREID) + LOG_WARNING("Failed to locate texture for id #%i, returning 0.") << id; +#endif + return 0; } -textureid_t Textures_ResolveUriCString(char const* path) +TextureMetaFile *Textures::find(Uri const &uri) const { - return Textures_ResolveUriCString2(path, !(verbose >= 1)/*log warnings if verbose*/); + LOG_AS("Textures::find"); + + if(!Textures::size()) return 0; + + if(!d->validateUri(uri, AnyScheme, true /*quiet please*/)) + { +#if _DEBUG + LOG_WARNING("URI \"%s\" failed validation, returning NULL.") << uri; +#endif + return 0; + } + + // Perform the search. + return d->metafileByUri(uri); } -static textureid_t Textures_Declare2(de::Uri& uri, int uniqueId, de::Uri const* resourcePath) +TextureMetaFile *Textures::declare(Uri const &uri, int uniqueId, Uri const *resourceUri) { LOG_AS("Textures::declare"); + if(uri.isEmpty()) return 0; + // We require a properly formed uri (but not a urn - this is a path). - if(!validateTextureUri(uri, VTUF_NO_URN, (verbose >= 1))) + if(!d->validateUri(uri, NotUrn, (verbose >= 1))) { - LOG_WARNING("Failed declaring texture \"%s\" (invalid Uri), ignoring.") << uri; - return NOTEXTUREID; + LOG_WARNING("Failed declaring texture \"%s\" (invalid URI), ignoring.") << uri; + return 0; } // Have we already created a binding for this? - TextureRepository::Node* node = findDirectoryNodeForUri(uri); - TextureRecord* record; - textureid_t id; - if(node) - { - record = reinterpret_cast(node->userPointer()); - DENG2_ASSERT(record); - id = findBindIdForDirectoryNode(*node); - } - else + TextureMetaFile *metafile = d->metafileByUri(uri); + if(!metafile) { /* * A new binding. */ + metafile = &scheme(uri.scheme()).insertMetaFile(uri.path()); + metafile->setUniqueId(uniqueId); - record = (TextureRecord*)M_Malloc(sizeof *record); - if(!record) throw de::Error("Textures::Declare", de::String("Failed on allocation of %1 bytes for new TextureRecord.").arg((unsigned long) sizeof *record)); - - record->texture = NULL; - record->resourcePath = NULL; - record->uniqueId = uniqueId; - - textureschemeid_t schemeId = Textures_ParseSchemeName(uri.schemeCStr()); - TextureScheme* tn = &schemes[schemeId - TEXTURESCHEME_FIRST]; - - node = &tn->directory->insert(uri.path()); - node->setUserPointer(record); - - // We'll need to rebuild the unique id map too. - tn->uniqueIdMapDirty = true; - - id = textureIdMapSize + 1; // 1-based identfier - // Link it into the id map. - textureIdMap = (TextureRepository::Node**) M_Realloc(textureIdMap, sizeof *textureIdMap * ++textureIdMapSize); - if(!textureIdMap) throw de::Error("Textures::Declare", de::String("Failed on (re)allocation of %1 bytes enlarging bindId => TextureRepository::Node LUT.").arg((unsigned long) sizeof *textureIdMap * textureIdMapSize)); - - textureIdMap[id - 1] = node; + // Link it into the id LUT. + d->textureIdLut.push_back(metafile); } /** @@ -891,491 +742,331 @@ static textureid_t Textures_Declare2(de::Uri& uri, int uniqueId, de::Uri const* // We don't care whether these identfiers are truely unique. Our only // responsibility is to release textures when they change. bool releaseTexture = false; - if(record->uniqueId != uniqueId) - { - textureschemeid_t const schemeId = schemeIdForDirectoryNode(*node); - TextureScheme* tn = &schemes[schemeId - TEXTURESCHEME_FIRST]; - record->uniqueId = uniqueId; + if(resourceUri && metafile->setResourceUri(*resourceUri)) + { releaseTexture = true; - - // We'll need to rebuild the id map too. - tn->uniqueIdMapDirty = true; } - if(resourcePath) - { - if(!record->resourcePath) - { - record->resourcePath = new de::Uri(*resourcePath); - releaseTexture = true; - } - else if(record->resourcePath != resourcePath) - { - *record->resourcePath = *resourcePath; - releaseTexture = true; - } - } - else if(record->resourcePath) + if(metafile->setUniqueId(uniqueId)) { - delete record->resourcePath; record->resourcePath = NULL; releaseTexture = true; } - if(releaseTexture && record->texture) + if(releaseTexture && metafile->texture()) { // The mapped resource is being replaced, so release any existing Texture. /// @todo Only release if this Texture is bound to only this binding. - Textures_Release(record->texture); - } - - return id; -} - -textureid_t Textures_Declare(Uri* uri, int uniqueId, Uri const* resourcePath) -{ - if(!uri) return NOTEXTUREID; - return Textures_Declare2(reinterpret_cast(*uri), uniqueId, reinterpret_cast(resourcePath)); -} - -Texture* Textures_CreateWithDimensions(textureid_t id, boolean custom, const Size2Raw* size, - void* userData) -{ - LOG_AS("Textures_CreateWithDimensions"); - - if(!size) - { - LOG_WARNING("Failed defining Texture #%u (invalid size), ignoring.") << id; - return NULL; - } - - TextureRepository::Node* node = directoryNodeForBindId(id); - TextureRecord* record = (node? reinterpret_cast(node->userPointer()) : NULL); - if(!record) - { - LOG_WARNING("Failed defining Texture #%u (invalid id), ignoring.") << id; - return NULL; + release(metafile->texture()); } - if(record->texture) - { - /// @todo Do not update textures here (not enough knowledge). We should instead - /// return an invalid reference/signal and force the caller to implement the - /// necessary update logic. - Texture* tex = record->texture; -#if _DEBUG - de::Uri* uri = reinterpret_cast(Textures_ComposeUri(id)); - LOG_WARNING("A Texture with uri \"%s\" already exists, returning existing.") << uri; - delete uri; -#endif - Texture_FlagCustom(tex, custom); - Texture_SetDimensions(tex, size); - Texture_SetUserDataPointer(tex, userData); - /// @todo Materials and Surfaces should be notified of this! - return tex; - } - - // A new texture. - Texture* tex = record->texture = Texture_NewWithSize(id, size, userData); - Texture_FlagCustom(tex, custom); - return tex; + return metafile; } -Texture* Textures_Create(textureid_t id, boolean custom, void* userData) -{ - Size2Raw size(0, 0); - return Textures_CreateWithDimensions(id, custom, &size, userData); -} - -int Textures_UniqueId(textureid_t id) +int Textures::uniqueId(textureid_t id) const { LOG_AS("Textures::uniqueId"); - - TextureRepository::Node* node = directoryNodeForBindId(id); - TextureRecord* record = (node? reinterpret_cast(node->userPointer()) : NULL); - if(record) + if(TextureMetaFile *metafile = d->metafileByTextureId(id)) { - return record->uniqueId; + return metafile->uniqueId(); } + #if _DEBUG if(id != NOTEXTUREID) - { LOG_WARNING("Attempted with unbound textureId #%u, returning zero.") << id; - } #endif return 0; } -Uri const* Textures_ResourcePath(textureid_t id) +Uri const &Textures::resourceUri(textureid_t id) const { LOG_AS("Textures::resourcePath"); - - TextureRepository::Node* node = directoryNodeForBindId(id); - TextureRecord* record = (node? reinterpret_cast(node->userPointer()) : NULL); - if(record) + if(TextureMetaFile *metafile = d->metafileByTextureId(id)) { - if(record->resourcePath) - { - return reinterpret_cast(record->resourcePath); - } + return metafile->resourceUri(); } + #if _DEBUG - else if(id != NOTEXTUREID) - { + if(id != NOTEXTUREID) LOG_WARNING("Attempted with unbound textureId #%u, returning null-object.") << id; - } #endif - return reinterpret_cast(emptyUri); + return emptyUri; } -textureid_t Textures_Id(Texture* tex) +textureid_t Textures::id(Texture &tex) const { LOG_AS("Textures::id"); - - if(tex) - { - return Texture_PrimaryBind(tex); - } -#if _DEBUG - LOG_WARNING("Attempted with invalid reference [%p], returning invalid id.") << de::dintptr(tex); -#endif - return NOTEXTUREID; + return tex.primaryBind(); } -textureschemeid_t Textures_Scheme(textureid_t id) +textureid_t Textures::idForMetaFile(Textures::MetaFile const &metafile) const { - LOG_AS("Textures::scheme"); - - TextureRepository::Node* node = directoryNodeForBindId(id); - if(node) - { - return schemeIdForDirectoryNode(*node); - } -#if _DEBUG - if(id != NOTEXTUREID) + LOG_AS("Textures::idForMetaFile"); + /// @todo Optimize: (Low priority) do not use a linear search. + int index = d->textureIdLut.indexOf(const_cast(&metafile)); + if(index >= 0) { - LOG_WARNING("Attempted with unbound textureId #%u, returning null-object.") << id; + return textureid_t(index + 1); // 1-based index. } -#endif - return TS_ANY; + return NOTEXTUREID; // Not linked. } -AutoStr* Textures_ComposePath(textureid_t id) +bool Textures::knownScheme(String name) const { - LOG_AS("Textures::composePath"); - - TextureRepository::Node* node = directoryNodeForBindId(id); - if(node) + if(!name.isEmpty()) { - QByteArray path = node->path().toUtf8(); - return AutoStr_FromTextStd(path.constData()); + DENG2_FOR_EACH(Schemes, i, d->schemes) + { + if(!(*i)->name().compareWithoutCase(name)) + return true; + } + //Schemes::iterator found = d->schemes.find(name.toLower()); + //if(found != d->schemes.end()) return true; } - - LOG_WARNING("Attempted with unbound textureId #%u, returning null-object.") << id; - return AutoStr_NewStd(); + return false; } -Uri* Textures_ComposeUri(textureid_t id) +Textures::Scheme &Textures::scheme(String name) const { - LOG_AS("Textures::composeUri"); - - TextureRepository::Node* node = directoryNodeForBindId(id); - if(node) - { - return reinterpret_cast(new de::Uri(composeUriForDirectoryNode(*node))); - } - -#if _DEBUG - if(id != NOTEXTUREID) + LOG_AS("Textures::scheme"); + DENG2_FOR_EACH(Schemes, i, d->schemes) { - LOG_WARNING("Attempted with unbound textureId #%u, returning null-object.") << id; + if(!(*i)->name().compareWithoutCase(name)) + return **i; } -#endif - return Uri_New(); + /// @throw UnknownSchemeError An unknown scheme was referenced. + throw Textures::UnknownSchemeError("Textures::scheme", "No scheme found matching '" + name + "'"); } -Uri* Textures_ComposeUrn(textureid_t id) +Textures::Schemes const& Textures::allSchemes() const { - LOG_AS("Textures::composeUrn"); - - TextureRepository::Node* node = directoryNodeForBindId(id); - TextureRecord const* record = (node? reinterpret_cast(node->userPointer()) : NULL); - de::Uri* uri = new de::Uri(); + return d->schemes; +} - if(record) +Uri Textures::composeUri(textureid_t id) const +{ + LOG_AS("Textures::composeUri"); + if(TextureMetaFile *metafile = d->metafileByTextureId(id)) { - Str const* schemeName = Textures_SchemeName(schemeIdForDirectoryNode(*node)); - AutoStr* path = AutoStr_NewStd(); - - Str_Reserve(path, Str_Length(schemeName) +1/*delimiter*/ + M_NumDigits(DDMAXINT)); - Str_Appendf(path, "%s:%i", Str_Text(schemeName), record->uniqueId); - - uri->setScheme("urn").setPath(Str_Text(path)); - - return reinterpret_cast(uri); + return metafile->composeUri(); } #if _DEBUG if(id != NOTEXTUREID) - { LOG_WARNING("Attempted with unbound textureId #%u, returning null-object.") << id; - } #endif - return reinterpret_cast(uri); + return Uri(); } -int Textures_Iterate2(textureschemeid_t schemeId, - int (*callback)(Texture* tex, void* parameters), void* parameters) +int Textures::iterate(String nameOfScheme, + int (*callback)(Texture &tex, void *parameters), void *parameters) const { if(!callback) return 0; - textureschemeid_t from, to; - if(VALID_TEXTURESCHEMEID(schemeId)) - { - from = to = schemeId; - } - else - { - from = TEXTURESCHEME_FIRST; - to = TEXTURESCHEME_LAST; - } - - for(uint i = uint(from); i <= uint(to); ++i) + if(!nameOfScheme.isEmpty()) { - TextureRepository& directory = schemeById(textureschemeid_t(i)); - - de::PathTreeIterator iter(directory.leafNodes()); + PathTreeIterator iter(scheme(nameOfScheme).index().leafNodes()); while(iter.hasNext()) { - TextureRecord* record = reinterpret_cast(iter.next().userPointer()); - if(!record || !record->texture) continue; + TextureMetaFile &metafile = static_cast(iter.next()); + if(!metafile.texture()) continue; - int result = callback(record->texture, parameters); + int result = callback(*metafile.texture(), parameters); if(result) return result; } } - return 0; -} - -int Textures_Iterate(textureschemeid_t schemeId, - int (*callback)(Texture* tex, void* parameters)) -{ - return Textures_Iterate2(schemeId, callback, NULL/*no parameters*/); -} - -int Textures_IterateDeclared2(textureschemeid_t schemeId, - int (*callback)(textureid_t textureId, void* parameters), void* parameters) -{ - if(!callback) return 0; - - textureschemeid_t from, to; - if(VALID_TEXTURESCHEMEID(schemeId)) - { - from = to = schemeId; - } else { - from = TEXTURESCHEME_FIRST; - to = TEXTURESCHEME_LAST; - } - - for(uint i = uint(from); i <= uint(to); ++i) - { - TextureRepository& directory = schemeById(textureschemeid_t(i)); - - de::PathTreeIterator iter(directory.leafNodes()); - while(iter.hasNext()) + DENG2_FOR_EACH_CONST(Schemes, i, d->schemes) { - TextureRecord* record = reinterpret_cast(iter.next().userPointer()); - if(!record) continue; - - // If we have bound a texture it can provide the id. - textureid_t textureId = NOTEXTUREID; - if(record->texture) - textureId = Texture_PrimaryBind(record->texture); - - // Otherwise look it up. - if(!validTextureId(textureId)) - textureId = findBindIdForDirectoryNode(iter.value()); - - // Sanity check. - DENG2_ASSERT(validTextureId(textureId)); + PathTreeIterator iter((*i)->index().leafNodes()); + while(iter.hasNext()) + { + TextureMetaFile &metafile = static_cast(iter.next()); + if(!metafile.texture()) continue; - int result = callback(textureId, parameters); - if(result) return result; + int result = callback(*metafile.texture(), parameters); + if(result) return result; + } } } return 0; } -int Textures_IterateDeclared(textureschemeid_t schemeId, - int (*callback)(textureid_t textureId, void* parameters)) +int Textures::iterateDeclared(String nameOfScheme, + int (*callback)(TextureMetaFile &metafile, void *parameters), void *parameters) const { - return Textures_IterateDeclared2(schemeId, callback, NULL/*no parameters*/); -} + if(!callback) return 0; -/// @note Part of the Doomsday public API. -int R_TextureUniqueId2(Uri const* uri, boolean quiet) -{ - textureid_t texId = Textures_ResolveUri2(uri, quiet); - if(texId != NOTEXTUREID) + if(!nameOfScheme.isEmpty()) { - return Textures_UniqueId(texId); + PathTreeIterator iter(scheme(nameOfScheme).index().leafNodes()); + while(iter.hasNext()) + { + TextureMetaFile &metafile = static_cast(iter.next()); + int result = callback(metafile, parameters); + if(result) return result; + } } - if(!quiet) + else { - AutoStr* path = Uri_ToString(uri); - Con_Message("Warning: Unknown Texture \"%s\"\n", Str_Text(path)); + DENG2_FOR_EACH_CONST(Schemes, i, d->schemes) + { + PathTreeIterator iter((*i)->index().leafNodes()); + while(iter.hasNext()) + { + TextureMetaFile &metafile = static_cast(iter.next()); + int result = callback(metafile, parameters); + if(result) return result; + } + } } - return -1; + + return 0; } -/// @note Part of the Doomsday public API. -int R_TextureUniqueId(Uri const* uri) +void Textures::deindex(TextureMetaFile &metafile) { - return R_TextureUniqueId2(uri, false); + d->unlinkFromTextureIdLut(metafile); } -static int printVariantInfo(TextureVariant* variant, void* parameters) +static void printVariantInfo(TextureVariant &variant) { - uint* variantIdx = (uint*)parameters; - DENG2_ASSERT(variantIdx); - - Con_Printf("Variant #%i: GLName:%u\n", *variantIdx, - TextureVariant_GLName(variant)); - float s, t; - TextureVariant_Coords(variant, &s, &t); + variant.coords(&s, &t); Con_Printf(" Source:%s Masked:%s Prepared:%s Uploaded:%s\n Coords:(s:%g t:%g)\n", - TexSource_Name(TextureVariant_Source(variant)), - TextureVariant_IsMasked(variant) ? "yes":"no", - TextureVariant_IsPrepared(variant)? "yes":"no", - TextureVariant_IsUploaded(variant)? "yes":"no", s, t); + TexSource_Name(variant.source()), + variant.isMasked() ? "yes":"no", + variant.isPrepared()? "yes":"no", + variant.isUploaded()? "yes":"no", s, t); Con_Printf(" Specification: "); - GL_PrintTextureVariantSpecification(TextureVariant_Spec(variant)); - - ++(*variantIdx); - return 0; // Continue iteration. + GL_PrintTextureVariantSpecification(variant.spec()); } -static void printTextureInfo(Texture* tex) +static void printTextureInfo(Texture &tex) { - Uri* uri = Textures_ComposeUri(Textures_Id(tex)); - AutoStr* path = Uri_ToString(uri); + Textures &textures = *App_Textures(); + Uri uri = textures.composeUri(textures.id(tex)); + QByteArray path = NativePath(uri.asText()).pretty().toUtf8(); - Con_Printf("Texture \"%s\" [%p] x%u uid:%u origin:%s\nSize: %d x %d\n", - F_PrettyPath(Str_Text(path)), (void*) tex, Texture_VariantCount(tex), - (uint) Textures_Id(tex), Texture_IsCustom(tex)? "addon" : "game", - Texture_Width(tex), Texture_Height(tex)); + Con_Printf("Texture \"%s\" [%p] x%u origin:%s\n", + path.constData(), (void *)&tex, tex.variantCount(), + tex.isCustom()? "addon" : "game"); + + bool willAssumeImageDimensions = (tex.width() == 0 && tex.height() == 0); + if(willAssumeImageDimensions) + Con_Printf("Dimensions: unknown (not yet loaded)\n"); + else + Con_Printf("Dimensions: %d x %d\n", tex.width(), tex.height()); uint variantIdx = 0; - Texture_IterateVariants(tex, printVariantInfo, (void*)&variantIdx); + DENG2_FOR_EACH_CONST(Texture::Variants, i, tex.variantList()) + { + TextureVariant &variant = **i; + + Con_Printf("Variant #%i: GLName:%u\n", variantIdx, variant.glName()); + printVariantInfo(variant); - Uri_Delete(uri); + ++variantIdx; + } } -static void printTextureOverview(TextureRepository::Node& node, bool printSchemeName) +static void printTextureSummary(TextureMetaFile &metafile, bool printSchemeName) { - TextureRecord* record = reinterpret_cast(node.userPointer()); - textureid_t texId = findBindIdForDirectoryNode(node); - int numUidDigits = MAX_OF(3/*uid*/, M_NumDigits(Textures_Size())); - Uri* uri = record->texture? Textures_ComposeUri(texId) : Uri_New(); - AutoStr* path = printSchemeName? Uri_ToString(uri) : Str_PercentDecode(AutoStr_FromTextStd(Str_Text(Uri_Path(uri)))); - AutoStr* resourcePath = Uri_ToString(Textures_ResourcePath(texId)); + Uri uri = metafile.composeUri(); + QByteArray path = printSchemeName? uri.asText().toUtf8() : QByteArray::fromPercentEncoding(uri.path().toStringRef().toUtf8()); - Con_FPrintf(!record->texture? CPF_LIGHT : CPF_WHITE, - "%-*s %*u %-6s x%u %s\n", printSchemeName? 22 : 14, F_PrettyPath(Str_Text(path)), - numUidDigits, texId, !record->texture? "unknown" : Texture_IsCustom(record->texture)? "addon" : "game", - Texture_VariantCount(record->texture), resourcePath? F_PrettyPath(Str_Text(resourcePath)) : "N/A"); + QByteArray resourceUri = metafile.resourceUri().asText().toUtf8(); + if(resourceUri.isEmpty()) resourceUri = "N/A"; - Uri_Delete(uri); + Con_FPrintf(!metafile.texture()? CPF_LIGHT : CPF_WHITE, + "%-*s %-6s x%u %s\n", printSchemeName? 22 : 14, path.constData(), + !metafile.texture()? "unknown" : metafile.texture()->isCustom()? "addon" : "game", + metafile.texture()->variantCount(), resourceUri.constData()); } /** - * @todo A horridly inefficent algorithm. This should be implemented in TextureRepository - * itself and not force users of this class to implement this sort of thing themselves. - * However this is only presently used for the texture search/listing console commands - * so is not hugely important right now. + * @todo This logic should be implemented in de::PathTree -ds */ -static TextureRepository::Node** collectDirectoryNodes(textureschemeid_t schemeId, - de::String like, uint* count, TextureRepository::Node** storage) +static QList collectTextureMetaFiles(Textures::Scheme *scheme, + Path const &path, QList *storage = 0) { - textureschemeid_t fromId, toId; + int count = 0; - if(VALID_TEXTURESCHEMEID(schemeId)) + if(scheme) { // Only consider textures in this scheme. - fromId = toId = schemeId; - } - else - { - // Consider textures in any scheme. - fromId = TEXTURESCHEME_FIRST; - toId = TEXTURESCHEME_LAST; - } - - int idx = 0; - for(uint i = uint(fromId); i <= uint(toId); ++i) - { - TextureRepository& directory = schemeById(textureschemeid_t(i)); - - de::PathTreeIterator iter(directory.leafNodes()); + PathTreeIterator iter(scheme->index().leafNodes()); while(iter.hasNext()) { - TextureRepository::Node& node = iter.next(); - if(!like.isEmpty()) + TextureMetaFile &metafile = static_cast(iter.next()); + if(!path.isEmpty()) { - de::String path = node.path(); - if(!path.beginsWith(like)) continue; // Continue iteration. + /// @todo Use PathTree::Node::compare() + if(!metafile.path().toString().beginsWith(path, Qt::CaseInsensitive)) continue; } - if(storage) + if(storage) // Store mode. { - // Store mode. - storage[idx++] = &node; + storage->push_back(&metafile); } - else + else // Count mode. { - // Count mode. - ++idx; + ++count; } } } - - if(storage) + else { - storage[idx] = NULL; // Terminate. - if(count) *count = idx; - return storage; + // Consider textures in any scheme. + Textures::Schemes const &schemes = App_Textures()->allSchemes(); + DENG2_FOR_EACH_CONST(Textures::Schemes, i, schemes) + { + PathTreeIterator iter((*i)->index().leafNodes()); + while(iter.hasNext()) + { + TextureMetaFile &metafile = static_cast(iter.next()); + if(!path.isEmpty()) + { + /// @todo Use PathTree::Node::compare() + if(!metafile.path().toString().beginsWith(path, Qt::CaseInsensitive)) continue; + } + + if(storage) // Store mode. + { + storage->push_back(&metafile); + } + else // Count mode. + { + ++count; + } + } + } } - if(idx == 0) + if(storage) { - if(count) *count = 0; - return NULL; + return *storage; } - storage = static_cast(M_Malloc(sizeof *storage * (idx+1))); - if(!storage) - { - throw de::Error("Textures::collectDirectoryNodes", - de::String("Failed on allocation of %1 bytes for new collection.") - .arg((unsigned long) (sizeof* storage * (idx+1)) )); - } - return collectDirectoryNodes(schemeId, like, count, storage); + QList result; + if(count == 0) return result; + + result.reserve(count); + return collectTextureMetaFiles(scheme, path, &result); } -static int composeAndCompareDirectoryNodePaths(void const* a, void const* b) +/** + * Decode and then lexicographically compare the two metafile + * paths, returning @c true if @a is less than @a b. + */ +static bool compareTextureMetaFilePathsAssending(TextureMetaFile const *a, + TextureMetaFile const *b) { - // Decode paths before determining a lexicographical delta. - TextureRepository::Node const& nodeA = **(TextureRepository::Node const**)a; - TextureRepository::Node const& nodeB = **(TextureRepository::Node const**)b; - QByteArray pathAUtf8 = nodeA.path().toUtf8(); - QByteArray pathBUtf8 = nodeB.path().toUtf8(); - AutoStr* pathA = Str_PercentDecode(AutoStr_FromTextStd(pathAUtf8)); - AutoStr* pathB = Str_PercentDecode(AutoStr_FromTextStd(pathBUtf8)); - return Str_CompareIgnoreCase(pathA, Str_Text(pathB)); + String pathA = QString(QByteArray::fromPercentEncoding(a->path().toUtf8())); + String pathB = QString(QByteArray::fromPercentEncoding(b->path().toUtf8())); + return pathA.compareWithoutCase(pathB) < 0; } /** @@ -1391,202 +1082,252 @@ static int composeAndCompareDirectoryNodePaths(void const* a, void const* b) /** * @param flags @ref printTextureFlags */ -static size_t printTextures3(textureschemeid_t schemeId, const char* like, int flags) +static int printTextures2(Textures::Scheme *scheme, Path const &path, int flags) { - const bool printSchemeName = !(flags & PTF_TRANSFORM_PATH_NO_SCHEME); - uint count = 0; - TextureRepository::Node** foundTextures = collectDirectoryNodes(schemeId, like, &count, NULL); + QList found = collectTextureMetaFiles(scheme, path); + if(found.isEmpty()) return 0; - if(!foundTextures) return 0; + bool const printSchemeName = !(flags & PTF_TRANSFORM_PATH_NO_SCHEME); - if(!printSchemeName) - Con_FPrintf(CPF_YELLOW, "Known textures in scheme '%s'", Str_Text(Textures_SchemeName(schemeId))); - else // Any scheme. - Con_FPrintf(CPF_YELLOW, "Known textures"); + // Compose a heading. + String heading = "Known textures"; + if(!printSchemeName && scheme) + heading += " in scheme '" + scheme->name() + "'"; + if(!path.isEmpty()) + heading += " like \"" + NativePath(path).withSeparators('/') + "\""; + heading += ":\n"; - if(like && like[0]) - Con_FPrintf(CPF_YELLOW, " like \"%s\"", like); - Con_FPrintf(CPF_YELLOW, ":\n"); + // Print the result heading. + Con_FPrintf(CPF_YELLOW, "%s", heading.toUtf8().constData()); // Print the result index key. - int numFoundDigits = MAX_OF(3/*idx*/, M_NumDigits((int)count)); - int numUidDigits = MAX_OF(3/*uid*/, M_NumDigits((int)Textures_Size())); + int numFoundDigits = MAX_OF(3/*idx*/, M_NumDigits(found.count())); + int numUidDigits = MAX_OF(3/*uid*/, M_NumDigits(App_Textures()->count())); - Con_Printf(" %*s: %-*s %*s origin x# path\n", numFoundDigits, "idx", - printSchemeName? 22 : 14, printSchemeName? "scheme:name" : "name", - numUidDigits, "uid"); + Con_Printf(" %*s: %-*s %*s origin n# uri\n", numFoundDigits, "idx", + printSchemeName? 22 : 14, printSchemeName? "scheme:path" : "path", + numUidDigits, "uid"); Con_PrintRuler(); // Sort and print the index. - qsort(foundTextures, (size_t)count, sizeof(*foundTextures), composeAndCompareDirectoryNodePaths); - - uint idx = 0; - for(TextureRepository::Node** iter = foundTextures; *iter; ++iter) + qSort(found.begin(), found.end(), compareTextureMetaFilePathsAssending); + int idx = 0; + DENG2_FOR_EACH(QList, i, found) { - TextureRepository::Node& node = **iter; - Con_Printf(" %*u: ", numFoundDigits, idx++); - printTextureOverview(node, printSchemeName); + Con_Printf(" %*i: ", numFoundDigits, idx++); + printTextureSummary(**i, printSchemeName); } - M_Free(foundTextures); - return count; + return found.count(); } -static void printTextures2(textureschemeid_t schemeId, const char* like, int flags) +static void printTextures(de::Uri const &search, int flags = DEFAULT_PRINTTEXTUREFLAGS) { - size_t printTotal = 0; - // Do we care which scheme? - if(schemeId == TS_ANY && like && like[0]) + Textures &textures = *App_Textures(); + + int printTotal = 0; + + // Collate and print results from all schemes? + if(search.scheme().isEmpty() && !search.path().isEmpty()) { - printTotal = printTextures3(schemeId, like, flags & ~PTF_TRANSFORM_PATH_NO_SCHEME); + printTotal = printTextures2(0/*any scheme*/, search.path(), flags & ~PTF_TRANSFORM_PATH_NO_SCHEME); Con_PrintRuler(); } - // Only one scheme to print? - else if(VALID_TEXTURESCHEMEID(schemeId)) + // Print results within only the one scheme? + else if(textures.knownScheme(search.scheme())) { - printTotal = printTextures3(schemeId, like, flags | PTF_TRANSFORM_PATH_NO_SCHEME); + printTotal = printTextures2(&textures.scheme(search.scheme()), search.path(), flags | PTF_TRANSFORM_PATH_NO_SCHEME); Con_PrintRuler(); } else { - // Collect and sort in each scheme separately. - for(int i = TEXTURESCHEME_FIRST; i <= TEXTURESCHEME_LAST; ++i) + // Collect and sort results in each scheme separately. + Textures::Schemes const &schemes = textures.allSchemes(); + DENG2_FOR_EACH_CONST(Textures::Schemes, i, schemes) { - size_t printed = printTextures3((textureschemeid_t)i, like, flags | PTF_TRANSFORM_PATH_NO_SCHEME); - if(printed != 0) + int numPrinted = printTextures2(*i, search.path(), flags | PTF_TRANSFORM_PATH_NO_SCHEME); + if(numPrinted) { - printTotal += printed; Con_PrintRuler(); + printTotal += numPrinted; + } + } + } + Con_Printf("Found %i %s.\n", printTotal, printTotal == 1? "Texture" : "Textures"); +} + +} // namespace de + +/** + * Arguments are assumed to be in a human-friendly, non-encoded representation. + * + * Supported forms (where <> denote keyword component names): + *
+ *     [0: :]
+ *     [0: ]             - if @a matchSchemeOnly
+ *     [0: ]
+ *     [0: , 1: ]
+ * 
+ */ +static de::Uri composeSearchUri(char **argv, int argc, bool matchSchemeOnly = true) +{ + if(argv) + { + // [0: :] or [0: ] or [0: ]. + if(argc == 1) + { + // Try to extract the scheme and encode the rest of the path. + de::String rawUri = de::String(argv[0]); + int pos = rawUri.indexOf(':'); + if(pos >= 0) + { + de::String scheme = rawUri.left(pos); + rawUri.remove(0, pos + 1); + return de::Uri(scheme, QString(QByteArray(rawUri.toUtf8()).toPercentEncoding())); + } + + // Just a scheme name? + if(matchSchemeOnly && App_Textures()->knownScheme(rawUri)) + { + return de::Uri().setScheme(rawUri); } + + // Just a path. + return de::Uri(de::Path(QString(QByteArray(rawUri.toUtf8()).toPercentEncoding()))); + } + // [0: , 1: ] + if(argc == 2) + { + // Assign the scheme and encode the path. + return de::Uri(argv[0], QString(QByteArray(argv[1]).toPercentEncoding())); } } - Con_Printf("Found %lu %s.\n", (unsigned long) printTotal, printTotal == 1? "Texture" : "Textures"); + return de::Uri(); } -static void printTextures(textureschemeid_t schemeId, const char* like) +static de::Textures* textures; + +de::Textures* App_Textures() { - printTextures2(schemeId, like, DEFAULT_PRINTTEXTUREFLAGS); + if(!textures) throw de::Error("App_Textures", "Textures collection not yet initialized"); + return textures; } -D_CMD(ListTextures) +void Textures_Init(void) { - DENG2_UNUSED(src); + DENG_ASSERT(!textures); + textures = new de::Textures(); +} - if(!Textures_Size()) - { - Con_Message("There are currently no textures defined/loaded.\n"); - return true; - } +void Textures_Shutdown(void) +{ + if(!textures) return; + delete textures; textures = 0; +} - textureschemeid_t schemeId = TS_ANY; - char const* like = 0; - de::Uri uri; +/// @note Part of the Doomsday public API. +int Textures_UniqueId2(Uri const *_uri, boolean quiet) +{ + LOG_AS("Textures_UniqueId"); + if(!_uri) return -1; + de::Uri const &uri = reinterpret_cast(*_uri); - // "listtextures [scheme] [path]" - if(argc > 2) + de::Textures &textures = *App_Textures(); + if(de::TextureMetaFile *metafile = textures.find(uri)) { - uri.setScheme(argv[1]).setPath(argv[2]); - - schemeId = Textures_ParseSchemeName(uri.schemeCStr()); - if(!VALID_TEXTURESCHEMEID(schemeId)) - { - Con_Printf("Invalid scheme \"%s\".\n", uri.schemeCStr()); - return false; - } - like = uri.pathCStr(); + return metafile->uniqueId(); } - // "listtextures [scheme:name]" (i.e., a partial URI) - else if(argc > 1) + + if(!quiet) { - uri = uri.setUri(argv[1], RC_NULL); + LOG_WARNING("Unknown texture %s.") << uri; + } + return -1; +} - if(!uri.scheme().isEmpty()) - { - schemeId = Textures_ParseSchemeName(uri.schemeCStr()); - if(!VALID_TEXTURESCHEMEID(schemeId)) - { - Con_Printf("Invalid scheme \"%s\".\n", uri.schemeCStr()); - return false; - } +/// @note Part of the Doomsday public API. +int Textures_UniqueId(Uri const *uri) +{ + return Textures_UniqueId2(uri, false); +} - if(!uri.path().isEmpty()) - like = uri.pathCStr(); - } - else - { - schemeId = Textures_ParseSchemeName(uri.pathCStr()); - if(!VALID_TEXTURESCHEMEID(schemeId)) - { - schemeId = TS_ANY; - like = argv[1]; - } - } +D_CMD(ListTextures) +{ + DENG2_UNUSED(src); + + de::Textures &textures = *App_Textures(); + + if(!textures.count()) + { + Con_Message("There are currently no textures defined/loaded.\n"); + return true; } - printTextures(schemeId, like); + de::Uri search = composeSearchUri(&argv[1], argc - 1); + if(!search.scheme().isEmpty() && !textures.knownScheme(search.scheme())) + { + Con_Printf("Unknown scheme '%s'.\n", search.schemeCStr()); + return false; + } + de::printTextures(search); return true; } D_CMD(InspectTexture) { DENG2_UNUSED(src); - DENG2_UNUSED(argc); - - // Path is assumed to be in a human-friendly, non-encoded representation. - Str path; Str_Init(&path); - Str_PercentEncode(Str_Set(&path, argv[1])); - de::Uri search = de::Uri(Str_Text(&path), RC_NULL); - Str_Free(&path); + de::Textures &textures = *App_Textures(); - if(!search.scheme().isEmpty()) + if(!textures.count()) { - textureschemeid_t schemeId = Textures_ParseSchemeName(search.schemeCStr()); - if(!VALID_TEXTURESCHEMEID(schemeId)) - { - Con_Printf("Invalid scheme \"%s\".\n", search.schemeCStr()); - return false; - } + Con_Message("There are currently no textures defined/loaded.\n"); + return true; } - Texture* tex = Textures_ToTexture(Textures_ResolveUri(reinterpret_cast(&search))); - if(tex) + de::Uri search = composeSearchUri(&argv[1], argc - 1, false /*don't match schemes*/); + if(!search.scheme().isEmpty() && !textures.knownScheme(search.scheme())) { - printTextureInfo(tex); + Con_Printf("Unknown scheme '%s'.\n", search.schemeCStr()); + return false; } - else + + if(de::TextureMetaFile *metafile = textures.find(search)) + if(de::Texture* tex = metafile->texture()) { - AutoStr* path = Uri_ToString(reinterpret_cast(&search)); - Con_Printf("Unknown texture \"%s\".\n", Str_Text(path)); + de::printTextureInfo(*tex); + return true; } - return true; + Con_Printf("Unknown texture \"%s\".\n", search.asText().toUtf8().constData()); + return false; } #if _DEBUG D_CMD(PrintTextureStats) { - DENG2_UNUSED(src); - DENG2_UNUSED(argc); - DENG2_UNUSED(argv); + DENG2_UNUSED(src); DENG2_UNUSED(argc); DENG2_UNUSED(argv); + + de::Textures &textures = *App_Textures(); - if(!Textures_Size()) + if(!textures.count()) { Con_Message("There are currently no textures defined/loaded.\n"); return true; } Con_FPrintf(CPF_YELLOW, "Texture Statistics:\n"); - for(uint i = uint(TEXTURESCHEME_FIRST); i <= uint(TEXTURESCHEME_LAST); ++i) + de::Textures::Schemes const &schemes = textures.allSchemes(); + DENG2_FOR_EACH_CONST(de::Textures::Schemes, i, schemes) { - textureschemeid_t schemeId = textureschemeid_t(i); - TextureRepository& directory = schemeById(schemeId); + de::Textures::Scheme &scheme = **i; + de::Textures::Scheme::Index const &index = scheme.index(); - uint size = directory.size(); - Con_Printf("Scheme: %s (%u %s)\n", Str_Text(Textures_SchemeName(schemeId)), size, size==1? "texture":"textures"); - directory.debugPrintHashDistribution(); - directory.debugPrint(); + uint const count = index.count(); + Con_Printf("Scheme: %s (%u %s)\n", scheme.name().toUtf8().constData(), count, count == 1? "texture" : "textures"); + index.debugPrintHashDistribution(); + index.debugPrint(); } return true; } diff --git a/doomsday/engine/src/ui/ui2_main.cpp b/doomsday/engine/src/ui/ui2_main.cpp index bcf5a9d447..6bcfc20819 100644 --- a/doomsday/engine/src/ui/ui2_main.cpp +++ b/doomsday/engine/src/ui/ui2_main.cpp @@ -26,9 +26,7 @@ #include "de_render.h" #include "de_graphics.h" #include "de_audio.h" - -#include "resource/texturevariant.h" -#include "resource/materialvariant.h" +#include "de_resource.h" #include #include @@ -1021,37 +1019,40 @@ static void drawPicFrame(fidata_pic_t *p, uint frame, float const _origin[3], ms->size.height + TS_GENERAL(texSpec)->border*2, 0); TextureVariant_Coords(MST(ms, MTU_PRIMARY), &texScale[VX], &texScale[VY]); - switch(Textures_Scheme(Textures_Id(MSU_texture(ms, MTU_PRIMARY)))) + de::Textures &textures = *App_Textures(); + de::Uri uri = textures.composeUri(textures.id(reinterpret_cast(*MSU_texture(ms, MTU_PRIMARY)))); + if(!uri.scheme().compareWithoutCase("Sprites")) { - case TS_SPRITES: { - patchtex_t *sTex = (patchtex_t *)Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY)); + patchtex_t *sTex = reinterpret_cast(Texture_UserDataPointer(MSU_texture(ms, MTU_PRIMARY))); if(sTex) { V3f_Set(offset, sTex->offX, sTex->offY, 0); - break; - }} - - // Fall through. - default: + } + else + { + V3f_Set(offset, 0, 0, 0); + } + } + else + { V3f_Set(offset, 0, 0, 0); - break; } } break; } case PFT_PATCH: { - Texture *texture = Textures_ToTexture(Textures_TextureForUniqueId(TS_PATCHES, f->texRef.patch)); + de::Texture *texture = App_Textures()->scheme("Patches").findByUniqueId(f->texRef.patch).texture(); if(texture) { - TextureVariant *tex = GL_PreparePatchTexture(texture); + TextureVariant *tex = GL_PreparePatchTexture(reinterpret_cast(texture)); GL_BindTexture(tex); glEnable(GL_TEXTURE_2D); textureEnabled = true; - patchtex_t* pTex = reinterpret_cast(Texture_UserDataPointer(texture)); + patchtex_t* pTex = reinterpret_cast(texture->userDataPointer()); DENG_ASSERT(pTex); V3f_Set(offset, pTex->offX, pTex->offY, 0); - V3f_Set(dimensions, Texture_Width(texture), Texture_Height(texture), 0); + V3f_Set(dimensions, texture->width(), texture->height(), 0); } break; } diff --git a/doomsday/plugins/common/src/p_floor.c b/doomsday/plugins/common/src/p_floor.c index c71a6b7b1e..6c093c50dd 100644 --- a/doomsday/plugins/common/src/p_floor.c +++ b/doomsday/plugins/common/src/p_floor.c @@ -458,7 +458,7 @@ int findLineInSectorSmallestBottomMaterial(void *ptr, void *context) * present, the height is taken from the very first texture. */ if(!mat) - mat = P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_TEXTURES, 0)); + mat = P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Textures", 0)); if(mat) { @@ -474,7 +474,7 @@ int findLineInSectorSmallestBottomMaterial(void *ptr, void *context) side = P_GetPtrp(li, DMU_SIDEDEF1); mat = P_GetPtrp(side, DMU_BOTTOM_MATERIAL); if(!mat) - mat = P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_TEXTURES, 0)); + mat = P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Textures", 0)); if(mat) { diff --git a/doomsday/plugins/common/src/p_xgfile.c b/doomsday/plugins/common/src/p_xgfile.c index 7001d4b9e5..cc53f0d6d5 100644 --- a/doomsday/plugins/common/src/p_xgfile.c +++ b/doomsday/plugins/common/src/p_xgfile.c @@ -384,8 +384,8 @@ void XG_ReadXGLump(lumpnum_t lumpNum) li->actChain = ReadShort(); li->deactChain = ReadShort(); li->wallSection = ReadByte(); - li->actMaterial = DD_MaterialForTextureUniqueId(TS_TEXTURES, ReadShort()); - li->deactMaterial = DD_MaterialForTextureUniqueId(TS_TEXTURES, ReadShort()); + li->actMaterial = DD_MaterialForTextureUniqueId("Textures", ReadShort()); + li->deactMaterial = DD_MaterialForTextureUniqueId("Textures", ReadShort()); ReadString(&li->actMsg); ReadString(&li->deactMsg); li->materialMoveAngle = ReadFloat(); diff --git a/doomsday/plugins/jdoom/src/p_oldsvg.c b/doomsday/plugins/jdoom/src/p_oldsvg.c index d515cb5356..2def165e53 100644 --- a/doomsday/plugins/jdoom/src/p_oldsvg.c +++ b/doomsday/plugins/jdoom/src/p_oldsvg.c @@ -375,8 +375,8 @@ static void P_v19_UnArchiveWorld(void) P_SetDoublep(sec, DMU_FLOOR_HEIGHT, (coord_t) Reader_ReadInt16(svReader)); P_SetDoublep(sec, DMU_CEILING_HEIGHT, (coord_t) Reader_ReadInt16(svReader)); - P_SetPtrp (sec, DMU_FLOOR_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_FLATS, Reader_ReadInt16(svReader)))); - P_SetPtrp (sec, DMU_CEILING_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_FLATS, Reader_ReadInt16(svReader)))); + P_SetPtrp (sec, DMU_FLOOR_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Flats", Reader_ReadInt16(svReader)))); + P_SetPtrp (sec, DMU_CEILING_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Flats", Reader_ReadInt16(svReader)))); P_SetFloatp(sec, DMU_LIGHT_LEVEL, (float) (Reader_ReadInt16(svReader)) / 255.0f); xsec->special = Reader_ReadInt16(svReader); // needed? @@ -407,9 +407,9 @@ static void P_v19_UnArchiveWorld(void) P_SetFloatpv(sdef, DMU_MIDDLE_MATERIAL_OFFSET_XY, matOffset); P_SetFloatpv(sdef, DMU_BOTTOM_MATERIAL_OFFSET_XY, matOffset); - P_SetPtrp (sdef, DMU_TOP_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_TEXTURES, Reader_ReadInt16(svReader)))); - P_SetPtrp (sdef, DMU_BOTTOM_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_TEXTURES, Reader_ReadInt16(svReader)))); - P_SetPtrp (sdef, DMU_MIDDLE_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_TEXTURES, Reader_ReadInt16(svReader)))); + P_SetPtrp (sdef, DMU_TOP_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Textures", Reader_ReadInt16(svReader)))); + P_SetPtrp (sdef, DMU_BOTTOM_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Textures", Reader_ReadInt16(svReader)))); + P_SetPtrp (sdef, DMU_MIDDLE_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Textures", Reader_ReadInt16(svReader)))); } } } @@ -566,7 +566,7 @@ typedef struct { floor->state = (int) Reader_ReadInt32(svReader); floor->newSpecial = Reader_ReadInt32(svReader); - floor->material = P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_FLATS, Reader_ReadInt16(svReader))); + floor->material = P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Flats", Reader_ReadInt16(svReader))); floor->floorDestHeight = FIX2FLT(Reader_ReadInt32(svReader)); floor->speed = FIX2FLT(Reader_ReadInt32(svReader)); diff --git a/doomsday/plugins/jdoom/src/p_spec.c b/doomsday/plugins/jdoom/src/p_spec.c index 755fe48eb6..faa0814da7 100644 --- a/doomsday/plugins/jdoom/src/p_spec.c +++ b/doomsday/plugins/jdoom/src/p_spec.c @@ -174,8 +174,8 @@ static void loadAnimDefs(animdef_t* animDefs, boolean isCustom) Str_PercentEncode(Str_StripRight(Str_Set(&endPath, animDefs[i].endname))); Uri_SetPath(endUri, Str_Text(&endPath)); - startFrame = R_TextureUniqueId2(startUri, !isCustom); - endFrame = R_TextureUniqueId2(endUri, !isCustom); + startFrame = Textures_UniqueId2(startUri, !isCustom); + endFrame = Textures_UniqueId2(endUri, !isCustom); if(-1 == startFrame || -1 == endFrame) continue; numFrames = endFrame - startFrame + 1; diff --git a/doomsday/plugins/jdoom64/src/p_spec.c b/doomsday/plugins/jdoom64/src/p_spec.c index 88ea0b517e..f31025610a 100644 --- a/doomsday/plugins/jdoom64/src/p_spec.c +++ b/doomsday/plugins/jdoom64/src/p_spec.c @@ -162,8 +162,8 @@ static void loadAnimDefs(animdef_t* animDefs, boolean isCustom) Str_PercentEncode(Str_StripRight(Str_Set(&endPath, animDefs[i].endname))); Uri_SetPath(endUri, Str_Text(&endPath)); - startFrame = R_TextureUniqueId2(startUri, !isCustom); - endFrame = R_TextureUniqueId2(endUri, !isCustom); + startFrame = Textures_UniqueId2(startUri, !isCustom); + endFrame = Textures_UniqueId2(endUri, !isCustom); if(-1 == startFrame || -1 == endFrame) continue; numFrames = (endFrame > startFrame? endFrame - startFrame : startFrame - endFrame) + 1; diff --git a/doomsday/plugins/jheretic/src/p_oldsvg.c b/doomsday/plugins/jheretic/src/p_oldsvg.c index 1db5b5a8ab..a6dd8a8284 100644 --- a/doomsday/plugins/jheretic/src/p_oldsvg.c +++ b/doomsday/plugins/jheretic/src/p_oldsvg.c @@ -391,8 +391,8 @@ static void P_v13_UnArchiveWorld(void) P_SetDoublep(sec, DMU_FLOOR_HEIGHT, (coord_t)Reader_ReadInt16(svReader)); P_SetDoublep(sec, DMU_CEILING_HEIGHT, (coord_t)Reader_ReadInt16(svReader)); - P_SetPtrp (sec, DMU_FLOOR_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_FLATS, Reader_ReadInt16(svReader)))); - P_SetPtrp (sec, DMU_CEILING_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_FLATS, Reader_ReadInt16(svReader)))); + P_SetPtrp (sec, DMU_FLOOR_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Flats", Reader_ReadInt16(svReader)))); + P_SetPtrp (sec, DMU_CEILING_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Flats", Reader_ReadInt16(svReader)))); P_SetFloatp (sec, DMU_LIGHT_LEVEL, (float) (Reader_ReadInt16(svReader)) / 255.0f); xsec->special = Reader_ReadInt16(svReader); // needed? /*xsec->tag = **/Reader_ReadInt16(svReader); // needed? @@ -423,9 +423,9 @@ static void P_v13_UnArchiveWorld(void) P_SetFixedp(sdef, DMU_MIDDLE_MATERIAL_OFFSET_Y, offy); P_SetFixedp(sdef, DMU_BOTTOM_MATERIAL_OFFSET_X, offx); P_SetFixedp(sdef, DMU_BOTTOM_MATERIAL_OFFSET_Y, offy); - P_SetPtrp (sdef, DMU_TOP_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_TEXTURES, Reader_ReadInt16(svReader)))); - P_SetPtrp (sdef, DMU_BOTTOM_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_TEXTURES, Reader_ReadInt16(svReader)))); - P_SetPtrp (sdef, DMU_MIDDLE_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_TEXTURES, Reader_ReadInt16(svReader)))); + P_SetPtrp (sdef, DMU_TOP_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Textures", Reader_ReadInt16(svReader)))); + P_SetPtrp (sdef, DMU_BOTTOM_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Textures", Reader_ReadInt16(svReader)))); + P_SetPtrp (sdef, DMU_MIDDLE_MATERIAL, P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Textures", Reader_ReadInt16(svReader)))); } } } @@ -583,7 +583,7 @@ typedef struct { floor->state = (int) Reader_ReadInt32(svReader); floor->newSpecial = Reader_ReadInt32(svReader); - floor->material = P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId(TS_FLATS, Reader_ReadInt16(svReader))); + floor->material = P_ToPtr(DMU_MATERIAL, DD_MaterialForTextureUniqueId("Flats", Reader_ReadInt16(svReader))); floor->floorDestHeight = FIX2FLT(Reader_ReadInt32(svReader)); floor->speed = FIX2FLT(Reader_ReadInt32(svReader)); diff --git a/doomsday/plugins/jheretic/src/p_spec.c b/doomsday/plugins/jheretic/src/p_spec.c index 0552eac1ee..7ff4c8f5aa 100644 --- a/doomsday/plugins/jheretic/src/p_spec.c +++ b/doomsday/plugins/jheretic/src/p_spec.c @@ -311,8 +311,8 @@ static void loadAnimDefs(animdef_t* animDefs, boolean isCustom) Str_PercentEncode(Str_StripRight(Str_Set(&endPath, animDefs[i].endname))); Uri_SetPath(endUri, Str_Text(&endPath)); - startFrame = R_TextureUniqueId2(startUri, !isCustom); - endFrame = R_TextureUniqueId2(endUri, !isCustom); + startFrame = Textures_UniqueId2(startUri, !isCustom); + endFrame = Textures_UniqueId2(endUri, !isCustom); if(-1 == startFrame || -1 == endFrame) continue; numFrames = (endFrame > startFrame? endFrame - startFrame : startFrame - endFrame) + 1; diff --git a/doomsday/plugins/jhexen/src/p_anim.c b/doomsday/plugins/jhexen/src/p_anim.c index 87e3937a3a..b672142268 100644 --- a/doomsday/plugins/jhexen/src/p_anim.c +++ b/doomsday/plugins/jhexen/src/p_anim.c @@ -48,7 +48,7 @@ static void parseAnimGroup(boolean isTexture, boolean isCustom) Uri_SetPath(uri, Str_Text(&path)); Str_Free(&path); - texNumBase = R_TextureUniqueId2(uri, !isCustom); + texNumBase = Textures_UniqueId2(uri, !isCustom); if(texNumBase != -1) ignore = false; diff --git a/doomsday/plugins/wadmapconverter/src/id1map.cpp b/doomsday/plugins/wadmapconverter/src/id1map.cpp index b5cc5ed4de..8e91247cea 100644 --- a/doomsday/plugins/wadmapconverter/src/id1map.cpp +++ b/doomsday/plugins/wadmapconverter/src/id1map.cpp @@ -62,7 +62,7 @@ MaterialDictId Id1Map::addMaterialToDictionary(char const* name, MaterialDictGro //char name[9]; //sprintf(name, "UNK%05i", uniqueId); name[8] = '\0'; - Uri* uri = Materials_ComposeUri(DD_MaterialForTextureUniqueId((group == MG_PLANE? TS_FLATS : TS_TEXTURES), uniqueId)); + Uri* uri = Materials_ComposeUri(DD_MaterialForTextureUniqueId((group == MG_PLANE? "Flats" : "Textures"), uniqueId)); uriCString = Uri_Compose(uri); Uri_Delete(uri); }