/// <summary> /// /// </summary> /// <param name="name"></param> /// <param name="handle"></param> /// <param name="group"></param> /// <param name="isManual"></param> /// <param name="loader"></param> /// <param name="createParams"></param> /// <returns></returns> protected override Resource _create(string name, ulong handle, string group, bool isManual, IManualResourceLoader loader, NameValuePairList createParams) { var s = new Quake3Shader(this, name, handle, ResourceGroupManager.Instance.WorldResourceGroupName); return(s); }
public override Resource Create(string name) { Quake3Shader s = new Quake3Shader(name); Load(s, 1); return(s); }
/// <summary> /// /// </summary> /// <param name="line"></param> /// <param name="shader"></param> protected void ParseShaderAttrib(string line, Quake3Shader shader) { string[] attribParams = line.Replace("(", "").Replace(")", "").Split(' ', '\t'); if (attribParams[0] == "skyparms") { if (attribParams[1] != "-") { shader.Farbox = true; shader.FarboxName = attribParams[1]; } if (attribParams[2] != "-") { shader.SkyDome = true; if (attribParams[2] == "full") { shader.CloudHeight = 512; } else { shader.CloudHeight = StringConverter.ParseFloat(attribParams[2]); } } // nearbox not supported } else if (attribParams[0] == "cull") { if ((attribParams[1] == "disable") || (attribParams[1] == "none")) { shader.CullingMode = ManualCullingMode.None; } else if (attribParams[1] == "front") { shader.CullingMode = ManualCullingMode.Front; } else if (attribParams[1] == "back") { shader.CullingMode = ManualCullingMode.Back; } } else if (attribParams[0] == "deformvertexes") { // TODO } else if (attribParams[0] == "fogparms") { var fogValues = new string[4]; Array.Copy(attribParams, 1, fogValues, 0, 4); shader.Fog = true; shader.FogColor = StringConverter.ParseColor(fogValues); shader.FogDistance = StringConverter.ParseFloat(attribParams[4]); } }
/// <summary> /// /// </summary> /// <param name="stream"></param> /// <param name="shader"></param> protected void ParseNewShaderPass(StreamReader stream, Quake3Shader shader) { string line; var pass = new ShaderPass(); // Default pass details pass.animNumFrames = 0; pass.blend = LayerBlendOperation.Replace; pass.blendDest = SceneBlendFactor.Zero; pass.blendSrc = SceneBlendFactor.One; pass.depthFunc = CompareFunction.LessEqual; pass.flags = 0; pass.rgbGenFunc = ShaderGen.Identity; pass.tcModRotate = 0; pass.tcModScale[0] = pass.tcModScale[1] = 1.0f; pass.tcModScroll[0] = pass.tcModScroll[1] = 0.0f; pass.tcModStretchWave = ShaderWaveType.None; pass.tcModTransform[0] = pass.tcModTransform[1] = 0.0f; pass.tcModTurbOn = false; pass.tcModTurb[0] = pass.tcModTurb[1] = pass.tcModTurb[2] = pass.tcModTurb[3] = 0.0f; pass.texGen = ShaderTextureGen.Base; pass.addressMode = TextureAddressing.Wrap; pass.customBlend = false; pass.alphaVal = 0; pass.alphaFunc = CompareFunction.AlwaysPass; shader.Pass.Add(pass); while ((line = stream.ReadLine()) != null) { line = line.Trim(); // Ignore comments & blanks if ((line != String.Empty) && !line.StartsWith("//")) { if (line == "}") { return; } else { ParseShaderPassAttrib(line, shader, pass); } } } }
/// <summary> /// /// </summary> /// <param name="stream"></param> /// <param name="groupName"></param> /// <param name="fileName"></param> public override void ParseScript(Stream stream, string groupName, string fileName) { var file = new StreamReader(stream, Encoding.UTF8); string line; Quake3Shader shader = null; while ((line = file.ReadLine()) != null) { line = line.Trim(); // Ignore comments & blanks if ((line != String.Empty) && !line.StartsWith("//")) { if (shader == null) { LogManager.Instance.Write("Creating {0}...", line); // No current shader // So first valid data should be a shader name shader = (Quake3Shader)Create(line, groupName); // Skip to and over next brace ParseHelper.SkipToNextOpenBrace(file); } else { // Already in a shader if (line == "}") { LogManager.Instance.Write("End of shader."); shader = null; } else if (line == "{") { LogManager.Instance.Write("New pass..."); ParseNewShaderPass(file, shader); } else { LogManager.Instance.Write("New attrib, {0}...", line); ParseShaderAttrib(line.ToLower(), shader); } } } } }
/// <summary> /// /// </summary> /// <param name="line"></param> /// <param name="shader"></param> /// <param name="pass"></param> protected void ParseShaderPassAttrib(string line, Quake3Shader shader, ShaderPass pass) { string[] attribParams = line.Split(' ', '\t'); attribParams[0] = attribParams[0].ToLower(); LogManager.Instance.Write("Attrib {0}", attribParams[0]); if ((attribParams[0] != "map") && (attribParams[0] != "clampmap") && (attribParams[0] != "animmap")) { // lower case all except textures for (int i = 1; i < attribParams.Length; ++i) { attribParams[i] = attribParams[i].ToLower(); } } // MAP if (attribParams[0] == "map") { pass.textureName = attribParams[1]; if (attribParams[1].ToLower() == "$lightmap") { pass.texGen = ShaderTextureGen.Lightmap; } } // CLAMPMAP else if (attribParams[0] == "clampmap") { pass.textureName = attribParams[1]; if (attribParams[1].ToLower() == "$lightmap") { pass.texGen = ShaderTextureGen.Lightmap; } pass.addressMode = TextureAddressing.Clamp; } // ANIMMAP else if (attribParams[0] == "animmap") { pass.animFps = StringConverter.ParseFloat(attribParams[1]); pass.animNumFrames = attribParams.Length - 2; for (uint frame = 0; frame < pass.animNumFrames; ++frame) { pass.frames[frame] = attribParams[frame + 2]; } } // BLENDFUNC else if (attribParams[0] == "blendfunc") { if ((attribParams[1] == "add") || (attribParams[1] == "gl_add")) { pass.blend = LayerBlendOperation.Add; pass.blendDest = SceneBlendFactor.One; pass.blendSrc = SceneBlendFactor.One; } else if ((attribParams[1] == "filter") || (attribParams[1] == "gl_filter")) { pass.blend = LayerBlendOperation.Modulate; pass.blendDest = SceneBlendFactor.Zero; pass.blendSrc = SceneBlendFactor.DestColor; } else if ((attribParams[1] == "blend") || (attribParams[1] == "gl_blend")) { pass.blend = LayerBlendOperation.AlphaBlend; pass.blendDest = SceneBlendFactor.OneMinusSourceAlpha; pass.blendSrc = SceneBlendFactor.SourceAlpha; } else { // Manual blend pass.blendSrc = ConvertBlendFunc(attribParams[1]); pass.blendDest = ConvertBlendFunc(attribParams[2]); // Detect common blends if ((pass.blendSrc == SceneBlendFactor.One) && (pass.blendDest == SceneBlendFactor.Zero)) { pass.blend = LayerBlendOperation.Replace; } else if ((pass.blendSrc == SceneBlendFactor.One) && (pass.blendDest == SceneBlendFactor.One)) { pass.blend = LayerBlendOperation.Add; } else if (((pass.blendSrc == SceneBlendFactor.Zero) && (pass.blendDest == SceneBlendFactor.SourceColor)) || ((pass.blendSrc == SceneBlendFactor.DestColor) && (pass.blendDest == SceneBlendFactor.Zero))) { pass.blend = LayerBlendOperation.Modulate; } else if ((pass.blendSrc == SceneBlendFactor.SourceAlpha) && (pass.blendDest == SceneBlendFactor.OneMinusSourceAlpha)) { pass.blend = LayerBlendOperation.AlphaBlend; } else { pass.customBlend = true; } // NB other custom blends might not work due to OGRE trying to use multitexture over multipass } } // RGBGEN else if (attribParams[0] == "rgbgen") { // TODO } // ALPHAGEN else if (attribParams[0] == "alphagen") { // TODO } // TCGEN else if (attribParams[0] == "tcgen") { if (attribParams[1] == "base") { pass.texGen = ShaderTextureGen.Base; } else if (attribParams[1] == "lightmap") { pass.texGen = ShaderTextureGen.Lightmap; } else if (attribParams[1] == "environment") { pass.texGen = ShaderTextureGen.Environment; } } // TCMOD else if (attribParams[0] == "tcmod") { if (attribParams[1] == "rotate") { pass.tcModRotate = -StringConverter.ParseFloat(attribParams[2]) / 360; // +ve is clockwise degrees in Q3 shader, anticlockwise complete rotations in Ogre } else if (attribParams[1] == "scroll") { pass.tcModScroll[0] = StringConverter.ParseFloat(attribParams[2]); pass.tcModScroll[1] = StringConverter.ParseFloat(attribParams[3]); } else if (attribParams[1] == "scale") { pass.tcModScale[0] = StringConverter.ParseFloat(attribParams[2]); pass.tcModScale[1] = StringConverter.ParseFloat(attribParams[3]); } else if (attribParams[1] == "stretch") { if (attribParams[2] == "sin") { pass.tcModStretchWave = ShaderWaveType.Sin; } else if (attribParams[2] == "triangle") { pass.tcModStretchWave = ShaderWaveType.Triangle; } else if (attribParams[2] == "square") { pass.tcModStretchWave = ShaderWaveType.Square; } else if (attribParams[2] == "sawtooth") { pass.tcModStretchWave = ShaderWaveType.SawTooth; } else if (attribParams[2] == "inversesawtooth") { pass.tcModStretchWave = ShaderWaveType.InverseSawtooth; } pass.tcModStretchParams[0] = StringConverter.ParseFloat(attribParams[3]); pass.tcModStretchParams[1] = StringConverter.ParseFloat(attribParams[4]); pass.tcModStretchParams[2] = StringConverter.ParseFloat(attribParams[5]); pass.tcModStretchParams[3] = StringConverter.ParseFloat(attribParams[6]); } } // TURB else if (attribParams[0] == "turb") { pass.tcModTurbOn = true; pass.tcModTurb[0] = StringConverter.ParseFloat(attribParams[2]); pass.tcModTurb[1] = StringConverter.ParseFloat(attribParams[3]); pass.tcModTurb[2] = StringConverter.ParseFloat(attribParams[4]); pass.tcModTurb[3] = StringConverter.ParseFloat(attribParams[5]); } // DEPTHFUNC else if (attribParams[0] == "depthfunc") { // TODO } // DEPTHWRITE else if (attribParams[0] == "depthwrite") { // TODO } // ALPHAFUNC else if (attribParams[0] == "alphafunc") { if (attribParams[1] == "gt0") { pass.alphaVal = 0; pass.alphaFunc = CompareFunction.Greater; } else if (attribParams[1] == "ge128") { pass.alphaVal = 128; pass.alphaFunc = CompareFunction.GreaterEqual; } else if (attribParams[1] == "lt128") { pass.alphaVal = 128; pass.alphaFunc = CompareFunction.Less; } } }
public override Resource Create(string name) { Quake3Shader s = new Quake3Shader(name); Load(s, 1); return s; }
protected void ParseShaderPassAttrib(string line, Quake3Shader shader, ShaderPass pass) { string[] attribParams = line.Split(' ', '\t'); attribParams[0] = attribParams[0].ToLower(); LogManager.Instance.Write("Attrib {0}", attribParams[0]); if((attribParams[0] != "map") && (attribParams[0] != "clampmap") && (attribParams[0] != "animmap")) { // lower case all except textures for (int i = 1; i < attribParams.Length; i++) { attribParams[i] = attribParams[i].ToLower(); } } // MAP if(attribParams[0] == "map") { pass.textureName = attribParams[1]; if (attribParams[1].ToLower() == "$lightmap") { pass.texGen = ShaderTextureGen.Lightmap; } } // CLAMPMAP else if(attribParams[0] == "clampmap") { pass.textureName = attribParams[1]; if(attribParams[1].ToLower() == "$lightmap") pass.texGen = ShaderTextureGen.Lightmap; pass.addressMode = TextureAddressing.Clamp; } // ANIMMAP else if(attribParams[0] == "animmap") { pass.animFps = StringConverter.ParseFloat(attribParams[1]); pass.animNumFrames = attribParams.Length - 2; for(uint frame = 0; frame < pass.animNumFrames; frame++) pass.frames[frame] = attribParams[frame + 2]; } // BLENDFUNC else if(attribParams[0] == "blendfunc") { if((attribParams[1] == "add") || (attribParams[1] == "gl_add")) { pass.blend = LayerBlendOperation.Add; pass.blendDest = SceneBlendFactor.One; pass.blendSrc = SceneBlendFactor.One; } else if((attribParams[1] == "filter") || (attribParams[1] == "gl_filter")) { pass.blend = LayerBlendOperation.Modulate; pass.blendDest = SceneBlendFactor.Zero; pass.blendSrc = SceneBlendFactor.DestColor; } else if((attribParams[1] == "blend") || (attribParams[1] == "gl_blend")) { pass.blend = LayerBlendOperation.AlphaBlend; pass.blendDest = SceneBlendFactor.OneMinusSourceAlpha; pass.blendSrc = SceneBlendFactor.SourceAlpha; } else { // Manual blend pass.blendSrc = ConvertBlendFunc(attribParams[1]); pass.blendDest = ConvertBlendFunc(attribParams[2]); // Detect common blends if((pass.blendSrc == SceneBlendFactor.One) && (pass.blendDest == SceneBlendFactor.Zero)) pass.blend = LayerBlendOperation.Replace; else if((pass.blendSrc == SceneBlendFactor.One) && (pass.blendDest == SceneBlendFactor.One)) pass.blend = LayerBlendOperation.Add; else if(((pass.blendSrc == SceneBlendFactor.Zero) && (pass.blendDest == SceneBlendFactor.SourceColor)) || ((pass.blendSrc == SceneBlendFactor.DestColor) && (pass.blendDest == SceneBlendFactor.Zero))) pass.blend = LayerBlendOperation.Modulate; else if((pass.blendSrc == SceneBlendFactor.SourceAlpha) && (pass.blendDest == SceneBlendFactor.OneMinusSourceAlpha)) pass.blend = LayerBlendOperation.AlphaBlend; else pass.customBlend = true; // NB other custom blends might not work due to OGRE trying to use multitexture over multipass } } // RGBGEN else if(attribParams[0] == "rgbgen") { // TODO } // ALPHAGEN else if(attribParams[0] == "alphagen") { // TODO } // TCGEN else if(attribParams[0] == "tcgen") { if(attribParams[1] == "base") pass.texGen = ShaderTextureGen.Base; else if(attribParams[1] == "lightmap") pass.texGen = ShaderTextureGen.Lightmap; else if(attribParams[1] == "environment") pass.texGen = ShaderTextureGen.Environment; } // TCMOD else if(attribParams[0] == "tcmod") { if(attribParams[1] == "rotate") { pass.tcModRotate = -StringConverter.ParseFloat(attribParams[2]) / 360; // +ve is clockwise degrees in Q3 shader, anticlockwise complete rotations in Ogre } else if(attribParams[1] == "scroll") { pass.tcModScroll[0] = StringConverter.ParseFloat(attribParams[2]); pass.tcModScroll[1] = StringConverter.ParseFloat(attribParams[3]); } else if(attribParams[1] == "scale") { pass.tcModScale[0] = StringConverter.ParseFloat(attribParams[2]); pass.tcModScale[1] = StringConverter.ParseFloat(attribParams[3]); } else if(attribParams[1] == "stretch") { if(attribParams[2] == "sin") pass.tcModStretchWave = ShaderWaveType.Sin; else if(attribParams[2] == "triangle") pass.tcModStretchWave = ShaderWaveType.Triangle; else if(attribParams[2] == "square") pass.tcModStretchWave = ShaderWaveType.Square; else if(attribParams[2] == "sawtooth") pass.tcModStretchWave = ShaderWaveType.SawTooth; else if(attribParams[2] == "inversesawtooth") pass.tcModStretchWave = ShaderWaveType.InverseSawtooth; pass.tcModStretchParams[0] = StringConverter.ParseFloat(attribParams[3]); pass.tcModStretchParams[1] = StringConverter.ParseFloat(attribParams[4]); pass.tcModStretchParams[2] = StringConverter.ParseFloat(attribParams[5]); pass.tcModStretchParams[3] = StringConverter.ParseFloat(attribParams[6]); } } // TURB else if(attribParams[0] == "turb") { pass.tcModTurbOn = true; pass.tcModTurb[0] = StringConverter.ParseFloat(attribParams[2]); pass.tcModTurb[1] = StringConverter.ParseFloat(attribParams[3]); pass.tcModTurb[2] = StringConverter.ParseFloat(attribParams[4]); pass.tcModTurb[3] = StringConverter.ParseFloat(attribParams[5]); } // DEPTHFUNC else if(attribParams[0] == "depthfunc") { // TODO } // DEPTHWRITE else if(attribParams[0] == "depthwrite") { // TODO } // ALPHAFUNC else if(attribParams[0] == "alphafunc") { if(attribParams[1] == "gt0") { pass.alphaVal = 0; pass.alphaFunc = CompareFunction.Greater; } else if(attribParams[1] == "ge128") { pass.alphaVal = 128; pass.alphaFunc = CompareFunction.GreaterEqual; } else if(attribParams[1] == "lt128") { pass.alphaVal = 128; pass.alphaFunc = CompareFunction.Less; } } }
protected void ParseShaderAttrib(string line, Quake3Shader shader) { string[] attribParams = line.Replace("(", "").Replace(")", "").Split(' ', '\t'); if(attribParams[0] == "skyparms") { if(attribParams[1] != "-") { shader.Farbox = true; shader.FarboxName = attribParams[1]; } if(attribParams[2] != "-") { shader.SkyDome = true; if(attribParams[2] == "full") shader.CloudHeight = 512; else shader.CloudHeight = StringConverter.ParseFloat(attribParams[2]); } // nearbox not supported } else if(attribParams[0] == "cull") { if((attribParams[1] == "diable") || (attribParams[1] == "none")) shader.CullingMode = ManualCullingMode.None; else if(attribParams[1] == "front") shader.CullingMode = ManualCullingMode.Front; else if(attribParams[1] == "back") shader.CullingMode = ManualCullingMode.Back; } else if (attribParams[0] == "deformvertexes") { // TODO } else if(attribParams[0] == "fogparms") { string[] fogValues = new string[4]; Array.Copy(attribParams, 1, fogValues, 0, 4); /*shader.Fog = true; shader.FogColour = StringConverter.ParseColor(fogValues); shader.FogDistance = StringConverter.ParseFloat(attribParams[4]);*/ } }
protected void ParseNewShaderPass(StreamReader stream, Quake3Shader shader) { string line; ShaderPass pass = new ShaderPass(); // Default pass details pass.animNumFrames = 0; pass.blend = LayerBlendOperation.Replace; pass.blendDest = SceneBlendFactor.Zero; pass.depthFunc = CompareFunction.LessEqual; pass.flags = 0; pass.rgbGenFunc = ShaderGen.Identity; pass.tcModRotate = 0; pass.tcModScale[0] = pass.tcModScale[1] = 1.0f; pass.tcModScroll[0] = pass.tcModScroll[1] = 0.0f; pass.tcModStretchWave = ShaderWaveType.None; pass.tcModTransform[0] = pass.tcModTransform[1] = 0.0f; pass.tcModTurbOn = false; pass.tcModTurb[0] = pass.tcModTurb[1] = pass.tcModTurb[2] = pass.tcModTurb[3] = 0.0f; pass.texGen = ShaderTextureGen.Base; pass.addressMode = TextureAddressing.Wrap; pass.customBlend = false; pass.alphaVal = 0; pass.alphaFunc = CompareFunction.AlwaysPass; shader.Pass.Add(pass); while((line = stream.ReadLine()) != null) { line = line.Trim(); // Ignore comments & blanks if((line != String.Empty) && !line.StartsWith("//")) { if(line == "}") return; else ParseShaderPassAttrib(line, shader, pass); } } }
private void CreateShaderMaterials(Quake3Level q3lvl, SceneManager sm) { // NB this only works for the 'default' shaders for now // i.e. those that don't have a .shader script and thus default // to just texture + lightmap // TODO: pre-parse all .shader files and create lookup for next stage (use ROGL shader_file_t) // Material names are shadername#lightmapnumber // This is because I like to define materials up front completely // rather than combine lightmap and shader dynamically (it's // more generic). It results in more materials, but they're small // beer anyway. Texture duplication is prevented by infrastructure. // To do this I actually need to parse the faces since they have the // shader/lightmap combo (lightmap number is not in the shader since // it can be used with multiple lightmaps) string shaderName; int face = q3lvl.Faces.Length; while (face-- > 0) { // Check to see if existing material // Format shader#lightmap int shadIdx = q3lvl.Faces[face].shader; shaderName = String.Format("{0}#{1}", q3lvl.Shaders[shadIdx].name, q3lvl.Faces[face].lmTexture); Material shadMat = sm.GetMaterial(shaderName); if (shadMat == null && !bspOptions.useLightmaps) { // try the no-lightmap material shaderName = String.Format("{0}#n", q3lvl.Shaders[shadIdx].name); shadMat = sm.GetMaterial(shaderName); } if (shadMat == null) { // Colour layer // NB no extension in Q3A(doh), have to try shader, .jpg, .tga string tryName = q3lvl.Shaders[shadIdx].name; // Try shader first Quake3Shader shader = (Quake3Shader)Quake3ShaderManager.Instance.GetByName(tryName); if (shader != null) { shadMat = shader.CreateAsMaterial(sm, q3lvl.Faces[face].lmTexture); } else { // No shader script, try default type texture shadMat = sm.CreateMaterial(shaderName); Pass shadPass = shadMat.GetTechnique(0).GetPass(0); // Try jpg TextureUnitState tex = shadPass.CreateTextureUnitState(tryName + ".jpg"); tex.Load(); if (tex.IsBlank) { // Try tga tex.SetTextureName(tryName + ".tga"); } // Set replace on all first layer textures for now tex.SetColorOperation(LayerBlendOperation.Replace); tex.TextureAddressing = TextureAddressing.Wrap; // for ambient lighting tex.ColorBlendMode.source2 = LayerBlendSource.Manual; if (bspOptions.useLightmaps && q3lvl.Faces[face].lmTexture != -1) { // Add lightmap, additive blending tex = shadPass.CreateTextureUnitState(String.Format("@lightmap{0}", q3lvl.Faces[face].lmTexture)); // Blend tex.SetColorOperation(LayerBlendOperation.Modulate); // Use 2nd texture co-ordinate set tex.TextureCoordSet = 1; // Clamp tex.TextureAddressing = TextureAddressing.Clamp; } shadMat.CullingMode = CullingMode.None; shadMat.Lighting = false; } } shadMat.Load(); // Copy face data BspStaticFaceGroup dest = CopyShaderFaceData(q3lvl, face, shadMat, shadIdx); faceGroups[face] = dest; } }