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
22 #include <util/buffer.h>
25 #include "debugging/debugging.h"
28 #include "itextures.h"
30 #include "preferencesystem.h"
33 #include "texturelib.h"
34 #include "container/hashfunc.h"
35 #include "container/cache.h"
36 #include "generic/callback.h"
41 #include "preferences.h"
47 eTextures_NEAREST = 0,
48 eTextures_NEAREST_MIPMAP_NEAREST = 1,
49 eTextures_NEAREST_MIPMAP_LINEAR = 2,
51 eTextures_LINEAR_MIPMAP_NEAREST = 4,
52 eTextures_LINEAR_MIPMAP_LINEAR = 5,
53 eTextures_MAX_ANISOTROPY = 6,
56 enum TextureCompressionFormat
58 TEXTURECOMPRESSION_NONE = 0,
59 TEXTURECOMPRESSION_RGBA = 1,
60 TEXTURECOMPRESSION_RGBA_S3TC_DXT1 = 2,
61 TEXTURECOMPRESSION_RGBA_S3TC_DXT3 = 3,
62 TEXTURECOMPRESSION_RGBA_S3TC_DXT5 = 4,
65 struct texture_globals_t
68 // texture compression format
69 TextureCompressionFormat m_nTextureCompressionFormat;
73 bool bTextureCompressionSupported; // is texture compression supported by hardware?
74 GLint texture_components;
76 // temporary values that should be initialised only once at run-time
77 bool m_bOpenGLCompressionSupported;
78 bool m_bS3CompressionSupported;
80 texture_globals_t( GLint components ) :
81 m_nTextureCompressionFormat( TEXTURECOMPRESSION_NONE ),
83 bTextureCompressionSupported( false ),
84 texture_components( components ),
85 m_bOpenGLCompressionSupported( false ),
86 m_bS3CompressionSupported( false ){
90 texture_globals_t g_texture_globals( GL_RGBA );
92 void SetTexParameters( ETexturesMode mode ){
93 float maxAniso = QGL_maxTextureAnisotropy();
95 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f );
98 if ( mode == eTextures_MAX_ANISOTROPY ) {
99 mode = eTextures_LINEAR_MIPMAP_LINEAR;
104 case eTextures_NEAREST:
105 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
106 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
108 case eTextures_NEAREST_MIPMAP_NEAREST:
109 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
110 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
112 case eTextures_NEAREST_MIPMAP_LINEAR:
113 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR );
114 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
116 case eTextures_LINEAR:
117 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
118 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
120 case eTextures_LINEAR_MIPMAP_NEAREST:
121 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
122 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
124 case eTextures_LINEAR_MIPMAP_LINEAR:
125 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
126 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
128 case eTextures_MAX_ANISOTROPY:
129 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso );
132 globalOutputStream() << "invalid texture mode\n";
136 ETexturesMode g_texture_mode = eTextures_LINEAR_MIPMAP_LINEAR;
141 u::BufferVal<256> g_gammatable;
142 void ResampleGamma( float fGamma ){
144 auto buf = g_gammatable.mut();
145 if (fGamma == 1.0 ) {
146 for ( i = 0; i < 256; i++ )
151 for ( i = 0; i < 256; i++ )
153 inf = (int)( 255 * pow( static_cast<double>( ( i + 0.5 ) / 255.5 ), static_cast<double>( fGamma ) ) + 0.5 );
165 inline const int& min_int( const int& left, const int& right ){
166 return std::min( left, right );
169 int max_tex_size = 0;
170 const int max_texture_quality = 3;
171 LatchedInt g_Textures_textureQuality( 3, "Texture Quality" );
173 /// \brief This function does the actual processing of raw RGBA data into a GL texture.
174 /// It will also resample to power-of-two dimensions, generate the mipmaps and adjust gamma.
175 void LoadTextureRGBA( qtexture_t* q, unsigned char* pPixels, int nWidth, int nHeight ){
176 static float fGamma = -1;
179 int nCount = nWidth * nHeight;
181 if ( fGamma != g_texture_globals.fGamma ) {
182 fGamma = g_texture_globals.fGamma;
183 ResampleGamma( fGamma );
189 total[0] = total[1] = total[2] = 0.0f;
191 // resample texture gamma according to user settings
192 for ( int i = 0; i < ( nCount * 4 ); i += 4 )
194 for ( int j = 0; j < 3; j++ )
196 total[j] += ( pPixels + i )[j];
197 byte b = ( pPixels + i )[j];
198 ( pPixels + i )[j] = g_gammatable[b];
202 q->color[0] = total[0] / ( nCount * 255 );
203 q->color[1] = total[1] / ( nCount * 255 );
204 q->color[2] = total[2] / ( nCount * 255 );
206 glGenTextures( 1, &q->texture_number );
208 glBindTexture( GL_TEXTURE_2D, q->texture_number );
210 SetTexParameters( g_texture_mode );
213 while ( gl_width < nWidth )
217 while ( gl_height < nHeight )
220 bool resampled = false;
221 if ( !( gl_width == nWidth && gl_height == nHeight ) ) {
223 outpixels = (byte *)malloc( gl_width * gl_height * 4 );
224 R_ResampleTexture( pPixels, nWidth, nHeight, outpixels, gl_width, gl_height, 4 );
231 int quality_reduction = max_texture_quality - g_Textures_textureQuality.m_value;
232 int target_width = min_int( gl_width >> quality_reduction, max_tex_size );
233 int target_height = min_int( gl_height >> quality_reduction, max_tex_size );
235 while ( gl_width > target_width || gl_height > target_height )
237 GL_MipReduce( outpixels, outpixels, gl_width, gl_height, target_width, target_height );
239 if ( gl_width > target_width ) {
242 if ( gl_height > target_height ) {
248 glTexImage2D( GL_TEXTURE_2D, mip++, g_texture_globals.texture_components, gl_width, gl_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels );
249 while ( gl_width > 1 || gl_height > 1 )
251 GL_MipReduce( outpixels, outpixels, gl_width, gl_height, 1, 1 );
253 if ( gl_width > 1 ) {
256 if ( gl_height > 1 ) {
260 glTexImage2D( GL_TEXTURE_2D, mip++, g_texture_globals.texture_components, gl_width, gl_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels );
263 glBindTexture( GL_TEXTURE_2D, 0 );
275 void Texture_InitPalette( byte *pal ){
279 auto gammatable = u::buffer<256>();
282 gamma = g_texture_globals.fGamma;
284 if ( gamma == 1.0 ) {
285 for ( i = 0 ; i < 256 ; i++ )
290 for ( i = 0 ; i < 256 ; i++ )
292 inf = (int)( 255 * pow( ( i + 0.5 ) / 255.5, gamma ) + 0.5 );
303 for ( i = 0 ; i < 256 ; i++ )
305 r = gammatable[pal[0]];
306 g = gammatable[pal[1]];
307 b = gammatable[pal[2]];
310 //v = (r<<24) + (g<<16) + (b<<8) + 255;
313 //tex_palette[i] = v;
314 tex_palette[i * 3 + 0] = r;
315 tex_palette[i * 3 + 1] = g;
316 tex_palette[i * 3 + 2] = b;
326 HashTable<CopiedString, CopiedString, HashStringNoCase, StringEqualNoCase> strings;
327 strings["Monkey"] = "bleh";
328 strings["MonkeY"] = "blah";
332 const TestHashtable g_testhashtable;
336 typedef std::pair<LoadImageCallback, CopiedString> TextureKey;
338 void qtexture_realise( qtexture_t& texture, const TextureKey& key ){
339 texture.texture_number = 0;
340 if ( !string_empty( key.second.c_str() ) ) {
341 Image* image = key.first.loadImage( key.second.c_str() );
343 LoadTextureRGBA( &texture, image->getRGBAPixels(), image->getWidth(), image->getHeight() );
344 texture.surfaceFlags = image->getSurfaceFlags();
345 texture.contentFlags = image->getContentFlags();
346 texture.value = image->getValue();
348 globalOutputStream() << "Loaded Texture: \"" << key.second.c_str() << "\"\n";
349 GlobalOpenGL_debugAssertNoErrors();
353 globalErrorStream() << "Texture load failed: \"" << key.second.c_str() << "\"\n";
358 void qtexture_unrealise( qtexture_t& texture ){
359 if ( GlobalOpenGL().contextValid && texture.texture_number != 0 ) {
360 glDeleteTextures( 1, &texture.texture_number );
361 GlobalOpenGL_debugAssertNoErrors();
365 class TextureKeyEqualNoCase
368 bool operator()( const TextureKey& key, const TextureKey& other ) const {
369 return key.first == other.first && string_equal_nocase( key.second.c_str(), other.second.c_str() );
373 class TextureKeyHashNoCase
376 typedef hash_t hash_type;
377 hash_t operator()( const TextureKey& key ) const {
378 return hash_combine( string_hash_nocase( key.second.c_str() ), pod_hash( key.first ) );
382 #define DEBUG_TEXTURES 0
384 class TexturesMap : public TexturesCache
386 class TextureConstructor
388 TexturesMap* m_cache;
390 explicit TextureConstructor( TexturesMap* cache )
393 qtexture_t* construct( const TextureKey& key ){
394 qtexture_t* texture = new qtexture_t( key.first, key.second.c_str() );
395 if ( m_cache->realised() ) {
396 qtexture_realise( *texture, key );
400 void destroy( qtexture_t* texture ){
401 if ( m_cache->realised() ) {
402 qtexture_unrealise( *texture );
408 typedef HashedCache<TextureKey, qtexture_t, TextureKeyHashNoCase, TextureKeyEqualNoCase, TextureConstructor> qtextures_t;
409 qtextures_t m_qtextures;
410 TexturesCacheObserver* m_observer;
411 std::size_t m_unrealised;
414 virtual ~TexturesMap() = default;
415 TexturesMap() : m_qtextures( TextureConstructor( this ) ), m_observer( 0 ), m_unrealised( 1 ){
417 typedef qtextures_t::iterator iterator;
420 return m_qtextures.begin();
423 return m_qtextures.end();
426 LoadImageCallback defaultLoader() const {
427 return LoadImageCallback( 0, QERApp_LoadImage );
429 Image* loadImage( const char* name ){
430 return defaultLoader().loadImage( name );
432 qtexture_t* capture( const char* name ){
433 return capture( defaultLoader(), name );
435 qtexture_t* capture( const LoadImageCallback& loader, const char* name ){
437 globalOutputStream() << "textures capture: " << makeQuoted( name ) << '\n';
439 return m_qtextures.capture( TextureKey( loader, name ) ).get();
441 void release( qtexture_t* texture ){
443 globalOutputStream() << "textures release: " << makeQuoted( texture->name ) << '\n';
445 m_qtextures.release( TextureKey( texture->load, texture->name ) );
447 void attach( TexturesCacheObserver& observer ){
448 ASSERT_MESSAGE( m_observer == 0, "TexturesMap::attach: cannot attach observer" );
449 m_observer = &observer;
451 void detach( TexturesCacheObserver& observer ){
452 ASSERT_MESSAGE( m_observer == &observer, "TexturesMap::detach: cannot detach observer" );
456 if ( --m_unrealised == 0 ) {
457 g_texture_globals.bTextureCompressionSupported = false;
459 if ( GlobalOpenGL().ARB_texture_compression() ) {
460 g_texture_globals.bTextureCompressionSupported = true;
461 g_texture_globals.m_bOpenGLCompressionSupported = true;
464 if ( GlobalOpenGL().EXT_texture_compression_s3tc() ) {
465 g_texture_globals.bTextureCompressionSupported = true;
466 g_texture_globals.m_bS3CompressionSupported = true;
469 switch ( g_texture_globals.texture_components )
473 case GL_COMPRESSED_RGBA_ARB:
474 if ( !g_texture_globals.m_bOpenGLCompressionSupported ) {
475 globalOutputStream() << "OpenGL extension GL_ARB_texture_compression not supported by current graphics drivers\n";
476 g_texture_globals.m_nTextureCompressionFormat = TEXTURECOMPRESSION_NONE;
477 g_texture_globals.texture_components = GL_RGBA;
480 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
481 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
482 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
483 if ( !g_texture_globals.m_bS3CompressionSupported ) {
484 globalOutputStream() << "OpenGL extension GL_EXT_texture_compression_s3tc not supported by current graphics drivers\n";
485 if ( g_texture_globals.m_bOpenGLCompressionSupported ) {
486 g_texture_globals.m_nTextureCompressionFormat = TEXTURECOMPRESSION_RGBA;
487 g_texture_globals.texture_components = GL_COMPRESSED_RGBA_ARB;
491 g_texture_globals.m_nTextureCompressionFormat = TEXTURECOMPRESSION_NONE;
492 g_texture_globals.texture_components = GL_RGBA;
497 globalOutputStream() << "Unknown texture compression selected, reverting\n";
498 g_texture_globals.m_nTextureCompressionFormat = TEXTURECOMPRESSION_NONE;
499 g_texture_globals.texture_components = GL_RGBA;
504 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_tex_size );
505 if ( max_tex_size == 0 ) {
509 for ( qtextures_t::iterator i = m_qtextures.begin(); i != m_qtextures.end(); ++i )
511 if ( !( *i ).value.empty() ) {
512 qtexture_realise( *( *i ).value, ( *i ).key );
515 if ( m_observer != 0 ) {
516 m_observer->realise();
521 if ( ++m_unrealised == 1 ) {
522 if ( m_observer != 0 ) {
523 m_observer->unrealise();
525 for ( qtextures_t::iterator i = m_qtextures.begin(); i != m_qtextures.end(); ++i )
527 if ( !( *i ).value.empty() ) {
528 qtexture_unrealise( *( *i ).value );
534 return m_unrealised == 0;
538 TexturesMap* g_texturesmap;
540 TexturesCache& GetTexturesCache(){
541 return *g_texturesmap;
545 void Textures_Realise(){
546 g_texturesmap->realise();
549 void Textures_Unrealise(){
550 g_texturesmap->unrealise();
554 Callback g_texturesModeChangedNotify;
556 void Textures_setModeChangedNotify( const Callback& notify ){
557 g_texturesModeChangedNotify = notify;
560 void Textures_ModeChanged(){
561 if ( g_texturesmap->realised() ) {
562 SetTexParameters( g_texture_mode );
564 for ( TexturesMap::iterator i = g_texturesmap->begin(); i != g_texturesmap->end(); ++i )
566 glBindTexture( GL_TEXTURE_2D, ( *i ).value->texture_number );
567 SetTexParameters( g_texture_mode );
570 glBindTexture( GL_TEXTURE_2D, 0 );
572 g_texturesModeChangedNotify();
575 void Textures_SetMode( ETexturesMode mode ){
576 if ( g_texture_mode != mode ) {
577 g_texture_mode = mode;
579 Textures_ModeChanged();
583 void Textures_setTextureComponents( GLint texture_components ){
584 if ( g_texture_globals.texture_components != texture_components ) {
585 Textures_Unrealise();
586 g_texture_globals.texture_components = texture_components;
591 void Textures_UpdateTextureCompressionFormat(){
592 GLint texture_components = GL_RGBA;
594 switch ( g_texture_globals.m_nTextureCompressionFormat )
596 case ( TEXTURECOMPRESSION_NONE ):
598 texture_components = GL_RGBA;
601 case ( TEXTURECOMPRESSION_RGBA ):
603 texture_components = GL_COMPRESSED_RGBA_ARB;
606 case ( TEXTURECOMPRESSION_RGBA_S3TC_DXT1 ):
608 texture_components = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
611 case ( TEXTURECOMPRESSION_RGBA_S3TC_DXT3 ):
613 texture_components = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
616 case ( TEXTURECOMPRESSION_RGBA_S3TC_DXT5 ):
618 texture_components = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
623 Textures_setTextureComponents( texture_components );
626 void TextureCompressionImport( TextureCompressionFormat& self, int value ){
627 if ( !g_texture_globals.m_bOpenGLCompressionSupported
628 && g_texture_globals.m_bS3CompressionSupported
635 self = TEXTURECOMPRESSION_NONE;
638 self = TEXTURECOMPRESSION_RGBA;
641 self = TEXTURECOMPRESSION_RGBA_S3TC_DXT1;
644 self = TEXTURECOMPRESSION_RGBA_S3TC_DXT3;
647 self = TEXTURECOMPRESSION_RGBA_S3TC_DXT5;
650 Textures_UpdateTextureCompressionFormat();
652 typedef ReferenceCaller1<TextureCompressionFormat, int, TextureCompressionImport> TextureCompressionImportCaller;
654 void TextureGammaImport( float& self, float value ){
655 if ( self != value ) {
656 Textures_Unrealise();
661 typedef ReferenceCaller1<float, float, TextureGammaImport> TextureGammaImportCaller;
663 void TextureModeImport( ETexturesMode& self, int value ){
667 Textures_SetMode( eTextures_NEAREST );
670 Textures_SetMode( eTextures_NEAREST_MIPMAP_NEAREST );
673 Textures_SetMode( eTextures_LINEAR );
676 Textures_SetMode( eTextures_NEAREST_MIPMAP_LINEAR );
679 Textures_SetMode( eTextures_LINEAR_MIPMAP_NEAREST );
682 Textures_SetMode( eTextures_LINEAR_MIPMAP_LINEAR );
685 Textures_SetMode( eTextures_MAX_ANISOTROPY );
688 typedef ReferenceCaller1<ETexturesMode, int, TextureModeImport> TextureModeImportCaller;
690 void TextureModeExport( ETexturesMode& self, const IntImportCallback& importer ){
693 case eTextures_NEAREST:
696 case eTextures_NEAREST_MIPMAP_NEAREST:
699 case eTextures_LINEAR:
702 case eTextures_NEAREST_MIPMAP_LINEAR:
705 case eTextures_LINEAR_MIPMAP_NEAREST:
708 case eTextures_LINEAR_MIPMAP_LINEAR:
711 case eTextures_MAX_ANISOTROPY:
718 typedef ReferenceCaller1<ETexturesMode, const IntImportCallback&, TextureModeExport> TextureModeExportCaller;
720 void Textures_constructPreferences( PreferencesPage& page ){
722 const char* percentages[] = { "12.5%", "25%", "50%", "100%", };
725 STRING_ARRAY_RANGE( percentages ),
726 LatchedIntImportCaller( g_Textures_textureQuality ),
727 IntExportCaller( g_Textures_textureQuality.m_latched )
735 FloatImportCallback( TextureGammaImportCaller( g_texture_globals.fGamma ) ),
736 FloatExportCallback( FloatExportCaller( g_texture_globals.fGamma ) )
739 const char* texture_mode[] = { "Nearest", "Nearest Mipmap", "Linear", "Bilinear", "Bilinear Mipmap", "Trilinear", "Anisotropy" };
741 "Texture Render Mode",
742 STRING_ARRAY_RANGE( texture_mode ),
743 IntImportCallback( TextureModeImportCaller( g_texture_mode ) ),
744 IntExportCallback( TextureModeExportCaller( g_texture_mode ) )
748 const char* compression_none[] = { "None" };
749 const char* compression_opengl[] = { "None", "OpenGL ARB" };
750 const char* compression_s3tc[] = { "None", "S3TC DXT1", "S3TC DXT3", "S3TC DXT5" };
751 const char* compression_opengl_s3tc[] = { "None", "OpenGL ARB", "S3TC DXT1", "S3TC DXT3", "S3TC DXT5" };
752 StringArrayRange compression(
753 ( g_texture_globals.m_bOpenGLCompressionSupported )
754 ? ( g_texture_globals.m_bS3CompressionSupported )
755 ? STRING_ARRAY_RANGE( compression_opengl_s3tc )
756 : STRING_ARRAY_RANGE( compression_opengl )
757 : ( g_texture_globals.m_bS3CompressionSupported )
758 ? STRING_ARRAY_RANGE( compression_s3tc )
759 : STRING_ARRAY_RANGE( compression_none )
762 "Hardware Texture Compression",
764 TextureCompressionImportCaller( g_texture_globals.m_nTextureCompressionFormat ),
765 IntExportCaller( reinterpret_cast<int&>( g_texture_globals.m_nTextureCompressionFormat ) )
769 void Textures_constructPage( PreferenceGroup& group ){
770 PreferencesPage page( group.createPage( "Textures", "Texture Settings" ) );
771 Textures_constructPreferences( page );
773 void Textures_registerPreferencesPage(){
774 PreferencesDialog_addDisplayPage( FreeCaller1<PreferenceGroup&, Textures_constructPage>() );
777 void TextureCompression_importString( const char* string ){
778 g_texture_globals.m_nTextureCompressionFormat = static_cast<TextureCompressionFormat>( atoi( string ) );
779 Textures_UpdateTextureCompressionFormat();
781 typedef FreeCaller1<const char*, TextureCompression_importString> TextureCompressionImportStringCaller;
784 void Textures_Construct(){
785 g_texturesmap = new TexturesMap;
787 GlobalPreferenceSystem().registerPreference( "TextureCompressionFormat", TextureCompressionImportStringCaller(), IntExportStringCaller( reinterpret_cast<int&>( g_texture_globals.m_nTextureCompressionFormat ) ) );
788 GlobalPreferenceSystem().registerPreference( "TextureFiltering", IntImportStringCaller( reinterpret_cast<int&>( g_texture_mode ) ), IntExportStringCaller( reinterpret_cast<int&>( g_texture_mode ) ) );
789 GlobalPreferenceSystem().registerPreference( "TextureQuality", IntImportStringCaller( g_Textures_textureQuality.m_latched ), IntExportStringCaller( g_Textures_textureQuality.m_latched ) );
790 GlobalPreferenceSystem().registerPreference( "SI_Gamma", FloatImportStringCaller( g_texture_globals.fGamma ), FloatExportStringCaller( g_texture_globals.fGamma ) );
792 g_Textures_textureQuality.useLatched();
794 Textures_registerPreferencesPage();
796 Textures_ModeChanged();
798 void Textures_Destroy(){
799 delete g_texturesmap;
803 #include "modulesystem/modulesmap.h"
804 #include "modulesystem/singletonmodule.h"
805 #include "modulesystem/moduleregistry.h"
807 class TexturesDependencies :
808 public GlobalRadiantModuleRef,
809 public GlobalOpenGLModuleRef,
810 public GlobalPreferenceSystemModuleRef
812 ImageModulesRef m_image_modules;
814 TexturesDependencies() :
815 m_image_modules( GlobalRadiant().getRequiredGameDescriptionKeyValue( "texturetypes" ) ){
817 ImageModules& getImageModules(){
818 return m_image_modules.get();
824 TexturesCache* m_textures;
826 typedef TexturesCache Type;
827 STRING_CONSTANT( Name, "*" );
830 Textures_Construct();
832 m_textures = &GetTexturesCache();
837 TexturesCache* getTable(){
842 typedef SingletonModule<TexturesAPI, TexturesDependencies> TexturesModule;
843 typedef Static<TexturesModule> StaticTexturesModule;
844 StaticRegisterModule staticRegisterTextures( StaticTexturesModule::instance() );
846 ImageModules& Textures_getImageModules(){
847 return StaticTexturesModule::instance().getDependencies().getImageModules();