diff --git a/doomsday/client/include/resource/texturevariantspec.h b/doomsday/client/include/resource/texturevariantspec.h index 8142f43383..0168b47bf8 100644 --- a/doomsday/client/include/resource/texturevariantspec.h +++ b/doomsday/client/include/resource/texturevariantspec.h @@ -65,20 +65,6 @@ typedef enum { #define TSF_HAS_COLORPALETTE_XLAT 0x80000000 /*@}*/ -typedef enum { - TST_GENERAL = 0, - TST_DETAIL -} texturevariantspecificationtype_t; - -#define TEXTUREVARIANTSPECIFICATIONTYPE_FIRST TST_GENERAL -#define TEXTUREVARIANTSPECIFICATIONTYPE_LAST TST_DETAIL - -#define TEXTUREVARIANTSPECIFICATIONTYPE_COUNT (\ - TEXTUREVARIANTSPECIFICATIONTYPE_LAST + 1 - TEXTUREVARIANTSPECIFICATIONTYPE_FIRST ) - -#define VALID_TEXTUREVARIANTSPECIFICATIONTYPE(t) (\ - (t) >= TEXTUREVARIANTSPECIFICATIONTYPE_FIRST && (t) <= TEXTUREVARIANTSPECIFICATIONTYPE_LAST) - struct colorpalettetranslationspecification_t { int tClass, tMap; @@ -128,11 +114,25 @@ struct variantspecification_t int anisoFilter; /// Additional color palette translation spec. - colorpalettetranslationspecification_t *translated; + QScopedPointer translated; GLint glMinFilter() const; GLint glMagFilter() const; int logicalAnisoLevel() const; + + variantspecification_t(); + variantspecification_t(variantspecification_t const &other); + + /** + * Magnification, Anisotropic filter level and GL texture wrap modes are + * handled through dynamic changes to GL's texture environment state. + * Consequently, they are ignored during spec equality comparison. + */ + bool operator == (variantspecification_t const &other) const; + + inline bool operator != (variantspecification_t const &other) const { + return !(*this == other); + } }; /** @@ -148,18 +148,46 @@ struct variantspecification_t struct detailvariantspecification_t { uint8_t contrast; + + bool operator == (detailvariantspecification_t const &other) const; + + inline bool operator != (detailvariantspecification_t const &other) const { + return !(*this == other); + } }; +enum texturevariantspecificationtype_t +{ + TST_GENERAL, + TST_DETAIL +}; + +#define TEXTUREVARIANTSPECIFICATIONTYPE_FIRST TST_GENERAL +#define TEXTUREVARIANTSPECIFICATIONTYPE_LAST TST_DETAIL + +#define TEXTUREVARIANTSPECIFICATIONTYPE_COUNT (\ + TEXTUREVARIANTSPECIFICATIONTYPE_LAST + 1 - TEXTUREVARIANTSPECIFICATIONTYPE_FIRST ) + +#define VALID_TEXTUREVARIANTSPECIFICATIONTYPE(t) (\ + (t) >= TEXTUREVARIANTSPECIFICATIONTYPE_FIRST && (t) <= TEXTUREVARIANTSPECIFICATIONTYPE_LAST) + #define TS_GENERAL(ts) ((ts).data.variant) #define TS_DETAIL(ts) ((ts).data.detailvariant) struct texturevariantspecification_t { texturevariantspecificationtype_t type; - union { - variantspecification_t variant; - detailvariantspecification_t detailvariant; - } data; // type-specific data. + variantspecification_t variant; + detailvariantspecification_t detailVariant; + + texturevariantspecification_t(texturevariantspecificationtype_t type = TST_GENERAL); + texturevariantspecification_t(texturevariantspecification_t const &other); + + bool operator == (texturevariantspecification_t const &other) const; + + inline bool operator != (texturevariantspecification_t const &other) const { + return !(*this == other); + } /** * Returns a textual, human-readable representation of the specification. @@ -167,12 +195,4 @@ struct texturevariantspecification_t de::String asText() const; }; -/** - * Compare the given TextureVariantSpecifications and determine whether they can - * be considered equal (dependent on current engine state and the available features - * of the GL implementation). - */ -int TextureVariantSpec_Compare(texturevariantspecification_t const *a, - texturevariantspecification_t const *b); - #endif // DENG_RESOURCE_TEXTUREVARIANTSPEC_H diff --git a/doomsday/client/src/gl/gl_texmanager.cpp b/doomsday/client/src/gl/gl_texmanager.cpp index 89aff761de..3fabcf56c2 100644 --- a/doomsday/client/src/gl/gl_texmanager.cpp +++ b/doomsday/client/src/gl/gl_texmanager.cpp @@ -42,8 +42,10 @@ #include "resource/hq2x.h" -#include +//#include #include +#include +#include #include using namespace de; @@ -61,95 +63,19 @@ struct texturevariantspecificationlist_node_t texturevariantspecificationlist_node_t *next; texturevariantspecification_t *spec; }; -typedef texturevariantspecificationlist_node_t variantspecificationlist_t; -static variantspecificationlist_t *variantSpecs; +typedef QList VariantSpecs; +static VariantSpecs variantSpecs; /// @c TST_DETAIL type specifications are stored separately into a set of /// buckets. Bucket selection is determined by their quantized contrast value. #define DETAILVARIANT_CONTRAST_HASHSIZE (DETAILTEXTURE_CONTRAST_QUANTIZATION_FACTOR+1) -static variantspecificationlist_t *detailVariantSpecs[DETAILVARIANT_CONTRAST_HASHSIZE]; +static VariantSpecs detailVariantSpecs[DETAILVARIANT_CONTRAST_HASHSIZE]; static int hashDetailVariantSpecification(detailvariantspecification_t const &spec) { return (spec.contrast * (1/255.f) * DETAILTEXTURE_CONTRAST_QUANTIZATION_FACTOR + .5f); } -static void unlinkVariantSpecification(texturevariantspecification_t &spec) -{ - variantspecificationlist_t **listHead; - DENG2_ASSERT(initedOk); - - // Select list head according to variant specification type. - switch(spec.type) - { - case TST_GENERAL: listHead = &variantSpecs; break; - case TST_DETAIL: { - int hash = hashDetailVariantSpecification(TS_DETAIL(spec)); - listHead = &detailVariantSpecs[hash]; - break; } - } - - if(*listHead) - { - texturevariantspecificationlist_node_t *node = 0; - if((*listHead)->spec == &spec) - { - node = (*listHead); - *listHead = (*listHead)->next; - } - else - { - // Find the previous node. - texturevariantspecificationlist_node_t *prevNode = (*listHead); - while(prevNode->next && prevNode->next->spec != &spec) - { - prevNode = prevNode->next; - } - if(prevNode) - { - node = prevNode->next; - prevNode->next = prevNode->next->next; - } - } - M_Free(node); - } -} - -static void destroyVariantSpecification(texturevariantspecification_t &spec) -{ - unlinkVariantSpecification(spec); - if(spec.type == TST_GENERAL && (TS_GENERAL(spec).flags & TSF_HAS_COLORPALETTE_XLAT)) - { - M_Free(TS_GENERAL(spec).translated); - } - M_Free(&spec); -} - -static texturevariantspecification_t *copyVariantSpecification( - texturevariantspecification_t const &tpl) -{ - texturevariantspecification_t *spec = (texturevariantspecification_t *) M_Malloc(sizeof(*spec)); - - std::memcpy(spec, &tpl, sizeof(texturevariantspecification_t)); - if(TS_GENERAL(tpl).flags & TSF_HAS_COLORPALETTE_XLAT) - { - colorpalettetranslationspecification_t *cpt = (colorpalettetranslationspecification_t *) M_Malloc(sizeof(*cpt)); - - std::memcpy(cpt, TS_GENERAL(tpl).translated, sizeof(colorpalettetranslationspecification_t)); - TS_GENERAL(*spec).translated = cpt; - } - return spec; -} - -static texturevariantspecification_t *copyDetailVariantSpecification( - texturevariantspecification_t const &tpl) -{ - texturevariantspecification_t *spec = (texturevariantspecification_t *) M_Malloc(sizeof(*spec)); - - std::memcpy(spec, &tpl, sizeof(texturevariantspecification_t)); - return spec; -} - static colorpalettetranslationspecification_t *applyColorPaletteTranslationSpecification( colorpalettetranslationspecification_t *spec, int tClass, int tMap) { @@ -179,26 +105,23 @@ static variantspecification_t &applyVariantSpecification( flags &= ~TSF_INTERNAL_MASK; - spec.context = tc; - spec.flags = flags; - spec.border = (flags & TSF_UPSCALE_AND_SHARPEN)? 1 : border; - spec.mipmapped = mipmapped; - spec.wrapS = wrapS; - spec.wrapT = wrapT; - spec.minFilter = MINMAX_OF(-1, minFilter, spec.mipmapped? 3:1); - spec.magFilter = MINMAX_OF(-3, magFilter, 1); - spec.anisoFilter = MINMAX_OF(-1, anisoFilter, 4); + spec.context = tc; + spec.flags = flags; + spec.border = (flags & TSF_UPSCALE_AND_SHARPEN)? 1 : border; + spec.mipmapped = mipmapped; + spec.wrapS = wrapS; + spec.wrapT = wrapT; + spec.minFilter = de::clamp(-1, minFilter, spec.mipmapped? 3:1); + spec.magFilter = de::clamp(-3, magFilter, 1); + spec.anisoFilter = de::clamp(-1, anisoFilter, 4); spec.gammaCorrection = gammaCorrection; - spec.noStretch = noStretch; - spec.toAlpha = toAlpha; + spec.noStretch = noStretch; + spec.toAlpha = toAlpha; + if(colorPaletteTranslationSpec) { spec.flags |= TSF_HAS_COLORPALETTE_XLAT; - spec.translated = colorPaletteTranslationSpec; - } - else - { - spec.translated = NULL; + spec.translated.reset(colorPaletteTranslationSpec); // takes ownership } return spec; @@ -209,68 +132,64 @@ static detailvariantspecification_t &applyDetailVariantSpecification( { int const quantFactor = DETAILTEXTURE_CONTRAST_QUANTIZATION_FACTOR; - spec.contrast = 255 * (int)MINMAX_OF(0, contrast * quantFactor + .5f, quantFactor) * (1 / float(quantFactor)); + spec.contrast = 255 * de::clamp(0, contrast * quantFactor + .5f, quantFactor) * (1 / float(quantFactor)); return spec; } static texturevariantspecification_t &linkVariantSpecification( - texturevariantspecificationtype_t type, texturevariantspecification_t &spec) + texturevariantspecification_t *spec) { - texturevariantspecificationlist_node_t *node; - DENG2_ASSERT(initedOk && VALID_TEXTUREVARIANTSPECIFICATIONTYPE(type)); + DENG2_ASSERT(initedOk && spec != 0); - node = (texturevariantspecificationlist_node_t *) M_Malloc(sizeof(*node)); - node->spec = &spec; - switch(type) + switch(spec->type) { case TST_GENERAL: - node->next = variantSpecs; - variantSpecs = (variantspecificationlist_t *)node; + variantSpecs.append(spec); break; case TST_DETAIL: { - int hash = hashDetailVariantSpecification(TS_DETAIL(spec)); - node->next = detailVariantSpecs[hash]; - detailVariantSpecs[hash] = (variantspecificationlist_t *)node; + int hash = hashDetailVariantSpecification(spec->detailVariant); + detailVariantSpecs[hash].append(spec); break; } } - return spec; + return *spec; } static texturevariantspecification_t *findVariantSpecification( - texturevariantspecificationtype_t type, texturevariantspecification_t const &tpl, - bool canCreate) + texturevariantspecification_t const &tpl, bool canCreate) { - texturevariantspecificationlist_node_t *node = 0; - DENG2_ASSERT(initedOk && VALID_TEXTUREVARIANTSPECIFICATIONTYPE(type)); + DENG2_ASSERT(initedOk); - // Select list head according to variant specification type. - switch(type) + // Do we already have a concrete version of the template specification? + switch(tpl.type) { - case TST_GENERAL: node = variantSpecs; break; - case TST_DETAIL: { - int hash = hashDetailVariantSpecification(TS_DETAIL(tpl)); - node = detailVariantSpecs[hash]; + case TST_GENERAL: { + foreach(texturevariantspecification_t *varSpec, variantSpecs) + { + if(*varSpec == tpl) + { + return varSpec; + } + } break; } - } - // Do we already have a concrete version of the template specification? - for(; node; node = node->next) - { - if(TextureVariantSpec_Compare(node->spec, &tpl)) + case TST_DETAIL: { + int hash = hashDetailVariantSpecification(tpl.detailVariant); + foreach(texturevariantspecification_t *varSpec, detailVariantSpecs[hash]) { - return node->spec; + if(*varSpec == tpl) + { + return varSpec; + } + } + break; } } // Not found, can we create? if(canCreate) { - switch(type) - { - case TST_GENERAL: return &linkVariantSpecification(type, *copyVariantSpecification(tpl)); - case TST_DETAIL: return &linkVariantSpecification(type, *copyDetailVariantSpecification(tpl)); - } + return &linkVariantSpecification(new texturevariantspecification_t(tpl)); } return 0; @@ -296,12 +215,14 @@ static texturevariantspecification_t *getVariantSpecificationForContext( haveCpt = true; } - applyVariantSpecification(TS_GENERAL(tpl), tc, flags, border, haveCpt? &cptTpl : NULL, + applyVariantSpecification(tpl.variant, tc, flags, border, haveCpt? &cptTpl : NULL, wrapS, wrapT, minFilter, magFilter, anisoFilter, mipmapped, gammaCorrection, noStretch, toAlpha); // Retrieve a concrete version of the rationalized specification. - return findVariantSpecification(tpl.type, tpl, true); + texturevariantspecification_t *intern = findVariantSpecification(tpl, true); + tpl.variant.translated.reset(); + return intern; } static texturevariantspecification_t *getDetailVariantSpecificationForContext( @@ -312,21 +233,8 @@ static texturevariantspecification_t *getDetailVariantSpecificationForContext( static texturevariantspecification_t tpl; tpl.type = TST_DETAIL; - applyDetailVariantSpecification(TS_DETAIL(tpl), contrast); - return findVariantSpecification(tpl.type, tpl, true); -} - -static void emptyVariantSpecificationList(variantspecificationlist_t *list) -{ - DENG2_ASSERT(initedOk); - - texturevariantspecificationlist_node_t *node = (texturevariantspecificationlist_node_t *) list; - while(node) - { - texturevariantspecificationlist_node_t *next = node->next; - destroyVariantSpecification(*node->spec); - node = next; - } + applyDetailVariantSpecification(tpl.detailVariant, contrast); + return findVariantSpecification(tpl, true); } static bool variantSpecInUse(texturevariantspecification_t const &spec) @@ -342,49 +250,51 @@ static bool variantSpecInUse(texturevariantspecification_t const &spec) return false; } -static int pruneUnusedVariantSpecificationsInList(variantspecificationlist_t *list) +static int pruneUnusedTextureVariantSpecs(VariantSpecs &list) { - texturevariantspecificationlist_node_t *node = list; int numPruned = 0; - while(node) + QMutableListIterator it(list); + while(it.hasNext()) { - texturevariantspecificationlist_node_t *next = node->next; - - if(!variantSpecInUse(*node->spec)) + texturevariantspecification_t *spec = it.next(); + if(!variantSpecInUse(*spec)) { - destroyVariantSpecification(*node->spec); - ++numPruned; + it.remove(); + delete &spec; + numPruned += 1; } - - node = next; } return numPruned; } -static int pruneUnusedVariantSpecifications(texturevariantspecificationtype_t specType) +static int pruneUnusedTextureVariantSpecs(texturevariantspecificationtype_t specType) { DENG2_ASSERT(initedOk); switch(specType) { - case TST_GENERAL: return pruneUnusedVariantSpecificationsInList(variantSpecs); + case TST_GENERAL: return pruneUnusedTextureVariantSpecs(variantSpecs); case TST_DETAIL: { int numPruned = 0; for(int i = 0; i < DETAILVARIANT_CONTRAST_HASHSIZE; ++i) { - numPruned += pruneUnusedVariantSpecificationsInList(detailVariantSpecs[i]); + numPruned += pruneUnusedTextureVariantSpecs(detailVariantSpecs[i]); } return numPruned; } } + return 0; } -static void destroyVariantSpecifications() +static void clearTextureVariantSpecs() { DENG2_ASSERT(initedOk); - emptyVariantSpecificationList(variantSpecs); variantSpecs = 0; + qDeleteAll(variantSpecs); + variantSpecs.clear(); + for(int i = 0; i < DETAILVARIANT_CONTRAST_HASHSIZE; ++i) { - emptyVariantSpecificationList(detailVariantSpecs[i]); detailVariantSpecs[i] = 0; + qDeleteAll(detailVariantSpecs[i]); + detailVariantSpecs[i].clear(); } } @@ -409,15 +319,20 @@ void GL_InitTextureManager() zap(sysFlareTextures); zap(lightingTextures); - variantSpecs = 0; - zap(detailVariantSpecs); - GL_InitSmartFilterHQ2x(); // Initialization done. initedOk = true; } +void GL_ShutdownTextureManager() +{ + if(!initedOk) return; + + clearTextureVariantSpecs(); + initedOk = false; +} + void GL_ResetTextureManager() { if(!initedOk) return; @@ -475,8 +390,8 @@ void GL_PruneTextureVariantSpecifications() if(Sys_IsShuttingDown()) return; int numPruned = 0; - numPruned += pruneUnusedVariantSpecifications(TST_GENERAL); - numPruned += pruneUnusedVariantSpecifications(TST_DETAIL); + numPruned += pruneUnusedTextureVariantSpecs(TST_GENERAL); + numPruned += pruneUnusedTextureVariantSpecs(TST_DETAIL); #ifdef DENG_DEBUG LOG_VERBOSE("Pruned %i unused texture variant %s.") @@ -499,10 +414,10 @@ texturevariantspecification_t &GL_TextureVariantSpec( #ifdef DENG_DEBUG if(tClass || tMap) { - DENG2_ASSERT(tvs->data.variant.flags & TSF_HAS_COLORPALETTE_XLAT); - DENG2_ASSERT(tvs->data.variant.translated); - DENG2_ASSERT(tvs->data.variant.translated->tClass == tClass); - DENG2_ASSERT(tvs->data.variant.translated->tMap == tMap); + DENG2_ASSERT(tvs->variant.flags & TSF_HAS_COLORPALETTE_XLAT); + DENG2_ASSERT(!tvs->variant.translated.isNull()); + DENG2_ASSERT(tvs->variant.translated->tClass == tClass); + DENG2_ASSERT(tvs->variant.translated->tMap == tMap); } #endif @@ -515,14 +430,6 @@ texturevariantspecification_t &GL_DetailTextureSpec(float contrast) return *getDetailVariantSpecificationForContext(contrast); } -void GL_ShutdownTextureManager() -{ - if(!initedOk) return; - - destroyVariantSpecifications(); - initedOk = false; -} - void GL_LoadLightingSystemTextures() { if(novideo || !initedOk) return; @@ -533,19 +440,6 @@ void GL_LoadLightingSystemTextures() GL_PrepareLSTexture(LST_CAMERA_VIGNETTE); } -void GL_LoadFlareTextures() -{ - if(novideo || !initedOk) return; - - GL_PrepareSysFlaremap(FXT_ROUND); - GL_PrepareSysFlaremap(FXT_FLARE); - if(!haloRealistic) - { - GL_PrepareSysFlaremap(FXT_BRFLARE); - GL_PrepareSysFlaremap(FXT_BIGFLARE); - } -} - void GL_ReleaseAllLightingSystemTextures() { if(novideo || !initedOk) return; @@ -554,14 +448,6 @@ void GL_ReleaseAllLightingSystemTextures() zap(lightingTextures); } -void GL_ReleaseAllFlareTextures() -{ - if(novideo || !initedOk) return; - - glDeleteTextures(NUM_SYSFLARE_TEXTURES, (GLuint const *) sysFlareTextures); - zap(sysFlareTextures); -} - GLuint GL_PrepareLSTexture(lightingtexid_t which) { if(novideo) return 0; @@ -607,6 +493,27 @@ GLuint GL_PrepareLSTexture(lightingtexid_t which) return lightingTextures[which]; } +void GL_LoadFlareTextures() +{ + if(novideo || !initedOk) return; + + GL_PrepareSysFlaremap(FXT_ROUND); + GL_PrepareSysFlaremap(FXT_FLARE); + if(!haloRealistic) + { + GL_PrepareSysFlaremap(FXT_BRFLARE); + GL_PrepareSysFlaremap(FXT_BIGFLARE); + } +} + +void GL_ReleaseAllFlareTextures() +{ + if(novideo || !initedOk) return; + + glDeleteTextures(NUM_SYSFLARE_TEXTURES, (GLuint const *) sysFlareTextures); + zap(sysFlareTextures); +} + GLuint GL_PrepareSysFlaremap(flaretexid_t which) { if(novideo) return 0; diff --git a/doomsday/client/src/resource/materialvariant.cpp b/doomsday/client/src/resource/materialvariant.cpp index b2752c7082..37574e8fdd 100644 --- a/doomsday/client/src/resource/materialvariant.cpp +++ b/doomsday/client/src/resource/materialvariant.cpp @@ -109,5 +109,5 @@ bool MaterialVariantSpec::compare(MaterialVariantSpec const &other) const { if(this == &other) return 1; if(context != other.context) return 0; - return 1 == TextureVariantSpec_Compare(primarySpec, other.primarySpec); + return primarySpec == other.primarySpec; } diff --git a/doomsday/client/src/resource/texture.cpp b/doomsday/client/src/resource/texture.cpp index 2143f347c1..a9092efac3 100644 --- a/doomsday/client/src/resource/texture.cpp +++ b/doomsday/client/src/resource/texture.cpp @@ -193,7 +193,7 @@ Texture::Variant *Texture::chooseVariant(ChooseVariantMethod method, break; case FuzzyMatchSpec: - if(TextureVariantSpec_Compare(&cand, &spec)) + if(cand == spec) { // This will do fine. return variant; diff --git a/doomsday/client/src/resource/texturevariant.cpp b/doomsday/client/src/resource/texturevariant.cpp index 44adb41acd..2f79074924 100644 --- a/doomsday/client/src/resource/texturevariant.cpp +++ b/doomsday/client/src/resource/texturevariant.cpp @@ -22,18 +22,146 @@ #include "resource/texture.h" #include "r_util.h" + #include "gl/gl_defer.h" #include "gl/gl_main.h" #include "gl/gl_tex.h" -#include "gl/gl_texmanager.h" // misc global vars awaiting new home #include "gl/texturecontent.h" + #include "resource/colorpalettes.h" #include "resource/image.h" // GL_LoadSourceImage + +#include "render/rend_main.h" // misc global vars awaiting new home + #include #include // M_CeilPow using namespace de; +variantspecification_t::variantspecification_t() + : context(TC_UNKNOWN) + , flags(0) + , border(0) + , wrapS(GL_REPEAT) + , wrapT(GL_REPEAT) + , mipmapped(false) + , gammaCorrection(true) + , noStretch(false) + , toAlpha(false) + , minFilter(GL_LINEAR) + , magFilter(GL_LINEAR) + , anisoFilter(0) +{} + +variantspecification_t::variantspecification_t(variantspecification_t const &other) + : context(other.context) + , flags(other.flags) + , border(other.border) + , wrapS(other.wrapS) + , wrapT(other.wrapT) + , mipmapped(other.mipmapped) + , gammaCorrection(other.gammaCorrection) + , noStretch(other.noStretch) + , toAlpha(other.toAlpha) + , minFilter(other.minFilter) + , magFilter(other.magFilter) + , anisoFilter(other.anisoFilter) +{ + if(!other.translated.isNull()) + { + translated.reset(new colorpalettetranslationspecification_t(*other.translated)); + } +} + +bool variantspecification_t::operator == (variantspecification_t const &other) const +{ + if(this == &other) return 1; + /// @todo We can be a bit cleverer here... + if(context != other.context) return 0; + if(flags != other.flags) return 0; + if(wrapS != other.wrapS || wrapT != other.wrapT) return 0; + //if(magFilter != b.magFilter) return 0; + //if(anisoFilter != b.anisoFilter) return 0; + if(mipmapped != other.mipmapped) return 0; + if(noStretch != other.noStretch) return 0; + if(gammaCorrection != other.gammaCorrection) return 0; + if(toAlpha != other.toAlpha) return 0; + if(border != other.border) return 0; + if(flags & TSF_HAS_COLORPALETTE_XLAT) + { + DENG2_ASSERT(!translated.isNull()); + colorpalettetranslationspecification_t const &cpt = *translated; + DENG2_ASSERT(other.translated.isNull()); + colorpalettetranslationspecification_t const &cptOther = *other.translated; + if(cpt.tClass != cptOther.tClass) return 0; + if(cpt.tMap != cptOther.tMap) return 0; + } + return 1; // Equal. +} + +GLint variantspecification_t::glMinFilter() const +{ + if(minFilter >= 0) // Constant logical value. + { + return (mipmapped? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST) + minFilter; + } + // "No class" preference. + return mipmapped? glmode[mipmapping] : GL_LINEAR; +} + +GLint variantspecification_t::glMagFilter() const +{ + if(magFilter >= 0) // Constant logical value. + { + return GL_NEAREST + magFilter; + } + + // Preference for texture class id. + switch(abs(magFilter)-1) + { + case 1: // Sprite class. + return filterSprites? GL_LINEAR : GL_NEAREST; + case 2: // UI class. + return filterUI? GL_LINEAR : GL_NEAREST; + default: // "No class" preference. + return glmode[texMagMode]; + } +} + +int variantspecification_t::logicalAnisoLevel() const +{ + return anisoFilter < 0? texAniso : anisoFilter; +} + +texturevariantspecification_t::texturevariantspecification_t(texturevariantspecificationtype_t type) + : type(type) +{} + +texturevariantspecification_t::texturevariantspecification_t(texturevariantspecification_t const &other) + : type(other.type) + , variant(other.variant) + , detailVariant(other.detailVariant) +{} + +bool detailvariantspecification_t::operator == (detailvariantspecification_t const &other) const +{ + if(this == &other) return true; + return contrast == other.contrast; // Equal. +} + +bool texturevariantspecification_t::operator == (texturevariantspecification_t const &other) const +{ + if(this == &other) return true; + if(type != other.type) return false; + switch(type) + { + case TST_GENERAL: return variant == other.variant; + case TST_DETAIL: return detailVariant == other.detailVariant; + } + DENG2_ASSERT(false); + return false; +} + static String nameForGLTextureWrapMode(int mode) { if(mode == GL_REPEAT) return "repeat"; @@ -73,14 +201,14 @@ String texturevariantspecification_t::asText() const switch(type) { case TST_DETAIL: { - detailvariantspecification_t const &spec = data.detailvariant; + detailvariantspecification_t const &spec = detailVariant; text += " Contrast:" + String::number(int(.5f + spec.contrast / 255.f * 100)) + "%"; break; } case TST_GENERAL: { - variantspecification_t const &spec = data.variant; + variantspecification_t const &spec = variant; texturevariantusagecontext_t tc = spec.context; - DENG_ASSERT(tc == TC_UNKNOWN || VALID_TEXTUREVARIANTUSAGECONTEXT(tc)); + DENG2_ASSERT(tc == TC_UNKNOWN || VALID_TEXTUREVARIANTUSAGECONTEXT(tc)); int glMinFilterNameIdx; if(spec.minFilter >= 0) // Constant logical value. @@ -129,10 +257,10 @@ String texturevariantspecification_t::asText() const if(spec.flags & TSF_HAS_COLORPALETTE_XLAT) { - colorpalettetranslationspecification_t const *cpt = spec.translated; - DENG_ASSERT(cpt); - text += " Translated:(tclass:" + String::number(cpt->tClass) - + " tmap:" + String::number(cpt->tMap) + ")"; + DENG2_ASSERT(!spec.translated.isNull()); + colorpalettetranslationspecification_t const &cpt = *spec.translated; + text += " Translated:(tclass:" + String::number(cpt.tClass) + + " tmap:" + String::number(cpt.tMap) + ")"; } break; } } @@ -140,91 +268,6 @@ String texturevariantspecification_t::asText() const return text; } -GLint variantspecification_t::glMinFilter() const -{ - if(minFilter >= 0) // Constant logical value. - { - return (mipmapped? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST) + minFilter; - } - // "No class" preference. - return mipmapped? glmode[mipmapping] : GL_LINEAR; -} - -GLint variantspecification_t::glMagFilter() const -{ - if(magFilter >= 0) // Constant logical value. - { - return GL_NEAREST + magFilter; - } - - // Preference for texture class id. - switch(abs(magFilter)-1) - { - case 1: // Sprite class. - return filterSprites? GL_LINEAR : GL_NEAREST; - case 2: // UI class. - return filterUI? GL_LINEAR : GL_NEAREST; - default: // "No class" preference. - return glmode[texMagMode]; - } -} - -int variantspecification_t::logicalAnisoLevel() const -{ - return anisoFilter < 0? texAniso : anisoFilter; -} - -/** - * @todo Magnification, Anisotropic filter level and GL texture wrap modes - * will be handled through dynamic changes to GL's texture environment state. - * Consequently they should be ignored here. - */ -static int compareVariantSpecifications(variantspecification_t const &a, - variantspecification_t const &b) -{ - /// @todo We can be a bit cleverer here... - if(a.context != b.context) return 0; - if(a.flags != b.flags) return 0; - if(a.wrapS != b.wrapS || a.wrapT != b.wrapT) return 0; - //if(a.magFilter != b.magFilter) return 0; - //if(a.anisoFilter != b.anisoFilter) return 0; - if(a.mipmapped != b.mipmapped) return 0; - if(a.noStretch != b.noStretch) return 0; - if(a.gammaCorrection != b.gammaCorrection) return 0; - if(a.toAlpha != b.toAlpha) return 0; - if(a.border != b.border) return 0; - if(a.flags & TSF_HAS_COLORPALETTE_XLAT) - { - colorpalettetranslationspecification_t const *cptA = a.translated; - colorpalettetranslationspecification_t const *cptB = b.translated; - DENG_ASSERT(cptA && cptB); - if(cptA->tClass != cptB->tClass) return 0; - if(cptA->tMap != cptB->tMap) return 0; - } - return 1; // Equal. -} - -static int compareDetailVariantSpecifications(detailvariantspecification_t const &a, - detailvariantspecification_t const &b) -{ - if(a.contrast != b.contrast) return 0; - return 1; // Equal. -} - -int TextureVariantSpec_Compare(texturevariantspecification_t const *a, - texturevariantspecification_t const *b) -{ - DENG_ASSERT(a && b); - if(a == b) return 1; - if(a->type != b->type) return 0; - switch(a->type) - { - case TST_GENERAL: return compareVariantSpecifications(TS_GENERAL(*a), TS_GENERAL(*b)); - case TST_DETAIL: return compareDetailVariantSpecifications(TS_DETAIL(*a), TS_DETAIL(*b)); - } - throw Error("TextureVariantSpec_Compare", QString("Invalid type %1").arg(a->type)); -} - DENG2_PIMPL(Texture::Variant) { /// Superior Texture of which this is a derivative. @@ -482,8 +525,8 @@ uint Texture::Variant::prepare() // Do we need to perform any image pixel data analyses? if(d->spec.type == TST_GENERAL) { - performImageAnalyses(image, TS_GENERAL(d->spec).context, - d->texture, true /*force update*/); + performImageAnalyses(image, d->spec.variant.context, d->texture, + true /*force update*/); } // Are we preparing a new GL texture?