/// <summary> /// Parses a vertex parameter. /// </summary> /// <remarks> /// If there is a single value, it will be repeated across all elements. /// If there are two values, 3 = 0.0, 4 = 1.0. /// if there are three values, 4 = 1.0. /// </remarks> /// <param name="lexer"></param> /// <param name="newStage"></param> private void ParseVertexParameter(idLexer lexer, ref NewMaterialStage newStage) { idToken token = lexer.ReadTokenOnLine(); int parm = token.ToInt32(); int tmp = 0; string tokenValue = token.ToString(); if((int.TryParse(tokenValue, out tmp) == false) || (parm < 0)) { idConsole.Warning("bad vertexParm number"); this.MaterialFlag = MaterialFlags.Defaulted; return; } newStage.VertexParameters[parm, 0] = ParseExpression(lexer); token = lexer.ReadTokenOnLine(); if((token == null) || (token.ToString() != ",")) { newStage.VertexParameters[parm, 1] = newStage.VertexParameters[parm, 2] = newStage.VertexParameters[parm, 3] = newStage.VertexParameters[parm, 0]; } else { newStage.VertexParameters[parm, 1] = ParseExpression(lexer); token = lexer.ReadTokenOnLine(); if((token == null) || (token.ToString() != ",")) { newStage.VertexParameters[parm, 2] = GetExpressionConstant(0); newStage.VertexParameters[parm, 3] = GetExpressionConstant(1); } else { newStage.VertexParameters[parm, 2] = ParseExpression(lexer); token = lexer.ReadTokenOnLine(); if((token == null) || (token.ToString() != ",")) { newStage.VertexParameters[parm, 3] = GetExpressionConstant(1); } else { newStage.VertexParameters[parm, 3] = ParseExpression(lexer); } } } }
private void ParseFragmentMap(idLexer lexer, ref NewMaterialStage newStage) { TextureFilter textureFilter = TextureFilter.Default; TextureRepeat textureRepeat = TextureRepeat.Repeat; TextureDepth textureDepth = TextureDepth.Default; CubeFiles cubeMap = CubeFiles.TwoD; bool allowPicmip = true; idToken token = lexer.ReadTokenOnLine(); int unit = token.ToInt32(); int tmp; if((int.TryParse(token.ToString(), out tmp) == false) || (unit < 0)) { idConsole.Warning("bad fragmentMap number"); this.MaterialFlag = MaterialFlags.Defaulted; return; } // unit 1 is the normal map.. make sure it gets flagged as the proper depth if(unit == 1) { textureDepth = TextureDepth.Bump; } string tokenValue; string tokenLower; while(true) { token = lexer.ReadTokenOnLine(); tokenValue = token.ToString(); tokenLower = tokenValue.ToLower(); if(tokenLower == "cubemap") { cubeMap = CubeFiles.Native; } else if(tokenLower == "cameracubemap") { cubeMap = CubeFiles.Camera; } 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 == "forcehighquality") { textureDepth = TextureDepth.HighQuality; } else if((tokenLower == "uncompressed") || (tokenLower == "highquality")) { if(idE.CvarSystem.GetInteger("image_ignoreHighQuality") == 0) { textureDepth = TextureDepth.HighQuality; } } else if(tokenLower == "nopicmip") { allowPicmip = false; } else { // assume anything else is the image name. lexer.UnreadToken = token; break; } } // TODO string image = ParsePastImageProgram(lexer); // TODO: fragment program images. remember we use a global // sampler state. it'll ignore these texturemin/max filters. idConsole.Warning("TODO: fragment program images"); /* newStage->fragmentProgramImages[unit] = globalImages->ImageFromFile( str, tf, allowPicmip, trp, td, cubeMap ); if ( !newStage->fragmentProgramImages[unit] ) { newStage->fragmentProgramImages[unit] = globalImages->defaultImage; }*/ }
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); }