LCOV - code coverage report
Current view: top level - source/lib/res/graphics - ogl_tex.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 2 343 0.6 %
Date: 2021-02-02 11:00:08 Functions: 1 35 2.9 %

          Line data    Source code
       1             : /* Copyright (C) 2019 Wildfire Games.
       2             :  *
       3             :  * Permission is hereby granted, free of charge, to any person obtaining
       4             :  * a copy of this software and associated documentation files (the
       5             :  * "Software"), to deal in the Software without restriction, including
       6             :  * without limitation the rights to use, copy, modify, merge, publish,
       7             :  * distribute, sublicense, and/or sell copies of the Software, and to
       8             :  * permit persons to whom the Software is furnished to do so, subject to
       9             :  * the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included
      12             :  * in all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      15             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      16             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      17             :  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      18             :  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      19             :  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      20             :  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      21             :  */
      22             : 
      23             : /*
      24             :  * wrapper for all OpenGL texturing calls. provides caching, hotloading
      25             :  * and lifetime management.
      26             :  */
      27             : 
      28             : #include "precompiled.h"
      29             : #include "ogl_tex.h"
      30             : 
      31             : #include <cstdio>
      32             : 
      33             : #include "lib/app_hooks.h"
      34             : #include "lib/ogl.h"
      35             : #include "lib/bits.h"
      36             : #include "lib/sysdep/gfx.h"
      37             : #include "lib/tex/tex.h"
      38             : 
      39             : #include "lib/res/h_mgr.h"
      40             : #include "lib/fnv_hash.h"
      41             : 
      42             : 
      43             : //----------------------------------------------------------------------------
      44             : // OpenGL helper routines
      45             : //----------------------------------------------------------------------------
      46             : 
      47             : static bool filter_valid(GLint filter)
      48             : {
      49           0 :     switch(filter)
      50             :     {
      51             :     case GL_NEAREST:
      52             :     case GL_LINEAR:
      53             :     case GL_NEAREST_MIPMAP_NEAREST:
      54             :     case GL_LINEAR_MIPMAP_NEAREST:
      55             :     case GL_NEAREST_MIPMAP_LINEAR:
      56             :     case GL_LINEAR_MIPMAP_LINEAR:
      57             :         return true;
      58           0 :     default:
      59           0 :         return false;
      60             :     }
      61             : }
      62             : 
      63             : 
      64             : static bool wrap_valid(GLint wrap)
      65             : {
      66           0 :     switch(wrap)
      67             :     {
      68             : #if !CONFIG2_GLES
      69             :     case GL_CLAMP:
      70             :     case GL_CLAMP_TO_BORDER:
      71             : #endif
      72             :     case GL_CLAMP_TO_EDGE:
      73             :     case GL_REPEAT:
      74             :     case GL_MIRRORED_REPEAT:
      75             :         return true;
      76           0 :     default:
      77           0 :         return false;
      78             :     }
      79             : }
      80             : 
      81             : 
      82             : static bool are_mipmaps_needed(size_t width, size_t height, GLint filter)
      83             : {
      84             :     // can't upload the entire texture; we're going to skip some
      85             :     // levels until it no longer exceeds the OpenGL dimension limit.
      86           0 :     if((GLint)width > ogl_max_tex_size || (GLint)height > ogl_max_tex_size)
      87             :         return true;
      88             : 
      89           0 :     switch(filter)
      90             :     {
      91             :     case GL_NEAREST_MIPMAP_NEAREST:
      92             :     case GL_LINEAR_MIPMAP_NEAREST:
      93             :     case GL_NEAREST_MIPMAP_LINEAR:
      94             :     case GL_LINEAR_MIPMAP_LINEAR:
      95             :         return true;
      96           0 :     default:
      97           0 :         return false;
      98             :     }
      99             : }
     100             : 
     101             : 
     102             : static bool fmt_is_s3tc(GLenum fmt)
     103             : {
     104           0 :     switch(fmt)
     105             :     {
     106             :     case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
     107             :     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
     108             :     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
     109             :     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
     110             :         return true;
     111           0 :     default:
     112           0 :         return false;
     113             :     }
     114             : }
     115             : 
     116             : 
     117             : // determine OpenGL texture format, given <bpp> and Tex <flags>.
     118           0 : static GLint choose_fmt(size_t bpp, size_t flags)
     119             : {
     120           0 :     const bool alpha = (flags & TEX_ALPHA) != 0;
     121           0 :     const bool bgr   = (flags & TEX_BGR  ) != 0;
     122           0 :     const bool grey  = (flags & TEX_GREY ) != 0;
     123           0 :     const size_t dxt   = flags & TEX_DXT;
     124             : 
     125             :     // S3TC
     126           0 :     if(dxt != 0)
     127             :     {
     128           0 :         switch(dxt)
     129             :         {
     130             :         case DXT1A:
     131             :             return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
     132           0 :         case 1:
     133           0 :             return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
     134           0 :         case 3:
     135           0 :             return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
     136           0 :         case 5:
     137           0 :             return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
     138           0 :         default:
     139           0 :             DEBUG_WARN_ERR(ERR::LOGIC); // invalid DXT value
     140           0 :             return 0;
     141             :         }
     142             :     }
     143             : 
     144             :     // uncompressed
     145           0 :     switch(bpp)
     146             :     {
     147           0 :     case 8:
     148           0 :         ENSURE(grey);
     149             :         return GL_LUMINANCE;
     150             :     case 16:
     151             :         return GL_LUMINANCE_ALPHA;
     152           0 :     case 24:
     153           0 :         ENSURE(!alpha);
     154             : #if CONFIG2_GLES
     155             :         // GLES never supports BGR
     156             :         ENSURE(!bgr);
     157             :         return GL_RGB;
     158             : #else
     159           0 :         return bgr? GL_BGR : GL_RGB;
     160             : #endif
     161           0 :     case 32:
     162           0 :         ENSURE(alpha);
     163             :         // GLES can support BGRA via GL_EXT_texture_format_BGRA8888
     164             :         // (TODO: can we rely on support for that extension?)
     165           0 :         return bgr? GL_BGRA_EXT : GL_RGBA;
     166           0 :     default:
     167           0 :         DEBUG_WARN_ERR(ERR::LOGIC); // invalid bpp
     168             :         return 0;
     169             :     }
     170             : 
     171             :     UNREACHABLE;
     172             : }
     173             : 
     174             : 
     175             : //----------------------------------------------------------------------------
     176             : // quality mechanism
     177             : //----------------------------------------------------------------------------
     178             : 
     179             : static GLint default_filter = GL_LINEAR;    // one of the GL *minify* filters
     180             : static int default_q_flags = OGL_TEX_FULL_QUALITY;  // OglTexQualityFlags
     181             : 
     182             : static bool q_flags_valid(int q_flags)
     183             : {
     184           0 :     const size_t bits = OGL_TEX_FULL_QUALITY|OGL_TEX_HALF_BPP|OGL_TEX_HALF_RES;
     185             :     // unrecognized bits are set - invalid
     186           0 :     if((q_flags & ~bits) != 0)
     187             :         return false;
     188             :     // "full quality" but other reduction bits are set - invalid
     189           0 :     if(q_flags & OGL_TEX_FULL_QUALITY && q_flags & ~OGL_TEX_FULL_QUALITY)
     190             :         return false;
     191             :     return true;
     192             : }
     193             : 
     194             : 
     195             : // change default settings - these affect performance vs. quality.
     196             : // may be overridden for individual textures via parameter to
     197             : // ogl_tex_upload or ogl_tex_set_filter, respectively.
     198             : //
     199             : // pass 0 to keep the current setting; defaults and legal values are:
     200             : // - q_flags: OGL_TEX_FULL_QUALITY; combination of OglTexQualityFlags
     201             : // - filter: GL_LINEAR; any valid OpenGL minification filter
     202           0 : void ogl_tex_set_defaults(int q_flags, GLint filter)
     203             : {
     204           0 :     if(q_flags)
     205             :     {
     206           0 :         ENSURE(q_flags_valid(q_flags));
     207           0 :         default_q_flags = q_flags;
     208             :     }
     209             : 
     210           0 :     if(filter)
     211             :     {
     212           0 :         ENSURE(filter_valid(filter));
     213           0 :         default_filter = filter;
     214             :     }
     215           0 : }
     216             : 
     217             : 
     218             : // choose an internal format for <fmt> based on the given q_flags.
     219           0 : static GLint choose_int_fmt(GLenum fmt, int q_flags)
     220             : {
     221             :     // true => 4 bits per component; otherwise, 8
     222           0 :     const bool half_bpp = (q_flags & OGL_TEX_HALF_BPP) != 0;
     223             : 
     224             :     // early-out for S3TC textures: they don't need an internal format
     225             :     // (because upload is via glCompressedTexImage2DARB), but we must avoid
     226             :     // triggering the default case below. we might as well return a
     227             :     // meaningful value (i.e. int_fmt = fmt).
     228           0 :     if(fmt_is_s3tc(fmt))
     229           0 :         return fmt;
     230             : 
     231             : #if CONFIG2_GLES
     232             : 
     233             :     UNUSED2(half_bpp);
     234             : 
     235             :     // GLES only supports internal format == external format
     236             :     return fmt;
     237             : 
     238             : #else
     239             : 
     240           0 :     switch(fmt)
     241             :     {
     242             :     // 8bpp
     243           0 :     case GL_LUMINANCE:
     244           0 :         return half_bpp? GL_LUMINANCE4 : GL_LUMINANCE8;
     245           0 :     case GL_INTENSITY:
     246           0 :         return half_bpp? GL_INTENSITY4 : GL_INTENSITY8;
     247           0 :     case GL_ALPHA:
     248           0 :         return half_bpp? GL_ALPHA4 : GL_ALPHA8;
     249             : 
     250             :     // 16bpp
     251           0 :     case GL_LUMINANCE_ALPHA:
     252           0 :         return half_bpp? GL_LUMINANCE4_ALPHA4 : GL_LUMINANCE8_ALPHA8;
     253             : 
     254             :     // 24bpp
     255           0 :     case GL_RGB:
     256           0 :     case GL_BGR:    // note: BGR can't be used as internal format
     257           0 :         return half_bpp? GL_RGB4 : GL_RGB8;
     258             : 
     259             :     // 32bpp
     260           0 :     case GL_RGBA:
     261           0 :     case GL_BGRA:   // note: BGRA can't be used as internal format
     262           0 :         return half_bpp? GL_RGBA4 : GL_RGBA8;
     263             : 
     264           0 :     default:
     265           0 :         {
     266           0 :         wchar_t buf[100];
     267           0 :         swprintf_s(buf, ARRAY_SIZE(buf), L"choose_int_fmt: fmt 0x%x isn't covered! please add it", fmt);
     268           0 :         DEBUG_DISPLAY_ERROR(buf);
     269           0 :         DEBUG_WARN_ERR(ERR::LOGIC); // given fmt isn't covered! please add it.
     270             :         // fall back to a reasonable default
     271           0 :         return half_bpp? GL_RGB4 : GL_RGB8;
     272             :         }
     273             :     }
     274             : 
     275             :     UNREACHABLE;
     276             : 
     277             : #endif  // #if CONFIG2_GLES
     278             : }
     279             : 
     280             : 
     281             : //----------------------------------------------------------------------------
     282             : // texture state to allow seamless reload
     283             : //----------------------------------------------------------------------------
     284             : 
     285             : // see "Texture Parameters" in docs.
     286             : 
     287             : // all GL state tied to the texture that must be reapplied after reload.
     288             : // (this mustn't get too big, as it's stored in the already sizeable OglTex)
     289             : struct OglTexState
     290             : {
     291             :     // glTexParameter
     292             :     // note: there are more options, but they do not look to
     293             :     //       be important and will not be applied after a reload!
     294             :     //       in particular, LOD_BIAS isn't needed because that is set for
     295             :     //       the entire texturing unit via glTexEnv.
     296             :     // .. texture filter
     297             :     //    note: this is the minification filter value; magnification filter
     298             :     //          is GL_NEAREST if it's GL_NEAREST, otherwise GL_LINEAR.
     299             :     //          we don't store mag_filter explicitly because it
     300             :     //          doesn't appear useful - either apps can tolerate LINEAR, or
     301             :     //          mipmaps aren't called for and filter could be NEAREST anyway).
     302             :     GLint filter;
     303             :     // .. wrap mode
     304             :     GLint wrap_s;
     305             :     GLint wrap_t;
     306             :     // .. anisotropy
     307             :     //    note: ignored unless EXT_texture_filter_anisotropic is supported.
     308             :     GLfloat anisotropy;
     309             : };
     310             : 
     311             : 
     312             : // fill the given state object with default values.
     313             : static void state_set_to_defaults(OglTexState* ots)
     314             : {
     315           0 :     ots->filter = default_filter;
     316           0 :     ots->wrap_s = GL_REPEAT;
     317           0 :     ots->wrap_t = GL_REPEAT;
     318           0 :     ots->anisotropy = 1.0f;
     319             : }
     320             : 
     321             : 
     322             : // send all state to OpenGL (actually the currently bound texture).
     323             : // called from ogl_tex_upload.
     324           0 : static void state_latch(OglTexState* ots)
     325             : {
     326             :     // filter
     327           0 :     const GLint filter = ots->filter;
     328           0 :     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
     329           0 :     const GLint mag_filter = (filter == GL_NEAREST)? GL_NEAREST : GL_LINEAR;
     330           0 :     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
     331             : 
     332             :     // wrap
     333           0 :     const GLint wrap_s = ots->wrap_s;
     334           0 :     const GLint wrap_t = ots->wrap_t;
     335           0 :     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
     336           0 :     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
     337             :     // .. only CLAMP and REPEAT are guaranteed to be available.
     338             :     //    if we're using one of the others, we squelch the error that
     339             :     //    may have resulted if this GL implementation is old.
     340             : #if !CONFIG2_GLES
     341           0 :     if((wrap_s != GL_CLAMP && wrap_s != GL_REPEAT) || (wrap_t != GL_CLAMP && wrap_t != GL_REPEAT))
     342           0 :         ogl_SquelchError(GL_INVALID_ENUM);
     343             : #endif
     344             : 
     345             :     // anisotropy
     346           0 :     const GLfloat anisotropy = ots->anisotropy;
     347           0 :     if (anisotropy != 1.0f && ogl_tex_has_anisotropy())
     348             :     {
     349           0 :         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
     350             :     }
     351           0 : }
     352             : 
     353             : 
     354             : //----------------------------------------------------------------------------
     355             : // texture resource object
     356             : //----------------------------------------------------------------------------
     357             : 
     358             : // ideally we would split OglTex into data and state objects as in
     359             : // SndData / VSrc. this gives us the benefits of caching while still
     360             : // leaving each "instance" (state object, which owns a data reference)
     361             : // free to change its state. however, unlike in OpenAL, there is no state
     362             : // independent of the data object - all parameters are directly tied to the
     363             : // GL texture object. therefore, splitting them up is impossible.
     364             : // (we shouldn't even keep the texel data in memory since that's already
     365             : // covered by the FS cache).
     366             : //
     367             : // given that multiple "instances" share the state stored here, we conclude:
     368             : // - a refcount is necessary to prevent ogl_tex_upload from freeing
     369             : //   <t> as long as other instances are active.
     370             : // - concurrent use risks cross-talk (if the 2nd "instance" changes state and
     371             : //   the first is reloaded, its state may change to that of the 2nd)
     372             : //
     373             : // as bad as it sounds, the latter issue isn't a problem: we do not expect
     374             : // multiple instances of the same texture where someone changes its filter.
     375             : // even if it is reloaded, the differing state is not critical.
     376             : // the alternative is even worse: disabling *all* caching/reuse would
     377             : // really hurt performance and h_mgr doesn't support only disallowing
     378             : // reuse of active objects (this would break the index lookup code, since
     379             : // multiple instances may then exist).
     380             : 
     381             : // note: make sure these values fit inside OglTex.flags (only 16 bits)
     382             : enum OglTexFlags
     383             : {
     384             :     // "the texture is currently uploaded"; reset in dtor.
     385             :     OT_IS_UPLOADED = 1,
     386             : 
     387             :     // "the enclosed Tex object is valid and holds a texture";
     388             :     // reset in dtor and after ogl_tex_upload's tex_free.
     389             :     OT_TEX_VALID = 2,
     390             :     //size_t tex_valid : 1;
     391             : 
     392             :     // "reload() should automatically re-upload the texture" (because
     393             :     // it had been uploaded before the reload); never reset.
     394             :     OT_NEED_AUTO_UPLOAD = 4,
     395             : 
     396             :     // (used for validating flags)
     397             :     OT_ALL_FLAGS = OT_IS_UPLOADED|OT_TEX_VALID|OT_NEED_AUTO_UPLOAD
     398             : };
     399             : 
     400             : struct OglTex
     401             : {
     402             :     Tex t;
     403             : 
     404             :     // allocated by OglTex_reload; indicates the texture is currently uploaded.
     405             :     GLuint id;
     406             : 
     407             :     // ogl_tex_upload calls choose_fmt to determine these from <t>.
     408             :     // however, its caller may override those values via parameters.
     409             :     // note: these are stored here to allow retrieving via ogl_tex_get_format;
     410             :     // they are only used within ogl_tex_upload.
     411             :     GLenum fmt;
     412             :     GLint int_fmt;
     413             : 
     414             :     OglTexState state;
     415             : 
     416             :     // OglTexQualityFlags
     417             :     u8 q_flags;
     418             : 
     419             :     // to which Texture Mapping Unit was this bound?
     420             :     u8 tmu;
     421             : 
     422             :     u16 flags;
     423             : 
     424             :     u32 uploaded_size;
     425             : };
     426             : 
     427             : H_TYPE_DEFINE(OglTex);
     428             : 
     429           0 : static void OglTex_init(OglTex* ot, va_list args)
     430             : {
     431           0 :     Tex* wrapped_tex = va_arg(args, Tex*);
     432           0 :     if(wrapped_tex)
     433             :     {
     434           0 :         ot->t = *wrapped_tex;
     435             :         // indicate ot->t is now valid, thus skipping loading from file.
     436             :         // note: ogl_tex_wrap prevents actual reloads from happening.
     437           0 :         ot->flags |= OT_TEX_VALID;
     438             :     }
     439             : 
     440           0 :     state_set_to_defaults(&ot->state);
     441           0 :     ot->q_flags = default_q_flags;
     442           0 : }
     443             : 
     444           0 : static void OglTex_dtor(OglTex* ot)
     445             : {
     446           0 :     if(ot->flags & OT_TEX_VALID)
     447             :     {
     448           0 :         ot->t.free();
     449           0 :         ot->flags &= ~OT_TEX_VALID;
     450             :     }
     451             : 
     452             :     // note: do not check if OT_IS_UPLOADED is set, because we allocate
     453             :     // OglTex.id without necessarily having done an upload.
     454           0 :     glDeleteTextures(1, &ot->id);
     455           0 :     ot->id = 0;
     456           0 :     ot->flags &= ~OT_IS_UPLOADED;
     457           0 :     ot->uploaded_size = 0;
     458           0 : }
     459             : 
     460           0 : static Status OglTex_reload(OglTex* ot, const PIVFS& vfs, const VfsPath& pathname, Handle h)
     461             : {
     462             :     // we're reusing a freed but still in-memory OglTex object
     463           0 :     if(ot->flags & OT_IS_UPLOADED)
     464             :         return INFO::OK;
     465             : 
     466             :     // if we don't already have the texture in memory (*), load from file.
     467             :     // * this happens if the texture is "wrapped".
     468           0 :     if(!(ot->flags & OT_TEX_VALID))
     469             :     {
     470           0 :         shared_ptr<u8> file; size_t fileSize;
     471           0 :         RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, file, fileSize));
     472           0 :         if(ot->t.decode(file, fileSize) >= 0)
     473           0 :             ot->flags |= OT_TEX_VALID;
     474             :     }
     475             : 
     476           0 :     glGenTextures(1, &ot->id);
     477             : 
     478             :     // if it had already been uploaded before this reload,
     479             :     // re-upload it (this also does state_latch).
     480           0 :     if(ot->flags & OT_NEED_AUTO_UPLOAD)
     481           0 :         (void)ogl_tex_upload(h);
     482             : 
     483             :     return INFO::OK;
     484             : }
     485             : 
     486           0 : static Status OglTex_validate(const OglTex* ot)
     487             : {
     488           0 :     if(ot->flags & OT_TEX_VALID)
     489             :     {
     490           0 :         RETURN_STATUS_IF_ERR(ot->t.validate());
     491             : 
     492             :         // width, height
     493             :         // (note: this is done here because tex.cpp doesn't impose any
     494             :         // restrictions on dimensions, while OpenGL does).
     495           0 :         size_t w = ot->t.m_Width;
     496           0 :         size_t h = ot->t.m_Height;
     497             :         // .. == 0; texture file probably not loaded successfully.
     498           0 :         if(w == 0 || h == 0)
     499           0 :             WARN_RETURN(ERR::_11);
     500             :         // .. not power-of-2.
     501             :         //    note: we can't work around this because both NV_texture_rectangle
     502             :         //    and subtexture require work for the client (changing tex coords).
     503             :         //    TODO: ARB_texture_non_power_of_two
     504           0 :         if(!is_pow2(w) || !is_pow2(h))
     505           0 :             WARN_RETURN(ERR::_13);
     506             : 
     507             :         // no longer verify dimensions are less than ogl_max_tex_size,
     508             :         // because we just use the higher mip levels in that case.
     509             :     }
     510             : 
     511             :     // texture state
     512           0 :     if(!filter_valid(ot->state.filter))
     513           0 :         WARN_RETURN(ERR::_14);
     514           0 :     if(!wrap_valid(ot->state.wrap_s))
     515           0 :         WARN_RETURN(ERR::_15);
     516           0 :     if(!wrap_valid(ot->state.wrap_t))
     517           0 :         WARN_RETURN(ERR::_16);
     518             : 
     519             :     // misc
     520           0 :     if(!q_flags_valid(ot->q_flags))
     521           0 :         WARN_RETURN(ERR::_17);
     522           0 :     if(ot->tmu >= 128)    // unexpected that there will ever be this many
     523           0 :         WARN_RETURN(ERR::_18);
     524           0 :     if(ot->flags > OT_ALL_FLAGS)
     525           0 :         WARN_RETURN(ERR::_19);
     526             :     // .. note: don't check ot->fmt and ot->int_fmt - they aren't set
     527             :     //    until during ogl_tex_upload.
     528             : 
     529             :     return INFO::OK;
     530             : }
     531             : 
     532           0 : static Status OglTex_to_string(const OglTex* ot, wchar_t* buf)
     533             : {
     534           0 :     swprintf_s(buf, H_STRING_LEN, L"OglTex id=%u flags=%x", ot->id, (unsigned int)ot->flags);
     535           0 :     return INFO::OK;
     536             : }
     537             : 
     538             : 
     539             : // load and return a handle to the texture given in <pathname>.
     540             : // for a list of supported formats, see tex.h's tex_load.
     541           0 : Handle ogl_tex_load(const PIVFS& vfs, const VfsPath& pathname, size_t flags)
     542             : {
     543           0 :     Tex* wrapped_tex = 0;   // we're loading from file
     544           0 :     return h_alloc(H_OglTex, vfs, pathname, flags, wrapped_tex);
     545             : }
     546             : 
     547             : 
     548             : // return Handle to an existing object, if it has been loaded and
     549             : // is still in memory; otherwise, a negative error code.
     550           0 : Handle ogl_tex_find(const VfsPath& pathname)
     551             : {
     552           0 :     const uintptr_t key = fnv_hash(pathname.string().c_str(), pathname.string().length()*sizeof(pathname.string()[0]));
     553           0 :     return h_find(H_OglTex, key);
     554             : }
     555             : 
     556             : 
     557             : // make the given Tex object ready for use as an OpenGL texture
     558             : // and return a handle to it. this will be as if its contents
     559             : // had been loaded by ogl_tex_load.
     560             : //
     561             : // we need only add bookkeeping information and "wrap" it in
     562             : // a resource object (accessed via Handle), hence the name.
     563             : //
     564             : // <fn> isn't strictly needed but should describe the texture so that
     565             : // h_filename will return a meaningful comment for debug purposes.
     566             : // note: because we cannot guarantee that callers will pass distinct
     567             : // "filenames", caching is disabled for the created object. this avoids
     568             : // mistakenly reusing previous objects that share the same comment.
     569           0 : Handle ogl_tex_wrap(Tex* t, const PIVFS& vfs, const VfsPath& pathname, size_t flags)
     570             : {
     571             :     // this object may not be backed by a file ("may", because
     572             :     // someone could do tex_load and then ogl_tex_wrap).
     573             :     // if h_mgr asks for a reload, the dtor will be called but
     574             :     // we won't be able to reconstruct it. therefore, disallow reloads.
     575             :     // (they are improbable anyway since caller is supposed to pass a
     576             :     // 'descriptive comment' instead of filename, but don't rely on that)
     577             :     // also disable caching as explained above.
     578           0 :     flags |= RES_DISALLOW_RELOAD|RES_NO_CACHE;
     579           0 :     return h_alloc(H_OglTex, vfs, pathname, flags, t);
     580             : }
     581             : 
     582             : 
     583             : // free all resources associated with the texture and make further
     584             : // use of it impossible. (subject to refcount)
     585           6 : Status ogl_tex_free(Handle& ht)
     586             : {
     587           6 :     return h_free(ht, H_OglTex);
     588             : }
     589             : 
     590             : 
     591             : //----------------------------------------------------------------------------
     592             : // state setters (see "Texture Parameters" in docs)
     593             : //----------------------------------------------------------------------------
     594             : 
     595             : // we require the below functions be called before uploading; this avoids
     596             : // potentially redundant glTexParameter calls (we'd otherwise need to always
     597             : // set defaults because we don't know if an override is forthcoming).
     598             : 
     599             : // raise a debug warning if the texture has already been uploaded
     600             : // (except in the few cases where this is allowed; see below).
     601             : // this is so that you will notice incorrect usage - only one instance of a
     602             : // texture should be active at a time, because otherwise they vie for
     603             : // control of one shared OglTexState.
     604           0 : static void warn_if_uploaded(Handle ht, const OglTex* ot)
     605             : {
     606             : #ifndef NDEBUG
     607             :     // we do not require users of this module to remember if they've
     608             :     // already uploaded a texture (inconvenient). since they also can't
     609             :     // tell if the texture was newly loaded (due to h_alloc interface),
     610             :     // we have to squelch this warning in 2 cases:
     611             :     // - it's ogl_tex_loaded several times (i.e. refcount > 1) and the
     612             :     //   caller (typically a higher-level LoadTexture) is setting filter etc.
     613             :     // - caller is using our Handle as a caching mechanism, and calls
     614             :     //   ogl_tex_set_* before every use of the texture. note: this
     615             :     //   need not fall under the above check, e.g. if freed but cached.
     616             :     //   workaround is that ogl_tex_set_* won't call us if the
     617             :     //   same state values are being set (harmless anyway).
     618             :     intptr_t refs = h_get_refcnt(ht);
     619             :     if(refs > 1)
     620             :         return; // don't complain
     621             : 
     622             :     if(ot->flags & OT_IS_UPLOADED)
     623             :         DEBUG_WARN_ERR(ERR::LOGIC); // ogl_tex_set_*: texture already uploaded and shouldn't be changed
     624             : #else
     625             :     // (prevent warnings; the alternative of wrapping all call sites in
     626             :     // #ifndef is worse)
     627           0 :     UNUSED2(ht);
     628           0 :     UNUSED2(ot);
     629             : #endif
     630           0 : }
     631             : 
     632             : 
     633             : // override default filter (as set above) for this texture.
     634             : // must be called before uploading (raises a warning if called afterwards).
     635             : // filter is as defined by OpenGL; it is applied for both minification and
     636             : // magnification (for rationale and details, see OglTexState)
     637           0 : Status ogl_tex_set_filter(Handle ht, GLint filter)
     638             : {
     639           0 :     H_DEREF(ht, OglTex, ot);
     640             : 
     641           0 :     if(!filter_valid(filter))
     642           0 :         WARN_RETURN(ERR::INVALID_PARAM);
     643             : 
     644           0 :     if(ot->state.filter != filter)
     645             :     {
     646           0 :         warn_if_uploaded(ht, ot);
     647           0 :         ot->state.filter = filter;
     648             :     }
     649             :     return INFO::OK;
     650             : }
     651             : 
     652             : 
     653             : // override default wrap mode (GL_REPEAT) for this texture.
     654             : // must be called before uploading (raises a warning if called afterwards).
     655             : // wrap is as defined by OpenGL.
     656           0 : Status ogl_tex_set_wrap(Handle ht, GLint wrap_s, GLint wrap_t)
     657             : {
     658           0 :     H_DEREF(ht, OglTex, ot);
     659             : 
     660           0 :     if(!wrap_valid(wrap_s))
     661           0 :         WARN_RETURN(ERR::INVALID_PARAM);
     662             : 
     663           0 :     if(!wrap_valid(wrap_t))
     664           0 :         WARN_RETURN(ERR::INVALID_PARAM);
     665             : 
     666           0 :     if(ot->state.wrap_s != wrap_s || ot->state.wrap_t != wrap_t)
     667             :     {
     668           0 :         warn_if_uploaded(ht, ot);
     669           0 :         ot->state.wrap_s = wrap_s;
     670           0 :         ot->state.wrap_t = wrap_t;
     671             :     }
     672             :     return INFO::OK;
     673             : }
     674             : 
     675             : 
     676             : // override default anisotropy for this texture.
     677             : // must be called before uploading (raises a warning if called afterwards).
     678           0 : Status ogl_tex_set_anisotropy(Handle ht, GLfloat anisotropy)
     679             : {
     680           0 :     H_DEREF(ht, OglTex, ot);
     681             : 
     682           0 :     if(anisotropy < 1.0f)
     683           0 :         WARN_RETURN(ERR::INVALID_PARAM);
     684             : 
     685           0 :     if(ot->state.anisotropy != anisotropy)
     686             :     {
     687           0 :         warn_if_uploaded(ht, ot);
     688           0 :         ot->state.anisotropy = anisotropy;
     689             :     }
     690             :     return INFO::OK;
     691             : }
     692             : 
     693             : 
     694             : //----------------------------------------------------------------------------
     695             : // upload
     696             : //----------------------------------------------------------------------------
     697             : 
     698             : // OpenGL has several features that are helpful for uploading but not
     699             : // available in all implementations. we check for their presence but
     700             : // provide for user override (in case they don't work on a card/driver
     701             : // combo we didn't test).
     702             : 
     703             : // tristate; -1 is undecided
     704             : static int have_auto_mipmap_gen = -1;
     705             : static int have_s3tc = -1;
     706             : static int have_anistropy = -1;
     707             : 
     708             : // override the default decision and force/disallow use of the
     709             : // given feature. should be called from ah_override_gl_upload_caps.
     710           0 : void ogl_tex_override(OglTexOverrides what, OglTexAllow allow)
     711             : {
     712           0 :     ENSURE(allow == OGL_TEX_ENABLE || allow == OGL_TEX_DISABLE);
     713           0 :     const bool enable = (allow == OGL_TEX_ENABLE);
     714             : 
     715           0 :     switch(what)
     716             :     {
     717           0 :     case OGL_TEX_S3TC:
     718           0 :         have_s3tc = enable;
     719           0 :         break;
     720           0 :     case OGL_TEX_AUTO_MIPMAP_GEN:
     721           0 :         have_auto_mipmap_gen = enable;
     722           0 :         break;
     723           0 :     case OGL_TEX_ANISOTROPY:
     724           0 :         have_anistropy = enable;
     725           0 :         break;
     726           0 :     default:
     727           0 :         DEBUG_WARN_ERR(ERR::LOGIC); // invalid <what>
     728             :         break;
     729             :     }
     730           0 : }
     731             : 
     732             : 
     733             : // detect caps (via OpenGL extension list) and give an app_hook the chance to
     734             : // override this (e.g. via list of card/driver combos on which S3TC breaks).
     735             : // called once from the first ogl_tex_upload.
     736           0 : static void detect_gl_upload_caps()
     737             : {
     738             :     // note: gfx_card will be empty if running in quickstart mode;
     739             :     // in that case, we won't be able to check for known faulty cards.
     740             : 
     741             :     // detect features, but only change the variables if they were at
     742             :     // "undecided" (if overrides were set before this, they must remain).
     743           0 :     if(have_auto_mipmap_gen == -1)
     744             :     {
     745           0 :         have_auto_mipmap_gen = ogl_HaveExtension("GL_SGIS_generate_mipmap");
     746             :     }
     747           0 :     if(have_s3tc == -1)
     748             :     {
     749             : #if CONFIG2_GLES
     750             :         // some GLES implementations have GL_EXT_texture_compression_dxt1
     751             :         // but that only supports DXT1 so we can't use it.
     752             :         have_s3tc = ogl_HaveExtensions(0, "GL_EXT_texture_compression_s3tc", NULL) == 0;
     753             : #else
     754             :         // note: we don't bother checking for GL_S3_s3tc - it is incompatible
     755             :         // and irrelevant (was never widespread).
     756           0 :         have_s3tc = ogl_HaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", NULL) == 0;
     757             : #endif
     758             :     }
     759           0 :     if(have_anistropy == -1)
     760             :     {
     761           0 :         have_anistropy = ogl_HaveExtension("GL_EXT_texture_filter_anisotropic");
     762             :     }
     763             : 
     764             :     // allow app hook to make ogl_tex_override calls
     765           0 :     if(AH_IS_DEFINED(override_gl_upload_caps))
     766             :     {
     767           0 :         ah_override_gl_upload_caps();
     768             :     }
     769             :     // no app hook defined - have our own crack at blacklisting some hardware.
     770             :     else
     771             :     {
     772           0 :         const std::wstring cardName = gfx::CardName();
     773             :         // rationale: janwas's laptop's S3 card blows up if S3TC is used
     774             :         // (oh, the irony). it'd be annoying to have to share this between all
     775             :         // projects, hence this default implementation here.
     776           0 :         if(cardName == L"S3 SuperSavage/IXC 1014")
     777           0 :             ogl_tex_override(OGL_TEX_S3TC, OGL_TEX_DISABLE);
     778             :     }
     779           0 : }
     780             : 
     781             : 
     782             : // take care of mipmaps. if they are called for by <filter>, either
     783             : // arrange for OpenGL to create them, or see to it that the Tex object
     784             : // contains them (if need be, creating them in software).
     785             : // sets *plevels_to_skip to influence upload behavior (depending on
     786             : // whether mipmaps are needed and the quality settings).
     787             : // returns 0 to indicate success; otherwise, caller must disable
     788             : // mipmapping by switching filter to e.g. GL_LINEAR.
     789           0 : static Status get_mipmaps(Tex* t, GLint filter, int q_flags, int* plevels_to_skip)
     790             : {
     791             :     // decisions:
     792             :     // .. does filter call for uploading mipmaps?
     793           0 :     const bool need_mipmaps = are_mipmaps_needed(t->m_Width, t->m_Height, filter);
     794             :     // .. does the image data include mipmaps? (stored as separate
     795             :     //    images after the regular texels)
     796           0 :     const bool includes_mipmaps = (t->m_Flags & TEX_MIPMAPS) != 0;
     797             :     // .. is this texture in S3TC format? (more generally, "compressed")
     798           0 :     const bool is_s3tc = (t->m_Flags & TEX_DXT) != 0;
     799             : 
     800           0 :     *plevels_to_skip = TEX_BASE_LEVEL_ONLY;
     801           0 :     if(!need_mipmaps)
     802             :         return INFO::OK;
     803             : 
     804             :     // image already contains pregenerated mipmaps; we need do nothing.
     805             :     // this is the nicest case, because they are fastest to load
     806             :     // (no extra processing needed) and typically filtered better than
     807             :     // if automatically generated.
     808           0 :     if(includes_mipmaps)
     809           0 :         *plevels_to_skip = 0;   // t contains mipmaps
     810             :     // OpenGL supports automatic generation; we need only
     811             :     // activate that and upload the base image.
     812             : #if !CONFIG2_GLES
     813           0 :     else if(have_auto_mipmap_gen)
     814             :     {
     815             :         // note: we assume GL_GENERATE_MIPMAP and GL_GENERATE_MIPMAP_SGIS
     816             :         // have the same values - it's heavily implied by the spec
     817             :         // governing 'promoted' ARB extensions and just plain makes sense.
     818           0 :         glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
     819             :     }
     820             : #endif
     821             :     // image is S3TC-compressed and the previous 2 alternatives weren't
     822             :     // available; we're going to cheat and just disable mipmapping.
     823             :     // rationale: having tex_transform add mipmaps would be slow (since
     824             :     // all<->all transforms aren't implemented, it'd have to decompress
     825             :     // from S3TC first), and DDS images ought to include mipmaps!
     826           0 :     else if(is_s3tc)
     827             :         return ERR::FAIL;   // NOWARN
     828             :     // image is uncompressed and we're on an old OpenGL implementation;
     829             :     // we will generate mipmaps in software.
     830             :     else
     831             :     {
     832           0 :         RETURN_STATUS_IF_ERR(t->transform_to(t->m_Flags|TEX_MIPMAPS));
     833           0 :         *plevels_to_skip = 0;   // t contains mipmaps
     834             :     }
     835             : 
     836             :     // t contains mipmaps; we can apply our resolution reduction trick:
     837           0 :     if(*plevels_to_skip == 0)
     838             :     {
     839             :         // if OpenGL's texture dimension limit is too small, use the
     840             :         // higher mipmap levels. NB: the minimum guaranteed size is
     841             :         // far too low, and menu background textures may be large.
     842           0 :         GLint w = (GLint)t->m_Width, h = (GLint)t->m_Height;
     843           0 :         while(w > ogl_max_tex_size || h > ogl_max_tex_size)
     844             :         {
     845           0 :             (*plevels_to_skip)++;
     846           0 :             w /= 2; h /= 2; // doesn't matter if either dimension drops to 0
     847             :         }
     848             : 
     849             :         // this saves texture memory by skipping some of the lower
     850             :         // (high-resolution) mip levels.
     851             :         //
     852             :         // note: we don't just use GL_TEXTURE_BASE_LEVEL because it would
     853             :         // require uploading unused levels, which is wasteful.
     854             :         // .. can be expanded to reduce to 1/4, 1/8 by encoding factor in q_flags.
     855           0 :         if(q_flags & OGL_TEX_HALF_RES)
     856           0 :             (*plevels_to_skip)++;
     857             :     }
     858             : 
     859             :     return INFO::OK;
     860             : }
     861             : 
     862             : 
     863             : // tex_util_foreach_mipmap callbacks: upload the given level to OpenGL.
     864             : 
     865             : struct UploadParams
     866             : {
     867             :     GLenum fmt;
     868             :     GLint int_fmt;
     869             :     u32* uploaded_size;
     870             : };
     871             : 
     872           0 : static void upload_level(size_t level, size_t level_w, size_t level_h, const u8* RESTRICT level_data, size_t level_data_size, void* RESTRICT cbData)
     873             : {
     874           0 :     const UploadParams* up = (const UploadParams*)cbData;
     875           0 :     glTexImage2D(GL_TEXTURE_2D, (GLint)level, up->int_fmt, (GLsizei)level_w, (GLsizei)level_h, 0, up->fmt, GL_UNSIGNED_BYTE, level_data);
     876           0 :     *up->uploaded_size += (u32)level_data_size;
     877           0 : }
     878             : 
     879           0 : static void upload_compressed_level(size_t level, size_t level_w, size_t level_h, const u8* RESTRICT level_data, size_t level_data_size, void* RESTRICT cbData)
     880             : {
     881           0 :     const UploadParams* up = (const UploadParams*)cbData;
     882           0 :     pglCompressedTexImage2DARB(GL_TEXTURE_2D, (GLint)level, up->fmt, (GLsizei)level_w, (GLsizei)level_h, 0, (GLsizei)level_data_size, level_data);
     883           0 :     *up->uploaded_size += (u32)level_data_size;
     884           0 : }
     885             : 
     886             : // upload the texture in the specified (internal) format.
     887             : // split out of ogl_tex_upload because it was too big.
     888             : //
     889             : // pre: <t> is valid for OpenGL use; texture is bound.
     890           0 : static void upload_impl(Tex* t, GLenum fmt, GLint int_fmt, int levels_to_skip, u32* uploaded_size)
     891             : {
     892           0 :     const GLsizei w  = (GLsizei)t->m_Width;
     893           0 :     const GLsizei h  = (GLsizei)t->m_Height;
     894           0 :     const size_t bpp   = t->m_Bpp;
     895           0 :     const u8* data = (const u8*)t->get_data();
     896           0 :     const UploadParams up = { fmt, int_fmt, uploaded_size };
     897             : 
     898           0 :     if(t->m_Flags & TEX_DXT)
     899           0 :         tex_util_foreach_mipmap(w, h, bpp, data, levels_to_skip, 4, upload_compressed_level, (void*)&up);
     900             :     else
     901           0 :         tex_util_foreach_mipmap(w, h, bpp, data, levels_to_skip, 1, upload_level, (void*)&up);
     902           0 : }
     903             : 
     904             : 
     905             : // upload the texture to OpenGL.
     906             : // if not 0, parameters override the following:
     907             : //   fmt_ovr     : OpenGL format (e.g. GL_RGB) decided from bpp / Tex flags;
     908             : //   q_flags_ovr : global default "quality vs. performance" flags;
     909             : //   int_fmt_ovr : internal format (e.g. GL_RGB8) decided from fmt / q_flags.
     910             : //
     911             : // side effects:
     912             : // - enables texturing on TMU 0 and binds the texture to it;
     913             : // - frees the texel data! see ogl_tex_get_data.
     914           0 : Status ogl_tex_upload(const Handle ht, GLenum fmt_ovr, int q_flags_ovr, GLint int_fmt_ovr)
     915             : {
     916           0 :     ONCE(detect_gl_upload_caps());
     917             : 
     918           0 :     H_DEREF(ht, OglTex, ot);
     919           0 :     Tex* t = &ot->t;
     920           0 :     ENSURE(q_flags_valid(q_flags_ovr));
     921             :     // we don't bother verifying *fmt_ovr - there are too many values
     922             : 
     923             :     // upload already happened; no work to do.
     924             :     // (this also happens if a cached texture is "loaded")
     925           0 :     if(ot->flags & OT_IS_UPLOADED)
     926             :         return INFO::OK;
     927             : 
     928           0 :     if(ot->flags & OT_TEX_VALID)
     929             :     {
     930             :         // decompress S3TC if that's not supported by OpenGL.
     931           0 :         if((t->m_Flags & TEX_DXT) && !have_s3tc)
     932           0 :             (void)t->transform_to(t->m_Flags & ~TEX_DXT);
     933             : 
     934             :         // determine fmt and int_fmt, allowing for user override.
     935           0 :         ot->fmt = choose_fmt(t->m_Bpp, t->m_Flags);
     936           0 :         if(fmt_ovr) ot->fmt = fmt_ovr;
     937           0 :         if(q_flags_ovr) ot->q_flags = q_flags_ovr;
     938           0 :         ot->int_fmt = choose_int_fmt(ot->fmt, ot->q_flags);
     939           0 :         if(int_fmt_ovr) ot->int_fmt = int_fmt_ovr;
     940             : 
     941           0 :         ot->uploaded_size = 0;
     942             : 
     943             :         // now actually send to OpenGL:
     944           0 :         ogl_WarnIfError();
     945           0 :         {
     946             :             // (note: we know ht is valid due to H_DEREF, but ogl_tex_bind can
     947             :             // fail in debug builds if OglTex.id isn't a valid texture name)
     948           0 :             RETURN_STATUS_IF_ERR(ogl_tex_bind(ht, ot->tmu));
     949           0 :             int levels_to_skip;
     950           0 :             if(get_mipmaps(t, ot->state.filter, ot->q_flags, &levels_to_skip) < 0)
     951             :                 // error => disable mipmapping
     952           0 :                 ot->state.filter = GL_LINEAR;
     953             :             // (note: if first time, applies our defaults/previous overrides;
     954             :             // otherwise, replays all state changes)
     955           0 :             state_latch(&ot->state);
     956           0 :             upload_impl(t, ot->fmt, ot->int_fmt, levels_to_skip, &ot->uploaded_size);
     957             :         }
     958           0 :         ogl_WarnIfError();
     959             : 
     960           0 :         ot->flags |= OT_IS_UPLOADED;
     961             : 
     962             :         // see rationale for <refs> at declaration of OglTex.
     963           0 :         intptr_t refs = h_get_refcnt(ht);
     964           0 :         if(refs == 1)
     965             :         {
     966             :             // note: we verify above that OT_TEX_VALID is set
     967           0 :             ot->flags &= ~OT_TEX_VALID;
     968             :         }
     969             :     }
     970             : 
     971           0 :     ot->flags |= OT_NEED_AUTO_UPLOAD;
     972             : 
     973           0 :     return INFO::OK;
     974             : }
     975             : 
     976             : 
     977             : //----------------------------------------------------------------------------
     978             : // getters
     979             : //----------------------------------------------------------------------------
     980             : 
     981             : // retrieve texture dimensions and bits per pixel.
     982             : // all params are optional and filled if non-NULL.
     983           0 : Status ogl_tex_get_size(Handle ht, size_t* w, size_t* h, size_t* bpp)
     984             : {
     985           0 :     H_DEREF(ht, OglTex, ot);
     986             : 
     987           0 :     if(w)
     988           0 :         *w = ot->t.m_Width;
     989           0 :     if(h)
     990           0 :         *h = ot->t.m_Height;
     991           0 :     if(bpp)
     992           0 :         *bpp = ot->t.m_Bpp;
     993             :     return INFO::OK;
     994             : }
     995             : 
     996             : 
     997             : // retrieve TexFlags and the corresponding OpenGL format.
     998             : // the latter is determined during ogl_tex_upload and is 0 before that.
     999             : // all params are optional and filled if non-NULL.
    1000           0 : Status ogl_tex_get_format(Handle ht, size_t* flags, GLenum* fmt)
    1001             : {
    1002           0 :     H_DEREF(ht, OglTex, ot);
    1003             : 
    1004           0 :     if(flags)
    1005           0 :         *flags = ot->t.m_Flags;
    1006           0 :     if(fmt)
    1007             :     {
    1008           0 :         ENSURE(ot->flags & OT_IS_UPLOADED);
    1009           0 :         *fmt = ot->fmt;
    1010             :     }
    1011             :     return INFO::OK;
    1012             : }
    1013             : 
    1014             : 
    1015             : // retrieve pointer to texel data.
    1016             : //
    1017             : // note: this memory is freed after a successful ogl_tex_upload for
    1018             : // this texture. after that, the pointer we retrieve is NULL but
    1019             : // the function doesn't fail (negative return value) by design.
    1020             : // if you still need to get at the data, add a reference before
    1021             : // uploading it or read directly from OpenGL (discouraged).
    1022           0 : Status ogl_tex_get_data(Handle ht, u8** p)
    1023             : {
    1024           0 :     H_DEREF(ht, OglTex, ot);
    1025             : 
    1026           0 :     *p = ot->t.get_data();
    1027           0 :     return INFO::OK;
    1028             : }
    1029             : 
    1030           0 : Status ogl_tex_get_uploaded_size(Handle ht, size_t* size)
    1031             : {
    1032           0 :     H_DEREF(ht, OglTex, ot);
    1033             : 
    1034           0 :     *size = ot->uploaded_size;
    1035           0 :     return INFO::OK;
    1036             : }
    1037             : 
    1038             : // retrieve color of 1x1 mipmap level
    1039           0 : extern Status ogl_tex_get_average_color(Handle ht, u32* p)
    1040             : {
    1041           0 :     H_DEREF(ht, OglTex, ot);
    1042           0 :     warn_if_uploaded(ht, ot);
    1043             : 
    1044           0 :     *p = ot->t.get_average_color();
    1045           0 :     return INFO::OK;
    1046             : }
    1047             : 
    1048             : //----------------------------------------------------------------------------
    1049             : // misc API
    1050             : //----------------------------------------------------------------------------
    1051             : 
    1052             : // bind the texture to the specified unit [number] in preparation for
    1053             : // using it in rendering. if <ht> is 0, texturing is disabled instead.
    1054             : //
    1055             : // side effects:
    1056             : // - changes the active texture unit;
    1057             : // - (if return value is 0:) texturing was enabled/disabled on that unit.
    1058             : //
    1059             : // notes:
    1060             : // - assumes multitexturing is available.
    1061             : // - not necessary before calling ogl_tex_upload!
    1062             : // - on error, the unit's texture state is unchanged; see implementation.
    1063           0 : Status ogl_tex_bind(Handle ht, size_t unit)
    1064             : {
    1065             :     // note: there are many call sites of glActiveTextureARB, so caching
    1066             :     // those and ignoring redundant sets isn't feasible.
    1067           0 :     pglActiveTextureARB((int)(GL_TEXTURE0+unit));
    1068             : 
    1069             :     // special case: disable texturing
    1070           0 :     if(ht == 0)
    1071             :     {
    1072             : #if !CONFIG2_GLES
    1073           0 :         glDisable(GL_TEXTURE_2D);
    1074             : #endif
    1075           0 :         return INFO::OK;
    1076             :     }
    1077             : 
    1078             :     // if this fails, the texture unit's state remains unchanged.
    1079             :     // we don't bother catching that and disabling texturing because a
    1080             :     // debug warning is raised anyway, and it's quite unlikely.
    1081           0 :     H_DEREF(ht, OglTex, ot);
    1082           0 :     ot->tmu = (u8)unit;
    1083             : 
    1084             :     // if 0, there's a problem in the OglTex reload/dtor logic.
    1085             :     // binding it results in whiteness, which can have many causes;
    1086             :     // we therefore complain so this one can be ruled out.
    1087           0 :     ENSURE(ot->id != 0);
    1088             : 
    1089             : #if !CONFIG2_GLES
    1090           0 :     glEnable(GL_TEXTURE_2D);
    1091             : #endif
    1092           0 :     glBindTexture(GL_TEXTURE_2D, ot->id);
    1093           0 :     return INFO::OK;
    1094             : }
    1095             : 
    1096           0 : Status ogl_tex_get_texture_id(Handle ht, GLuint* id)
    1097             : {
    1098           0 :     *id = 0;
    1099           0 :     H_DEREF(ht, OglTex, ot);
    1100           0 :     *id = ot->id;
    1101           0 :     return INFO::OK;
    1102             : }
    1103             : 
    1104             : // apply the specified transforms (as in tex_transform) to the image.
    1105             : // must be called before uploading (raises a warning if called afterwards).
    1106           0 : Status ogl_tex_transform(Handle ht, size_t transforms)
    1107             : {
    1108           0 :     H_DEREF(ht, OglTex, ot);
    1109           0 :     Status ret = ot->t.transform(transforms);
    1110           0 :     return ret;
    1111             : }
    1112             : 
    1113             : 
    1114             : // change the pixel format to that specified by <new_flags>.
    1115             : // (note: this is equivalent to ogl_tex_transform(ht, ht_flags^new_flags).
    1116           0 : Status ogl_tex_transform_to(Handle ht, size_t new_flags)
    1117             : {
    1118           0 :     H_DEREF(ht, OglTex, ot);
    1119           0 :     Status ret = ot->t.transform_to(new_flags);
    1120           0 :     return ret;
    1121             : }
    1122             : 
    1123             : 
    1124             : // return whether native S3TC support is available
    1125           0 : bool ogl_tex_has_s3tc()
    1126             : {
    1127             :     // ogl_tex_upload must be called before this
    1128           0 :     ENSURE(have_s3tc != -1);
    1129             : 
    1130           0 :     return (have_s3tc != 0);
    1131             : }
    1132             : 
    1133             : // return whether anisotropic filtering support is available
    1134           0 : bool ogl_tex_has_anisotropy()
    1135             : {
    1136             :     // ogl_tex_upload must be called before this
    1137           0 :     ENSURE(have_anistropy != -1);
    1138             : 
    1139           0 :     return (have_anistropy != 0);
    1140             : }

Generated by: LCOV version 1.13