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