private ModelMeshMaterialPass CreateModelMeshMaterialPassShaderMaterial( ContentManager contentManager, W3dMesh w3dMesh, W3dMaterialPass w3dMaterialPass, W3dShaderMaterial w3dShaderMaterial, Effect effect) { var texCoords = new MeshVertex.TexCoords[w3dMesh.Header.NumVertices]; if (w3dMaterialPass.TexCoords != null) { for (var i = 0; i < texCoords.Length; i++) { texCoords[i].UV0 = w3dMaterialPass.TexCoords[i]; } } var meshParts = new List <ModelMeshPart>(); // TODO: Extract state properties from shader material. var rasterizerState = RasterizerStateDescriptionUtility.DefaultFrontIsCounterClockwise; var depthState = DepthStencilStateDescription.DepthOnlyLessEqual; var blendState = BlendStateDescription.SingleDisabled; var material = new ShaderMaterial(contentManager, effect) { PipelineState = new EffectPipelineState( rasterizerState, depthState, blendState, contentManager.GraphicsDevice.SwapchainFramebuffer.OutputDescription) }; var materialConstantsResourceBinding = effect.GetParameter("MaterialConstants").ResourceBinding; var materialConstantsBuffer = AddDisposable(contentManager.GraphicsDevice.ResourceFactory.CreateBuffer( new BufferDescription( materialConstantsResourceBinding.Size, BufferUsage.UniformBuffer | BufferUsage.Dynamic))); var materialConstantsBytes = new byte[materialConstantsResourceBinding.Size]; void setMaterialConstant <T>(string name, T value) where T : struct { var constantBufferField = materialConstantsResourceBinding.GetField(name); var valueBytes = StructInteropUtility.ToBytes(ref value); if (valueBytes.Length != constantBufferField.Size) { throw new InvalidOperationException(); } Buffer.BlockCopy( valueBytes, 0, materialConstantsBytes, constantBufferField.Offset, constantBufferField.Size); } foreach (var w3dShaderProperty in w3dShaderMaterial.Properties) { switch (w3dShaderProperty.PropertyType) { case W3dShaderMaterialPropertyType.Texture: var texture = CreateTexture(contentManager, w3dShaderProperty.StringValue); material.SetProperty(w3dShaderProperty.PropertyName, texture); break; case W3dShaderMaterialPropertyType.Bool: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Bool); break; case W3dShaderMaterialPropertyType.Color: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Color); break; case W3dShaderMaterialPropertyType.Float: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Float); break; case W3dShaderMaterialPropertyType.Vector2: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector2); break; case W3dShaderMaterialPropertyType.Vector3: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector3); break; case W3dShaderMaterialPropertyType.Int: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Int); break; default: throw new NotSupportedException(); } } contentManager.GraphicsDevice.UpdateBuffer(materialConstantsBuffer, 0, materialConstantsBytes); material.SetProperty("MaterialConstants", materialConstantsBuffer); meshParts.Add(new ModelMeshPart( 0, w3dMesh.Header.NumTris * 3, material)); return(new ModelMeshMaterialPass( contentManager.GraphicsDevice, texCoords, meshParts)); }
private ModelMeshMaterialPass CreateModelMeshMaterialPassShaderMaterial( ContentManager contentManager, W3dMesh w3dMesh, W3dMaterialPass w3dMaterialPass, W3dShaderMaterial w3dShaderMaterial, Effect effect) { var texCoords = new MeshVertex.TexCoords[w3dMesh.Header.NumVertices]; if (w3dMaterialPass.TexCoords != null) { for (var i = 0; i < texCoords.Length; i++) { texCoords[i].UV0 = w3dMaterialPass.TexCoords.Items[i]; } } var meshParts = new List <ModelMeshPart>(); // TODO: Extract state properties from shader material. var rasterizerState = RasterizerStateDescriptionUtility.DefaultFrontIsCounterClockwise; var depthState = DepthStencilStateDescription.DepthOnlyLessEqual; var blendState = BlendStateDescription.SingleDisabled; var material = new ShaderMaterial(contentManager, effect) { PipelineState = new EffectPipelineState( rasterizerState, depthState, blendState, RenderPipeline.GameOutputDescription) }; var materialConstantsBuilder = new ShaderMaterialConstantsBuilder(effect); foreach (var w3dShaderProperty in w3dShaderMaterial.Properties) { switch (w3dShaderProperty.PropertyType) { case W3dShaderMaterialPropertyType.Texture: var texture = CreateTexture(contentManager, w3dShaderProperty.StringValue); material.SetProperty(w3dShaderProperty.PropertyName, texture); break; case W3dShaderMaterialPropertyType.Bool: materialConstantsBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Bool); break; case W3dShaderMaterialPropertyType.Float: materialConstantsBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Float); break; case W3dShaderMaterialPropertyType.Vector2: materialConstantsBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector2); break; case W3dShaderMaterialPropertyType.Vector3: materialConstantsBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector3); break; case W3dShaderMaterialPropertyType.Vector4: materialConstantsBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector4); break; case W3dShaderMaterialPropertyType.Int: materialConstantsBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Int); break; default: throw new NotSupportedException(); } } material.SetMaterialConstants(AddDisposable(materialConstantsBuilder.CreateBuffer())); meshParts.Add(new ModelMeshPart( 0, w3dMesh.Header.NumTris * 3, material, _meshDepthMaterialShader)); return(new ModelMeshMaterialPass( contentManager.GraphicsDevice, texCoords, meshParts)); }
// One ModelMeshMaterialPass for each W3D_CHUNK_MATERIAL_PASS private ModelMeshMaterialPass CreateModelMeshMaterialPassFixedFunction( ContentManager contentManager, W3dMesh w3dMesh, W3dMaterialPass w3dMaterialPass, FixedFunction.VertexMaterial[] vertexMaterials, FixedFunction.ShadingConfiguration[] shadingConfigurations) { var hasTextureStage0 = w3dMaterialPass.TextureStages.Count > 0; var textureStage0 = hasTextureStage0 ? w3dMaterialPass.TextureStages[0] : null; var hasTextureStage1 = w3dMaterialPass.TextureStages.Count > 1 && w3dMaterialPass.TextureStages[1].TexCoords != null; var textureStage1 = hasTextureStage1 ? w3dMaterialPass.TextureStages[1] : null; var numTextureStages = hasTextureStage0 && hasTextureStage1 ? 2u : hasTextureStage0 ? 1u : 0u; var texCoords = new MeshVertex.TexCoords[w3dMesh.Header.NumVertices]; if (hasTextureStage0) { for (var i = 0; i < texCoords.Length; i++) { // TODO: What to do when this is null? if (textureStage0.TexCoords != null) { texCoords[i].UV0 = textureStage0.TexCoords.Items[i]; } if (hasTextureStage1) { texCoords[i].UV1 = textureStage1.TexCoords.Items[i]; } } } var meshParts = new List <ModelMeshPart>(); // Optimisation for a fairly common case. if (w3dMaterialPass.VertexMaterialIds.Items.Length == 1 && w3dMaterialPass.ShaderIds.Items.Length == 1 && w3dMaterialPass.TextureStages.Count == 1 && w3dMaterialPass.TextureStages[0].TextureIds.Items.Count == 1) { meshParts.Add(CreateModelMeshPart( contentManager, 0, w3dMesh.Header.NumTris * 3, w3dMesh, vertexMaterials, shadingConfigurations, w3dMaterialPass.VertexMaterialIds.Items[0], w3dMaterialPass.ShaderIds.Items[0], numTextureStages, w3dMaterialPass.TextureStages[0].TextureIds.Items[0], null)); } else { // Expand ShaderIds and TextureIds, if they have a single entry // (which means same ID for all faces) IEnumerable <uint?> getExpandedTextureIds(List <uint?> ids) { if (ids == null) { for (var i = 0; i < w3dMesh.Header.NumTris; i++) { yield return(null); } } else if (ids.Count == 1) { var result = ids[0]; for (var i = 0; i < w3dMesh.Header.NumTris; i++) { yield return(result); } } else { foreach (var id in ids) { yield return(id); } } } IEnumerable <uint> getExpandedShaderIds() { var ids = w3dMaterialPass.ShaderIds.Items; if (ids.Length == 1) { var result = ids[0]; for (var i = 0; i < w3dMesh.Header.NumTris; i++) { yield return(result); } } else { foreach (var id in ids) { yield return(id); } } } IEnumerable <uint> getExpandedVertexMaterialIDs() { var ids = w3dMaterialPass.VertexMaterialIds.Items; if (ids.Length == 1) { var result = ids[0]; for (var i = 0; i < w3dMesh.Header.NumTris; i++) { yield return(result); } } else { for (var i = 0; i < w3dMesh.Header.NumTris; i++) { var triangle = w3dMesh.Triangles.Items[i]; var materialID0 = ids[(int)triangle.VIndex0]; var materialID1 = ids[(int)triangle.VIndex1]; var materialID2 = ids[(int)triangle.VIndex2]; if (materialID0 != materialID1 || materialID1 != materialID2) { throw new NotSupportedException(); } yield return(materialID0); } foreach (var id in ids) { yield return(id); } } } var combinedIds = getExpandedVertexMaterialIDs() .Zip(getExpandedShaderIds(), (x, y) => new { VertexMaterialID = x, ShaderID = y }) .Zip(getExpandedTextureIds(textureStage0?.TextureIds.Items), (x, y) => new { x.VertexMaterialID, x.ShaderID, TextureIndex0 = y }) .Zip(getExpandedTextureIds(textureStage1?.TextureIds.Items), (x, y) => new CombinedMaterialPermutation { VertexMaterialID = x.VertexMaterialID, ShaderID = x.ShaderID, TextureIndex0 = x.TextureIndex0, TextureIndex1 = y }); var combinedId = combinedIds.First(); var startIndex = 0u; var indexCount = 0u; foreach (var newCombinedId in combinedIds) { if (combinedId != newCombinedId) { meshParts.Add(CreateModelMeshPart( contentManager, startIndex, indexCount, w3dMesh, vertexMaterials, shadingConfigurations, combinedId.VertexMaterialID, combinedId.ShaderID, numTextureStages, combinedId.TextureIndex0, combinedId.TextureIndex1)); startIndex = startIndex + indexCount; indexCount = 0; } combinedId = newCombinedId; indexCount += 3; } if (indexCount > 0) { meshParts.Add(CreateModelMeshPart( contentManager, startIndex, indexCount, w3dMesh, vertexMaterials, shadingConfigurations, combinedId.VertexMaterialID, combinedId.ShaderID, numTextureStages, combinedId.TextureIndex0, combinedId.TextureIndex1)); } } return(new ModelMeshMaterialPass( contentManager.GraphicsDevice, texCoords, meshParts)); }
private ModelMeshMaterialPass CreateModelMeshMaterialPassShaderMaterial( ContentManager contentManager, W3dMesh w3dMesh, W3dMaterialPass w3dMaterialPass, W3dShaderMaterial w3dShaderMaterial, Effect effect) { var texCoords = new MeshVertex.TexCoords[w3dMesh.Header.NumVertices]; if (w3dMaterialPass.TexCoords != null) { for (var i = 0; i < texCoords.Length; i++) { texCoords[i].UV0 = w3dMaterialPass.TexCoords[i]; } } var meshParts = new List <ModelMeshPart>(); // TODO: Extract state properties from shader material. var rasterizerState = RasterizerStateDescription.CullBackSolid; var depthState = DepthStencilStateDescription.Default; var blendState = BlendStateDescription.Opaque; var material = new ShaderMaterial(effect); material.PipelineState = new EffectPipelineState( rasterizerState, depthState, blendState); var materialConstantsResourceBinding = effect.GetParameter("MaterialConstants").ResourceBinding; var materialConstantsBuffer = AddDisposable(OpenSage.LowLevel.Graphics3D.Buffer.CreateDynamic( contentManager.GraphicsDevice, (uint)materialConstantsResourceBinding.ConstantBufferSizeInBytes, BufferBindFlags.ConstantBuffer)); var materialConstantsBytes = new byte[materialConstantsResourceBinding.ConstantBufferSizeInBytes]; void setMaterialConstant <T>(string name, T value) where T : struct { var constantBufferField = materialConstantsResourceBinding.GetConstantBufferField(name); var valueBytes = StructInteropUtility.ToBytes(ref value); if (valueBytes.Length != constantBufferField.Size) { throw new InvalidOperationException(); } System.Buffer.BlockCopy( valueBytes, 0, materialConstantsBytes, constantBufferField.Offset, constantBufferField.Size); } foreach (var w3dShaderProperty in w3dShaderMaterial.Properties) { switch (w3dShaderProperty.PropertyType) { case W3dShaderMaterialPropertyType.Texture: var texture = CreateTexture(contentManager, w3dShaderProperty.StringValue); material.SetProperty(w3dShaderProperty.PropertyName, texture); break; case W3dShaderMaterialPropertyType.Bool: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Bool); break; case W3dShaderMaterialPropertyType.Color: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Color); break; case W3dShaderMaterialPropertyType.Float: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Float); break; case W3dShaderMaterialPropertyType.Vector2: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector2); break; case W3dShaderMaterialPropertyType.Vector3: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector3); break; case W3dShaderMaterialPropertyType.Int: setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Int); break; default: throw new NotSupportedException(); } } materialConstantsBuffer.SetData(materialConstantsBytes); material.SetProperty("MaterialConstants", materialConstantsBuffer); meshParts.Add(new ModelMeshPart( 0, w3dMesh.Header.NumTris * 3, material)); return(new ModelMeshMaterialPass( contentManager.GraphicsDevice, texCoords, meshParts)); }