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; } }