Line data Source code
1 0 : /*
2 :
3 : OOMaterialConvenienceCreators.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 : #ifndef USE_NEW_SHADER_SYNTHESIZER
29 0 : #define USE_NEW_SHADER_SYNTHESIZER 0
30 : #endif
31 :
32 :
33 : #import "OOMaterialConvenienceCreators.h"
34 : #import "OOMaterialSpecifier.h"
35 :
36 : #if USE_NEW_SHADER_SYNTHESIZER
37 : #import "OODefaultShaderSynthesizer.h"
38 : #import "ResourceManager.h"
39 : #endif
40 :
41 : #import "OOOpenGLExtensionManager.h"
42 : #import "OOShaderMaterial.h"
43 : #import "OOSingleTextureMaterial.h"
44 : #import "OOMultiTextureMaterial.h"
45 : #import "OOCollectionExtractors.h"
46 : #import "Universe.h"
47 : #import "OOCacheManager.h"
48 : #import "OOTexture.h"
49 : #import "OODebugFlags.h"
50 :
51 :
52 : #if !USE_NEW_SHADER_SYNTHESIZER
53 0 : typedef struct
54 : {
55 0 : NSDictionary *inConfig;
56 0 : NSMutableDictionary *outConfig;
57 0 : NSUInteger texturesUsed;
58 0 : NSUInteger maxTextures;
59 :
60 0 : NSMutableDictionary *macros;
61 0 : NSMutableArray *textures;
62 0 : NSMutableDictionary *uniforms;
63 : } OOMaterialSynthContext;
64 :
65 :
66 : static void SetUniform(NSMutableDictionary *uniforms, NSString *key, NSString *type, id value);
67 : static void SetUniformFloat(OOMaterialSynthContext *context, NSString *key, float value);
68 :
69 : /* AddTexture(): add a texture to the configuration being synthesized.
70 : * specifier is added to the textures array.
71 : * uniformName is mapped to the appropriate texture unit in the uniforms dictionary.
72 : * If nonShaderKey is not nil, nonShaderKey (e.g. diffuse_map) is set to specifier.
73 : * If macroName is not nil, macroName is set to 1 in the macros dictionary.
74 : */
75 : static void AddTexture(OOMaterialSynthContext *context, NSString *uniformName, NSString *nonShaderKey, NSString *macroName, NSDictionary *specifier);
76 :
77 : static void AddColorIfAppropriate(OOMaterialSynthContext *context, SEL selector, NSString *key, NSString *macroName);
78 : static void AddMacroColorIfAppropriate(OOMaterialSynthContext *context, SEL selector, NSString *macroName);
79 :
80 : static void SynthDiffuse(OOMaterialSynthContext *context, NSString *name);
81 : static void SynthEmissionAndIllumination(OOMaterialSynthContext *context);
82 : static void SynthNormalMap(OOMaterialSynthContext *context);
83 : static void SynthSpecular(OOMaterialSynthContext *context);
84 :
85 : #endif
86 :
87 :
88 : @implementation OOMaterial (OOConvenienceCreators)
89 :
90 : #if !USE_NEW_SHADER_SYNTHESIZER
91 :
92 0 : + (NSDictionary *)synthesizeMaterialDictionaryWithName:(NSString *)name
93 : configuration:(NSDictionary *)configuration
94 : macros:(NSDictionary *)macros
95 : {
96 : if (configuration == nil) configuration = [NSDictionary dictionary];
97 : OOMaterialSynthContext context =
98 : {
99 : .inConfig = configuration,
100 : .outConfig = [NSMutableDictionary dictionary],
101 : .maxTextures = [[OOOpenGLExtensionManager sharedManager] textureImageUnitCount],
102 :
103 : .macros = [NSMutableDictionary dictionaryWithDictionary:macros],
104 : .textures = [NSMutableArray array],
105 : .uniforms = [NSMutableDictionary dictionary]
106 : };
107 :
108 : if ([UNIVERSE reducedDetail])
109 : {
110 : context.maxTextures = 3;
111 : }
112 :
113 : // Basic stuff.
114 :
115 : /* Set up the various material attributes.
116 : Order is significant here, because it determines the order in which
117 : features will be dropped if we exceed the hardware's texture image
118 : unit limit.
119 : */
120 : SynthDiffuse(&context, name);
121 : SynthEmissionAndIllumination(&context);
122 : SynthNormalMap(&context);
123 : SynthSpecular(&context);
124 :
125 : if ([UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS)
126 : {
127 : // Add uniforms required for hull heat glow.
128 : [context.uniforms setObject:@"hullHeatLevel" forKey:@"uHullHeatLevel"];
129 : [context.uniforms setObject:@"timeElapsedSinceSpawn" forKey:@"uTime"];
130 : [context.uniforms setObject:@"fogUniform" forKey:@"uFogColor"];
131 : }
132 :
133 : // Stuff in the general properties.
134 : [context.outConfig setObject:@"true" forKey:@"_oo_is_synthesized_config"];
135 : [context.outConfig setObject:@"oolite-tangent-space-vertex.vertex" forKey:@"vertex_shader"];
136 : [context.outConfig setObject:@"oolite-default-shader.fragment" forKey:@"fragment_shader"];
137 :
138 : if ([context.textures count] != 0) [context.outConfig setObject:context.textures forKey:@"textures"];
139 : if ([context.uniforms count] != 0) [context.outConfig setObject:context.uniforms forKey:@"uniforms"];
140 : if ([context.macros count] != 0) [context.outConfig setObject:context.macros forKey:@"_oo_synthesized_material_macros"];
141 :
142 : return context.outConfig;
143 : }
144 :
145 :
146 0 : + (OOMaterial *)defaultShaderMaterialWithName:(NSString *)name
147 : cacheKey:(NSString *)cacheKey
148 : configuration:(NSDictionary *)configuration
149 : macros:(NSDictionary *)macros
150 : bindingTarget:(id<OOWeakReferenceSupport>)target
151 : {
152 : OOCacheManager *cache = nil;
153 : NSDictionary *synthesizedConfig = nil;
154 : OOMaterial *result = nil;
155 :
156 : // Avoid looping (can happen if shader fails to compile).
157 : if ([configuration objectForKey:@"_oo_is_synthesized_config"] != nil)
158 : {
159 : OOLog(@"material.synthesize.loop", @"Synthesis loop for material %@.", name);
160 : return nil;
161 : }
162 :
163 : if (cacheKey != nil)
164 : {
165 : cache = [OOCacheManager sharedCache];
166 : // configuration must be in cache key, as otherwise changes in
167 : // non-diffuse map can end up miscached
168 : cacheKey = [NSString stringWithFormat:@"%@/%@/%@", cacheKey, name, configuration];
169 : synthesizedConfig = [cache objectForKey:cacheKey inCache:@"synthesized shader materials"];
170 : }
171 :
172 : if (synthesizedConfig == nil)
173 : {
174 : synthesizedConfig = [self synthesizeMaterialDictionaryWithName:name
175 : configuration:configuration
176 : macros:macros];
177 : if (synthesizedConfig != nil && cacheKey != nil)
178 : {
179 : [cache setObject:synthesizedConfig
180 : forKey:cacheKey
181 : inCache:@"synthesized shader materials"];
182 : }
183 : }
184 :
185 : if (synthesizedConfig != nil)
186 : {
187 : result = [self materialWithName:name
188 : cacheKey:cacheKey
189 : configuration:synthesizedConfig
190 : macros:[synthesizedConfig objectForKey:@"_oo_synthesized_material_macros"]
191 : bindingTarget:target
192 : forSmoothedMesh:YES];
193 : }
194 :
195 : return result;
196 : }
197 :
198 : #else
199 :
200 : #ifndef NDEBUG
201 : static BOOL sDumpShaderSource = NO;
202 :
203 : + (void) initialize
204 : {
205 : sDumpShaderSource = [[NSUserDefaults standardUserDefaults] boolForKey:@"dump-synthesized-shaders"];
206 : }
207 : #endif
208 :
209 :
210 : + (OOMaterial *) defaultShaderMaterialWithName:(NSString *)name
211 : cacheKey:(NSString *)cacheKey
212 : configuration:(NSDictionary *)configuration
213 : macros:(NSDictionary *)macros
214 : bindingTarget:(id<OOWeakReferenceSupport>)target
215 : {
216 : NSString *vertexShader = nil;
217 : NSString *fragmentShader = nil;
218 : NSArray *textureSpecs = nil;
219 : NSDictionary *uniformSpecs = nil;
220 :
221 : if (!OOSynthesizeMaterialShader(configuration, name, cacheKey /* FIXME: entity name for error reporting */, &vertexShader, &fragmentShader, &textureSpecs, &uniformSpecs))
222 : {
223 : return nil;
224 : }
225 :
226 : NSDictionary *synthesizedConfig = [NSDictionary dictionaryWithObjectsAndKeys:
227 : [NSNumber numberWithBool:YES], kOOIsSynthesizedMaterialConfigurationKey,
228 : textureSpecs, kOOTexturesKey,
229 : uniformSpecs, kOOUniformsKey,
230 : vertexShader, kOOVertexShaderSourceKey,
231 : fragmentShader, kOOFragmentShaderSourceKey,
232 : nil];
233 :
234 : #ifndef NDEBUG
235 : if (sDumpShaderSource)
236 : {
237 : NSString *dumpPath = [NSString stringWithFormat:@"Synthesized Materials/%@/%@", cacheKey, name];
238 :
239 : [ResourceManager writeDiagnosticString:vertexShader toFileNamed:[dumpPath stringByAppendingPathExtension:@"vertex"]];
240 : [ResourceManager writeDiagnosticString:fragmentShader toFileNamed:[dumpPath stringByAppendingPathExtension:@"fragment"]];
241 :
242 : // Hide internal keys in the synthesized config before writing it.
243 : NSMutableDictionary *humanFriendlyConfig = [[synthesizedConfig mutableCopy] autorelease];
244 : [humanFriendlyConfig removeObjectForKey:kOOVertexShaderSourceKey];
245 : [humanFriendlyConfig removeObjectForKey:kOOFragmentShaderSourceKey];
246 : [humanFriendlyConfig removeObjectForKey:kOOIsSynthesizedMaterialConfigurationKey];
247 : [humanFriendlyConfig setObject:[NSString stringWithFormat:@"%@.vertex", name] forKey:kOOVertexShaderNameKey];
248 : [humanFriendlyConfig setObject:[NSString stringWithFormat:@"%@.fragment", name] forKey:kOOFragmentShaderNameKey];
249 :
250 : [ResourceManager writeDiagnosticPList:humanFriendlyConfig toFileNamed:[dumpPath stringByAppendingPathExtension:@"plist"]];
251 :
252 : [ResourceManager writeDiagnosticPList:configuration toFileNamed:[[dumpPath stringByAppendingString:@"-original"] stringByAppendingPathExtension:@"plist"]];
253 : }
254 : #endif
255 :
256 : return [self materialWithName:name
257 : cacheKey:cacheKey
258 : configuration:synthesizedConfig
259 : macros:nil
260 : bindingTarget:target
261 : forSmoothedMesh:YES];
262 : }
263 :
264 : #endif
265 :
266 :
267 : + (OOMaterial *) materialWithName:(NSString *)name
268 : cacheKey:(NSString *)cacheKey
269 : configuration:(NSDictionary *)configuration
270 : macros:(NSDictionary *)macros
271 : bindingTarget:(id<OOWeakReferenceSupport>)object
272 : forSmoothedMesh:(BOOL)smooth // Internally, this flg really means "force use of shaders".
273 : {
274 : id result = nil;
275 :
276 : #if OO_SHADERS
277 :
278 : if ([UNIVERSE useShaders])
279 : {
280 : if ([OOShaderMaterial configurationDictionarySpecifiesShaderMaterial:configuration])
281 : {
282 : result = [OOShaderMaterial shaderMaterialWithName:name
283 : configuration:configuration
284 : macros:macros
285 : bindingTarget:object];
286 : }
287 :
288 : // Use default shader if smoothing is on, or shader detail is full, DEBUG_NO_SHADER_FALLBACK is set, or material uses an effect map.
289 : if (result == nil &&
290 : (smooth ||
291 : gDebugFlags & DEBUG_NO_SHADER_FALLBACK ||
292 : [UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS ||
293 : [configuration oo_combinedSpecularMapSpecifier] != nil ||
294 : [configuration oo_normalMapSpecifier] != nil ||
295 : [configuration oo_parallaxMapSpecifier] != nil ||
296 : [configuration oo_normalAndParallaxMapSpecifier] != nil ||
297 : [configuration oo_emissionMapSpecifier] != nil ||
298 : [configuration oo_illuminationMapSpecifier] != nil ||
299 : [configuration oo_emissionAndIlluminationMapSpecifier] != nil
300 : ))
301 : {
302 : result = [self defaultShaderMaterialWithName:name
303 : cacheKey:cacheKey
304 : configuration:configuration
305 : macros:macros
306 : bindingTarget:(id<OOWeakReferenceSupport>)object];
307 : }
308 : }
309 : #endif
310 :
311 : #if OO_MULTITEXTURE
312 : if (result == nil /*&& ![UNIVERSE reducedDetail]*/)
313 : {
314 : if ([configuration oo_emissionMapSpecifier] != nil ||
315 : [configuration oo_illuminationMapSpecifier] ||
316 : [configuration oo_emissionAndIlluminationMapSpecifier] != nil)
317 : {
318 : result = [[OOMultiTextureMaterial alloc] initWithName:name configuration:configuration];
319 : [result autorelease];
320 : }
321 : }
322 : #endif
323 :
324 : if (result == nil)
325 : {
326 : if ([configuration oo_diffuseMapSpecifierWithDefaultName:name] == nil)
327 : {
328 : result = [[OOBasicMaterial alloc] initWithName:name configuration:configuration];
329 : }
330 : else
331 : {
332 : result = [[OOSingleTextureMaterial alloc] initWithName:name configuration:configuration];
333 : }
334 : if (result == nil)
335 : {
336 : result = [[OOBasicMaterial alloc] initWithName:name configuration:configuration];
337 : }
338 : [result autorelease];
339 : }
340 : return result;
341 : }
342 :
343 :
344 : + (OOMaterial *) materialWithName:(NSString *)name
345 : cacheKey:(NSString *)cacheKey
346 : materialDictionary:(NSDictionary *)materialDict
347 : shadersDictionary:(NSDictionary *)shadersDict
348 : macros:(NSDictionary *)macros
349 : bindingTarget:(id<OOWeakReferenceSupport>)object
350 : forSmoothedMesh:(BOOL)smooth
351 : {
352 : NSDictionary *configuration = nil;
353 :
354 : #if OO_SHADERS
355 :
356 : if ([UNIVERSE useShaders])
357 : {
358 : configuration = [shadersDict oo_dictionaryForKey:name];
359 : }
360 : #endif
361 :
362 : if (configuration == nil)
363 : {
364 : configuration = [materialDict oo_dictionaryForKey:name];
365 : }
366 :
367 : if (configuration == nil)
368 : {
369 : // Use fallback material for non-existent simple texture.
370 : // Texture caching means this won't be wasted in the general case.
371 : OOTexture *texture = [OOTexture textureWithName:name inFolder:@"Textures"];
372 : if (texture == nil) return nil;
373 :
374 : configuration = [NSDictionary dictionary];
375 : }
376 :
377 : return [self materialWithName:name
378 : cacheKey:cacheKey
379 : configuration:configuration
380 : macros:macros
381 : bindingTarget:object
382 : forSmoothedMesh:smooth];
383 : }
384 :
385 : @end
386 :
387 :
388 : #if !USE_NEW_SHADER_SYNTHESIZER
389 :
390 0 : static void SetUniform(NSMutableDictionary *uniforms, NSString *key, NSString *type, id value)
391 : {
392 : [uniforms setObject:[NSDictionary dictionaryWithObjectsAndKeys:type, @"type", value, @"value", nil] forKey:key];
393 : }
394 :
395 :
396 0 : static void SetUniformFloat(OOMaterialSynthContext *context, NSString *key, float value)
397 : {
398 : SetUniform(context->uniforms, key, @"float", [NSNumber numberWithFloat:value]);
399 : }
400 :
401 :
402 0 : static void AddTexture(OOMaterialSynthContext *context, NSString *uniformName, NSString *nonShaderKey, NSString *macroName, NSDictionary *specifier)
403 : {
404 : NSCParameterAssert(context->texturesUsed < context->maxTextures);
405 :
406 : context->texturesUsed++;
407 : SetUniform(context->uniforms, uniformName, @"texture", [NSNumber numberWithUnsignedInteger:[context->textures count]]);
408 : [context->textures addObject:specifier];
409 : if (nonShaderKey != nil)
410 : {
411 : [context->outConfig setObject:specifier forKey:kOOMaterialDiffuseMapName];
412 : }
413 : if (macroName != nil)
414 : {
415 : [context->macros setObject:@"1" forKey:macroName];
416 : }
417 : }
418 :
419 :
420 0 : static void AddColorIfAppropriate(OOMaterialSynthContext *context, SEL selector, NSString *key, NSString *macroName)
421 : {
422 : OOColor *color = [context->inConfig performSelector:selector];
423 :
424 : if (color != nil)
425 : {
426 : [context->outConfig setObject:[color normalizedArray] forKey:key];
427 : if (macroName != nil) [context->macros setObject:@"1" forKey:macroName];
428 : }
429 : }
430 :
431 :
432 0 : static void AddMacroColorIfAppropriate(OOMaterialSynthContext *context, SEL selector, NSString *macroName)
433 : {
434 : OOColor *color = [context->inConfig performSelector:selector];
435 :
436 : if (color != nil)
437 : {
438 : NSString *macroText = [NSString stringWithFormat:@"vec4(%g, %g, %g, %g)",
439 : [color redComponent],
440 : [color greenComponent],
441 : [color blueComponent],
442 : [color alphaComponent]];
443 : [context->macros setObject:macroText forKey:macroName];
444 : }
445 : }
446 :
447 :
448 0 : static void SynthDiffuse(OOMaterialSynthContext *context, NSString *name)
449 : {
450 : // Set up diffuse map if appropriate.
451 : NSDictionary *diffuseMapSpec = [context->inConfig oo_diffuseMapSpecifierWithDefaultName:name];
452 : if (diffuseMapSpec != nil && context->texturesUsed < context->maxTextures)
453 : {
454 : AddTexture(context, @"uDiffuseMap", kOOMaterialDiffuseMapName, @"OOSTD_DIFFUSE_MAP", diffuseMapSpec);
455 :
456 : if ([diffuseMapSpec oo_boolForKey:@"cube_map"])
457 : {
458 : [context->macros setObject:@"1" forKey:@"OOSTD_DIFFUSE_MAP_IS_CUBE_MAP"];
459 : }
460 : }
461 : else
462 : {
463 : // No diffuse map must be specified explicitly.
464 : [context->outConfig setObject:@"" forKey:kOOMaterialDiffuseMapName];
465 : }
466 :
467 : // Set up diffuse colour if any.
468 : AddColorIfAppropriate(context, @selector(oo_diffuseColor), kOOMaterialDiffuseColorName, nil);
469 : }
470 :
471 :
472 0 : static void SynthEmissionAndIllumination(OOMaterialSynthContext *context)
473 : {
474 : // Read the various emission and illumination textures, and decide what to do with them.
475 : NSDictionary *emissionMapSpec = [context->inConfig oo_emissionMapSpecifier];
476 : NSDictionary *illuminationMapSpec = [context->inConfig oo_illuminationMapSpecifier];
477 : NSDictionary *emissionAndIlluminationSpec = [context->inConfig oo_emissionAndIlluminationMapSpecifier];
478 : BOOL isCombinedSpec = NO;
479 : BOOL haveIlluminationMap = NO;
480 :
481 : if (emissionMapSpec == nil && emissionAndIlluminationSpec != nil)
482 : {
483 : emissionMapSpec = emissionAndIlluminationSpec;
484 : if (illuminationMapSpec == nil) isCombinedSpec = YES; // Else use only emission part of emission_and_illumination_map, combined with full illumination_map.
485 : }
486 :
487 : if (emissionMapSpec != nil && context->texturesUsed < context->maxTextures)
488 : {
489 : /* FIXME: at this point, if there is an illumination map, we should
490 : consider merging it into the emission map using
491 : OOCombinedEmissionMapGenerator if the total number of texture
492 : specifiers is greater than context->maxTextures. This will
493 : require adding a new type of texture specifier - not a big deal.
494 : -- Ahruman 2010-05-21
495 : */
496 : AddTexture(context, @"uEmissionMap", nil, isCombinedSpec ? @"OOSTD_EMISSION_AND_ILLUMINATION_MAP" : @"OOSTD_EMISSION_MAP", emissionMapSpec);
497 : /* Note that this sets emission_color, not emission_modulate_color.
498 : This is because the emission colour value is sent through the
499 : standard OpenGL emission colour attribute by OOBasicMaterial.
500 : */
501 : AddColorIfAppropriate(context, @selector(oo_emissionModulateColor), kOOMaterialEmissionColorName, @"OOSTD_EMISSION");
502 :
503 : haveIlluminationMap = isCombinedSpec;
504 : }
505 : else
506 : {
507 : // No emission map, use overall emission colour if specified.
508 : AddColorIfAppropriate(context, @selector(oo_emissionColor), kOOMaterialEmissionColorName, @"OOSTD_EMISSION");
509 : }
510 :
511 : if (illuminationMapSpec != nil && context->texturesUsed < context->maxTextures)
512 : {
513 : AddTexture(context, @"uIlluminationMap", nil, @"OOSTD_ILLUMINATION_MAP", illuminationMapSpec);
514 : haveIlluminationMap = YES;
515 : }
516 :
517 : if (haveIlluminationMap)
518 : {
519 : AddMacroColorIfAppropriate(context, @selector(oo_illuminationModulateColor), @"OOSTD_ILLUMINATION_COLOR");
520 : }
521 : }
522 :
523 :
524 0 : static void SynthNormalMap(OOMaterialSynthContext *context)
525 : {
526 : if (context->texturesUsed < context->maxTextures)
527 : {
528 : BOOL hasParallax = YES;
529 : NSDictionary *normalMapSpec = [context->inConfig oo_normalAndParallaxMapSpecifier];
530 : if (normalMapSpec == nil)
531 : {
532 : hasParallax = NO;
533 : normalMapSpec = [context->inConfig oo_normalMapSpecifier];
534 : }
535 :
536 : if (normalMapSpec != nil)
537 : {
538 : AddTexture(context, @"uNormalMap", nil, @"OOSTD_NORMAL_MAP", normalMapSpec);
539 :
540 : if (hasParallax)
541 : {
542 : [context->macros setObject:@"1" forKey:@"OOSTD_NORMAL_AND_PARALLAX_MAP"];
543 : SetUniformFloat(context, @"uParallaxScale", [context->inConfig oo_parallaxScale]);
544 : SetUniformFloat(context, @"uParallaxBias", [context->inConfig oo_parallaxBias]);
545 : }
546 : }
547 : }
548 : }
549 :
550 :
551 0 : static void SynthSpecular(OOMaterialSynthContext *context)
552 : {
553 : GLint shininess = [context->inConfig oo_specularExponent];
554 : if (shininess <= 0) return;
555 :
556 : GLfloat gloss = [context->inConfig oo_gloss];
557 : if (gloss < 0.0f || gloss > 1.0f) return;
558 :
559 : BOOL gammaCorrect = [context->inConfig oo_gammaCorrect];
560 :
561 : NSDictionary *specularMapSpec = nil;
562 : OOColor *specularColor = nil;
563 :
564 : if (context->texturesUsed < context->maxTextures)
565 : {
566 : specularMapSpec = [context->inConfig oo_combinedSpecularMapSpecifier];
567 : }
568 :
569 : if (specularMapSpec != nil) specularColor = [context->inConfig oo_specularModulateColor];
570 : else specularColor = [context->inConfig oo_specularColor];
571 : if ([specularColor isBlack]) return;
572 :
573 : SetUniformFloat(context, @"uGloss", gloss);
574 :
575 : [context->outConfig setObject:[NSNumber numberWithUnsignedInt:shininess] forKey:kOOMaterialSpecularExponentLegacyName];
576 :
577 : if (specularMapSpec != nil)
578 : {
579 : AddTexture(context, @"uSpecularMap", kOOMaterialDiffuseMapName, @"OOSTD_SPECULAR_MAP", specularMapSpec);
580 : }
581 :
582 : if (specularColor != nil)
583 : {
584 : /* As with emission colour, specular_modulate_color is transformed to
585 : specular_color here because the shader reads it from the standard
586 : material specular colour property set by OOBasicMaterial.
587 : */
588 : [context->outConfig setObject:[specularColor normalizedArray] forKey:kOOMaterialSpecularColorName];
589 : }
590 : [context->macros setObject:@"1" forKey:@"OOSTD_SPECULAR"];
591 :
592 : // setting a bool as a float uniform, to be used in the shader as a bool again
593 : // this is how hackish I can get... maybe a better way exists, but this is quick
594 : // and can be used also for the shader materials in a not too different way
595 : // - Nikos 20181001
596 : SetUniformFloat(context, @"uGammaCorrect", (float)gammaCorrect);
597 : }
598 :
599 : #endif
|