/// <summary> /// Parses the material, if there are any errors during parsing the defaultShader will be set. /// </summary> /// <param name="lexer"></param> private void ParseMaterial(idLexer lexer) { _registerCount = PredefinedRegisterCount; // leave space for the parms to be copied in. for(int i = 0; i < _registerCount; i++) { _parsingData.RegisterIsTemporary[i] = true; // they aren't constants that can be folded. } TextureRepeat textureRepeatDefault = TextureRepeat.Repeat; // allow a global setting for repeat. idToken token = null; string tokenValue; string tokenLower; int count; while(true) { if(TestMaterialFlag(Renderer.MaterialFlags.Defaulted) == true) { // we have a parse error. return; } if((token = lexer.ExpectAnyToken()) == null) { this.MaterialFlag = MaterialFlags.Defaulted; return; } tokenValue = token.ToString(); tokenLower = tokenValue.ToLower(); // end of material definition if(tokenLower == "}") { break; } else if(tokenLower == "qer_editorimage") { token = lexer.ReadTokenOnLine(); _editorImageName = (token != null) ? token.ToString() : string.Empty; lexer.SkipRestOfLine(); } else if(tokenLower == "description") { token = lexer.ReadTokenOnLine(); _description = (token != null) ? token.ToString() : string.Empty; } // check for the surface / content bit flags. else if(CheckSurfaceParameter(token) == true) { } else if(tokenLower == "polygonoffset") { this.MaterialFlag = Renderer.MaterialFlags.PolygonOffset; if((token = lexer.ReadTokenOnLine()) == null) { _polygonOffset = 1; } else { _polygonOffset = token.ToFloat(); } } // noshadow. else if(tokenLower == "noshadows") { this.MaterialFlag = MaterialFlags.NoShadows; } else if(tokenLower == "suppressinsubview") { _suppressInSubview = true; } else if(tokenLower == "portalsky") { _portalSky = true; } else if(tokenLower == "noselfshadow") { this.MaterialFlag = Renderer.MaterialFlags.NoSelfShadow; } else if(tokenLower == "noportalfog") { this.MaterialFlag = Renderer.MaterialFlags.NoPortalFog; } // forceShadows allows nodraw surfaces to cast shadows. else if(tokenLower == "forceshadows") { this.MaterialFlag = Renderer.MaterialFlags.ForceShadows; } // overlay / decal suppression. else if(tokenLower == "nooverlays") { _allowOverlays = false; } // moster blood overlay forcing for alpha tested or translucent surfaces. else if(tokenLower == "forceoverlays") { _parsingData.ForceOverlays = true; } else if(tokenLower == "translucent") { _coverage = MaterialCoverage.Translucent; } // global zero clamp. else if(tokenLower == "zeroclamp") { textureRepeatDefault = TextureRepeat.ClampToZero; } // global clamp. else if(tokenLower == "clamp") { textureRepeatDefault = TextureRepeat.Clamp; } // global clamp. else if(tokenLower == "alphazeroclamp") { textureRepeatDefault = TextureRepeat.ClampToZero; } // forceOpaque is used for skies-behind-windows. else if(tokenLower == "forceopaque") { _coverage = MaterialCoverage.Opaque; } else if(tokenLower == "twosided") { _cullType = CullType.TwoSided; // twoSided implies no-shadows, because the shadow // volume would be coplanar with the surface, giving depth fighting // we could make this no-self-shadows, but it may be more important // to receive shadows from no-self-shadow monsters. this.MaterialFlag = Renderer.MaterialFlags.NoShadows; } else if(tokenLower == "backsided") { _cullType = CullType.Back; // the shadow code doesn't handle this, so just disable shadows. // We could fix this in the future if there was a need. this.MaterialFlag = Renderer.MaterialFlags.NoShadows; } else if(tokenLower == "foglight") { _fogLight = true; } else if(tokenLower == "blendlight") { _blendLight = true; } else if(tokenLower == "ambientlight") { _ambientLight = true; } else if(tokenLower == "mirror") { _sort = (float) MaterialSort.Subview; _coverage = MaterialCoverage.Opaque; } else if(tokenLower == "nofog") { _noFog = true; } else if(tokenLower == "unsmoothedtangents") { _unsmoothedTangents = true; } // lightFallofImage <imageprogram> // specifies the image to use for the third axis of projected // light volumes. else if(tokenLower == "lightfalloffimage") { _lightFalloffImage = idE.ImageManager.ImageFromFile(ParsePastImageProgram(lexer), TextureFilter.Default, false, TextureRepeat.Clamp, TextureDepth.Default); } // guisurf <guifile> | guisurf entity // an entity guisurf must have an idUserInterface // specified in the renderEntity. else if(tokenLower == "guisurf") { token = lexer.ReadTokenOnLine(); tokenLower = token.ToString().ToLower(); if(tokenLower == "entity") { _entityGui = 1; } else if(tokenLower == "entity2") { _entityGui = 2; } else if(tokenLower == "entity3") { _entityGui = 3; } else { _userInterface = idE.UIManager.FindInterface(token.ToString(), true); } } // sort. else if(tokenLower == "sort") { ParseSort(lexer); } // spectrum <integer>. else if(tokenLower == "spectrum") { int.TryParse(lexer.ReadTokenOnLine().ToString(), out _spectrum); } // deform < sprite | tube | flare >. else if(tokenLower == "deform") { ParseDeform(lexer); } // decalInfo <staySeconds> <fadeSeconds> (<start rgb>) (<end rgb>). else if(tokenLower == "decalinfo") { ParseDecalInfo(lexer); } // renderbump <args...>. else if(tokenLower == "renderbump") { _renderBump = lexer.ParseRestOfLine(); } // diffusemap for stage shortcut. else if(tokenLower == "diffusemap") { idLexer newLexer = new idLexer(LexerOptions.NoFatalErrors | LexerOptions.NoStringConcatination | LexerOptions.NoStringEscapeCharacters | LexerOptions.AllowPathNames); newLexer.LoadMemory(string.Format("blend diffusemap\nmap {0}\n}}\n", ParsePastImageProgram(lexer)), "diffusemap"); ParseStage(newLexer, textureRepeatDefault); } // specularmap for stage shortcut. else if(tokenLower == "specularmap") { idLexer newLexer = new idLexer(LexerOptions.NoFatalErrors | LexerOptions.NoStringConcatination | LexerOptions.NoStringEscapeCharacters | LexerOptions.AllowPathNames); newLexer.LoadMemory(string.Format("blend specularmap\nmap {0}\n}}\n", ParsePastImageProgram(lexer)), "specularmap"); ParseStage(newLexer, textureRepeatDefault); } // normalmap for stage shortcut. else if(tokenLower == "bumpmap") { idLexer newLexer = new idLexer(LexerOptions.NoFatalErrors | LexerOptions.NoStringConcatination | LexerOptions.NoStringEscapeCharacters | LexerOptions.AllowPathNames); newLexer.LoadMemory(string.Format("blend bumpmap\nmap {0}\n}}\n", ParsePastImageProgram(lexer)), "bumpmap"); ParseStage(newLexer, textureRepeatDefault); } // DECAL_MACRO for backwards compatibility with the preprocessor macros. else if(tokenLower == "decal_macro") { // polygonOffset this.MaterialFlag = Renderer.MaterialFlags.PolygonOffset; _polygonOffset = -1; // discrete _surfaceFlags |= SurfaceFlags.Discrete; _contentFlags &= ~ContentFlags.Solid; // sort decal. _sort = (float) MaterialSort.Decal; // noShadows this.MaterialFlag = Renderer.MaterialFlags.NoShadows; } else if(tokenValue == "{") { // create the new stage. ParseStage(lexer, textureRepeatDefault); } else { idConsole.WriteLine("unknown general material parameter '{0}' in '{1}'", tokenValue, this.Name); return; } } // add _flat or _white stages if needed. AddImplicitStages(); // order the diffuse / bump / specular stages properly. SortInteractionStages(); // if we need to do anything with normals (lighting or environment mapping) // and two sided lighting was asked for, flag // shouldCreateBackSides() and change culling back to single sided, // so we get proper tangent vectors on both sides. // we can't just call ReceivesLighting(), because the stages are still // in temporary form. if(_cullType == CullType.TwoSided) { count = _parsingData.Stages.Count; for(int i = 0; i < count; i++) { if((_parsingData.Stages[i].Lighting != StageLighting.Ambient) || (_parsingData.Stages[i].Texture.TextureCoordinates != TextureCoordinateGeneration.Explicit)) { if(_cullType == CullType.TwoSided) { _cullType = CullType.Front; _shouldCreateBackSides = true; } break; } } } // currently a surface can only have one unique texgen for all the stages on old hardware. TextureCoordinateGeneration firstGen = TextureCoordinateGeneration.Explicit; count = _parsingData.Stages.Count; for(int i = 0; i < count; i++) { if(_parsingData.Stages[i].Texture.TextureCoordinates != TextureCoordinateGeneration.Explicit) { if(firstGen == TextureCoordinateGeneration.Explicit) { firstGen = _parsingData.Stages[i].Texture.TextureCoordinates; } else if(firstGen != _parsingData.Stages[i].Texture.TextureCoordinates) { idConsole.Warning("material '{0}' has multiple stages with a texgen", this.Name); break; } } } }
private void ParseStage(idLexer lexer, TextureRepeat textureRepeatDefault) { TextureFilter textureFilter = TextureFilter.Default; TextureRepeat textureRepeat = textureRepeatDefault; TextureDepth textureDepth = TextureDepth.Default; CubeFiles cubeMap = CubeFiles.TwoD; bool allowPicmip = true; string imageName = string.Empty; NewMaterialStage newStage = new NewMaterialStage(); newStage.VertexParameters = new int[4, 4]; MaterialStage materialStage = new MaterialStage(); materialStage.ConditionRegister = GetExpressionConstant(1); materialStage.Color.Registers = new int[] { GetExpressionConstant(1), GetExpressionConstant(1), GetExpressionConstant(1), GetExpressionConstant(1) }; int[,] matrix = new int[2, 3]; idToken token; int a, b; string tokenValue; string tokenLower; while(true) { if(TestMaterialFlag(MaterialFlags.Defaulted) == true) { // we have a parse error return; } else if((token = lexer.ExpectAnyToken()) == null) { this.MaterialFlag = MaterialFlags.Defaulted; return; } tokenValue = token.ToString(); tokenLower = tokenValue.ToLower(); // the close brace for the entire material ends the draw block if(tokenLower == "}") { break; } // BSM Nerve: Added for stage naming in the material editor else if(tokenLower == "name") { lexer.SkipRestOfLine(); } // image options else if(tokenLower == "blend") { ParseBlend(lexer, ref materialStage); } else if(tokenLower == "map") { imageName = ParsePastImageProgram(lexer); } else if(tokenLower == "remoterendermap") { materialStage.Texture.Dynamic = DynamicImageType.RemoteRender; materialStage.Texture.Width = lexer.ParseInt(); materialStage.Texture.Height = lexer.ParseInt(); } else if(tokenLower == "mirrorrendermap") { materialStage.Texture.Dynamic = DynamicImageType.MirrorRender; materialStage.Texture.Width = lexer.ParseInt(); materialStage.Texture.Height = lexer.ParseInt(); materialStage.Texture.TextureCoordinates = TextureCoordinateGeneration.Screen; } else if(tokenLower == "xrayrendermap") { materialStage.Texture.Dynamic = DynamicImageType.XRayRender; materialStage.Texture.Width = lexer.ParseInt(); materialStage.Texture.Height = lexer.ParseInt(); materialStage.Texture.TextureCoordinates = TextureCoordinateGeneration.Screen; } else if(tokenLower == "screen") { materialStage.Texture.TextureCoordinates = TextureCoordinateGeneration.Screen; } else if(tokenLower == "screen2") { materialStage.Texture.TextureCoordinates = TextureCoordinateGeneration.Screen; } else if(tokenLower == "glasswarp") { materialStage.Texture.TextureCoordinates = TextureCoordinateGeneration.GlassWarp; } else if(tokenLower == "videomap") { // note that videomaps will always be in clamp mode, so texture // coordinates had better be in the 0 to 1 range if((token = lexer.ReadToken()) == null) { idConsole.Warning("missing parameter for 'videoMap' keyword in material '{0}'", this.Name); } else { bool loop = false; if(token.ToString().Equals("loop", StringComparison.OrdinalIgnoreCase) == true) { loop = true; if((token = lexer.ReadToken()) == null) { idConsole.Warning("missing parameter for 'videoMap' keyword in material '{0}'", this.Name); continue; } } idConsole.Warning("TODO: material videoMap keyword"); // TODO: cinematic /*ts->cinematic = idCinematic::Alloc(); ts->cinematic->InitFromFile( token.c_str(), loop );*/ } } else if(tokenLower == "soundmap") { if((token = lexer.ReadToken()) == null) { idConsole.Warning("missing parameter for 'soundMap' keyword in material '{0}'", this.Name); } else { idConsole.Warning("TODO: material soundMap keyword"); // TODO /*ts->cinematic = new idSndWindow(); ts->cinematic->InitFromFile( token.c_str(), true );*/ } } else if(tokenLower == "cubemap") { imageName = ParsePastImageProgram(lexer); cubeMap = CubeFiles.Native; } else if(tokenLower == "cameracubemap") { imageName = ParsePastImageProgram(lexer); cubeMap = CubeFiles.Camera; } else if(tokenLower == "ignorealphatest") { materialStage.IgnoreAlphaTest = true; } else if(tokenLower == "nearest") { textureFilter = TextureFilter.Nearest; } else if(tokenLower == "linear") { textureFilter = TextureFilter.Linear; } else if(tokenLower == "clamp") { textureRepeat = TextureRepeat.Clamp; } else if(tokenLower == "noclamp") { textureRepeat = TextureRepeat.Repeat; } else if(tokenLower == "zeroclamp") { textureRepeat = TextureRepeat.ClampToZero; } else if(tokenLower == "alphazeroclamp") { textureRepeat = TextureRepeat.ClampToZeroAlpha; } else if((tokenLower == "uncompressed") || (tokenLower == "highquality")) { if(idE.CvarSystem.GetInteger("image_ignoreHighQuality") == 0) { textureDepth = TextureDepth.HighQuality; } } else if(tokenLower == "forcehighquality") { textureDepth = TextureDepth.HighQuality; } else if(tokenLower == "nopicmip") { allowPicmip = false; } else if(tokenLower == "vertexcolor") { materialStage.VertexColor = StageVertexColor.Modulate; } else if(tokenLower == "inversevertexcolor") { materialStage.VertexColor = StageVertexColor.InverseModulate; } // privatePolygonOffset else if(tokenLower == "privatepolygonoffset") { if((token = lexer.ReadTokenOnLine()) == null) { materialStage.PrivatePolygonOffset = 1; } else { // explict larger (or negative) offset lexer.UnreadToken = token; materialStage.PrivatePolygonOffset = lexer.ParseFloat(); } } // texture coordinate generation else if(tokenLower == "texgen") { token = lexer.ExpectAnyToken(); tokenValue = token.ToString(); tokenLower = tokenValue.ToLower(); if(tokenLower == "normal") { materialStage.Texture.TextureCoordinates = TextureCoordinateGeneration.DiffuseCube; } else if(tokenLower == "reflect") { materialStage.Texture.TextureCoordinates = TextureCoordinateGeneration.ReflectCube; } else if(tokenLower == "skybox") { materialStage.Texture.TextureCoordinates = TextureCoordinateGeneration.SkyboxCube; } else if(tokenLower == "wobblesky") { materialStage.Texture.TextureCoordinates = TextureCoordinateGeneration.WobbleSkyCube; _texGenRegisters = new int[4]; _texGenRegisters[0] = ParseExpression(lexer); _texGenRegisters[1] = ParseExpression(lexer); _texGenRegisters[2] = ParseExpression(lexer); } else { idConsole.Warning("bad texGen '{0}' in material {1}", tokenValue, this.Name); this.MaterialFlag = MaterialFlags.Defaulted; } } else if((tokenLower == "scroll") || (tokenLower == "translate")) { a = ParseExpression(lexer); MatchToken(lexer, ","); b = ParseExpression(lexer); matrix[0, 0] = GetExpressionConstant(1); matrix[0, 1] = GetExpressionConstant(0); matrix[0, 2] = a; matrix[1, 0] = GetExpressionConstant(0); matrix[1, 1] = GetExpressionConstant(1); matrix[1, 2] = b; MultiplyTextureMatrix(ref materialStage.Texture, matrix); } else if(tokenLower == "scale") { a = ParseExpression(lexer); MatchToken(lexer, ","); b = ParseExpression(lexer); // this just scales without a centering matrix[0, 0] = a; matrix[0, 1] = GetExpressionConstant(0); matrix[0, 2] = GetExpressionConstant(0); matrix[1, 0] = GetExpressionConstant(0); matrix[1, 1] = b; matrix[1, 2] = GetExpressionConstant(0); MultiplyTextureMatrix(ref materialStage.Texture, matrix); } else if(tokenLower == "centerscale") { a = ParseExpression(lexer); MatchToken(lexer, ","); b = ParseExpression(lexer); // this subtracts 0.5, then scales, then adds 0.5 matrix[0, 0] = a; matrix[0, 1] = GetExpressionConstant(0); matrix[0, 2] = EmitOp(GetExpressionConstant(0.5f), EmitOp(GetExpressionConstant(0.5f), a, ExpressionOperationType.Multiply), ExpressionOperationType.Subtract); matrix[1, 0] = GetExpressionConstant(0); matrix[1, 1] = b; matrix[1, 2] = EmitOp(GetExpressionConstant(0.5f), EmitOp(GetExpressionConstant(0.5f), b, ExpressionOperationType.Multiply), ExpressionOperationType.Subtract); MultiplyTextureMatrix(ref materialStage.Texture, matrix); } else if(tokenLower == "shear") { a = ParseExpression(lexer); MatchToken(lexer, ","); b = ParseExpression(lexer); // this subtracts 0.5, then shears, then adds 0.5 matrix[0, 0] = GetExpressionConstant(1); matrix[0, 1] = a; matrix[0, 2] = EmitOp(GetExpressionConstant(-0.5f), a, ExpressionOperationType.Multiply); matrix[1, 0] = b; matrix[1, 1] = GetExpressionConstant(1); matrix[1, 2] = EmitOp(GetExpressionConstant(-0.5f), b, ExpressionOperationType.Multiply); MultiplyTextureMatrix(ref materialStage.Texture, matrix); } else if(tokenLower == "rotate") { int sinReg, cosReg; // in cycles a = ParseExpression(lexer); idDeclTable table = idE.DeclManager.FindType<idDeclTable>(DeclType.Table, "sinTable", false); if(table == null) { idConsole.Warning("no sinTable for rotate defined"); this.MaterialFlag = MaterialFlags.Defaulted; return; } sinReg = EmitOp(table.Index, a, ExpressionOperationType.Table); table = idE.DeclManager.FindType<idDeclTable>(DeclType.Table, "cosTable", false); if(table == null) { idConsole.Warning("no cosTable for rotate defined"); this.MaterialFlag = MaterialFlags.Defaulted; return; } cosReg = EmitOp(table.Index, a, ExpressionOperationType.Table); // this subtracts 0.5, then rotates, then adds 0.5 matrix[0, 0] = cosReg; matrix[0, 1] = EmitOp(GetExpressionConstant(0), sinReg, ExpressionOperationType.Subtract); matrix[0, 2] = EmitOp(EmitOp(EmitOp(GetExpressionConstant(-0.5f), cosReg, ExpressionOperationType.Multiply), EmitOp(GetExpressionConstant(0.5f), sinReg, ExpressionOperationType.Multiply), ExpressionOperationType.Add), GetExpressionConstant(0.5f), ExpressionOperationType.Add); matrix[1, 0] = sinReg; matrix[1, 1] = cosReg; matrix[1, 2] = EmitOp(EmitOp(EmitOp(GetExpressionConstant(-0.5f), sinReg, ExpressionOperationType.Multiply), EmitOp(GetExpressionConstant(-0.5f), cosReg, ExpressionOperationType.Multiply), ExpressionOperationType.Add), GetExpressionConstant(0.5f), ExpressionOperationType.Add); MultiplyTextureMatrix(ref materialStage.Texture, matrix); } // color mask options else if(tokenLower == "maskred") { materialStage.DrawStateBits |= MaterialStates.RedMask; } else if(tokenLower == "maskgreen") { materialStage.DrawStateBits |= MaterialStates.GreenMask; } else if(tokenLower == "maskblue") { materialStage.DrawStateBits |= MaterialStates.BlueMask; } else if(tokenLower == "maskalpha") { materialStage.DrawStateBits |= MaterialStates.AlphaMask; } else if(tokenLower == "maskcolor") { materialStage.DrawStateBits |= MaterialStates.ColorMask; } else if(tokenLower == "maskdepth") { materialStage.DrawStateBits |= MaterialStates.DepthMask; } else if(tokenLower == "alphatest") { materialStage.HasAlphaTest = true; materialStage.AlphaTestRegister = ParseExpression(lexer); _coverage = MaterialCoverage.Perforated; } // shorthand for 2D modulated else if(tokenLower == "colored") { materialStage.Color.Registers[0] = (int) ExpressionRegister.Parm0; materialStage.Color.Registers[1] = (int) ExpressionRegister.Parm1; materialStage.Color.Registers[2] = (int) ExpressionRegister.Parm2; materialStage.Color.Registers[3] = (int) ExpressionRegister.Parm3; _parsingData.RegistersAreConstant = false; } else if(tokenLower == "color") { materialStage.Color.Registers[0] = ParseExpression(lexer); MatchToken(lexer, ","); materialStage.Color.Registers[1] = ParseExpression(lexer); MatchToken(lexer, ","); materialStage.Color.Registers[2] = ParseExpression(lexer); MatchToken(lexer, ","); materialStage.Color.Registers[3] = ParseExpression(lexer); } else if(tokenLower == "red") { materialStage.Color.Registers[0] = ParseExpression(lexer); } else if(tokenLower == "green") { materialStage.Color.Registers[1] = ParseExpression(lexer); } else if(tokenLower == "blue") { materialStage.Color.Registers[2] = ParseExpression(lexer); } else if(tokenLower == "alpha") { materialStage.Color.Registers[3] = ParseExpression(lexer); } else if(tokenLower == "rgb") { materialStage.Color.Registers[0] = materialStage.Color.Registers[1] = materialStage.Color.Registers[2] = ParseExpression(lexer); } else if(tokenLower == "rgba") { materialStage.Color.Registers[0] = materialStage.Color.Registers[1] = materialStage.Color.Registers[2] = materialStage.Color.Registers[3] = ParseExpression(lexer); } else if(tokenLower == "if") { materialStage.ConditionRegister = ParseExpression(lexer); } else if(tokenLower == "program") { if((token = lexer.ReadTokenOnLine()) != null) { idConsole.Warning("TODO: material program keyword"); // TODO /*newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, token.c_str() ); newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, token.c_str() );*/ } } else if(tokenLower == "fragmentprogram") { if((token = lexer.ReadTokenOnLine()) != null) { idConsole.Warning("TODO: material fragmentProgram keyword"); // TODO //newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, token.c_str() ); } } else if(tokenLower == "vertexprogram") { if((token = lexer.ReadTokenOnLine()) != null) { idConsole.Warning("TODO: material vertexProgram keyword"); // TODO //newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, token.c_str() ); } } else if(tokenLower == "megatexture") { if((token = lexer.ReadTokenOnLine()) != null) { idConsole.Warning("TODO: material megaTexture keyword"); // TODO /*newStage.megaTexture = new idMegaTexture; if ( !newStage.megaTexture->InitFromMegaFile( token.c_str() ) ) { delete newStage.megaTexture; SetMaterialFlag( MF_DEFAULTED ); continue; } newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "megaTexture.vfp" ); newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "megaTexture.vfp" );*/ } } else if(tokenLower == "vertexparm") { ParseVertexParameter(lexer, ref newStage); } else if(tokenLower == "fragmentmap") { ParseFragmentMap(lexer, ref newStage); } else { idConsole.Warning("unknown token '{0}' in material '{1}'", tokenValue, this.Name); this.MaterialFlag = MaterialFlags.Defaulted; return; } } // if we are using newStage, allocate a copy of it if((newStage.FragmentProgram != 0) || (newStage.VertexProgram != 0)) { materialStage.NewStage = newStage; } // select a compressed depth based on what the stage is if(textureDepth == TextureDepth.Default) { switch(materialStage.Lighting) { case StageLighting.Bump: textureDepth = TextureDepth.Bump; break; case StageLighting.Diffuse: textureDepth = TextureDepth.Diffuse; break; case StageLighting.Specular: textureDepth = TextureDepth.Specular; break; } } // now load the image with all the parms we parsed if((imageName != null) && (imageName != string.Empty)) { materialStage.Texture.Image = idE.ImageManager.ImageFromFile(imageName, textureFilter, allowPicmip, textureRepeat, textureDepth, cubeMap); if(materialStage.Texture.Image == null) { materialStage.Texture.Image = idE.ImageManager.DefaultImage; } } else if(/*TODO: !ts->cinematic &&*/ (materialStage.Texture.Dynamic == 0) && (materialStage.NewStage.IsEmpty == true)) { idConsole.Warning("material '{0}' had stage with no image", this.Name); materialStage.Texture.Image = idE.ImageManager.DefaultImage; } // successfully parsed a stage. _parsingData.Stages.Add(materialStage); }