Oolite
Loading...
Searching...
No Matches
OOTexture.m
Go to the documentation of this file.
1/*
2
3 OOTexture.m
4
5 Copyright (C) 2007-2013 Jens Ayton and contributors
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24
25*/
26
27#import "OOTexture.h"
28#import "OOTextureInternal.h"
29#import "OOConcreteTexture.h"
30#import "OONullTexture.h"
31
32#import "OOTextureLoader.h"
34
36#import "Universe.h"
37#import "ResourceManager.h"
39#import "OOMacroOpenGL.h"
40#import "OOCPUInfo.h"
41#import "OOCache.h"
42#import "OOPixMap.h"
43
44
45NSString * const kOOTextureSpecifierNameKey = @"name";
46NSString * const kOOTextureSpecifierSwizzleKey = @"extract_channel";
47NSString * const kOOTextureSpecifierMinFilterKey = @"min_filter";
48NSString * const kOOTextureSpecifierMagFilterKey = @"mag_filter";
49NSString * const kOOTextureSpecifierNoShrinkKey = @"no_shrink";
50NSString * const kOOTextureSpecifierExtraShrinkKey = @"extra_shrink";
51NSString * const kOOTextureSpecifierRepeatSKey = @"repeat_s";
52NSString * const kOOTextureSpecifierRepeatTKey = @"repeat_t";
53NSString * const kOOTextureSpecifierCubeMapKey = @"cube_map";
54NSString * const kOOTextureSpecifierAnisotropyKey = @"anisotropy";
55NSString * const kOOTextureSpecifierLODBiasKey = @"texture_LOD_bias";
56
57NSString * const kOOTextureSpecifierModulateColorKey = @"color";
58NSString * const kOOTextureSpecifierIlluminationModeKey = @"illumination_mode";
59NSString * const kOOTextureSpecifierSelfColorKey = @"self_color";
60NSString * const kOOTextureSpecifierScaleFactorKey = @"scale_factor";
61NSString * const kOOTextureSpecifierBindingKey = @"binding";
62
63// Used only by "internal" specifiers from OOMakeTextureSpecifier.
64static NSString * const kOOTextureSpecifierFlagValueInternalKey = @"_oo_internal_flags";
65
66
67/* Texture caching:
68 two and a half parallel caching mechanisms are used. sLiveTextureCache
69 tracks all live texture objects with cache keys, without retaining them
70 (using NSValues to refer to the objects).
71
72 sAllLiveTextures tracks all textures, including ones without cache keys,
73 so that they can be notified of graphics resets. This also uses NSValues
74 to avoid retaining the textures.
75
76 sRecentTextures tracks up to kRecentTexturesCount textures which
77 have been used recently, and retains them.
78
79 This means that the number of live texture objects will never fall below
80 80% of kRecentTexturesCount (80% comes from the behaviour of OOCache), but
81 old textures will eventually be released. If the number of active textures
82 exceeds kRecentTexturesCount, all of them will be reusable through
83 sLiveTextureCache, but only a most-recently-fetched subset will be kept
84 around by the cache when the number drops.
85
86 Note the textures in sRecentTextures are a superset of the textures in
87 sLiveTextureCache, and the textures in sLiveTextureCache are a superset
88 of sRecentTextures.
89*/
90enum
91{
93};
94
95static NSMutableDictionary *sLiveTextureCache;
96static NSMutableSet *sAllLiveTextures;
98
99
102
103
104@interface OOTexture (OOPrivate)
105
106- (void) addToCaches;
107+ (OOTexture *) existingTextureForKey:(NSString *)key;
108
109- (void) forceRebind;
110
111+ (void)checkExtensions;
112
113#ifndef NDEBUG
114- (id) retainInContext:(NSString *)context;
115- (void) releaseInContext:(NSString *)context;
116- (id) autoreleaseInContext:(NSString *)context;
117#endif
118
119@end
121
122#ifndef NDEBUG
123static NSString *sGlobalTraceContext = nil;
124
125#define SET_TRACE_CONTEXT(str) do { sGlobalTraceContext = (str); } while (0)
126#else
127#define SET_TRACE_CONTEXT(str) do { } while (0)
128#endif
129#define CLEAR_TRACE_CONTEXT() SET_TRACE_CONTEXT(nil)
130
131
132@implementation OOTexture
133
134+ (id)textureWithName:(NSString *)name
135 inFolder:(NSString*)directory
136 options:(OOTextureFlags)options
137 anisotropy:(GLfloat)anisotropy
138 lodBias:(GLfloat)lodBias
139{
140 NSString *key = nil;
141 OOTexture *result = nil;
142 NSString *path = nil;
143 BOOL noFNF;
144
145 if (EXPECT_NOT(name == nil)) return nil;
146 if (EXPECT_NOT(!sCheckedExtensions)) [self checkExtensions];
147
149 {
150 anisotropy = 0.0f;
151 }
153 {
154 lodBias = 0.0f;
155 }
156
157 noFNF = (options & kOOTextureNoFNFMessage) != 0;
159
160 // Look for existing texture
161 key = OOGenerateTextureCacheKey(directory, name, options, anisotropy, lodBias);
162 result = [OOTexture existingTextureForKey:key];
163 if (result == nil)
164 {
165 path = [ResourceManager pathForFileNamed:name inFolder:directory];
166 if (path == nil)
167 {
168 if (!noFNF) OOLogWARN(kOOLogFileNotFound, @"Could not find texture file \"%@\".", name);
169 return nil;
170 }
171
172 // No existing texture, load texture.
173 result = [[[OOConcreteTexture alloc] initWithPath:path key:key options:options anisotropy:anisotropy lodBias:lodBias] autorelease];
174 }
175
176
177 return result;
178}
179
180
181+ (id)textureWithName:(NSString *)name
182 inFolder:(NSString*)directory
183{
184 return [self textureWithName:name
185 inFolder:directory
186 options:kOOTextureDefaultOptions
187 anisotropy:kOOTextureDefaultAnisotropy
188 lodBias:kOOTextureDefaultLODBias];
189}
190
191
192+ (id)textureWithConfiguration:(id)configuration
193{
194 return [self textureWithConfiguration:configuration extraOptions:0];
195}
196
197
198+ (id) textureWithConfiguration:(id)configuration extraOptions:(OOTextureFlags)extraOptions
199{
200 NSString *name = nil;
201 OOTextureFlags options = 0;
202 GLfloat anisotropy = 0.0f;
203 GLfloat lodBias = 0.0f;
204
205 if (!OOInterpretTextureSpecifier(configuration, &name, &options, &anisotropy, &lodBias, NO)) return nil;
206
207 return [self textureWithName:name inFolder:@"Textures" options:options | extraOptions anisotropy:anisotropy lodBias:lodBias];
208}
209
210
211+ (id) nullTexture
212{
214}
215
216
217+ (id) textureWithGenerator:(OOTextureGenerator *)generator
218{
219 return [self textureWithGenerator:generator enqueue: NO];
220}
221
222
223+ (id) textureWithGenerator:(OOTextureGenerator *)generator enqueue:(BOOL) enqueue
224{
225 if (generator == nil) return nil;
226
227#ifndef OOTEXTURE_NO_CACHE
228 OOTexture *existing = [OOTexture existingTextureForKey:[generator cacheKey]];
229 if (existing != nil && !enqueue) return [[existing retain] autorelease];
230#endif
231
232 if (![generator enqueue])
233 {
234 OOLogERR(@"texture.generator.queue.failed", @"Failed to queue generator %@", generator);
235 return nil;
236 }
237 OOLog(@"texture.generator.queue", @"Queued texture generator %@", generator);
238
239 OOTexture *result = [[[OOConcreteTexture alloc] initWithLoader:generator
240 key:[generator cacheKey]
241 options:OOApplyTextureOptionDefaults([generator textureOptions])
242 anisotropy:[generator anisotropy]
243 lodBias:[generator lodBias]] autorelease];
244
245 return result;
246}
247
248
249- (id) init
250{
251 if ((self = [super init]))
252 {
253 if (EXPECT_NOT(sAllLiveTextures == nil)) sAllLiveTextures = [[NSMutableSet alloc] init];
254 [sAllLiveTextures addObject:[NSValue valueWithPointer:self]];
255 }
256
257 return self;
258}
259
260
261- (void) dealloc
262{
263 [sAllLiveTextures removeObject:[NSValue valueWithPointer:self]];
264
265 [super dealloc];
266}
267
268
269- (void)apply
270{
272}
273
274
275+ (void)applyNone
276{
278 OOGL(glBindTexture(GL_TEXTURE_2D, 0));
279#if OO_TEXTURE_CUBE_MAP
280 if (OOCubeMapsAvailable()) OOGL(glBindTexture(GL_TEXTURE_CUBE_MAP, 0));
281#endif
282
283#if GL_EXT_texture_lod_bias
284 if (gOOTextureInfo.textureLODBiasAvailable) OOGL(glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0));
285#endif
286}
287
288
289- (void)ensureFinishedLoading
290{
291}
292
293
294- (BOOL) isFinishedLoading
295{
296 return YES;
297}
298
299
300- (NSString *) cacheKey
301{
302 return nil;
303}
304
305
306- (NSSize) dimensions
307{
309 return NSZeroSize;
310}
311
312
313- (NSSize) originalDimensions
314{
315 return [self dimensions];
316}
317
318
319- (BOOL) isMipMapped
320{
322 return NO;
323}
324
325
326- (struct OOPixMap) copyPixMapRepresentation
327{
328 return kOONullPixMap;
329}
330
331
332- (BOOL) isRectangleTexture
333{
334 return NO;
335}
336
337
338- (BOOL) isCubeMap
339{
340 return NO;
341}
342
343
344- (NSSize)texCoordsScale
345{
346 return NSMakeSize(1.0, 1.0);
347}
348
349
350- (GLint)glTextureName
351{
353 return 0;
354}
355
356
357+ (void)clearCache
358{
359 /* Does not clear sAllLiveTextures - that really must refer to all
360 live texture objects.
361 */
362 SET_TRACE_CONTEXT(@"clearing sLiveTextureCache");
363 [sLiveTextureCache autorelease];
365
366 SET_TRACE_CONTEXT(@"clearing sRecentTextures");
367 [sRecentTextures autorelease];
370}
371
372
373+ (void)rebindAllTextures
374{
375 NSEnumerator *textureEnum = nil;
376 id texture = nil;
377
378 // Keeping around unused, cached textures is unhelpful at this point.
380
381 for (textureEnum = [sAllLiveTextures objectEnumerator]; (texture = [[textureEnum nextObject] pointerValue]); )
382 {
383 [texture forceRebind];
384 }
385}
386
387
388#ifndef NDEBUG
389- (void) setTrace:(BOOL)trace
390{
391 if (trace && !_trace)
392 {
393 OOLog(@"texture.allocTrace.begin", @"Started tracing texture %p with retain count %llu.", self, [self retainCount]);
394 }
395 _trace = trace;
396}
397
398
399+ (NSArray *) cachedTexturesByAge
400{
401 return [sRecentTextures objectsByAge];
402}
403
404
405+ (NSSet *) allTextures
406{
407 NSMutableSet *result = [NSMutableSet setWithCapacity:[sAllLiveTextures count]];
408 NSValue *box = nil;
409 foreach (box, sAllLiveTextures)
410 {
411 [result addObject:[box pointerValue]];
412 }
413
414 return result;
415}
416
417
418- (size_t) dataSize
419{
420 NSSize dimensions = [self dimensions];
421 size_t size = dimensions.width * dimensions.height;
422 if ([self isCubeMap]) size *= 6;
423 if ([self isMipMapped]) size = size * 4 / 3;
424
425 return size;
426}
427
428
429- (NSString *) name
430{
432 return nil;
433}
434#endif
435
436
437- (void) forceRebind
438{
440}
441
442
443- (void) addToCaches
444{
445#ifndef OOTEXTURE_NO_CACHE
446 NSString *cacheKey = [self cacheKey];
447 if (cacheKey == nil) return;
448
449 // Add self to in-use textures cache, wrapped in an NSValue so the texture isn't retained by the cache.
450 if (EXPECT_NOT(sLiveTextureCache == nil)) sLiveTextureCache = [[NSMutableDictionary alloc] init];
451
452 SET_TRACE_CONTEXT(@"in-use textures cache - SHOULD NOT RETAIN");
453 [sLiveTextureCache setObject:[NSValue valueWithPointer:self] forKey:cacheKey];
455
456 // Add self to recent textures cache.
458 {
459 sRecentTextures = [[OOCache alloc] init];
460 [sRecentTextures setName:@"recent textures"];
461 [sRecentTextures setAutoPrune:YES];
462 [sRecentTextures setPruneThreshold:kRecentTexturesCount];
463 }
464
465 SET_TRACE_CONTEXT(@"adding to recent textures cache");
466 [sRecentTextures setObject:self forKey:cacheKey];
468#endif
469}
470
471
472- (void) removeFromCaches
473{
474#ifndef OOTEXTURE_NO_CACHE
475 NSString *cacheKey = [self cacheKey];
476 if (cacheKey == nil) return;
477
478 [sLiveTextureCache removeObjectForKey:cacheKey];
479 if (EXPECT_NOT([sRecentTextures objectForKey:cacheKey] == self))
480 {
481 /* Experimental for now: I think the recent crash problems may
482 * be because if the last reference to a texture is in
483 * sRecentTextures, and the texture is regenerated, it
484 * replaces the texture, causing a release. Therefore, if this
485 * texture *isn't* overretained in the texture cache, the 2009
486 * crash avoider will delete its replacement from the cache
487 * ... possibly before that texture has been fully added to
488 * the cache itself. So, the texture is only removed from the
489 * cache by key if it was in it with that key. The extra time
490 * needed to generate a planet texture compared with loading a
491 * standard one may be why this problem shows up. - CIM 20140122
492 */
493 NSAssert2(0, @"Texture retain count error for %@; cacheKey is %@.", self, cacheKey); //miscount in autorelease
494 // The following line is needed in order to avoid crashes when there's a 'texture retain count error'. Please do not delete. -- Kaks 20091221
495 [sRecentTextures removeObjectForKey:cacheKey]; // make sure there's no reference left inside sRecentTexture ( was a show stopper for 1.73)
496 }
497#endif
498}
499
500
501+ (OOTexture *) existingTextureForKey:(NSString *)key
502{
503#ifndef OOTEXTURE_NO_CACHE
504 if (key != nil)
505 {
506 return (OOTexture *)[[sLiveTextureCache objectForKey:key] pointerValue];
507 }
508 return nil;
509#else
510 return nil;
511#endif
512}
513
514
515+ (void)checkExtensions
516{
518
519 sCheckedExtensions = YES;
520
522 BOOL ver120 = [extMgr versionIsAtLeastMajor:1 minor:2];
523 BOOL ver130 = [extMgr versionIsAtLeastMajor:1 minor:3];
524
525#if GL_EXT_texture_filter_anisotropic
526 gOOTextureInfo.anisotropyAvailable = [extMgr haveExtension:@"GL_EXT_texture_filter_anisotropic"];
527 OOGL(glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gOOTextureInfo.anisotropyScale));
528 gOOTextureInfo.anisotropyScale *= OOClamp_0_1_f([[NSUserDefaults standardUserDefaults] oo_floatForKey:@"texture-anisotropy-scale" defaultValue:0.5]);
529#endif
530
531#ifdef GL_CLAMP_TO_EDGE
532 gOOTextureInfo.clampToEdgeAvailable = ver120 || [extMgr haveExtension:@"GL_SGIS_texture_edge_clamp"];
533#endif
534
535#if OO_GL_CLIENT_STORAGE
536 gOOTextureInfo.clientStorageAvailable = [extMgr haveExtension:@"GL_APPLE_client_storage"];
537#endif
538
539 gOOTextureInfo.textureMaxLevelAvailable = ver120 || [extMgr haveExtension:@"GL_SGIS_texture_lod"];
540
541#if GL_EXT_texture_lod_bias
542 if ([[NSUserDefaults standardUserDefaults] oo_boolForKey:@"use-texture-lod-bias" defaultValue:YES])
543 {
544 gOOTextureInfo.textureLODBiasAvailable = [extMgr haveExtension:@"GL_EXT_texture_lod_bias"];
545 }
546 else
547 {
549 }
550#endif
551
552#if GL_EXT_texture_rectangle
553 gOOTextureInfo.rectangleTextureAvailable = [extMgr haveExtension:@"GL_EXT_texture_rectangle"];
554#endif
555
556#if OO_TEXTURE_CUBE_MAP
557 if (![[NSUserDefaults standardUserDefaults] boolForKey:@"disable-cube-maps"])
558 {
559 gOOTextureInfo.cubeMapAvailable = ver130 || [extMgr haveExtension:@"GL_ARB_texture_cube_map"];
560 }
561 else
562 {
564 }
565
566#endif
567}
568
569
570#ifndef NDEBUG
571- (id) retainInContext:(NSString *)context
572{
573 if (_trace)
574 {
575 if (context) OOLog(@"texture.allocTrace.retain", @"Texture %p retained (retain count -> %llu) - %@.", self, [self retainCount] + 1, context);
576 else OOLog(@"texture.allocTrace.retain", @"Texture %p retained (retain count -> %llu).", self, [self retainCount] + 1);
577 }
578
579 return [super retain];
580}
581
582
583- (void) releaseInContext:(NSString *)context
584{
585 if (_trace)
586 {
587 if (context) OOLog(@"texture.allocTrace.release", @"Texture %p released (retain count -> %llu) - %@.", self, [self retainCount] - 1, context);
588 else OOLog(@"texture.allocTrace.release", @"Texture %p released (retain count -> %llu).", self, [self retainCount] - 1);
589 }
590
591 [super release];
592}
593
594
595- (id) autoreleaseInContext:(NSString *)context
596{
597 if (_trace)
598 {
599 if (context) OOLog(@"texture.allocTrace.autoreleased", @"Texture %p autoreleased - %@.", self, context);
600 else OOLog(@"texture.allocTrace.autoreleased", @"Texture %p autoreleased.", self);
601 }
602
603 return [super autorelease];
604}
605
606
607- (id) retain
608{
609 return [self retainInContext:sGlobalTraceContext];
610}
611
612
613- (oneway void) release
614{
615 [self releaseInContext:sGlobalTraceContext];
616}
617
618
619- (id) autorelease
620{
621 return [self autoreleaseInContext:sGlobalTraceContext];
622}
623#endif
624
625@end
626
627
628@implementation NSDictionary (OOTextureConveniences)
629
630- (NSDictionary *) oo_textureSpecifierForKey:(id)key defaultName:(NSString *)name
631{
632 return OOTextureSpecFromObject([self objectForKey:key], name);
633}
634
635@end
636
637@implementation NSArray (OOTextureConveniences)
638
639- (NSDictionary *) oo_textureSpecifierAtIndex:(unsigned)index defaultName:(NSString *)name
640{
641 return OOTextureSpecFromObject([self objectAtIndex:index], name);
642}
643
644@end
645
646NSDictionary *OOTextureSpecFromObject(id object, NSString *defaultName)
647{
648 if (object == nil) object = defaultName;
649 if ([object isKindOfClass:[NSString class]])
650 {
651 if ([object isEqualToString:@""]) return nil;
652 return [NSDictionary dictionaryWithObject:object forKey:@"name"];
653 }
654 if (![object isKindOfClass:[NSDictionary class]]) return nil;
655
656 // If we're here, it's a dictionary.
657 if (defaultName == nil || [object oo_stringForKey:@"name"] != nil) return object;
658
659 // If we get here, there's no "name" key and there is a default, so we fill it in:
660 NSMutableDictionary *mutableResult = [NSMutableDictionary dictionaryWithDictionary:object];
661 [mutableResult setObject:[[defaultName copy] autorelease] forKey:@"name"];
662 return mutableResult;
663}
664
665
667{
668 switch (format)
669 {
671 return 4;
672
674 return 1;
675
677 return 2;
678
680 break;
681 }
682
683 return 0;
684}
685
686
688{
690}
691
692
693BOOL OOInterpretTextureSpecifier(id specifier, NSString **outName, OOTextureFlags *outOptions, float *outAnisotropy, float *outLODBias, BOOL ignoreExtract)
694{
695 NSString *name = nil;
697 float anisotropy = kOOTextureDefaultAnisotropy;
698 float lodBias = kOOTextureDefaultLODBias;
699
700 if ([specifier isKindOfClass:[NSString class]])
701 {
702 name = specifier;
703 }
704 else if ([specifier isKindOfClass:[NSDictionary class]])
705 {
706 name = [specifier oo_stringForKey:kOOTextureSpecifierNameKey];
707 if (name == nil)
708 {
709 OOLog(@"texture.load.noName", @"Invalid texture configuration dictionary (must specify name):\n%@", specifier);
710 return NO;
711 }
712
713 int quickFlags = [specifier oo_intForKey:kOOTextureSpecifierFlagValueInternalKey defaultValue:-1];
714 if (quickFlags != -1)
715 {
716 options = quickFlags;
717 }
718 else
719 {
720 NSString *filterString = [specifier oo_stringForKey:kOOTextureSpecifierMinFilterKey defaultValue:@"default"];
721 if ([filterString isEqualToString:@"nearest"]) options |= kOOTextureMinFilterNearest;
722 else if ([filterString isEqualToString:@"linear"]) options |= kOOTextureMinFilterLinear;
723 else if ([filterString isEqualToString:@"mipmap"]) options |= kOOTextureMinFilterMipMap;
724 else options |= kOOTextureMinFilterDefault; // Covers "default"
725
726 filterString = [specifier oo_stringForKey:kOOTextureSpecifierMagFilterKey defaultValue:@"default"];
727 if ([filterString isEqualToString:@"nearest"]) options |= kOOTextureMagFilterNearest;
728 else options |= kOOTextureMagFilterLinear; // Covers "default" and "linear"
729
730 if ([specifier oo_boolForKey:kOOTextureSpecifierNoShrinkKey defaultValue:NO]) options |= kOOTextureNoShrink;
731 if ([specifier oo_boolForKey:kOOTextureSpecifierExtraShrinkKey defaultValue:NO]) options |= kOOTextureExtraShrink;
732 if ([specifier oo_boolForKey:kOOTextureSpecifierRepeatSKey defaultValue:NO]) options |= kOOTextureRepeatS;
733 if ([specifier oo_boolForKey:kOOTextureSpecifierRepeatTKey defaultValue:NO]) options |= kOOTextureRepeatT;
734 if ([specifier oo_boolForKey:kOOTextureSpecifierCubeMapKey defaultValue:NO]) options |= kOOTextureAllowCubeMap;
735
736 if (!ignoreExtract)
737 {
738 NSString *extractChannel = [specifier oo_stringForKey:@"extract_channel"];
739 if (extractChannel != nil)
740 {
741 if ([extractChannel isEqualToString:@"r"]) options |= kOOTextureExtractChannelR;
742 else if ([extractChannel isEqualToString:@"g"]) options |= kOOTextureExtractChannelG;
743 else if ([extractChannel isEqualToString:@"b"]) options |= kOOTextureExtractChannelB;
744 else if ([extractChannel isEqualToString:@"a"]) options |= kOOTextureExtractChannelA;
745 else
746 {
747 OOLogWARN(@"texture.load.extractChannel.invalid", @"Unknown value \"%@\" for extract_channel in specifier \"%@\" (should be \"r\", \"g\", \"b\" or \"a\").", extractChannel,specifier);
748 }
749 }
750 }
751 }
752 anisotropy = [specifier oo_floatForKey:@"anisotropy" defaultValue:kOOTextureDefaultAnisotropy];
753 lodBias = [specifier oo_floatForKey:@"texture_LOD_bias" defaultValue:kOOTextureDefaultLODBias];
754 }
755 else
756 {
757 // Bad type
758 if (specifier != nil) OOLog(kOOLogParameterError, @"%s: expected string or dictionary, got %@.", __PRETTY_FUNCTION__, [specifier class]);
759 return NO;
760 }
761
762 if ([name length] == 0) return NO;
763
764 if (outName != NULL) *outName = name;
765 if (outOptions != NULL) *outOptions = options;
766 if (outAnisotropy != NULL) *outAnisotropy = anisotropy;
767 if (outLODBias != NULL) *outLODBias = lodBias;
768
769 return YES;
770}
771
772
773NSDictionary *OOMakeTextureSpecifier(NSString *name, OOTextureFlags options, float anisotropy, float lodBias, BOOL internal)
774{
775 NSMutableDictionary *result = [NSMutableDictionary dictionary];
776
777 [result setObject:name forKey:kOOTextureSpecifierNameKey];
778
779 if (anisotropy != kOOTextureDefaultAnisotropy) [result oo_setFloat:anisotropy forKey:kOOTextureSpecifierAnisotropyKey];
780 if (lodBias != kOOTextureDefaultLODBias) [result oo_setFloat:lodBias forKey:kOOTextureSpecifierLODBiasKey];
781
782 if (internal)
783 {
784 [result oo_setUnsignedInteger:options forKey:kOOTextureSpecifierFlagValueInternalKey];
785 }
786 else
787 {
788 NSString *value = nil;
789 switch (options & kOOTextureMinFilterMask)
790 {
792 break;
793
795 value = @"nearest";
796 break;
797
799 value = @"linear";
800 break;
801
803 value = @"mipmap";
804 break;
805 }
806 if (value != nil) [result setObject:value forKey:kOOTextureSpecifierNoShrinkKey];
807
808 value = nil;
809 switch (options & kOOTextureMagFilterMask)
810 {
812 value = @"nearest";
813 break;
814
816 break;
817 }
818 if (value != nil) [result setObject:value forKey:kOOTextureSpecifierMagFilterKey];
819
820 value = nil;
821 switch (options & kOOTextureExtractChannelMask)
822 {
824 break;
825
827 value = @"r";
828 break;
829
831 value = @"g";
832 break;
833
835 value = @"b";
836 break;
837
839 value = @"a";
840 break;
841 }
842 if (value != nil) [result setObject:value forKey:kOOTextureSpecifierSwizzleKey];
843
844 if (options & kOOTextureNoShrink) [result oo_setBool:YES forKey:kOOTextureSpecifierNoShrinkKey];
845 if (options & kOOTextureRepeatS) [result oo_setBool:YES forKey:kOOTextureSpecifierRepeatSKey];
846 if (options & kOOTextureRepeatT) [result oo_setBool:YES forKey:kOOTextureSpecifierRepeatTKey];
847 if (options & kOOTextureAllowCubeMap) [result oo_setBool:YES forKey:kOOTextureSpecifierCubeMapKey];
848 }
849
850 return result;
851}
852
853
855{
856 // Set default flags if needed
858 {
859 if ([UNIVERSE reducedDetail])
860 {
861 options |= kOOTextureMinFilterLinear;
862 }
863 else
864 {
865 options |= kOOTextureMinFilterMipMap;
866 }
867 }
868
870 {
871 /* In the unlikely case of an OpenGL system without GL_SGIS_texture_lod,
872 disable mip-mapping completely. Strictly this is only needed for
873 non-square textures, but extra logic for such a rare case isn't
874 worth it.
875 */
877 {
879 }
880 }
881
882 if (options & kOOTextureAllowRectTexture)
883 {
884 // Apply rectangle texture restrictions (regardless of whether rectangle textures are available, for consistency)
887 {
888 options = (kOOTextureMinFilterMask & ~kOOTextureMinFilterMask) | kOOTextureMinFilterLinear;
889 }
890
891#if GL_EXT_texture_rectangle
893 {
894 options &= ~kOOTextureAllowRectTexture;
895 }
896#else
897 options &= ~kOOTextureAllowRectTexture;
898#endif
899 }
900
901 options &= kOOTextureDefinedFlags;
902
903 return options;
904}
905
906
907NSString *OOGenerateTextureCacheKey(NSString *directory, NSString *name, OOTextureFlags options, float anisotropy, float lodBias)
908{
910 {
911 anisotropy = 0.0f;
912 }
914 {
915 lodBias = 0.0f;
916 }
918
919 return [NSString stringWithFormat:@"%@%@%@:0x%.4X/%g/%g", directory ? directory : (NSString *)@"", directory ? @"/" : @"", name, options, anisotropy, lodBias];
920}
921
922
923NSString *OOTextureCacheKeyForSpecifier(id specifier)
924{
925 NSString *name;
926 OOTextureFlags options;
927 float anisotropy;
928 float lodBias;
929
930 OOInterpretTextureSpecifier(specifier, &name, &options, &anisotropy, &lodBias, NO);
931 return OOGenerateTextureCacheKey(@"Textures", name, options, anisotropy, lodBias);
932}
#define DESTROY(x)
Definition OOCocoa.h:75
#define EXPECT_NOT(x)
#define OOLogWARN(class, format,...)
Definition OOLogging.h:113
#define OOLogERR(class, format,...)
Definition OOLogging.h:112
#define OOLogGenericSubclassResponsibility()
Definition OOLogging.h:129
#define OOLog(class, format,...)
Definition OOLogging.h:88
NSString *const kOOLogParameterError
Definition OOLogging.m:647
NSString *const kOOLogFileNotFound
Definition OOLogging.m:652
#define OO_ENTER_OPENGL()
#define OOGL(statement)
Definition OOOpenGL.h:251
return self
OOPixMapFormat
Definition OOPixMap.h:39
const OOPixMap kOONullPixMap
Definition OOPixMap.m:31
return nil
NSString *const kOOTextureSpecifierNoShrinkKey
Definition OOTexture.m:49
BOOL OOCubeMapsAvailable(void)
Definition OOTexture.m:687
uint8_t OOTextureComponentsForFormat(OOTextureDataFormat format)
Definition OOTexture.m:666
@ kOOTextureDataGrayscaleAlpha
Definition OOTexture.h:111
@ kOOTextureDataGrayscale
Definition OOTexture.h:110
@ kOOTextureDataInvalid
Definition OOTexture.h:107
@ kOOTextureDataRGBA
Definition OOTexture.h:109
NSDictionary * OOMakeTextureSpecifier(NSString *name, OOTextureFlags options, float anisotropy, float lodBias, BOOL internal)
Definition OOTexture.m:773
NSString *const kOOTextureSpecifierRepeatTKey
Definition OOTexture.m:52
OOTextureFlags OOApplyTextureOptionDefaults(OOTextureFlags options)
Definition OOTexture.m:854
NSDictionary * OOTextureSpecFromObject(id object, NSString *defaultName)
Definition OOTexture.m:646
#define kOOTextureDefaultAnisotropy
Definition OOTexture.h:101
@ kOOTextureRepeatS
Definition OOTexture.h:55
@ kOOTextureAllowRectTexture
Definition OOTexture.h:57
@ kOOTextureExtractChannelA
Definition OOTexture.h:70
@ kOOTextureExtractChannelB
Definition OOTexture.h:69
@ kOOTextureNoFNFMessage
Definition OOTexture.h:58
@ kOOTextureNoShrink
Definition OOTexture.h:53
@ kOOTextureMinFilterDefault
Definition OOTexture.h:45
@ kOOTextureExtractChannelNone
Definition OOTexture.h:66
@ kOOTextureMagFilterMask
Definition OOTexture.h:73
@ kOOTextureExtractChannelMask
Definition OOTexture.h:65
@ kOOTextureDefinedFlags
Definition OOTexture.h:78
@ kOOTextureMinFilterLinear
Definition OOTexture.h:47
@ kOOTextureAllowCubeMap
Definition OOTexture.h:61
@ kOOTextureMinFilterMask
Definition OOTexture.h:72
@ kOOTextureRepeatT
Definition OOTexture.h:56
@ kOOTextureDefaultOptions
Definition OOTexture.h:76
@ kOOTextureMinFilterMipMap
Definition OOTexture.h:48
@ kOOTextureMagFilterNearest
Definition OOTexture.h:50
@ kOOTextureExtraShrink
Definition OOTexture.h:54
@ kOOTextureExtractChannelG
Definition OOTexture.h:68
@ kOOTextureFlagsAllowedForRectangleTexture
Definition OOTexture.h:91
@ kOOTextureExtractChannelR
Definition OOTexture.h:67
@ kOOTextureMagFilterLinear
Definition OOTexture.h:51
@ kOOTextureMinFilterNearest
Definition OOTexture.h:46
uint32_t OOTextureFlags
Definition OOTexture.h:98
NSString *const kOOTextureSpecifierRepeatSKey
Definition OOTexture.m:51
#define kOOTextureDefaultLODBias
Definition OOTexture.h:102
BOOL OOInterpretTextureSpecifier(id specifier, NSString **outName, OOTextureFlags *outOptions, float *outAnisotropy, float *outLODBias, BOOL ignoreExtract)
Definition OOTexture.m:693
NSString *const kOOTextureSpecifierCubeMapKey
Definition OOTexture.m:53
NSString *const kOOTextureSpecifierExtraShrinkKey
Definition OOTexture.m:50
#define CLEAR_TRACE_CONTEXT()
Definition OOTexture.m:129
NSString *const kOOTextureSpecifierSelfColorKey
Definition OOTexture.m:59
NSString *const kOOTextureSpecifierNoShrinkKey
Definition OOTexture.m:49
NSString *const kOOTextureSpecifierNameKey
Definition OOTexture.m:45
#define SET_TRACE_CONTEXT(str)
Definition OOTexture.m:125
static OOCache * sRecentTextures
Definition OOTexture.m:97
NSString *const kOOTextureSpecifierRepeatTKey
Definition OOTexture.m:52
static NSMutableDictionary * sLiveTextureCache
Definition OOTexture.m:95
NSString *const kOOTextureSpecifierScaleFactorKey
Definition OOTexture.m:60
static NSString * sGlobalTraceContext
Definition OOTexture.m:123
NSString * OOTextureCacheKeyForSpecifier(id specifier)
Definition OOTexture.m:923
static BOOL sCheckedExtensions
Definition OOTexture.m:100
NSString *const kOOTextureSpecifierBindingKey
Definition OOTexture.m:61
static NSMutableSet * sAllLiveTextures
Definition OOTexture.m:96
NSString *const kOOTextureSpecifierIlluminationModeKey
Definition OOTexture.m:58
NSString *const kOOTextureSpecifierMinFilterKey
Definition OOTexture.m:47
NSString *const kOOTextureSpecifierMagFilterKey
Definition OOTexture.m:48
@ kRecentTexturesCount
Definition OOTexture.m:92
NSString *const kOOTextureSpecifierAnisotropyKey
Definition OOTexture.m:54
static NSString *const kOOTextureSpecifierFlagValueInternalKey
Definition OOTexture.m:64
NSString *const kOOTextureSpecifierRepeatSKey
Definition OOTexture.m:51
NSString * OOGenerateTextureCacheKey(NSString *directory, NSString *name, OOTextureFlags options, float anisotropy, float lodBias)
Definition OOTexture.m:907
NSString *const kOOTextureSpecifierModulateColorKey
Definition OOTexture.m:57
NSString *const kOOTextureSpecifierCubeMapKey
Definition OOTexture.m:53
OOTextureInfo gOOTextureInfo
Definition OOTexture.m:101
NSString *const kOOTextureSpecifierSwizzleKey
Definition OOTexture.m:46
NSString *const kOOTextureSpecifierExtraShrinkKey
Definition OOTexture.m:50
NSString *const kOOTextureSpecifierLODBiasKey
Definition OOTexture.m:55
#define UNIVERSE
Definition Universe.h:842
void setPruneThreshold:(unsigned threshold)
Definition OOCache.m:299
void setName:(NSString *name)
Definition OOCache.m:375
NSArray * objectsByAge()
Definition OOCache.m:381
void setAutoPrune:(BOOL flag)
Definition OOCache.m:316
void removeObjectForKey:(id key)
Definition OOCache.m:289
void setObject:forKey:(id value,[forKey] id key)
Definition OOCache.m:275
OONullTexture * sharedNullTexture()
BOOL versionIsAtLeastMajor:minor:(unsigned maj,[minor] unsigned min)
OOOpenGLExtensionManager * sharedManager()
BOOL haveExtension:(NSString *extension)
OOTexture * existingTextureForKey:(NSString *key)
Definition OOTexture.m:501
NSString * pathForFileNamed:inFolder:(NSString *fileName,[inFolder] NSString *folderName)
voidpf void uLong size
Definition ioapi.h:134
unsigned clientStorageAvailable
unsigned textureMaxLevelAvailable
unsigned anisotropyAvailable
unsigned clampToEdgeAvailable
unsigned cubeMapAvailable
unsigned rectangleTextureAvailable
unsigned textureLODBiasAvailable