LCOV - code coverage report
Current view: top level - Core/Materials - OOShaderMaterial.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 2 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOShaderMaterial.m
       4             : 
       5             : 
       6             : Copyright (C) 2007-2013 Jens Ayton
       7             : 
       8             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9             : of this software and associated documentation files (the "Software"), to deal
      10             : in the Software without restriction, including without limitation the rights
      11             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12             : copies of the Software, and to permit persons to whom the Software is
      13             : furnished to do so, subject to the following conditions:
      14             : 
      15             : The above copyright notice and this permission notice shall be included in all
      16             : copies or substantial portions of the Software.
      17             : 
      18             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24             : SOFTWARE.
      25             : 
      26             : */
      27             : 
      28             : 
      29             : #import "OOShaderMaterial.h"
      30             : 
      31             : #if OO_SHADERS
      32             : 
      33             : #import "ResourceManager.h"
      34             : #import "OOShaderUniform.h"
      35             : #import "OOFunctionAttributes.h"
      36             : #import "OOCollectionExtractors.h"
      37             : #import "OOShaderProgram.h"
      38             : #import "OOTexture.h"
      39             : #import "OOOpenGLExtensionManager.h"
      40             : #import "OOMacroOpenGL.h"
      41             : #import "Universe.h"
      42             : #import "OOIsNumberLiteral.h"
      43             : #import "OOLogging.h"
      44             : #import "OODebugFlags.h"
      45             : #import "OOStringParsing.h"
      46             : 
      47             : 
      48             : NSString * const kOOVertexShaderSourceKey               = @"_oo_vertex_shader_source";
      49             : NSString * const kOOVertexShaderNameKey                 = @"vertex_shader";
      50             : NSString * const kOOFragmentShaderSourceKey             = @"_oo_fragment_shader_source";
      51             : NSString * const kOOFragmentShaderNameKey               = @"fragment_shader";
      52             : NSString * const kOOTexturesKey                                 = @"textures";
      53             : NSString * const kOOTextureObjectsKey                   = @"_oo_texture_objects";
      54             : NSString * const kOOUniformsKey                                 = @"uniforms";
      55             : NSString * const kOOIsSynthesizedMaterialConfigurationKey = @"_oo_is_synthesized_config";
      56             : NSString * const kOOIsSynthesizedMaterialMacrosKey = @"_oo_synthesized_material_macros";
      57             : 
      58             : 
      59             : static BOOL GetShaderSource(NSString *fileName, NSString *shaderType, NSString *prefix, NSString **outResult);
      60             : static NSString *MacrosToString(NSDictionary *macros);
      61             : 
      62             : 
      63             : @interface OOShaderMaterial (OOPrivate)
      64             : 
      65             : // Convert a "textures" array to an "_oo_texture_objects" array.
      66             : - (NSArray *) loadTexturesFromArray:(NSArray *)textureSpecs unitCount:(GLuint)max;
      67             : 
      68             : // Load up an array of texture objects.
      69             : - (void) addTexturesFromArray:(NSArray *)textureObjects unitCount:(GLuint)max;
      70             : 
      71             : @end
      72             : 
      73             : 
      74             : @implementation OOShaderMaterial
      75             : 
      76             : + (BOOL)configurationDictionarySpecifiesShaderMaterial:(NSDictionary *)configuration
      77             : {
      78             :         if (configuration == nil)  return NO;
      79             :         
      80             :         if ([configuration oo_stringForKey:kOOVertexShaderSourceKey] != nil)  return YES;
      81             :         if ([configuration oo_stringForKey:kOOFragmentShaderSourceKey] != nil)  return YES;
      82             :         if ([configuration oo_stringForKey:kOOVertexShaderNameKey] != nil)  return YES;
      83             :         if ([configuration oo_stringForKey:kOOVertexShaderNameKey] != nil)  return YES;
      84             :         
      85             :         return NO;
      86             : }
      87             : 
      88             : 
      89             : + (instancetype) shaderMaterialWithName:(NSString *)name
      90             :                                                   configuration:(NSDictionary *)configuration
      91             :                                                                  macros:(NSDictionary *)macros
      92             :                                                   bindingTarget:(id<OOWeakReferenceSupport>)target
      93             : {
      94             :         return [[[self alloc] initWithName:name configuration:configuration macros:macros bindingTarget:target] autorelease];
      95             : }
      96             : 
      97             : 
      98             : - (id) initWithName:(NSString *)name
      99             :           configuration:(NSDictionary *)configuration
     100             :                          macros:(NSDictionary *)macros
     101             :           bindingTarget:(id<OOWeakReferenceSupport>)target
     102             : {
     103             :         BOOL                                    OK = YES;
     104             :         NSString                                *macroString = nil;
     105             :         NSString                                *vertexShader = nil;
     106             :         NSString                                *fragmentShader = nil;
     107             :         GLint                                   textureUnits = [[OOOpenGLExtensionManager sharedManager] textureImageUnitCount];
     108             :         NSMutableDictionary             *modifiedMacros = nil;
     109             :         NSString                                *vsName = @"<synthesized>";
     110             :         NSString                                *fsName = @"<synthesized>";
     111             :         NSString                                *vsCacheKey = nil;
     112             :         NSString                                *fsCacheKey = nil;
     113             :         
     114             :         if (configuration == nil)  OK = NO;
     115             :         
     116             :         self = [super initWithName:name configuration:configuration];
     117             :         if (self == nil)  OK = NO;
     118             :         
     119             :         if (OK)
     120             :         {
     121             :                 modifiedMacros = macros ? [macros mutableCopy] : [[NSMutableDictionary alloc] init];
     122             :                 [modifiedMacros autorelease];
     123             :                 
     124             :                 [modifiedMacros setObject:[NSNumber numberWithUnsignedInt:textureUnits]
     125             :                                                    forKey:@"OO_TEXTURE_UNIT_COUNT"];
     126             :                 
     127             :                 // used to test for simplified shaders - OO_REDUCED_COMPLEXITY - here
     128             :                 macroString = MacrosToString(modifiedMacros);
     129             :         }
     130             :         
     131             :         if (OK)
     132             :         {
     133             :                 vertexShader = [configuration oo_stringForKey:kOOVertexShaderSourceKey];
     134             :                 if (vertexShader == nil)
     135             :                 {
     136             :                         vsName = [configuration oo_stringForKey:kOOVertexShaderNameKey];
     137             :                         vsCacheKey = vsName;
     138             :                         if (vsName != nil)
     139             :                         {
     140             :                                 if (!GetShaderSource(vsName, @"vertex", macroString, &vertexShader))  OK = NO;
     141             :                         }
     142             :                 }
     143             :                 else
     144             :                 {
     145             :                         vsCacheKey = vertexShader;
     146             :                 }
     147             :         }
     148             :         
     149             :         if (OK)
     150             :         {
     151             :                 fragmentShader = [configuration oo_stringForKey:kOOFragmentShaderSourceKey];
     152             :                 if (fragmentShader == nil)
     153             :                 {
     154             :                         fsName = [configuration oo_stringForKey:kOOFragmentShaderNameKey];
     155             :                         fsCacheKey = fsName;
     156             :                         if (fsName != nil)
     157             :                         {
     158             :                                 if (!GetShaderSource(fsName, @"fragment", macroString, &fragmentShader))  OK = NO;
     159             :                         }
     160             :                 }
     161             :                 else
     162             :                 {
     163             :                         fsCacheKey = fragmentShader;
     164             :                 }
     165             :         }
     166             :         
     167             :         if (OK)
     168             :         {
     169             :                 if (vertexShader != nil || fragmentShader != nil)
     170             :                 {
     171             :                         static NSDictionary *attributeBindings = nil;
     172             :                         if (attributeBindings == nil)
     173             :                         {
     174             :                                 attributeBindings = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kTangentAttributeIndex]
     175             :                                                                                                                                 forKey:@"tangent"];
     176             :                                 [attributeBindings retain];
     177             :                         }
     178             :                         
     179             :                         NSString *cacheKey = [NSString stringWithFormat:@"$VERTEX:\n%@\n\n$FRAGMENT:\n%@\n\n$MACROS:\n%@\n", vsCacheKey, fsCacheKey, macroString];
     180             :                         
     181             :                         OOLogIndent();
     182             :                         shaderProgram = [OOShaderProgram shaderProgramWithVertexShader:vertexShader
     183             :                                                                                                                         fragmentShader:fragmentShader
     184             :                                                                                                                   vertexShaderName:vsName
     185             :                                                                                                                 fragmentShaderName:fsName
     186             :                                                                                                                                         prefix:macroString
     187             :                                                                                                                  attributeBindings:attributeBindings
     188             :                                                                                                                                   cacheKey:cacheKey];
     189             :                         OOLogOutdent();
     190             : 
     191             : // no reduced complexity mode now
     192             : #if 0
     193             :                         if (shaderProgram == nil)
     194             :                         {
     195             : 
     196             :                                 BOOL canFallBack = ![modifiedMacros oo_boolForKey:@"OO_REDUCED_COMPLEXITY"];
     197             : #ifndef NDEBUG
     198             :                                 if (gDebugFlags & DEBUG_NO_SHADER_FALLBACK)  canFallBack = NO;
     199             : #endif
     200             :                                 if (canFallBack)
     201             :                                 {
     202             :                                         OOLogWARN(@"shader.load.fullModeFailed", @"Could not build shader %@/%@ in full complexity mode, trying simple mode.", vsName, fsName);
     203             :                                         
     204             :                                         [modifiedMacros setObject:[NSNumber numberWithInt:1] forKey:@"OO_REDUCED_COMPLEXITY"];
     205             :                                         macroString = MacrosToString(modifiedMacros);
     206             :                                         cacheKey = [cacheKey stringByAppendingString:@"\n$SIMPLIFIED FALLBACK\n"];
     207             :                                         
     208             :                                         OOLogIndent();
     209             :                                         shaderProgram = [OOShaderProgram shaderProgramWithVertexShader:vertexShader
     210             :                                                                                                                                         fragmentShader:fragmentShader
     211             :                                                                                                                                   vertexShaderName:vsName
     212             :                                                                                                                                 fragmentShaderName:fsName
     213             :                                                                                                                                                         prefix:macroString
     214             :                                                                                                                                  attributeBindings:attributeBindings
     215             :                                                                                                                                                   cacheKey:cacheKey];
     216             :                                         OOLogOutdent();
     217             :                                         
     218             :                                         if (shaderProgram != nil)
     219             :                                         {
     220             :                                                 OOLog(@"shader.load.fallbackSuccess", @"Simple mode fallback successful.");
     221             :                                         }
     222             :                                 }
     223             :                         }
     224             : #endif
     225             :                         
     226             :                         if (shaderProgram == nil)
     227             :                         {
     228             :                                 OOLogERR(@"shader.load.failed", @"Could not build shader %@/%@.", vsName, fsName);
     229             :                         }
     230             :                 }
     231             :                 else
     232             :                 {
     233             :                         OOLog(@"shader.load.noShader", @"***** Error: no vertex or fragment shader specified in shader dictionary:\n%@", configuration);
     234             :                 }
     235             :                 
     236             :                 OK = (shaderProgram != nil);
     237             :                 if (OK)  [shaderProgram retain];
     238             :         }
     239             :         
     240             :         if (OK)
     241             :         {
     242             :                 // Load uniforms and textures, which are a flavour of uniform for our purpose.
     243             :                 NSDictionary *uniformDefs = [configuration oo_dictionaryForKey:kOOUniformsKey];
     244             :                 
     245             :                 NSArray *textureArray = [configuration oo_arrayForKey:kOOTextureObjectsKey];
     246             :                 if (textureArray == nil)
     247             :                 {
     248             :                         NSArray *textureSpecs = [configuration oo_arrayForKey:kOOTexturesKey];
     249             :                         if (textureSpecs != nil)
     250             :                         {
     251             :                                 textureArray = [self loadTexturesFromArray:textureSpecs unitCount:textureUnits];
     252             :                         }
     253             :                 }
     254             :                 
     255             :                 uniforms = [[NSMutableDictionary alloc] initWithCapacity:[uniformDefs count] + [textureArray count]];
     256             :                 [self addUniformsFromDictionary:uniformDefs withBindingTarget:target];
     257             :                 [self addTexturesFromArray:textureArray unitCount:textureUnits];
     258             :         }
     259             :         
     260             :         if (OK)
     261             :         {
     262             :                 // write gloss and gamma correction preference to the uniforms dictionary
     263             :                 
     264             :                 if (![uniforms objectForKey:@"uGloss"])
     265             :                 {
     266             :                         float gloss = OOClamp_0_1_f([configuration oo_floatForKey:@"gloss"  defaultValue:0.5f]);
     267             :                         [self setUniform:@"uGloss" floatValue:gloss];
     268             :                 }
     269             :                 
     270             :                 if (![uniforms objectForKey:@"uGammaCorrect"])
     271             :                 {
     272             :                         BOOL gammaCorrect = [configuration oo_boolForKey:@"gamma_correct" 
     273             :                                                                 defaultValue:![[NSUserDefaults standardUserDefaults] boolForKey:@"no-gamma-correct"]];
     274             :                         [self setUniform:@"uGammaCorrect" floatValue:(float)gammaCorrect];
     275             :                 }
     276             :         }
     277             :         
     278             :         if (!OK)
     279             :         {
     280             :                 [self release];
     281             :                 self = nil;
     282             :         }
     283             :         return self;
     284             : }
     285             : 
     286             : 
     287             : - (void)dealloc
     288             : {
     289             :         uint32_t                        i;
     290             :         
     291             :         [self willDealloc];
     292             :         
     293             :         [shaderProgram release];
     294             :         [uniforms release];
     295             :         
     296             :         if (textures != NULL)
     297             :         {
     298             :                 for (i = 0; i != texCount; ++i)
     299             :                 {
     300             :                         [textures[i] release];
     301             :                 }
     302             :                 free(textures);
     303             :         }
     304             :         
     305             :         [bindingTarget release];
     306             :         
     307             :         [super dealloc];
     308             : }
     309             : 
     310             : 
     311             : - (BOOL)bindUniform:(NSString *)uniformName
     312             :                    toObject:(id<OOWeakReferenceSupport>)source
     313             :                    property:(SEL)selector
     314             :          convertOptions:(OOUniformConvertOptions)options
     315             : {
     316             :         OOShaderUniform                 *uniform = nil;
     317             :         
     318             :         if (uniformName == nil) return NO;
     319             :         
     320             :         uniform = [[OOShaderUniform alloc] initWithName:uniformName
     321             :                                                                           shaderProgram:shaderProgram
     322             :                                                                           boundToObject:source
     323             :                                                                                    property:selector
     324             :                                                                          convertOptions:options];
     325             :         if (uniform != nil)
     326             :         {
     327             :                 OOLog(@"shader.uniform.set", @"Set up uniform %@", uniform);
     328             :                 [uniforms setObject:uniform forKey:uniformName];
     329             :                 [uniform release];
     330             :                 return YES;
     331             :         }
     332             :         else
     333             :         {
     334             :                 OOLog(@"shader.uniform.unSet", @"Did not set uniform \"%@\"", uniformName);
     335             :                 [uniforms removeObjectForKey:uniformName];
     336             :                 return NO;
     337             :         }
     338             : }
     339             : 
     340             : 
     341             : - (BOOL)bindSafeUniform:(NSString *)uniformName
     342             :                            toObject:(id<OOWeakReferenceSupport>)target
     343             :                   propertyNamed:(NSString *)property
     344             :                  convertOptions:(OOUniformConvertOptions)options
     345             : {
     346             :         SEL                                     selector = NULL;
     347             :         
     348             :         selector = NSSelectorFromString(property);
     349             :         
     350             :         if (selector != NULL && OOUniformBindingPermitted(property, target))
     351             :         {
     352             :                 return [self bindUniform:uniformName
     353             :                                                 toObject:target
     354             :                                                 property:selector
     355             :                                   convertOptions:options];
     356             :         }
     357             :         else
     358             :         {
     359             :                 OOLog(@"shader.uniform.unpermittedMethod", @"Did not bind uniform \"%@\" to property -[%@ %@] - unpermitted method.", uniformName, [target class], property);
     360             :         }
     361             :         
     362             :         return NO;
     363             : }
     364             : 
     365             : 
     366             : - (void)setUniform:(NSString *)uniformName intValue:(int)value
     367             : {
     368             :         OOShaderUniform                 *uniform = nil;
     369             :         
     370             :         if (uniformName == nil) return;
     371             :         
     372             :         uniform = [[OOShaderUniform alloc] initWithName:uniformName
     373             :                                                                           shaderProgram:shaderProgram
     374             :                                                                                    intValue:value];
     375             :         if (uniform != nil)
     376             :         {
     377             :                 OOLog(@"shader.uniform.set", @"Set up uniform %@", uniform);
     378             :                 [uniforms setObject:uniform forKey:uniformName];
     379             :                 [uniform release];
     380             :         }
     381             :         else
     382             :         {
     383             :                 OOLog(@"shader.uniform.unSet", @"Did not set uniform \"%@\"", uniformName);
     384             :                 [uniforms removeObjectForKey:uniformName];
     385             :         }
     386             : }
     387             : 
     388             : 
     389             : - (void)setUniform:(NSString *)uniformName floatValue:(float)value
     390             : {
     391             :         OOShaderUniform                 *uniform = nil;
     392             :         
     393             :         if (uniformName == nil) return;
     394             :         
     395             :         uniform = [[OOShaderUniform alloc] initWithName:uniformName
     396             :                                                                           shaderProgram:shaderProgram
     397             :                                                                                  floatValue:value];
     398             :         if (uniform != nil)
     399             :         {
     400             :                 OOLog(@"shader.uniform.set", @"Set up uniform %@", uniform);
     401             :                 [uniforms setObject:uniform forKey:uniformName];
     402             :                 [uniform release];
     403             :         }
     404             :         else
     405             :         {
     406             :                 OOLog(@"shader.uniform.unSet", @"Did not set uniform \"%@\"", uniformName);
     407             :                 [uniforms removeObjectForKey:uniformName];
     408             :         }
     409             : }
     410             : 
     411             : 
     412             : - (void)setUniform:(NSString *)uniformName vectorValue:(GLfloat[4])value
     413             : {
     414             :         OOShaderUniform                 *uniform = nil;
     415             :         
     416             :         if (uniformName == nil) return;
     417             :         
     418             :         uniform = [[OOShaderUniform alloc] initWithName:uniformName
     419             :                                                                           shaderProgram:shaderProgram
     420             :                                                                                 vectorValue:value];
     421             :         if (uniform != nil)
     422             :         {
     423             :                 OOLog(@"shader.uniform.set", @"Set up uniform %@", uniform);
     424             :                 [uniforms setObject:uniform forKey:uniformName];
     425             :                 [uniform release];
     426             :         }
     427             :         else
     428             :         {
     429             :                 OOLog(@"shader.uniform.unSet", @"Did not set uniform \"%@\"", uniformName);
     430             :                 [uniforms removeObjectForKey:uniformName];
     431             :         }
     432             : }
     433             : 
     434             : 
     435             : - (void)setUniform:(NSString *)uniformName vectorObjectValue:(id)value
     436             : {
     437             :         if (uniformName == nil) return;
     438             :         
     439             :         GLfloat vecArray[4];
     440             :         if ([value isKindOfClass:[NSArray class]] && [value count] == 4)
     441             :         {
     442             :                 for (unsigned i = 0; i < 4; i++)
     443             :                 {
     444             :                         vecArray[i] = OOFloatFromObject([value objectAtIndex:i], 0.0f);
     445             :                 }
     446             :         }
     447             :         else
     448             :         {
     449             :                 Vector vec = OOVectorFromObject(value, kZeroVector);
     450             :                 vecArray[0] = vec.x;
     451             :                 vecArray[1] = vec.y;
     452             :                 vecArray[2] = vec.z;
     453             :                 vecArray[3] = 1.0;
     454             :         }
     455             :         
     456             :         OOShaderUniform *uniform = [[OOShaderUniform alloc] initWithName:uniformName
     457             :                                                                                                            shaderProgram:shaderProgram
     458             :                                                                                                                  vectorValue:vecArray];
     459             :         if (uniform != nil)
     460             :         {
     461             :                 OOLog(@"shader.uniform.set", @"Set up uniform %@", uniform);
     462             :                 [uniforms setObject:uniform forKey:uniformName];
     463             :                 [uniform release];
     464             :         }
     465             :         else
     466             :         {
     467             :                 OOLog(@"shader.uniform.unSet", @"Did not set uniform \"%@\"", uniformName);
     468             :                 [uniforms removeObjectForKey:uniformName];
     469             :         }
     470             : }
     471             : 
     472             : 
     473             : - (void)setUniform:(NSString *)uniformName quaternionValue:(Quaternion)value asMatrix:(BOOL)asMatrix
     474             : {
     475             :         OOShaderUniform                 *uniform = nil;
     476             :         
     477             :         if (uniformName == nil) return;
     478             :         
     479             :         uniform = [[OOShaderUniform alloc] initWithName:uniformName
     480             :                                                                           shaderProgram:shaderProgram
     481             :                                                                         quaternionValue:value
     482             :                                                                                    asMatrix:asMatrix];
     483             :         if (uniform != nil)
     484             :         {
     485             :                 OOLog(@"shader.uniform.set", @"Set up uniform %@", uniform);
     486             :                 [uniforms setObject:uniform forKey:uniformName];
     487             :                 [uniform release];
     488             :         }
     489             :         else
     490             :         {
     491             :                 OOLog(@"shader.uniform.unSet", @"Did not set uniform \"%@\"", uniformName);
     492             :                 [uniforms removeObjectForKey:uniformName];
     493             :         }
     494             : }
     495             : 
     496             : 
     497             : -(void)addUniformsFromDictionary:(NSDictionary *)uniformDefs withBindingTarget:(id<OOWeakReferenceSupport>)target
     498             : {
     499             :         NSEnumerator                    *uniformEnum = nil;
     500             :         NSString                                *name = nil;
     501             :         id                                              definition = nil;
     502             :         id                                              value = nil;
     503             :         NSString                                *binding = nil;
     504             :         NSString                                *type = nil;
     505             :         GLfloat                                 floatValue;
     506             :         BOOL                                    gotValue;
     507             :         OOUniformConvertOptions convertOptions;
     508             :         BOOL                                    quatAsMatrix = YES;
     509             :         GLfloat                                 scale = 1.0;
     510             :         uint32_t                                randomSeed;
     511             :         RANROTSeed                              savedSeed;
     512             :         NSArray                                 *keys = nil;
     513             :         
     514             :         if ([target respondsToSelector:@selector(randomSeedForShaders)])
     515             :         {
     516             :                 randomSeed = [(id)target randomSeedForShaders];
     517             :         }
     518             :         else
     519             :         {
     520             :                 randomSeed = (uint32_t)(uintptr_t)self;
     521             :         }
     522             :         savedSeed = RANROTGetFullSeed();
     523             :         ranrot_srand(randomSeed);
     524             :         
     525             :         keys = [[uniformDefs allKeys] sortedArrayUsingSelector:@selector(compare:)];
     526             :         for (uniformEnum = [keys objectEnumerator]; (name = [uniformEnum nextObject]); )
     527             :         {
     528             :                 gotValue = NO;
     529             :                 definition = [uniformDefs objectForKey:name];
     530             :                 
     531             :                 type = nil;
     532             :                 value = nil;
     533             :                 binding = nil;
     534             :                 
     535             :                 if ([definition isKindOfClass:[NSDictionary class]])
     536             :                 {
     537             :                         value = [(NSDictionary *)definition objectForKey:@"value"];
     538             :                         binding = [(NSDictionary *)definition oo_stringForKey:@"binding"];
     539             :                         type = [(NSDictionary *)definition oo_stringForKey:@"type"];
     540             :                         scale = [(NSDictionary *)definition oo_floatForKey:@"scale" defaultValue:1.0];
     541             :                         if (type == nil)
     542             :                         {
     543             :                                 if (value == nil && binding != nil)  type = @"binding";
     544             :                                 else  type = @"float";
     545             :                         }
     546             :                 }
     547             :                 else if ([definition isKindOfClass:[NSNumber class]])
     548             :                 {
     549             :                         value = definition;
     550             :                         type = @"float";
     551             :                 }
     552             :                 else if ([definition isKindOfClass:[NSString class]])
     553             :                 {
     554             :                         if (OOIsNumberLiteral(definition, NO))
     555             :                         {
     556             :                                 value = definition;
     557             :                                 type = @"float";
     558             :                         }
     559             :                         else
     560             :                         {
     561             :                                 binding = definition;
     562             :                                 type = @"binding";
     563             :                         }
     564             :                 }
     565             :                 else if ([definition isKindOfClass:[NSArray class]])
     566             :                 {
     567             :                         binding = definition;
     568             :                         type = @"vector";
     569             :                 }
     570             :                 
     571             :                 // Transform random values to concrete values
     572             :                 if ([type isEqualToString:@"randomFloat"])
     573             :                 {
     574             :                         type = @"float";
     575             :                         value = [NSNumber numberWithFloat:randf() * scale];
     576             :                 }
     577             :                 else if ([type isEqualToString:@"randomUnitVector"])
     578             :                 {
     579             :                         type = @"vector";
     580             :                         value = OOPropertyListFromVector(vector_multiply_scalar(OORandomUnitVector(), scale));
     581             :                 }
     582             :                 else if ([type isEqualToString:@"randomVectorSpatial"])
     583             :                 {
     584             :                         type = @"vector";
     585             :                         value = OOPropertyListFromVector(OOVectorRandomSpatial(scale));
     586             :                 }
     587             :                 else if ([type isEqualToString:@"randomVectorRadial"])
     588             :                 {
     589             :                         type = @"vector";
     590             :                         value = OOPropertyListFromVector(OOVectorRandomRadial(scale));
     591             :                 }
     592             :                 else if ([type isEqualToString:@"randomQuaternion"])
     593             :                 {
     594             :                         type = @"quaternion";
     595             :                         value = OOPropertyListFromQuaternion(OORandomQuaternion());
     596             :                 }
     597             :                 
     598             :                 if ([type isEqualToString:@"float"] || [type isEqualToString:@"real"])
     599             :                 {
     600             :                         gotValue = YES;
     601             :                         if ([value respondsToSelector:@selector(floatValue)])  floatValue = [value floatValue];
     602             :                         else if ([value respondsToSelector:@selector(doubleValue)])  floatValue = [value doubleValue];
     603             :                         else if ([value respondsToSelector:@selector(intValue)])  floatValue = [value intValue];
     604             :                         else gotValue = NO;
     605             :                         
     606             :                         if (gotValue)
     607             :                         {
     608             :                                 [self setUniform:name floatValue:floatValue];
     609             :                         }
     610             :                 }
     611             :                 else if ([type isEqualToString:@"int"] || [type isEqualToString:@"integer"] || [type isEqualToString:@"texture"])
     612             :                 {
     613             :                         /*      "texture" is allowed as a synonym for "int" because shader
     614             :                                 uniforms are mapped to texture units by specifying an integer
     615             :                                 index.
     616             :                                 uniforms = { diffuseMap = { type = texture; value = 0; }; };
     617             :                                 means "bind uniform diffuseMap to texture unit 0" (which will
     618             :                                 have the first texture in the textures array).
     619             :                         */
     620             :                         if ([value respondsToSelector:@selector(intValue)])
     621             :                         {
     622             :                                 [self setUniform:name intValue:[value intValue]];
     623             :                                 gotValue = YES;
     624             :                         }
     625             :                 }
     626             :                 else if ([type isEqualToString:@"vector"])
     627             :                 {
     628             :                         [self setUniform:name vectorObjectValue:value];
     629             :                         gotValue = YES;
     630             :                 }
     631             :                 else if ([type isEqualToString:@"quaternion"])
     632             :                 {
     633             :                         if ([definition isKindOfClass:[NSDictionary class]])
     634             :                         {
     635             :                                 quatAsMatrix = [definition oo_boolForKey:@"asMatrix" defaultValue:quatAsMatrix];
     636             :                         }
     637             :                         [self setUniform:name
     638             :                          quaternionValue:OOQuaternionFromObject(value, kIdentityQuaternion)
     639             :                                         asMatrix:quatAsMatrix];
     640             :                         gotValue = YES;
     641             :                 }
     642             :                 else if (target != nil && [type isEqualToString:@"binding"])
     643             :                 {
     644             :                         if ([definition isKindOfClass:[NSDictionary class]])
     645             :                         {
     646             :                                 convertOptions = 0;
     647             :                                 if ([definition oo_boolForKey:@"clamped" defaultValue:NO])  convertOptions |= kOOUniformConvertClamp;
     648             :                                 if ([definition oo_boolForKey:@"normalized" defaultValue:[definition oo_boolForKey:@"normalised" defaultValue:NO]])
     649             :                                 {
     650             :                                         convertOptions |= kOOUniformConvertNormalize;
     651             :                                 }
     652             :                                 if ([definition oo_boolForKey:@"asMatrix" defaultValue:YES])  convertOptions |= kOOUniformConvertToMatrix;
     653             :                                 if (![definition oo_boolForKey:@"bindToSubentity" defaultValue:NO])  convertOptions |= kOOUniformBindToSuperTarget;
     654             :                         }
     655             :                         else
     656             :                         {
     657             :                                 convertOptions = kOOUniformConvertDefaults;
     658             :                         }
     659             :                         
     660             :                         [self bindSafeUniform:name toObject:target propertyNamed:binding convertOptions:convertOptions];
     661             :                         gotValue = YES;
     662             :                 }
     663             :                 
     664             :                 if (!gotValue)
     665             :                 {
     666             :                         OOLog(@"shader.uniform.badDescription", @"----- Warning: could not bind uniform \"%@\" for target %@ -- could not interpret definition:\n%@", name, target, definition);
     667             :                 }
     668             :         }
     669             :         
     670             :         RANROTSetFullSeed(savedSeed);
     671             : }
     672             : 
     673             : 
     674             : - (BOOL)doApply
     675             : {
     676             :         NSEnumerator                    *uniformEnum = nil;
     677             :         OOShaderUniform                 *uniform = nil;
     678             :         uint32_t                                i;
     679             :         
     680             :         OO_ENTER_OPENGL();
     681             :         
     682             :         [super doApply];
     683             :         [shaderProgram apply];
     684             :         
     685             :         for (i = 0; i != texCount; ++i)
     686             :         {
     687             :                 OOGL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
     688             :                 [textures[i] apply];
     689             :         }
     690             :         if (texCount > 1)  OOGL(glActiveTextureARB(GL_TEXTURE0_ARB));
     691             :         
     692             :         @try
     693             :         {
     694             :                 for (uniformEnum = [uniforms objectEnumerator]; (uniform = [uniformEnum nextObject]); )
     695             :                 {
     696             :                         [uniform apply];
     697             :                 }
     698             :         }
     699             :         @catch (id exception) {}
     700             :         
     701             :         return YES;
     702             : }
     703             : 
     704             : 
     705             : - (void)ensureFinishedLoading
     706             : {
     707             :         uint32_t                        i;
     708             :         
     709             :         if (textures != NULL)
     710             :         {
     711             :                 for (i = 0; i != texCount; ++i)
     712             :                 {
     713             :                         [textures[i] ensureFinishedLoading];
     714             :                 }
     715             :         }
     716             : }
     717             : 
     718             : 
     719             : - (BOOL) isFinishedLoading
     720             : {
     721             :         uint32_t                        i;
     722             :         
     723             :         if (textures != NULL)
     724             :         {
     725             :                 for (i = 0; i != texCount; ++i)
     726             :                 {
     727             :                         if (![textures[i] isFinishedLoading])  return NO;
     728             :                 }
     729             :         }
     730             :         
     731             :         return YES;
     732             : }
     733             : 
     734             : 
     735             : - (void)unapplyWithNext:(OOMaterial *)next
     736             : {
     737             :         uint32_t                                i, count;
     738             :         
     739             :         if (![next isKindOfClass:[OOShaderMaterial class]])     // Avoid redundant state change
     740             :         {
     741             :                 OO_ENTER_OPENGL();
     742             :                 [OOShaderProgram applyNone];
     743             :                 
     744             :                 /*      BUG: unapplyWithNext: was failing to clear texture state. If a
     745             :                         shader material was followed by a basic material (with no texture),
     746             :                         the shader's #0 texture would be used.
     747             :                         It is necessary to clear at least one texture for the case where a
     748             :                         shader material with textures is followed by a shader material
     749             :                         without textures, then a basic material.
     750             :                         -- Ahruman 2007-08-13
     751             :                 */
     752             :                 count = texCount ? texCount : 1;
     753             :                 for (i = 0; i != count; ++i)
     754             :                 {
     755             :                         OOGL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
     756             :                         [OOTexture applyNone];
     757             :                 }
     758             :                 if (count != 1)  OOGL(glActiveTextureARB(GL_TEXTURE0_ARB));
     759             :         }
     760             : }
     761             : 
     762             : 
     763             : - (void)setBindingTarget:(id<OOWeakReferenceSupport>)target
     764             : {
     765             :         [[uniforms allValues] makeObjectsPerformSelector:@selector(setBindingTarget:) withObject:target];
     766             :         [bindingTarget release];
     767             :         bindingTarget = [target weakRetain];
     768             : }
     769             : 
     770             : 
     771             : - (BOOL) permitSpecular
     772             : {
     773             :         return YES;
     774             : }
     775             : 
     776             : 
     777             : #ifndef NDEBUG
     778             : - (NSSet *) allTextures
     779             : {
     780             :         return [NSSet setWithObjects:textures count:texCount];
     781             : }
     782             : #endif
     783             : 
     784             : @end
     785             : 
     786             : 
     787             : @implementation OOShaderMaterial (OOPrivate)
     788             : 
     789             : - (NSArray *) loadTexturesFromArray:(NSArray *)textureSpecs unitCount:(GLuint)max
     790             : {
     791             :         GLuint i, count = (GLuint)MIN([textureSpecs count], (NSUInteger)max);
     792             :         NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
     793             :         
     794             :         for (i = 0; i < count; i++)
     795             :         {
     796             :                 id textureSpec = [textureSpecs objectAtIndex:i];
     797             :                 OOTexture *texture = [OOTexture textureWithConfiguration:textureSpec];
     798             :                 if (texture == nil)  texture = [OOTexture nullTexture];
     799             :                 [result addObject:texture];
     800             :         }
     801             :         
     802             :         return result;
     803             : }
     804             : 
     805             : 
     806             : - (void) addTexturesFromArray:(NSArray *)textureObjects unitCount:(GLuint)max
     807             : {
     808             :         // Allocate space for texture object name array
     809             :         texCount = (uint32_t)MIN([textureObjects count], (NSUInteger)max);
     810             :         if (texCount == 0)  return;
     811             :         
     812             :         textures = malloc(texCount * sizeof *textures);
     813             :         if (textures == NULL)
     814             :         {
     815             :                 texCount = 0;
     816             :                 return;
     817             :         }
     818             :         
     819             :         // Set up texture object names and appropriate uniforms
     820             :         unsigned i;
     821             :         for (i = 0; i != texCount; ++i)
     822             :         {
     823             :                 textures[i] = [textureObjects objectAtIndex:i];
     824             :                 [textures[i] retain];
     825             :         }
     826             : }
     827             : 
     828             : @end
     829             : 
     830             : 
     831             : static NSString *MacrosToString(NSDictionary *macros)
     832             : {
     833             :         NSMutableString                 *result = nil;
     834             :         NSEnumerator                    *macroEnum = nil;
     835             :         id                                              key = nil, value = nil;
     836             :         
     837             :         if (macros == nil)  return nil;
     838             :         
     839             :         result = [NSMutableString string];
     840             :         for (macroEnum = [macros keyEnumerator]; (key = [macroEnum nextObject]); )
     841             :         {
     842             :                 if (![key isKindOfClass:[NSString class]]) continue;
     843             :                 value = [macros objectForKey:key];
     844             :                 
     845             :                 [result appendFormat:@"#define %@  %@\n", key, value];
     846             :         }
     847             :         
     848             :         if ([result length] == 0) return nil;
     849             :         [result appendString:@"\n\n"];
     850             :         return result;
     851             : }
     852             : 
     853             : #endif
     854             : 
     855             : 
     856             : /*      Attempt to load fragment or vertex shader source from a file.
     857             :         Returns YES if source was loaded or no shader was specified, and NO if an
     858             :         external shader was specified but could not be found.
     859             : */
     860           0 : static BOOL GetShaderSource(NSString *fileName, NSString *shaderType, NSString *prefix, NSString **outResult)
     861             : {
     862             :         NSString                                *result = nil;
     863             :         NSArray                                 *extensions = nil;
     864             :         NSEnumerator                    *extEnum = nil;
     865             :         NSString                                *extension = nil;
     866             :         NSString                                *nameWithExtension = nil;
     867             :         
     868             :         if (fileName == nil)  return YES;       // It's OK for one or the other of the shaders to be undefined.
     869             :         
     870             :         result = [ResourceManager stringFromFilesNamed:fileName inFolder:@"Shaders"];
     871             :         if (result == nil)
     872             :         {
     873             :                 extensions = [NSArray arrayWithObjects:shaderType, [shaderType substringToIndex:4], nil];       // vertex and vert, or fragment and frag
     874             :                 
     875             :                 // Futureproofing -- in future, we may wish to support automatic selection between supported shader languages.
     876             :                 if (![fileName pathHasExtensionInArray:extensions])
     877             :                 {
     878             :                         for (extEnum = [extensions objectEnumerator]; (extension = [extEnum nextObject]); )
     879             :                         {
     880             :                                 nameWithExtension = [fileName stringByAppendingPathExtension:extension];
     881             :                                 result = [ResourceManager stringFromFilesNamed:nameWithExtension
     882             :                                                                                                           inFolder:@"Shaders"];
     883             :                                 if (result != nil) break;
     884             :                         }
     885             :                 }
     886             :                 if (result == nil)
     887             :                 {
     888             :                         OOLog(kOOLogFileNotFound, @"GLSL ERROR: failed to find %@ program %@.", shaderType, fileName);
     889             :                         return NO;
     890             :                 }
     891             :         }
     892             :         
     893             :         if (outResult != NULL) *outResult = result;
     894             :         return YES;
     895             : }

Generated by: LCOV version 1.14