/// <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); }
private void ParseDeform(idLexer lexer) { idToken token = lexer.ExpectAnyToken(); if(token == null) { return; } string tokenValue = token.ToString(); string tokenLower = tokenValue.ToLower(); if(tokenLower == "sprite") { _deformType = DeformType.Sprite; _cullType = CullType.TwoSided; this.MaterialFlag = MaterialFlags.NoShadows; } else if(tokenLower == "tube") { _deformType = DeformType.Tube; _cullType = CullType.TwoSided; this.MaterialFlag = MaterialFlags.NoShadows; } else if(tokenLower == "flare") { _deformType = DeformType.Flare; _cullType = CullType.TwoSided; _deformRegisters[0] = ParseExpression(lexer); this.MaterialFlag = MaterialFlags.NoShadows; } else if(tokenLower == "expand") { _deformType = DeformType.Expand; _deformRegisters[0] = ParseExpression(lexer); } else if(tokenLower == "move") { _deformType = DeformType.Move; _deformRegisters[0] = ParseExpression(lexer); } else if(tokenLower == "turbulent") { _deformType = DeformType.Turbulent; if((token = lexer.ExpectAnyToken()) == null) { lexer.Warning("deform particle missing particle name"); this.MaterialFlag = MaterialFlags.Defaulted; } else { _deformDecl = idE.DeclManager.FindType(DeclType.Table, token.ToString(), true); _deformRegisters[0] = ParseExpression(lexer); _deformRegisters[1] = ParseExpression(lexer); _deformRegisters[2] = ParseExpression(lexer); } } else if(tokenLower == "eyeball") { _deformType = DeformType.Eyeball; } else if(tokenLower == "particle") { _deformType = DeformType.Particle; if((token = lexer.ExpectAnyToken()) == null) { lexer.Warning("deform particle missing particle name"); this.MaterialFlag = MaterialFlags.Defaulted; } else { _deformDecl = idE.DeclManager.FindType(DeclType.Particle, token.ToString(), true); } } else if(tokenLower == "particle2") { _deformType = DeformType.Particle2; if((token = lexer.ExpectAnyToken()) == null) { lexer.Warning("deform particle missing particle name"); this.MaterialFlag = MaterialFlags.Defaulted; } else { _deformDecl = idE.DeclManager.FindType(DeclType.Table, token.ToString(), true); _deformRegisters[0] = ParseExpression(lexer); _deformRegisters[1] = ParseExpression(lexer); _deformRegisters[2] = ParseExpression(lexer); } } else { lexer.Warning("Bad deform type '{0}'", tokenValue); this.MaterialFlag = MaterialFlags.Defaulted; } }
private idRenderModel ParseShadowModel(idLexer lexer) { lexer.ExpectTokenString("{"); // parse the name idToken token = lexer.ExpectAnyToken(); idRenderModel model = idE.RenderModelManager.AllocateModel(); model.InitEmpty(token.ToString()); RenderModelSurface modelSurface = new RenderModelSurface(); modelSurface.Material = idE.RenderSystem.DefaultMaterial; modelSurface.Geometry = new Surface(); modelSurface.Geometry.ShadowVertices = new ShadowVertex[lexer.ParseInt()]; modelSurface.Geometry.ShadowIndexesNoCapsCount = lexer.ParseInt(); modelSurface.Geometry.ShadowIndexesNoFrontCapsCount = lexer.ParseInt(); modelSurface.Geometry.Indexes = new int[lexer.ParseInt()]; modelSurface.Geometry.ShadowCapPlaneBits = lexer.ParseInt(); modelSurface.Geometry.Bounds.Clear(); int count = modelSurface.Geometry.ShadowVertices.Length; for(int j = 0; j < count; j++) { float[] vec = lexer.Parse1DMatrix(3); modelSurface.Geometry.ShadowVertices[j].Position = new Vector4(vec[0], vec[1], vec[2], 1); modelSurface.Geometry.Bounds.AddPoint(modelSurface.Geometry.ShadowVertices[j].Position); } count = modelSurface.Geometry.Indexes.Length; for(int j = 0; j < count; j++) { modelSurface.Geometry.Indexes[j] = lexer.ParseInt(); } // add the completed surface to the model model.AddSurface(modelSurface); lexer.ExpectTokenString("}"); // we do NOT do a model->FinishSurfaces, because we don't need sil edges, planes, tangents, etc. // model.FinishSurfaces(); return model; }
private idRenderModel ParseModel(idLexer lexer) { if(this.Disposed == true) { throw new ObjectDisposedException(this.GetType().Name); } RenderModelSurface modelSurface; lexer.ExpectTokenString("{"); // parse the name idToken token = lexer.ExpectAnyToken(); idRenderModel model = idE.RenderModelManager.AllocateModel(); model.InitEmpty(token.ToString()); int surfaceCount = lexer.ParseInt(); int loopCount = 0; if(surfaceCount < 0) { lexer.Error("ParseModel: bad surfaceCount"); } for(int i = 0; i < surfaceCount; i++) { lexer.ExpectTokenString("{"); token = lexer.ExpectAnyToken(); modelSurface = new RenderModelSurface(); modelSurface.Material = idE.DeclManager.FindMaterial(token.ToString()); modelSurface.Material.AddReference(); modelSurface.Geometry = new Surface(); modelSurface.Geometry.Vertices = new Vertex[lexer.ParseInt()]; modelSurface.Geometry.Indexes = new int[lexer.ParseInt()]; loopCount = modelSurface.Geometry.Vertices.Length; for(int j = 0; j < loopCount; j++) { float[] vec = lexer.Parse1DMatrix(8); modelSurface.Geometry.Vertices[j].Position = new Vector3(vec[0], vec[1], vec[2]); modelSurface.Geometry.Vertices[j].TextureCoordinates = new Vector2(vec[3], vec[4]); modelSurface.Geometry.Vertices[j].Normal = new Vector3(vec[5], vec[6], vec[7]); } loopCount = modelSurface.Geometry.Indexes.Length; for(int j = 0; j < loopCount; j++) { modelSurface.Geometry.Indexes[j] = lexer.ParseInt(); } lexer.ExpectTokenString("}"); // add the completed surface to the model model.AddSurface(modelSurface); } lexer.ExpectTokenString("}"); model.FinishSurfaces(); return model; }
private bool ParseMaterial(idLexer lexer) { _parameters.MinDistance = 1; _parameters.MaxDistance = 10; _parameters.Volume = 1; _speakerMask = 0; _altSound = null; idToken token; string tokenValue; int sampleCount = 0; while(true) { if((token = lexer.ExpectAnyToken()) == null) { return false; } tokenValue = token.ToString().ToLower(); if(tokenValue == "}") { break; } // minimum number of sounds else if(tokenValue == "minsamples") { sampleCount = lexer.ParseInt(); } else if(tokenValue == "description") { _description = lexer.ReadTokenOnLine().ToString(); } else if(tokenValue == "mindistance") { _parameters.MinDistance = lexer.ParseFloat(); } else if(tokenValue == "maxdistance") { _parameters.MaxDistance = lexer.ParseFloat(); } else if(tokenValue == "shakes") { token = lexer.ExpectAnyToken(); if(token.Type == TokenType.Number) { _parameters.Shakes = token.ToFloat(); } else { lexer.UnreadToken = token; _parameters.Shakes = 1.0f; } } else if(tokenValue == "reverb") { float reg0 = lexer.ParseFloat(); if(lexer.ExpectTokenString(",") == false) { return false; } float reg1 = lexer.ParseFloat(); // no longer supported } else if(tokenValue == "volume") { _parameters.Volume = lexer.ParseFloat(); } // leadinVolume is used to allow light breaking leadin sounds to be much louder than the broken loop else if(tokenValue == "leadinvolume") { _leadInVolume = lexer.ParseFloat(); } else if(tokenValue == "mask_center") { _speakerMask |= 1 << (int) Speakers.Center; } else if(tokenValue == "mask_left") { _speakerMask |= 1 << (int) Speakers.Left; } else if(tokenValue == "mask_right") { _speakerMask |= 1 << (int) Speakers.Right; } else if(tokenValue == "mask_backright") { _speakerMask |= 1 << (int) Speakers.BackRight; } else if(tokenValue == "mask_backleft") { _speakerMask |= 1 << (int) Speakers.BackLeft; } else if(tokenValue == "mask_lfe") { _speakerMask |= 1 << (int) Speakers.Lfe; } else if(tokenValue == "soundclass") { _parameters.SoundClass = lexer.ParseInt(); if(_parameters.SoundClass < 0) { lexer.Warning("SoundClass out of range"); return false; } } else if(tokenValue == "altsound") { if((token = lexer.ExpectAnyToken()) == null) { return false; } _altSound = idE.DeclManager.FindSound(token.ToString()); } else if(tokenValue == "ordered") { // no longer supported } else if(tokenValue == "no_dups") { _parameters.Flags |= SoundMaterialFlags.NoDuplicates; } else if(tokenValue == "no_flicker") { _parameters.Flags |= SoundMaterialFlags.NoFlicker; } else if(tokenValue == "plain") { // no longer supported } else if(tokenValue == "looping") { _parameters.Flags |= SoundMaterialFlags.Looping; } else if(tokenValue == "no_occlusion") { _parameters.Flags |= SoundMaterialFlags.NoOcclusion; } else if(tokenValue == "private") { _parameters.Flags |= SoundMaterialFlags.PrivateSound; } else if(tokenValue == "antiprivate") { _parameters.Flags |= SoundMaterialFlags.AntiPrivateSound; } else if(tokenValue == "playonce") { _parameters.Flags |= SoundMaterialFlags.PlayOnce; } else if(tokenValue == "global") { _parameters.Flags |= SoundMaterialFlags.Global; } else if(tokenValue == "unclamped") { _parameters.Flags |= SoundMaterialFlags.Unclamped; } else if(tokenValue == "omnidirectional") { _parameters.Flags |= SoundMaterialFlags.OmniDirectional; } // onDemand can't be a parms, because we must track all references and overrides would confuse it else if(tokenValue == "ondemand") { // no longer loading sounds on demand // _onDemand = true; } // the wave files else if(tokenValue == "leadin") { // add to the leadin list if((token = lexer.ReadToken()) == null) { lexer.Warning("Expected sound after leadin"); return false; } idConsole.Warning("TODO: leadin"); /*if(soundSystemLocal.soundCache && numLeadins < maxSamples) { leadins[numLeadins] = soundSystemLocal.soundCache->FindSound(token.c_str(), onDemand); numLeadins++; }*/ } else if((tokenValue.EndsWith(".wav") == true) || (tokenValue.EndsWith(".ogg") == true)) { idConsole.Warning("TODO: .wav|.ogg"); /*// add to the wav list if(soundSystemLocal.soundCache && numEntries < maxSamples) { token.BackSlashesToSlashes(); idStr lang = cvarSystem->GetCVarString("sys_lang"); if(lang.Icmp("english") != 0 && token.Find("sound/vo/", false) >= 0) { idStr work = token; work.ToLower(); work.StripLeading("sound/vo/"); work = va("sound/vo/%s/%s", lang.c_str(), work.c_str()); if(fileSystem->ReadFile(work, NULL, NULL) > 0) { token = work; } else { // also try to find it with the .ogg extension work.SetFileExtension(".ogg"); if(fileSystem->ReadFile(work, NULL, NULL) > 0) { token = work; } } } entries[numEntries] = soundSystemLocal.soundCache->FindSound(token.c_str(), onDemand); numEntries++; }*/ } else { lexer.Warning("unknown token '{0}'", token.ToString()); return false; } } if(_parameters.Shakes > 0.0f) { idConsole.Warning("TODO: CheckShakesAndOgg()"); } return true; }