2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "debugging/debugging.h"
27 #include "itextures.h"
29 #include "preferencesystem.h"
32 #include "texturelib.h"
33 #include "container/hashfunc.h"
34 #include "container/cache.h"
35 #include "generic/callback.h"
40 #include "preferences.h"
46 eTextures_NEAREST = 0,
47 eTextures_NEAREST_MIPMAP_NEAREST = 1,
48 eTextures_NEAREST_MIPMAP_LINEAR = 2,
50 eTextures_LINEAR_MIPMAP_NEAREST = 4,
51 eTextures_LINEAR_MIPMAP_LINEAR = 5,
52 eTextures_MAX_ANISOTROPY = 6,
55 enum TextureCompressionFormat
57 TEXTURECOMPRESSION_NONE = 0,
58 TEXTURECOMPRESSION_RGBA = 1,
59 TEXTURECOMPRESSION_RGBA_S3TC_DXT1 = 2,
60 TEXTURECOMPRESSION_RGBA_S3TC_DXT3 = 3,
61 TEXTURECOMPRESSION_RGBA_S3TC_DXT5 = 4,
64 struct texture_globals_t
67 // texture compression format
68 TextureCompressionFormat m_nTextureCompressionFormat;
72 bool bTextureCompressionSupported; // is texture compression supported by hardware?
73 GLint texture_components;
75 // temporary values that should be initialised only once at run-time
76 bool m_bOpenGLCompressionSupported;
77 bool m_bS3CompressionSupported;
79 texture_globals_t( GLint components ) :
80 m_nTextureCompressionFormat( TEXTURECOMPRESSION_NONE ),
82 bTextureCompressionSupported( false ),
83 texture_components( components ),
84 m_bOpenGLCompressionSupported( false ),
85 m_bS3CompressionSupported( false ){
89 texture_globals_t g_texture_globals( GL_RGBA );
91 void SetTexParameters( ETexturesMode mode ){
92 float maxAniso = QGL_maxTextureAnisotropy();
94 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f );
97 if ( mode == eTextures_MAX_ANISOTROPY ) {
98 mode = eTextures_LINEAR_MIPMAP_LINEAR;
103 case eTextures_NEAREST:
104 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
105 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
107 case eTextures_NEAREST_MIPMAP_NEAREST:
108 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
109 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
111 case eTextures_NEAREST_MIPMAP_LINEAR:
112 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR );
113 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
115 case eTextures_LINEAR:
116 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
117 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
119 case eTextures_LINEAR_MIPMAP_NEAREST:
120 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
121 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
123 case eTextures_LINEAR_MIPMAP_LINEAR:
124 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
125 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
127 case eTextures_MAX_ANISOTROPY:
128 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso );
131 globalOutputStream() << "invalid texture mode\n";
135 ETexturesMode g_texture_mode = eTextures_LINEAR_MIPMAP_LINEAR;
140 byte g_gammatable[256];
141 void ResampleGamma( float fGamma ){
143 if ( fGamma == 1.0 ) {
144 for ( i = 0; i < 256; i++ )
149 for ( i = 0; i < 256; i++ )
151 inf = (int)( 255 * pow( static_cast<double>( ( i + 0.5 ) / 255.5 ), static_cast<double>( fGamma ) ) + 0.5 );
158 g_gammatable[i] = inf;
163 inline const int& min_int( const int& left, const int& right ){
164 return std::min( left, right );
167 int max_tex_size = 0;
168 const int max_texture_quality = 3;
169 LatchedValue<int> g_Textures_textureQuality( 3, "Texture Quality" );
171 /// \brief This function does the actual processing of raw RGBA data into a GL texture.
172 /// It will also resample to power-of-two dimensions, generate the mipmaps and adjust gamma.
173 void LoadTextureRGBA( qtexture_t* q, unsigned char* pPixels, int nWidth, int nHeight ){
174 static float fGamma = -1;
177 int nCount = nWidth * nHeight;
179 if ( fGamma != g_texture_globals.fGamma ) {
180 fGamma = g_texture_globals.fGamma;
181 ResampleGamma( fGamma );
187 total[0] = total[1] = total[2] = 0.0f;
189 // resample texture gamma according to user settings
190 for ( int i = 0; i < ( nCount * 4 ); i += 4 )
192 for ( int j = 0; j < 3; j++ )
194 total[j] += ( pPixels + i )[j];
195 byte b = ( pPixels + i )[j];
196 ( pPixels + i )[j] = g_gammatable[b];
200 q->color[0] = total[0] / ( nCount * 255 );
201 q->color[1] = total[1] / ( nCount * 255 );
202 q->color[2] = total[2] / ( nCount * 255 );
204 glGenTextures( 1, &q->texture_number );
206 glBindTexture( GL_TEXTURE_2D, q->texture_number );
208 SetTexParameters( g_texture_mode );
211 while ( gl_width < nWidth )
215 while ( gl_height < nHeight )
218 bool resampled = false;
219 if ( !( gl_width == nWidth && gl_height == nHeight ) ) {
221 outpixels = (byte *)malloc( gl_width * gl_height * 4 );
222 R_ResampleTexture( pPixels, nWidth, nHeight, outpixels, gl_width, gl_height, 4 );
229 int quality_reduction = max_texture_quality - g_Textures_textureQuality.m_value;
230 int target_width = min_int( gl_width >> quality_reduction, max_tex_size );
231 int target_height = min_int( gl_height >> quality_reduction, max_tex_size );
233 while ( gl_width > target_width || gl_height > target_height )
235 GL_MipReduce( outpixels, outpixels, gl_width, gl_height, target_width, target_height );
237 if ( gl_width > target_width ) {
240 if ( gl_height > target_height ) {
246 glTexImage2D( GL_TEXTURE_2D, mip++, g_texture_globals.texture_components, gl_width, gl_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels );
247 while ( gl_width > 1 || gl_height > 1 )
249 GL_MipReduce( outpixels, outpixels, gl_width, gl_height, 1, 1 );
251 if ( gl_width > 1 ) {
254 if ( gl_height > 1 ) {
258 glTexImage2D( GL_TEXTURE_2D, mip++, g_texture_globals.texture_components, gl_width, gl_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels );
261 glBindTexture( GL_TEXTURE_2D, 0 );
273 void Texture_InitPalette( byte *pal ){
277 byte gammatable[256];
280 gamma = g_texture_globals.fGamma;
282 if ( gamma == 1.0 ) {
283 for ( i = 0 ; i < 256 ; i++ )
288 for ( i = 0 ; i < 256 ; i++ )
290 inf = (int)( 255 * pow( ( i + 0.5 ) / 255.5, gamma ) + 0.5 );
301 for ( i = 0 ; i < 256 ; i++ )
303 r = gammatable[pal[0]];
304 g = gammatable[pal[1]];
305 b = gammatable[pal[2]];
308 //v = (r<<24) + (g<<16) + (b<<8) + 255;
311 //tex_palette[i] = v;
312 tex_palette[i * 3 + 0] = r;
313 tex_palette[i * 3 + 1] = g;
314 tex_palette[i * 3 + 2] = b;
324 HashTable<CopiedString, CopiedString, HashStringNoCase, StringEqualNoCase> strings;
325 strings["Monkey"] = "bleh";
326 strings["MonkeY"] = "blah";
330 const TestHashtable g_testhashtable;
334 typedef std::pair<LoadImageCallback, CopiedString> TextureKey;
336 void qtexture_realise( qtexture_t& texture, const TextureKey& key ){
337 texture.texture_number = 0;
338 if ( !string_empty( key.second.c_str() ) ) {
339 Image* image = key.first.loadImage( key.second.c_str() );
341 LoadTextureRGBA( &texture, image->getRGBAPixels(), image->getWidth(), image->getHeight() );
342 texture.surfaceFlags = image->getSurfaceFlags();
343 texture.contentFlags = image->getContentFlags();
344 texture.value = image->getValue();
346 globalOutputStream() << "Loaded Texture: \"" << key.second.c_str() << "\"\n";
347 GlobalOpenGL_debugAssertNoErrors();
351 globalErrorStream() << "Texture load failed: \"" << key.second.c_str() << "\"\n";
356 void qtexture_unrealise( qtexture_t& texture ){
357 if ( GlobalOpenGL().contextValid && texture.texture_number != 0 ) {
358 glDeleteTextures( 1, &texture.texture_number );
359 GlobalOpenGL_debugAssertNoErrors();
363 class TextureKeyEqualNoCase
366 bool operator()( const TextureKey& key, const TextureKey& other ) const {
367 return key.first == other.first && string_equal_nocase( key.second.c_str(), other.second.c_str() );
371 class TextureKeyHashNoCase
374 typedef hash_t hash_type;
375 hash_t operator()( const TextureKey& key ) const {
376 return hash_combine( string_hash_nocase( key.second.c_str() ), pod_hash( key.first ) );
380 #define DEBUG_TEXTURES 0
382 class TexturesMap : public TexturesCache
384 class TextureConstructor
386 TexturesMap* m_cache;
388 explicit TextureConstructor( TexturesMap* cache )
391 qtexture_t* construct( const TextureKey& key ){
392 qtexture_t* texture = new qtexture_t( key.first, key.second.c_str() );
393 if ( m_cache->realised() ) {
394 qtexture_realise( *texture, key );
398 void destroy( qtexture_t* texture ){
399 if ( m_cache->realised() ) {
400 qtexture_unrealise( *texture );
406 typedef HashedCache<TextureKey, qtexture_t, TextureKeyHashNoCase, TextureKeyEqualNoCase, TextureConstructor> qtextures_t;
407 qtextures_t m_qtextures;
408 TexturesCacheObserver* m_observer;
409 std::size_t m_unrealised;
412 virtual ~TexturesMap() = default;
413 TexturesMap() : m_qtextures( TextureConstructor( this ) ), m_observer( 0 ), m_unrealised( 1 ){
415 typedef qtextures_t::iterator iterator;
418 return m_qtextures.begin();
421 return m_qtextures.end();
424 LoadImageCallback defaultLoader() const {
425 return LoadImageCallback( 0, QERApp_LoadImage );
427 Image* loadImage( const char* name ){
428 return defaultLoader().loadImage( name );
430 qtexture_t* capture( const char* name ){
431 return capture( defaultLoader(), name );
433 qtexture_t* capture( const LoadImageCallback& loader, const char* name ){
435 globalOutputStream() << "textures capture: " << makeQuoted( name ) << '\n';
437 return m_qtextures.capture( TextureKey( loader, name ) ).get();
439 void release( qtexture_t* texture ){
441 globalOutputStream() << "textures release: " << makeQuoted( texture->name ) << '\n';
443 m_qtextures.release( TextureKey( texture->load, texture->name ) );
445 void attach( TexturesCacheObserver& observer ){
446 ASSERT_MESSAGE( m_observer == 0, "TexturesMap::attach: cannot attach observer" );
447 m_observer = &observer;
449 void detach( TexturesCacheObserver& observer ){
450 ASSERT_MESSAGE( m_observer == &observer, "TexturesMap::detach: cannot detach observer" );
454 if ( --m_unrealised == 0 ) {
455 g_texture_globals.bTextureCompressionSupported = false;
457 if ( GlobalOpenGL().ARB_texture_compression() ) {
458 g_texture_globals.bTextureCompressionSupported = true;
459 g_texture_globals.m_bOpenGLCompressionSupported = true;
462 if ( GlobalOpenGL().EXT_texture_compression_s3tc() ) {
463 g_texture_globals.bTextureCompressionSupported = true;
464 g_texture_globals.m_bS3CompressionSupported = true;
467 switch ( g_texture_globals.texture_components )
471 case GL_COMPRESSED_RGBA_ARB:
472 if ( !g_texture_globals.m_bOpenGLCompressionSupported ) {
473 globalOutputStream() << "OpenGL extension GL_ARB_texture_compression not supported by current graphics drivers\n";
474 g_texture_globals.m_nTextureCompressionFormat = TEXTURECOMPRESSION_NONE;
475 g_texture_globals.texture_components = GL_RGBA;
478 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
479 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
480 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
481 if ( !g_texture_globals.m_bS3CompressionSupported ) {
482 globalOutputStream() << "OpenGL extension GL_EXT_texture_compression_s3tc not supported by current graphics drivers\n";
483 if ( g_texture_globals.m_bOpenGLCompressionSupported ) {
484 g_texture_globals.m_nTextureCompressionFormat = TEXTURECOMPRESSION_RGBA;
485 g_texture_globals.texture_components = GL_COMPRESSED_RGBA_ARB;
489 g_texture_globals.m_nTextureCompressionFormat = TEXTURECOMPRESSION_NONE;
490 g_texture_globals.texture_components = GL_RGBA;
495 globalOutputStream() << "Unknown texture compression selected, reverting\n";
496 g_texture_globals.m_nTextureCompressionFormat = TEXTURECOMPRESSION_NONE;
497 g_texture_globals.texture_components = GL_RGBA;
502 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_tex_size );
503 if ( max_tex_size == 0 ) {
507 for ( qtextures_t::iterator i = m_qtextures.begin(); i != m_qtextures.end(); ++i )
509 if ( !( *i ).value.empty() ) {
510 qtexture_realise( *( *i ).value, ( *i ).key );
513 if ( m_observer != 0 ) {
514 m_observer->realise();
519 if ( ++m_unrealised == 1 ) {
520 if ( m_observer != 0 ) {
521 m_observer->unrealise();
523 for ( qtextures_t::iterator i = m_qtextures.begin(); i != m_qtextures.end(); ++i )
525 if ( !( *i ).value.empty() ) {
526 qtexture_unrealise( *( *i ).value );
532 return m_unrealised == 0;
536 TexturesMap* g_texturesmap;
538 TexturesCache& GetTexturesCache(){
539 return *g_texturesmap;
543 void Textures_Realise(){
544 g_texturesmap->realise();
547 void Textures_Unrealise(){
548 g_texturesmap->unrealise();
552 Callback<void()> g_texturesModeChangedNotify;
554 void Textures_setModeChangedNotify( const Callback<void()>& notify ){
555 g_texturesModeChangedNotify = notify;
558 void Textures_ModeChanged(){
559 if ( g_texturesmap->realised() ) {
560 SetTexParameters( g_texture_mode );
562 for ( TexturesMap::iterator i = g_texturesmap->begin(); i != g_texturesmap->end(); ++i )
564 glBindTexture( GL_TEXTURE_2D, ( *i ).value->texture_number );
565 SetTexParameters( g_texture_mode );
568 glBindTexture( GL_TEXTURE_2D, 0 );
570 g_texturesModeChangedNotify();
573 void Textures_SetMode( ETexturesMode mode ){
574 if ( g_texture_mode != mode ) {
575 g_texture_mode = mode;
577 Textures_ModeChanged();
581 void Textures_setTextureComponents( GLint texture_components ){
582 if ( g_texture_globals.texture_components != texture_components ) {
583 Textures_Unrealise();
584 g_texture_globals.texture_components = texture_components;
589 void Textures_UpdateTextureCompressionFormat(){
590 GLint texture_components = GL_RGBA;
592 switch ( g_texture_globals.m_nTextureCompressionFormat )
594 case ( TEXTURECOMPRESSION_NONE ):
596 texture_components = GL_RGBA;
599 case ( TEXTURECOMPRESSION_RGBA ):
601 texture_components = GL_COMPRESSED_RGBA_ARB;
604 case ( TEXTURECOMPRESSION_RGBA_S3TC_DXT1 ):
606 texture_components = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
609 case ( TEXTURECOMPRESSION_RGBA_S3TC_DXT3 ):
611 texture_components = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
614 case ( TEXTURECOMPRESSION_RGBA_S3TC_DXT5 ):
616 texture_components = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
621 Textures_setTextureComponents( texture_components );
624 struct TextureCompression {
625 static void Export(const TextureCompressionFormat &self, const Callback<void(int)> &returnz) {
629 static void Import(TextureCompressionFormat &self, int value) {
630 if (!g_texture_globals.m_bOpenGLCompressionSupported
631 && g_texture_globals.m_bS3CompressionSupported
637 self = TEXTURECOMPRESSION_NONE;
640 self = TEXTURECOMPRESSION_RGBA;
643 self = TEXTURECOMPRESSION_RGBA_S3TC_DXT1;
646 self = TEXTURECOMPRESSION_RGBA_S3TC_DXT3;
649 self = TEXTURECOMPRESSION_RGBA_S3TC_DXT5;
652 Textures_UpdateTextureCompressionFormat();
656 struct TextureGamma {
657 static void Export(const float &self, const Callback<void(float)> &returnz) {
661 static void Import(float &self, float value) {
663 Textures_Unrealise();
671 static void Export(const ETexturesMode &self, const Callback<void(int)> &returnz) {
673 case eTextures_NEAREST:
676 case eTextures_NEAREST_MIPMAP_NEAREST:
679 case eTextures_LINEAR:
682 case eTextures_NEAREST_MIPMAP_LINEAR:
685 case eTextures_LINEAR_MIPMAP_NEAREST:
688 case eTextures_LINEAR_MIPMAP_LINEAR:
691 case eTextures_MAX_ANISOTROPY:
699 static void Import(ETexturesMode &self, int value) {
702 Textures_SetMode(eTextures_NEAREST);
705 Textures_SetMode(eTextures_NEAREST_MIPMAP_NEAREST);
708 Textures_SetMode(eTextures_LINEAR);
711 Textures_SetMode(eTextures_NEAREST_MIPMAP_LINEAR);
714 Textures_SetMode(eTextures_LINEAR_MIPMAP_NEAREST);
717 Textures_SetMode(eTextures_LINEAR_MIPMAP_LINEAR);
720 Textures_SetMode(eTextures_MAX_ANISOTROPY);
725 void Textures_constructPreferences( PreferencesPage& page ){
727 const char* percentages[] = { "12.5%", "25%", "50%", "100%", };
730 STRING_ARRAY_RANGE( percentages ),
731 make_property( g_Textures_textureQuality )
739 make_property<TextureGamma>(g_texture_globals.fGamma)
742 const char* texture_mode[] = { "Nearest", "Nearest Mipmap", "Linear", "Bilinear", "Bilinear Mipmap", "Trilinear", "Anisotropy" };
744 "Texture Render Mode",
745 STRING_ARRAY_RANGE( texture_mode ),
746 make_property<TextureMode>(g_texture_mode)
750 const char* compression_none[] = { "None" };
751 const char* compression_opengl[] = { "None", "OpenGL ARB" };
752 const char* compression_s3tc[] = { "None", "S3TC DXT1", "S3TC DXT3", "S3TC DXT5" };
753 const char* compression_opengl_s3tc[] = { "None", "OpenGL ARB", "S3TC DXT1", "S3TC DXT3", "S3TC DXT5" };
754 StringArrayRange compression(
755 ( g_texture_globals.m_bOpenGLCompressionSupported )
756 ? ( g_texture_globals.m_bS3CompressionSupported )
757 ? STRING_ARRAY_RANGE( compression_opengl_s3tc )
758 : STRING_ARRAY_RANGE( compression_opengl )
759 : ( g_texture_globals.m_bS3CompressionSupported )
760 ? STRING_ARRAY_RANGE( compression_s3tc )
761 : STRING_ARRAY_RANGE( compression_none )
764 "Hardware Texture Compression",
766 make_property<TextureCompression>(g_texture_globals.m_nTextureCompressionFormat)
770 void Textures_constructPage( PreferenceGroup& group ){
771 PreferencesPage page( group.createPage( "Textures", "Texture Settings" ) );
772 Textures_constructPreferences( page );
774 void Textures_registerPreferencesPage(){
775 PreferencesDialog_addDisplayPage( makeCallbackF(Textures_constructPage) );
778 struct TextureCompressionPreference {
779 static void Export(const Callback<void(int)> &returnz) {
780 returnz(g_texture_globals.m_nTextureCompressionFormat);
783 static void Import(int value) {
784 g_texture_globals.m_nTextureCompressionFormat = static_cast<TextureCompressionFormat>( value );
785 Textures_UpdateTextureCompressionFormat();
789 void Textures_Construct(){
790 g_texturesmap = new TexturesMap;
792 GlobalPreferenceSystem().registerPreference( "TextureCompressionFormat", make_property_string<TextureCompressionPreference>() );
793 GlobalPreferenceSystem().registerPreference( "TextureFiltering", make_property_string( reinterpret_cast<int&>( g_texture_mode ) ) );
794 GlobalPreferenceSystem().registerPreference( "TextureQuality", make_property_string( g_Textures_textureQuality.m_latched ) );
795 GlobalPreferenceSystem().registerPreference( "SI_Gamma", make_property_string( g_texture_globals.fGamma ) );
797 g_Textures_textureQuality.useLatched();
799 Textures_registerPreferencesPage();
801 Textures_ModeChanged();
803 void Textures_Destroy(){
804 delete g_texturesmap;
808 #include "modulesystem/modulesmap.h"
809 #include "modulesystem/singletonmodule.h"
810 #include "modulesystem/moduleregistry.h"
812 class TexturesDependencies :
813 public GlobalRadiantModuleRef,
814 public GlobalOpenGLModuleRef,
815 public GlobalPreferenceSystemModuleRef
817 ImageModulesRef m_image_modules;
819 TexturesDependencies() :
820 m_image_modules( GlobalRadiant().getRequiredGameDescriptionKeyValue( "texturetypes" ) ){
822 ImageModules& getImageModules(){
823 return m_image_modules.get();
829 TexturesCache* m_textures;
831 typedef TexturesCache Type;
832 STRING_CONSTANT( Name, "*" );
835 Textures_Construct();
837 m_textures = &GetTexturesCache();
842 TexturesCache* getTable(){
847 typedef SingletonModule<TexturesAPI, TexturesDependencies> TexturesModule;
848 typedef Static<TexturesModule> StaticTexturesModule;
849 StaticRegisterModule staticRegisterTextures( StaticTexturesModule::instance() );
851 ImageModules& Textures_getImageModules(){
852 return StaticTexturesModule::instance().getDependencies().getImageModules();