47#define NSIntegerHashCallBacks NSIntHashCallBacks
114- (id) initWithMaterialConfiguration:(NSDictionary *)configuration
115 materialKey:(NSString *)materialKey
116 entityName:(NSString *)name;
120- (NSString *) vertexShader;
121- (NSString *) fragmentShader;
122- (NSArray *) textureSpecifications;
123- (NSDictionary *) uniformSpecifications;
125- (NSString *) materialKey;
126- (NSString *) entityName;
128- (void) createTemporaries;
129- (void) destroyTemporaries;
131- (void) composeVertexShader;
132- (void) composeFragmentShader;
135- (void) appendVariable:(NSString *)name ofType:(NSString *)type withPrefix:(NSString *)prefix to:(NSMutableString *)buffer;
136- (void) addAttribute:(NSString *)name ofType:(NSString *)type;
137- (void) addVarying:(NSString *)name ofType:(NSString *)type;
138- (void) addVertexUniform:(NSString *)name ofType:(NSString *)type;
139- (void) addFragmentUniform:(NSString *)name ofType:(NSString *)type;
142- (NSString *) defineBindingUniform:(NSDictionary *)binding ofType:(NSString *)type;
144- (NSString *) readRGBForTextureSpec:(NSDictionary *)textureSpec mapName:(NSString *)mapName;
145- (NSString *) readOneChannelForTextureSpec:(NSDictionary *)textureSpec mapName:(NSString *)mapName;
148- (NSUInteger) textureIDForSpec:(NSDictionary *)textureSpec;
149- (void) setUpOneTexture:(NSDictionary *)textureSpec;
150- (void) getSampleName:(NSString **)outSampleName andSwizzleOp:(NSString **)outSwizzleOp forTextureSpec:(NSDictionary *)textureSpec;
161- (void) writeTextureCoordRead;
169- (void) writeDiffuseColorTermIfNeeded;
176- (void) writeDiffuseColorTerm;
182- (void) writeDiffuseLighting;
189- (void) writeLightVector;
195- (void) writeEyeVector;
201- (void) writeVertexTangentBasis;
209- (void) writeNormalIfNeeded;
220- (void) writeSpecularLighting;
225- (void) writeLightMaps;
230- (void) writeVertexPosition;
235- (void) writeTotalColor;
241- (void) writeFinalColorComposite;
252#define REQUIRE_STAGE(NAME) if (!_completed_##NAME) { [self performStage:@selector(NAME)]; _completed_##NAME = YES; }
253- (void) performStage:(
SEL)stage;
255#define REQUIRE_STAGE(NAME) if (!_completed_##NAME) { [self NAME]; _completed_##NAME = YES; }
264BOOL
OOSynthesizeMaterialShader(NSDictionary *configuration, NSString *materialKey, NSString *entityName, NSString **outVertexShader, NSString **outFragmentShader, NSArray **outTextureSpecs, NSDictionary **outUniformSpecs)
266 NSCParameterAssert(configuration !=
nil && outVertexShader != NULL && outFragmentShader != NULL && outTextureSpecs != NULL && outUniformSpecs != NULL);
268 NSAutoreleasePool *pool = [NSAutoreleasePool new];
271 initWithMaterialConfiguration:configuration
272 materialKey:materialKey
273 entityName:entityName];
274 [synthesizer autorelease];
276 BOOL OK = [synthesizer
run];
286 *outVertexShader =
nil;
287 *outFragmentShader =
nil;
288 *outTextureSpecs =
nil;
289 *outUniformSpecs =
nil;
294 [*outVertexShader autorelease];
295 [*outFragmentShader autorelease];
296 [*outTextureSpecs autorelease];
297 [*outUniformSpecs autorelease];
305- (id) initWithMaterialConfiguration:(NSDictionary *)configuration
306 materialKey:(NSString *)materialKey
307 entityName:(NSString *)name
309 if ((
self = [super init]))
311 _configuration = [CanonicalizeMaterialSpecifier(configuration, materialKey) retain];
322 [
self destroyTemporaries];
349 return [NSArray arrayWithArray:_textures];
359 return [NSDictionary dictionaryWithDictionary:_uniforms];
368 [
self createTemporaries];
369 _uniforms = [[NSMutableDictionary alloc] init];
370 [_vertexBody appendString:@"void main(void)\n{\n"];
371 [_fragmentPreTextures appendString:@"void main(void)\n{\n"];
377 [
self composeVertexShader];
378 [
self composeFragmentShader];
380 @catch (NSException *exception)
387 [
self destroyTemporaries];
409 if ([segment length] > 0)
411 if ([buffer length] > 0) [buffer appendString:@"\n\n"];
412 if ([name length] > 0) [buffer appendFormat:@"// %@\n", name];
413 [buffer appendString:segment];
420 NSString *result =
nil;
422 NSString *rawMode = [textureSpecifier oo_stringForKey:kOOTextureSpecifierSwizzleKey];
425 NSUInteger length = [rawMode length];
426 if (1 <= length && length <= 4)
428 static NSCharacterSet *nonRGBACharset =
nil;
429 if (nonRGBACharset ==
nil)
431 nonRGBACharset = [[[NSCharacterSet characterSetWithCharactersInString:@"rgba"] invertedSet] retain];
434 if ([rawMode rangeOfCharacterFromSet:nonRGBACharset].location == NSNotFound)
445- (void) appendVariable:(NSString *)name ofType:(NSString *)type withPrefix:(NSString *)prefix to:(NSMutableString *)buffer
447 NSUInteger typeDeclLength = [prefix length] + [type length] + 1;
448 NSUInteger padding = (typeDeclLength < 20) ? (23 - typeDeclLength) / 4 : 1;
449 [buffer appendFormat:@"%@ %@%@%@;\n", prefix, type, OOTabString(padding), name];
453- (void) addAttribute:(NSString *)name ofType:(NSString *)type
455 [
self appendVariable:name ofType:type withPrefix:@"attribute" to:_attributes];
459- (void) addVarying:(NSString *)name ofType:(NSString *)type
461 [
self appendVariable:name ofType:type withPrefix:@"varying" to:_varyings];
465- (void) addVertexUniform:(NSString *)name ofType:(NSString *)type
467 [
self appendVariable:name ofType:type withPrefix:@"uniform" to:_vertexUniforms];
471- (void) addFragmentUniform:(NSString *)name ofType:(NSString *)type
473 [
self appendVariable:name ofType:type withPrefix:@"uniform" to:_fragmentUniforms];
477- (NSString *) defineBindingUniform:(NSDictionary *)binding ofType:(NSString *)type
479 NSString *name = [binding oo_stringForKey:@"binding"];
480 NSParameterAssert([name length] > 0);
482 NSMutableDictionary *bindingSpec = [[binding mutableCopy] autorelease];
483 if ([bindingSpec oo_stringForKey:
@"type"] ==
nil) [bindingSpec setObject:@"binding" forKey:@"type"];
486 NSString *uniformName = [_uniformBindingNames objectForKey:bindingSpec];
487 if (uniformName !=
nil)
return uniformName;
490 unichar firstChar = toupper([name characterAtIndex:0]);
491 NSString *baseName = [NSString stringWithFormat:@"u%C%@", firstChar, [name substringFromIndex:1]];
498 name = [NSString stringWithFormat:@"%@%u", baseName, ++idx];
501 [
self addFragmentUniform:name ofType:type];
503 [_uniforms setObject:bindingSpec forKey:name];
504 [_uniformBindingNames setObject:name forKey:bindingSpec];
514 [_vertexBody deleteCharactersInRange:(NSRange){ [_vertexBody length] - 2, 2 }];
516 [_vertexBody appendString:@"}"];
518 NSMutableString *
vertexShader = [NSMutableString string];
537 [_fragmentBody deleteCharactersInRange:(NSRange){ [_fragmentBody length] - 2, 2 }];
547 [fragmentShader appendString:@"\t\n\t// Texture lookups\n"];
548 [fragmentShader appendString:_fragmentTextureLookups];
550 [fragmentShader appendString:@"\t\n"];
551 [fragmentShader appendString:_fragmentBody];
552 [fragmentShader appendString:@"}"];
575 options &= ~kOOTextureExtractChannelMask;
577 return [NSString stringWithFormat:@"%@:%X:%g:%g", name, options, anisotropy, lodBias];
582 NSString *texName =
nil;
584 float anisotropy, lodBias;
588 [NSException raise:NSGenericException format:@"Invalid texture specifier"];
595- (NSUInteger) assignIDForTexture:(NSDictionary *)spec
597 NSParameterAssert(spec !=
nil);
602 spec = [spec dictionaryByRemovingObjectForKey:kOOTextureSpecifierSwizzleKey];
605 NSString *texName =
nil;
607 float anisotropy, lodBias;
611 [NSException raise:NSGenericException format:@"Invalid texture specifier"];
617 OOLogERR(
@"material.synthesis.error.cubeMap",
@"The material \"%@\
" of \"%@\" specifies a cube map texture, but doesn't have custom shaders. Cube map textures are not supported with the default shaders.", [
self materialKey], [
self entityName]);
618 [NSException raise:NSGenericException format:@"Invalid material"];
623 NSObject *existing = [_texturesByName objectForKey:key];
626 texID = [_texturesByName count];
627 NSNumber *texIDObj = [NSNumber numberWithUnsignedInteger:texID];
628 NSString *texUniform = [NSString stringWithFormat:@"uTexture%lu", texID];
631 BOOL useInternalFormat = NO;
633 BOOL useInternalFormat = YES;
636 [_textures addObject:OOMakeTextureSpecifier(texName, texOptions, anisotropy, lodBias, useInternalFormat)];
637 [_texturesByName setObject:spec forKey:key];
638 [_textureIDs setObject:texIDObj forKey:key];
639 [_uniforms setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"texture", @"type", texIDObj, @"value", nil]
642 [
self addFragmentUniform:texUniform ofType:@"sampler2D"];
646 texID = [_textureIDs oo_unsignedIntegerForKey:texName];
653- (NSUInteger) textureIDForSpec:(NSDictionary *)textureSpec
655 return [_textureIDs oo_unsignedIntegerForKey:KeyFromTextureSpec(textureSpec)];
659- (void) setUpOneTexture:(NSDictionary *)textureSpec
661 if (textureSpec ==
nil)
return;
665 NSUInteger texID = [
self assignIDForTexture:textureSpec];
666 if ((NSUInteger)NSHashGet(
_sampledTextures, (
const void *)(texID + 1)) == 0)
669 [_fragmentTextureLookups appendFormat:@"\tvec4 tex%luSample = texture2D(uTexture%lu, texCoords); // %@\n", texID, texID, [textureSpec oo_stringForKey:kOOTextureSpecifierNameKey]];
674- (void) getSampleName:(NSString **)outSampleName andSwizzleOp:(NSString **)outSwizzleOp forTextureSpec:(NSDictionary *)textureSpec
676 NSParameterAssert(outSampleName != NULL && outSwizzleOp != NULL && textureSpec !=
nil);
678 [
self setUpOneTexture:textureSpec];
679 NSUInteger texID = [
self textureIDForSpec:textureSpec];
681 *outSampleName = [NSString stringWithFormat:@"tex%luSample", texID];
686- (NSString *) readRGBForTextureSpec:(NSDictionary *)textureSpec mapName:(NSString *)mapName
688 NSString *sample, *swizzle;
689 [
self getSampleName:&sample andSwizzleOp:&swizzle forTextureSpec:textureSpec];
693 return [sample stringByAppendingString:@".rgb"];
696 NSUInteger channelCount = [swizzle length];
698 if (channelCount == 1)
700 return [NSString stringWithFormat:@"%@.%@%@%@", sample, swizzle, swizzle, swizzle];
702 else if (channelCount == 3)
704 return [NSString stringWithFormat:@"%@.%@", sample, swizzle];
707 OOLogWARN(
@"material.synthesis.warning.extractionMismatch",
@"The %@ map for material \"%@\
" of \"%@\" specifies %lu channels to extract, but only %@ may be used.", mapName, [
self materialKey], [
self entityName], channelCount,
@"1 or 3");
712- (NSString *) readOneChannelForTextureSpec:(NSDictionary *)textureSpec mapName:(NSString *)mapName
714 NSString *sample, *swizzle;
715 [
self getSampleName:&sample andSwizzleOp:&swizzle forTextureSpec:textureSpec];
719 return [sample stringByAppendingString:@".r"];
722 NSUInteger channelCount = [swizzle length];
724 if (channelCount == 1)
726 return [NSString stringWithFormat:@"%@.%@", sample, swizzle];
729 OOLogWARN(
@"material.synthesis.warning.extractionMismatch",
@"The %@ map for material \"%@\
" of \"%@\" specifies %lu channels to extract, but only %@ may be used.", mapName, [
self materialKey], [
self entityName], channelCount,
@"1");
735- (void) performStage:(
SEL)stage
740 OOLogERR(
@"material.synthesis.error.recursion",
@"Shader synthesis recursion for stage %@.", NSStringFromSelector(stage));
741 [NSException raise:NSInternalInconsistencyException format:@"stage recursion"];
746 [
self performSelector:stage];
756 _varyings = [[NSMutableString alloc] init];
766 _textures = [[NSMutableArray alloc] init];
816 [
self addVarying:@"vTexCoords" ofType:@"vec2"];
817 [_vertexBody appendString:@"\tvTexCoords = gl_MultiTexCoord0.st;\n\t\n"];
819 BOOL haveTexCoords = NO;
820 NSDictionary *parallaxMap = [_configuration oo_parallaxMapSpecifier];
822 if (parallaxMap !=
nil)
824 float parallaxScale = [_configuration oo_parallaxScale];
825 if (parallaxScale != 0.0f)
832 NSString *swizzle =
GetExtractMode(parallaxMap) ?: (NSString *)
@"a";
833 NSUInteger channelCount = [swizzle length];
834 if (channelCount == 1)
840 [_fragmentPreTextures appendString:@"\t// Parallax mapping\n"];
842 NSUInteger texID = [
self assignIDForTexture:parallaxMap];
843 [_fragmentPreTextures appendFormat:@"\tfloat parallax = texture2D(uTexture%lu, vTexCoords).%@;\n", texID, swizzle];
845 if (parallaxScale != 1.0f)
847 [_fragmentPreTextures appendFormat:@"\tparallax *= %@; // Parallax scale\n", FormatFloat(parallaxScale)];
850 float parallaxBias = [_configuration oo_parallaxBias];
851 if (parallaxBias != 0.0)
853 [_fragmentPreTextures appendFormat:@"\tparallax += %@; // Parallax bias\n", FormatFloat(parallaxBias)];
856 [_fragmentPreTextures appendString:@"\tvec2 texCoords = vTexCoords - parallax * eyeVector.xy * vec2(1.0, -1.0);\n"];
860 OOLogWARN(
@"material.synthesis.warning.extractionMismatch",
@"The %@ map for material \"%@\
" of \"%@\" specifies %lu channels to extract, but only %@ may be used.",
@"parallax", [
self materialKey], [
self entityName], channelCount,
@"1");
867 [_fragmentPreTextures appendString:@"\tvec2 texCoords = vTexCoords;\n"];
874 NSDictionary *diffuseMap = [_configuration oo_diffuseMapSpecifierWithDefaultName:[
self materialKey]];
877 if ([diffuseColor isBlack])
return;
880 BOOL haveDiffuseColor = NO;
881 if (diffuseMap !=
nil)
883 NSString *readInstr = [
self readRGBForTextureSpec:diffuseMap mapName:@"diffuse"];
886 [_fragmentBody appendString:@"\t// INVALID EXTRACTION KEY\n\t\n"];
890 [_fragmentBody appendFormat:@"\tvec3 diffuseColor = %@;\n", readInstr];
891 haveDiffuseColor = YES;
895 if (!haveDiffuseColor || ![diffuseColor isWhite])
899 NSString *format =
nil;
900 if (haveDiffuseColor)
902 format =
@"\tdiffuseColor *= vec3(%@, %@, %@);\n";
906 format =
@"\tconst vec3 diffuseColor = vec3(%@, %@, %@);\n";
907 haveDiffuseColor = YES;
909 [_fragmentBody appendFormat:format, FormatFloat(rgba[0]), FormatFloat(rgba[1]), FormatFloat(rgba[2])];
912 (void) haveDiffuseColor;
913 [_fragmentBody appendString:@"\t\n"];
923 [_fragmentBody appendString:@"\tconst vec3 diffuseColor = vec3(0.0); // Diffuse colour is black.\n\t\n"];
939 NSString *normalDotLight =
_constZNormal ?
@"lightVector.z" :
@"dot(normal, lightVector)";
941 [_fragmentBody appendFormat:
942 @"\t// Diffuse (Lambertian) and ambient lighting\n"
943 "\tvec3 diffuseLight = (gl_LightSource[1].diffuse * max(0.0, %@) + gl_LightModel.ambient).rgb;\n\t\n",
955 [
self addVarying:@"vLightVector" ofType:@"vec3"];
957 [_vertexBody appendString:
958 @"\tvec3 lightVector = gl_LightSource[1].position.xyz;\n"
959 "\tvLightVector = lightVector * TBN;\n\t\n"];
960 [_fragmentBody appendFormat:@"\tvec3 lightVector = normalize(vLightVector);\n\t\n"];
969 [
self addVarying:@"vEyeVector" ofType:@"vec3"];
971 [_vertexBody appendString:@"\tvEyeVector = position.xyz * TBN;\n\t\n"];
972 [_fragmentPreTextures appendString:@"\tvec3 eyeVector = normalize(vEyeVector);\n\t\n"];
978 [
self addAttribute:@"tangent" ofType:@"vec3"];
980 [_vertexBody appendString:
981 @"\t// Build tangent space basis\n"
982 "\tvec3 n = gl_NormalMatrix * gl_Normal;\n"
983 "\tvec3 t = gl_NormalMatrix * tangent;\n"
984 "\tvec3 b = cross(n, t);\n"
985 "\tmat3 TBN = mat3(t, b, n);\n\t\n"];
994 NSDictionary *normalMap = [_configuration oo_normalMapSpecifier];
995 if (normalMap ==
nil)
998 normalMap = [_configuration oo_normalAndParallaxMapSpecifier];
1000 if (normalMap !=
nil)
1002 NSString *sample, *swizzle;
1003 [
self getSampleName:&sample andSwizzleOp:&swizzle forTextureSpec:normalMap];
1004 if (swizzle ==
nil) swizzle =
@"rgb";
1005 if ([swizzle length] == 3)
1007 [_fragmentBody appendFormat:@"\tvec3 normal = normalize(%@.%@ - 0.5);\n\t\n", sample, swizzle];
1013 OOLogWARN(
@"material.synthesis.warning.extractionMismatch",
@"The %@ map for material \"%@\
" of \"%@\" specifies %lu channels to extract, but only %@ may be used.",
@"normal", [
self materialKey], [
self entityName], [swizzle length],
@"3");
1026 [_fragmentBody appendString:@"\tconst vec3 normal = vec3(0.0, 0.0, 1.0);\n\t\n"];
1033 float specularExponent = [_configuration oo_specularExponent];
1034 if (specularExponent <= 0)
return;
1036 NSDictionary *specularColorMap = [_configuration oo_specularColorMapSpecifier];
1037 NSDictionary *specularExponentMap = [_configuration oo_specularExponentMapSpecifier];
1038 float scaleFactor = 1.0f;
1040 if (specularColorMap)
1042 scaleFactor = [specularColorMap oo_doubleForKey:kOOTextureSpecifierScaleFactorKey defaultValue:1.0f];
1046 if (specularColorMap ==
nil)
1048 specularColor = [_configuration oo_specularColor];
1052 specularColor = [_configuration oo_specularModulateColor];
1055 if ([specularColor isBlack])
return;
1057 BOOL modulateWithDiffuse = [specularColorMap oo_boolForKey:kOOTextureSpecifierSelfColorKey];
1063 if (modulateWithDiffuse)
1068 [_fragmentBody appendString:@"\t// Specular (Blinn-Phong) lighting\n"];
1070 BOOL haveSpecularColor = NO;
1071 if (specularColorMap !=
nil)
1073 NSString *readInstr = [
self readRGBForTextureSpec:specularColorMap mapName:@"specular colour"];
1076 [_fragmentBody appendString:@"\t// INVALID EXTRACTION KEY\n\t\n"];
1080 [_fragmentBody appendFormat:@"\tvec3 specularColor = %@;\n", readInstr];
1081 haveSpecularColor = YES;
1084 if (!haveSpecularColor || ![specularColor isWhite])
1089 NSString *comment = (scaleFactor == 1.0f) ?
@"Constant colour" :
@"Constant colour and scale factor";
1092 scaleFactor *= rgba[3];
1093 rgba[0] *= scaleFactor;
1094 rgba[1] *= scaleFactor;
1095 rgba[2] *= scaleFactor;
1100 NSString *format =
nil;
1101 if (haveSpecularColor)
1103 format =
@"\tspecularColor *= vec3(%@, %@, %@); // %@\n";
1107 format =
@"\tvec3 specularColor = vec3(%@, %@, %@); // %@\n";
1108 haveSpecularColor = YES;
1110 [_fragmentBody appendFormat:format, FormatFloat(rgba[0]), FormatFloat(rgba[1]), FormatFloat(rgba[2]), comment];
1114 if (haveSpecularColor && scaleFactor != 1.0f)
1116 [_fragmentBody appendFormat:@"\tspecularColor *= %@; // Scale factor\n", FormatFloat(scaleFactor)];
1120 if (modulateWithDiffuse)
1122 [_fragmentBody appendString:@"\tspecularColor *= diffuseColor; // Self-colouring\n"];
1126 BOOL haveSpecularExponent = NO;
1127 if (specularExponentMap !=
nil)
1129 NSString *readInstr = [
self readOneChannelForTextureSpec:specularExponentMap mapName:@"specular exponent"];
1132 [_fragmentBody appendString:@"\t// INVALID EXTRACTION KEY\n\t\n"];
1136 [_fragmentBody appendFormat:@"\tfloat specularExponent = %@ * %.1f;\n", readInstr, specularExponent];
1137 haveSpecularExponent = YES;
1139 if (!haveSpecularExponent)
1141 [_fragmentBody appendFormat:@"\tconst float specularExponent = %.1f;\n", specularExponent];
1146 [_fragmentBody appendFormat:@"\tvec3 reflection = reflect(lightVector, normal);\n"];
1153 [_fragmentBody appendFormat:@"\tvec3 reflection = vec3(lightVector.x, lightVector.y, -lightVector.z); // Equivalent to reflect(lightVector, normal) since normal is known to be (0, 0, 1) in tangent space.\n"];
1156 [_fragmentBody appendFormat:
1157 @"\tfloat specIntensity = dot(reflection, eyeVector);\n"
1158 "\tspecIntensity = pow(max(0.0, specIntensity), specularExponent);\n"
1159 "\ttotalColor += specIntensity * specularColor * gl_LightSource[1].specular.rgb;\n\t\n"];
1165 NSArray *lightMaps = [_configuration oo_arrayForKey:kOOMaterialLightMapsName];
1166 NSUInteger idx,
count = [lightMaps count];
1167 if (
count == 0)
return;
1172 for (idx = 0; idx <
count; idx++)
1174 NSDictionary *lightMapSpec = [lightMaps oo_dictionaryAtIndex:idx];
1183 [_fragmentBody appendString:@"\tvec3 lightMapColor;\n"];
1185 for (idx = 0; idx <
count; idx++)
1187 NSDictionary *lightMapSpec = [lightMaps oo_dictionaryAtIndex:idx];
1189 NSArray *color = [lightMapSpec oo_arrayForKey:kOOTextureSpecifierModulateColorKey];
1190 float rgba[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1191 BOOL isIllumination = [lightMapSpec oo_boolForKey:kOOTextureSpecifierIlluminationModeKey];
1195 [_fragmentBody appendString:@"\t// Light map with neither colour nor texture has no effect.\n\t\n"];
1201 NSUInteger idx,
count = [color count];
1203 for (idx = 0; idx <
count; idx++)
1205 rgba[idx] = [color oo_doubleAtIndex:idx];
1207 rgba[0] *= rgba[3]; rgba[1] *= rgba[3]; rgba[2] *= rgba[3];
1210 if (
EXPECT_NOT((rgba[0] == 0.0f && rgba[1] == 0.0f && rgba[2] == 0.0f) ||
1213 [_fragmentBody appendString:@"\t// Light map tinted black has no effect.\n\t\n"];
1217 if (textureSpec !=
nil)
1219 NSString *readInstr = [
self readRGBForTextureSpec:textureSpec mapName:@"light"];
1222 [_fragmentBody appendString:@"\t// INVALID EXTRACTION KEY\n\n"];
1226 [_fragmentBody appendFormat:@"\tlightMapColor = %@;\n", readInstr];
1228 if (rgba[0] != 1.0f || rgba[1] != 1.0f || rgba[2] != 1.0f)
1230 [_fragmentBody appendFormat:@"\tlightMapColor *= vec3(%@, %@, %@);\n", FormatFloat(rgba[0]), FormatFloat(rgba[1]), FormatFloat(rgba[2])];
1235 [_fragmentBody appendFormat:@"\tlightMapColor = vec3(%@, %@, %@);\n", FormatFloat(rgba[0]), FormatFloat(rgba[1]), FormatFloat(rgba[2])];
1238 NSDictionary *binding = [textureSpec oo_dictionaryForKey:kOOTextureSpecifierBindingKey];
1241 NSString *bindingName = [binding oo_stringForKey:@"binding"];
1243 NSString *bindingType = [typeDict oo_stringForKey:bindingName];
1244 NSString *glslType =
nil;
1245 NSString *swizzle =
@"";
1247 if ([bindingType isEqualToString:
@"float"])
1249 glslType =
@"float";
1251 else if ([bindingType isEqualToString:
@"vector"])
1255 else if ([bindingType isEqualToString:
@"color"])
1261 if (glslType !=
nil)
1263 NSString *uniformName = [
self defineBindingUniform:binding ofType:bindingType];
1264 [_fragmentBody appendFormat:@"\tlightMapColor *= %@%@;\n", uniformName, swizzle];
1268 if (bindingType ==
nil)
1270 OOLogERR(
@"material.binding.error.unknown",
@"Cannot bind light map to unknown attribute \"%@\
".", bindingName);
1274 OOLogERR(
@"material.binding.error.badType",
@"Cannot bind light map to attribute \"%@\
" of type %@.", bindingName, bindingType);
1276 [_fragmentBody appendString:@"\tlightMapColor = vec3(0.0); // Bad binding, see log.\n"];
1280 if (!isIllumination)
1282 [_fragmentBody appendString:@"\ttotalColor += lightMapColor;\n\t\n"];
1286 [_fragmentBody appendString:@"\tdiffuseLight += lightMapColor;\n\t\n"];
1294 [_vertexBody appendString:
1295 @"\tvec4 position = gl_ModelViewMatrix * gl_Vertex;\n"
1296 "\tgl_Position = gl_ProjectionMatrix * position;\n\t\n"];
1302 [_fragmentPreTextures appendString:@"\tvec3 totalColor = vec3(0.0);\n\t\n"];
1315 [_fragmentBody appendString:@"\ttotalColor += diffuseColor * diffuseLight;\n"];
1318 [_fragmentBody appendString:@"\tgl_FragColor = vec4(totalColor, 1.0);\n\t\n"];
1332 NSMutableDictionary *result = [NSMutableDictionary dictionary];
1339 if (col !=
nil) [result setObject:[col
normalizedArray] forKey:kOOMaterialDiffuseColorName];
1343 if (col !=
nil) [result setObject:[col
normalizedArray] forKey:kOOMaterialAmbientColorName];
1347 if (col !=
nil) [result setObject:[col
normalizedArray] forKey:kOOMaterialSpecularColorName];
1350 if (col !=
nil) [result setObject:[col
normalizedArray] forKey:kOOMaterialSpecularModulateColorName];
1354 if (col !=
nil) [result setObject:[col
normalizedArray] forKey:kOOMaterialEmissionColorName];
1357 texSpec = [spec objectForKey:kOOMaterialDiffuseMapName];
1358 if ([texSpec isKindOfClass:[NSString
class]])
1360 if ([texSpec length] > 0)
1362 texSpec = [NSDictionary dictionaryWithObject:texSpec forKey:kOOTextureSpecifierNameKey];
1365 else if ([texSpec isKindOfClass:[NSDictionary
class]])
1370 NSString *name = [texSpec objectForKey:kOOTextureSpecifierNameKey];
1371 if (name ==
nil) texSpec = [texSpec dictionaryByAddingObject:materialKey forKey:kOOTextureSpecifierNameKey];
1372 else if ([name length] == 0)
1374 texSpec = [texSpec dictionaryByRemovingObjectForKey:kOOTextureSpecifierNameKey];
1380 texSpec = [NSDictionary dictionaryWithObject:materialKey forKey:kOOTextureSpecifierNameKey];
1382 [result setObject:texSpec forKey:kOOMaterialDiffuseMapName];
1386 BOOL haveNewSpecular = NO;
1387 texSpec = [spec objectForKey:kOOMaterialSpecularColorMapName];
1388 if ([texSpec isKindOfClass:[NSString
class]])
1390 texSpec = [NSDictionary dictionaryWithObject:texSpec forKey:kOOTextureSpecifierNameKey];
1392 else if (![texSpec isKindOfClass:[NSDictionary
class]])
1398 haveNewSpecular = YES;
1399 [result setObject:texSpec forKey:kOOMaterialSpecularColorMapName];
1402 texSpec = [spec objectForKey:kOOMaterialSpecularExponentMapName];
1403 if ([texSpec isKindOfClass:[NSString
class]])
1405 texSpec = [NSDictionary dictionaryWithObject:texSpec forKey:kOOTextureSpecifierNameKey];
1407 else if (![texSpec isKindOfClass:[NSDictionary
class]])
1413 haveNewSpecular = YES;
1414 [result setObject:texSpec forKey:kOOMaterialSpecularExponentMapName];
1417 if (!haveNewSpecular)
1420 texSpec = [spec objectForKey:kOOMaterialCombinedSpecularMapName];
1421 if ([texSpec isKindOfClass:[NSString
class]])
1423 texSpec = [NSDictionary dictionaryWithObject:texSpec forKey:kOOTextureSpecifierNameKey];
1425 else if (![texSpec isKindOfClass:[NSDictionary
class]])
1431 [result setObject:texSpec forKey:kOOMaterialSpecularColorMapName];
1432 texSpec = [texSpec dictionaryByAddingObject:@"a" forKey:kOOTextureSpecifierSwizzleKey];
1433 [result setObject:texSpec forKey:kOOMaterialSpecularExponentMapName];
1440 BOOL haveParallax = NO;
1441 BOOL haveNewNormal = NO;
1442 texSpec = [spec objectForKey:kOOMaterialNormalMapName];
1443 if ([texSpec isKindOfClass:[NSString
class]])
1445 texSpec = [NSDictionary dictionaryWithObject:texSpec forKey:kOOTextureSpecifierNameKey];
1447 else if (![texSpec isKindOfClass:[NSDictionary
class]])
1453 haveNewNormal = YES;
1454 [result setObject:texSpec forKey:kOOMaterialNormalMapName];
1457 texSpec = [spec objectForKey:kOOMaterialParallaxMapName];
1458 if ([texSpec isKindOfClass:[NSString
class]])
1460 texSpec = [NSDictionary dictionaryWithObject:texSpec forKey:kOOTextureSpecifierNameKey];
1462 else if (![texSpec isKindOfClass:[NSDictionary
class]])
1468 haveNewNormal = YES;
1470 [result setObject:texSpec forKey:kOOMaterialParallaxMapName];
1476 texSpec = [spec objectForKey:kOOMaterialNormalAndParallaxMapName];
1477 if ([texSpec isKindOfClass:[NSString
class]])
1479 texSpec = [NSDictionary dictionaryWithObject:texSpec forKey:kOOTextureSpecifierNameKey];
1481 else if (![texSpec isKindOfClass:[NSDictionary
class]])
1488 [result setObject:texSpec forKey:kOOMaterialNormalMapName];
1489 texSpec = [texSpec dictionaryByAddingObject:@"a" forKey:kOOTextureSpecifierSwizzleKey];
1490 [result setObject:texSpec forKey:kOOMaterialParallaxMapName];
1497 float parallaxScale = [spec oo_floatForKey:kOOMaterialParallaxScaleName defaultValue:kOOMaterialDefaultParallaxScale];
1498 [result oo_setFloat:parallaxScale forKey:kOOMaterialParallaxScaleName];
1500 float parallaxBias = [spec oo_floatForKey:kOOMaterialParallaxBiasName];
1501 [result oo_setFloat:parallaxBias forKey:kOOMaterialParallaxBiasName];
1507 NSMutableArray *lightMaps = [NSMutableArray array];
1508 id lightMapSpecs = [spec objectForKey:kOOMaterialLightMapsName];
1509 if (lightMapSpecs !=
nil && ![lightMapSpecs isKindOfClass:[NSArray
class]])
1511 lightMapSpecs = [NSArray arrayWithObject:lightMapSpecs];
1515 foreach (lmSpec, lightMapSpecs)
1517 if ([lmSpec isKindOfClass:[NSString
class]])
1519 lmSpec = [NSMutableDictionary dictionaryWithObject:lmSpec forKey:kOOTextureSpecifierNameKey];
1521 else if ([lmSpec isKindOfClass:[NSDictionary
class]])
1523 lmSpec = [[lmSpec mutableCopy] autorelease];
1530 id modulateColor = [lmSpec objectForKey:kOOTextureSpecifierModulateColorKey];
1531 if (modulateColor !=
nil && ![modulateColor isKindOfClass:[NSArray
class]])
1535 [lmSpec setObject:[col
normalizedArray] forKey:kOOTextureSpecifierModulateColorKey];
1538 id binding = [lmSpec objectForKey:kOOTextureSpecifierBindingKey];
1541 if ([binding isKindOfClass:[NSString
class]])
1543 NSDictionary *expandedBinding = [NSDictionary dictionaryWithObjectsAndKeys:@"binding", @"type", binding, @"binding", nil];
1544 [lmSpec setObject:expandedBinding forKey:kOOTextureSpecifierBindingKey];
1546 else if (![binding isKindOfClass:[NSDictionary
class]] || [[binding oo_stringForKey:
@"binding"] length] == 0)
1548 [lmSpec removeObjectForKey:kOOTextureSpecifierBindingKey];
1552 [lightMaps addObject:[[lmSpec copy] autorelease]];
1555 if ([lightMaps
count] == 0)
1558 id emissionSpec = [spec objectForKey:kOOMaterialEmissionMapName];
1559 id illuminationSpec = [spec objectForKey:kOOMaterialIlluminationMapName];
1561 if (emissionSpec ==
nil && illuminationSpec ==
nil)
1563 emissionSpec = [spec objectForKey:kOOMaterialEmissionAndIlluminationMapName];
1564 if ([emissionSpec isKindOfClass:[NSString
class]])
1567 emissionSpec = [NSDictionary dictionaryWithObject:emissionSpec forKey:kOOTextureSpecifierNameKey];
1569 else if (![emissionSpec isKindOfClass:[NSDictionary
class]])
1574 if (emissionSpec !=
nil)
1576 illuminationSpec = [emissionSpec dictionaryByAddingObject:@"a" forKey:kOOTextureSpecifierSwizzleKey];
1580 if (emissionSpec !=
nil)
1582 if ([emissionSpec isKindOfClass:[NSString
class]])
1584 emissionSpec = [NSDictionary dictionaryWithObject:emissionSpec forKey:kOOTextureSpecifierNameKey];
1586 if ([emissionSpec isKindOfClass:[NSDictionary
class]])
1589 if (col !=
nil) emissionSpec = [emissionSpec dictionaryByAddingObject:[col
normalizedArray] forKey:kOOTextureSpecifierModulateColorKey];
1591 [lightMaps addObject:emissionSpec];
1595 if (illuminationSpec !=
nil)
1597 if ([illuminationSpec isKindOfClass:[NSString
class]])
1599 illuminationSpec = [NSDictionary dictionaryWithObject:illuminationSpec forKey:kOOTextureSpecifierNameKey];
1601 if ([illuminationSpec isKindOfClass:[NSDictionary
class]])
1604 if (col !=
nil) illuminationSpec = [illuminationSpec dictionaryByAddingObject:[col
normalizedArray] forKey:kOOTextureSpecifierModulateColorKey];
1606 illuminationSpec = [illuminationSpec dictionaryByAddingObject:[NSNumber numberWithBool:YES] forKey:kOOTextureSpecifierIlluminationModeKey];
1608 [lightMaps addObject:illuminationSpec];
1613 [result setObject:lightMaps forKey:kOOMaterialLightMapsName];
1616 OOLog(
@"material.canonicalForm",
@"Canonicalized material %@:\nORIGINAL:\n%@\n\n@CANONICAL:\n%@",
materialKey, spec, result);
1624 long long intValue = value;
1625 if (value == intValue)
1627 return [NSString stringWithFormat:@"%lli.0", intValue];
1631 return [NSString stringWithFormat:@"%g", value];
static NSString * GetExtractMode(NSDictionary *textureSpecifier)
static NSString * FormatFloat(double value)
#define REQUIRE_STAGE(NAME)
static NSDictionary * CanonicalizeMaterialSpecifier(NSDictionary *spec, NSString *materialKey)
BOOL OOSynthesizeMaterialShader(NSDictionary *configuration, NSString *materialKey, NSString *entityName, NSString **outVertexShader, NSString **outFragmentShader, NSArray **outTextureSpecs, NSDictionary **outUniformSpecs)
#define OOLogWARN(class, format,...)
#define OOLogERR(class, format,...)
#define OOLog(class, format,...)
OOTextureFlags OOApplyTextureOptionDefaults(OOTextureFlags options)
NSDictionary * OOTextureSpecFromObject(id object, NSString *defaultName)
NSString *const kOOTextureSpecifierIlluminationModeKey
BOOL OOInterpretTextureSpecifier(id specifier, NSString **outName, OOTextureFlags *outOptions, float *outAnisotropy, float *outLODBias, BOOL ignoreExtract)
NSString *const kOOTextureSpecifierSwizzleKey
OOColor * colorWithDescription:(id description)
void getRed:green:blue:alpha:(float *red,[green] float *green,[blue] float *blue,[alpha] float *alpha)
NSArray * normalizedArray()
NSHashTable * _sampledTextures
NSUInteger _completed_writeVertexTangentBasis
NSMutableDictionary * _textureIDs
void composeFragmentShader()
NSUInteger _completed_writeLightMaps
NSUInteger _usesNormalMap
NSMutableString * _vertexBody
static void AppendIfNotEmpty(NSMutableString *buffer, NSString *segment, NSString *name)
static NSString * KeyFromTextureSpec(NSDictionary *spec)
NSUInteger _completed_writeFinalColorComposite
NSUInteger _completed_writeSpecularLighting
void writeDiffuseColorTermIfNeeded()
NSString * _fragmentShader
NSUInteger _completed_writeTotalColor
NSMutableString * _fragmentHelpers
NSMutableString * _attributes
NSUInteger _haveDiffuseLight
void writeVertexTangentBasis()
NSMutableString * _vertexHelpers
void writeDiffuseColorTerm()
void writeDiffuseLighting()
NSUInteger _usesDiffuseTerm
NSMutableString * _varyings
NSMutableDictionary * _uniformBindingNames
NSMutableString * _fragmentBody
NSUInteger _completed_writeLightVector
void writeNormalIfNeeded()
NSString * fragmentShader()
NSMutableString * _fragmentUniforms
NSMutableArray * _textures
NSUInteger _completed_writeNormalIfNeeded
void writeVertexPosition()
NSArray * textureSpecifications()
static NSString * GetExtractMode(NSDictionary *textureSpecifier)
NSUInteger _completed_writeTextureCoordRead
void destroyTemporaries()
NSMutableString * _vertexUniforms
void writeFinalColorComposite()
NSUInteger _completed_writeDiffuseColorTermIfNeeded
static NSString * KeyFromTextureParameters(NSString *name, OOTextureFlags options, float anisotropy, float lodBias)
NSString * vertexShader()
NSHashTable * _stagesInProgress
NSUInteger _completed_writeDiffuseLighting
NSMutableString * _fragmentPreTextures
NSDictionary * uniformSpecifications()
NSMutableDictionary * _uniforms
NSUInteger _completed_writeEyeVector
void composeVertexShader()
NSUInteger _completed_writeVertexPosition
NSMutableDictionary * _texturesByName
void writeTextureCoordRead()
NSUInteger _completed_writeDiffuseColorTerm
void writeSpecularLighting()
NSMutableString * _fragmentTextureLookups
NSDictionary * _configuration
NSDictionary * shaderBindingTypesDictionary()