/// <summary> /// Builds a dictionary of parts to be emphasized if displaying wireframe. /// </summary> /// <remarks> /// During rendering, as the mesh tree is traversed each part is checked to /// see whether it should be displayed as wireframe or not. A part in the dictionary /// built by this method will be rendered as a solid part, otherwise the part /// will be rendered as wireframe. /// This method traverses the mesh tree looking for the named part. Once that /// named part is found, that part and all its children are added to the dictionary. /// The traversal is terminated once the named part has been found and all of its /// children have also been traversed (and added to the dictionary). /// </remarks> /// <param name="part">The current part to inspect</param> /// <param name="partName">The name of the root part to emphasize during rendering</param> /// <param name="fEmphasizeParent">True if the parent of this part will be emphasized, false otherwise</param> /// <returns>True if this part has been emphasized, false otherwise</returns> private bool BuildEmphasisDictionary(Part part, string partName, bool fEmphasizeParent) { if (fEmphasizeParent || (!string.IsNullOrEmpty(part.name) && part.name == partName)) { partEmphasis.Add(part); fEmphasizeParent = true; } foreach (Part childPart in part.parts) { if (BuildEmphasisDictionary(childPart, partName, fEmphasizeParent) && !fEmphasizeParent) { break; } } return fEmphasizeParent; }
private void GetParts(Part part, List<string> names) { if (!string.IsNullOrEmpty(part.name)) { names.Add(part.name); } foreach (Part childPart in part.parts) { GetParts(childPart, names); } }
internal override ShaderResourceView UpdateRasterizerStateForPart(Part part) { RasterizerState state = showOneTexture && !partEmphasis.Contains(part) ? wireframeRasterizerState : solidRasterizerState; if (state != currentRasterizerState) { this.manager.device.RS.State = currentRasterizerState = state; } ShaderResourceView textureOverride; if (!alternateTextures.TryGetValue(part.name, out textureOverride)) { textureOverride = null; } return textureOverride; }
internal virtual ShaderResourceView UpdateRasterizerStateForPart(Part part) { return null; }
/// <summary> /// Loads a mesh and creates the vertex/index buffers for the part /// </summary> /// <param name="part"></param> /// <param name="meshData"></param> void LoadMesh(ref Part part, IXDataObject dataObject) { // load vertex data int dataOffset = 0; Match vertexCount = findArrayCount.Match(dataObject.Body); if(!vertexCount.Success) throw new System.IO.InvalidDataException("problem reading vertex count"); List<Vector4F> vertexList = new List<Vector4F>(); int verticies = int.Parse(vertexCount.Groups[1].Value, CultureInfo.InvariantCulture); dataOffset = vertexCount.Index + vertexCount.Length; for(int vertexIndex = 0; vertexIndex < verticies; vertexIndex++) { Match vertex = findVector3F.Match(dataObject.Body, dataOffset); if(!vertex.Success) throw new System.IO.InvalidDataException("problem reading vertex"); else dataOffset = vertex.Index + vertex.Length; vertexList.Add( new Vector4F( float.Parse(vertex.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(vertex.Groups[2].Value, CultureInfo.InvariantCulture), float.Parse(vertex.Groups[3].Value, CultureInfo.InvariantCulture), 1.0f)); } // load triangle index data Match triangleIndexCount = findArrayCount.Match(dataObject.Body, dataOffset); dataOffset = triangleIndexCount.Index + triangleIndexCount.Length; if(!triangleIndexCount.Success) throw new System.IO.InvalidDataException("problem reading index count"); List<Int32> triangleIndiciesList = new List<Int32>(); int triangleIndexListCount = int.Parse(triangleIndexCount.Groups[1].Value, CultureInfo.InvariantCulture); dataOffset = triangleIndexCount.Index + triangleIndexCount.Length; for(int triangleIndicyIndex = 0; triangleIndicyIndex < triangleIndexListCount; triangleIndicyIndex++) { Match indexEntry = findVertexIndex.Match(dataObject.Body, dataOffset); if(!indexEntry.Success) throw new System.IO.InvalidDataException("problem reading vertex index entry"); else dataOffset = indexEntry.Index + indexEntry.Length; int indexEntryCount = int.Parse(indexEntry.Groups[1].Value, CultureInfo.InvariantCulture); string[] vertexIndexes = indexEntry.Groups[2].Value.Split(new char[] { ',' }); if(indexEntryCount != vertexIndexes.Length) throw new System.IO.InvalidDataException("vertex index count does not equal count of indicies found"); for(int entryIndex = 0; entryIndex <= indexEntryCount - 3; entryIndex++) { triangleIndiciesList.Add(int.Parse(vertexIndexes[0], CultureInfo.InvariantCulture)); triangleIndiciesList.Add(int.Parse(vertexIndexes[1 + entryIndex].ToString(), CultureInfo.InvariantCulture)); triangleIndiciesList.Add(int.Parse(vertexIndexes[2 + entryIndex].ToString(), CultureInfo.InvariantCulture)); } } // load mesh colors IXDataObject vertexColorData = GetSingleChild(dataObject, "MeshVertexColors"); Dictionary<int, Vector4F> colorDictionary = null; if (vertexColorData != null) colorDictionary = LoadMeshColors(vertexColorData); // load mesh normals IXDataObject meshNormalData = GetSingleChild(dataObject, "MeshNormals"); IndexedMeshNormals meshNormals = null; if(meshNormalData != null) { meshNormals = LoadMeshNormals(meshNormalData); } // load mesh texture coordinates IXDataObject meshTextureCoordsData = GetSingleChild(dataObject, "MeshTextureCoords"); List<Vector2F> meshTextureCoords = null; if(meshTextureCoordsData != null) { meshTextureCoords = LoadMeshTextureCoordinates(meshTextureCoordsData); } // load mesh material IXDataObject meshMaterialsData = GetSingleChild(dataObject, "MeshMaterialList"); List<MaterialSpecification> meshMaterials = null; if(meshMaterialsData != null) { meshMaterials = LoadMeshMaterialList(meshMaterialsData); } // copy vertex data to HGLOBAL int byteLength = Marshal.SizeOf(typeof(XMeshVertex)) * triangleIndiciesList.Count; IntPtr nativeVertex = Marshal.AllocHGlobal(byteLength); byte[] byteBuffer = new byte[byteLength]; XMeshVertex[] varray = new XMeshVertex[triangleIndiciesList.Count]; for(int n = 0; n < triangleIndiciesList.Count; n++) { XMeshVertex vertex = new XMeshVertex() { Vertex = vertexList[triangleIndiciesList[n]], Normal = (meshNormals == null) ? new Vector4F(0, 0, 0, 1.0f) : meshNormals.normalVectors[meshNormals.normalIndexMap[n]], Color = ((colorDictionary == null) ? new Vector4F(0, 0, 0, 0) : colorDictionary[triangleIndiciesList[n]]), Texture = ((meshTextureCoords == null) ? new Vector2F(0, 0) : meshTextureCoords[triangleIndiciesList[n]]) }; byte[] vertexData = RawSerialize(vertex); Buffer.BlockCopy(vertexData, 0, byteBuffer, vertexData.Length * n, vertexData.Length); } Marshal.Copy(byteBuffer, 0, nativeVertex, byteLength); // build vertex buffer BufferDescription bdv = new BufferDescription() { Usage = Usage.Default, ByteWidth = (uint)(Marshal.SizeOf(typeof(XMeshVertex)) * triangleIndiciesList.Count), BindingOptions = BindingOptions.VertexBuffer, CpuAccessOptions = CpuAccessOptions.None, MiscellaneousResourceOptions = MiscellaneousResourceOptions.None }; SubresourceData vertexInit = new SubresourceData() { SystemMemory = nativeVertex }; part.vertexBuffer = device.CreateBuffer(bdv, vertexInit); Debug.Assert(part.vertexBuffer != null); part.vertexCount = triangleIndiciesList.Count; if(meshMaterials != null) { // only a single material is currently supported MaterialSpecification m = meshMaterials[0]; part.material = new Material() { emissiveColor = m.emissiveColor, specularColor = m.specularColor, materialColor = m.materialColor, specularPower = m.specularPower }; string texturePath = ""; if(File.Exists(m.textureFileName)) texturePath = m.textureFileName; if(File.Exists(meshDirectory + "\\" + m.textureFileName)) texturePath = meshDirectory + "\\" + m.textureFileName; if(File.Exists(meshDirectory + "\\..\\" + m.textureFileName)) texturePath = meshDirectory + "\\..\\" + m.textureFileName; if(texturePath.Length == 0) { part.material.textureResource = null; } else { part.material.textureResource = D3D10XHelpers.CreateShaderResourceViewFromFile( device, texturePath); } } Marshal.FreeHGlobal(nativeVertex); }
private void DisposePart(Part part) { if (part.vertexBuffer != null) { part.vertexBuffer.Dispose(); part.vertexBuffer = null; } if ((part.material != null) && (part.material.textureResource != null)) { part.material.textureResource.Dispose(); part.material.textureResource = null; } foreach (Part childPart in part.parts) { DisposePart(childPart); } part.parts = null; }
private void RenderPart(Part part, Matrix3D parentMatrix, ShaderResourceView parentTextureOverride) { // set part transform Transform3DGroup partGroup = new Transform3DGroup(); partGroup.Children.Add(new MatrixTransform3D(PartAnimation(part.name))); partGroup.Children.Add(new MatrixTransform3D(part.partTransform.ToMatrix3D())); partGroup.Children.Add(new MatrixTransform3D(parentMatrix)); parentMatrix = partGroup.Value; ShaderResourceView textureOverride = UpdateRasterizerStateForPart(part); if (textureOverride == null) { textureOverride = parentTextureOverride; } else { parentTextureOverride = textureOverride; } if (part.vertexBuffer != null) { EffectTechnique technique; if (textureOverride != null) { technique = this.manager.techniqueRenderTexture; this.manager.diffuseVariable.Resource = textureOverride; } else if (part.material == null) { technique = this.manager.techniqueRenderVertexColor; } else { if (part.material.textureResource != null) { technique = this.manager.techniqueRenderTexture; this.manager.diffuseVariable.Resource = part.material.textureResource; } else { technique = this.manager.techniqueRenderMaterialColor; this.manager.materialColorVariable.FloatVector = part.material.materialColor; } } this.manager.worldVariable.Matrix = parentMatrix.ToMatrix4x4F(); //set up vertex buffer and index buffer uint stride = (uint)Marshal.SizeOf(typeof(XMeshVertex)); uint offset = 0; this.manager.device.IA.SetVertexBuffers(0, new D3DBuffer[] { part.vertexBuffer }, new uint[] { stride }, new uint[] { offset }); //Set primitive topology this.manager.device.IA.PrimitiveTopology = PrimitiveTopology.TriangleList; TechniqueDescription techDesc = technique.Description; for (uint p = 0; p < techDesc.Passes; ++p) { technique.GetPassByIndex(p).Apply(); PassDescription passDescription = technique.GetPassByIndex(p).Description; using (InputLayout inputLayout = this.manager.device.CreateInputLayout( part.dataDescription, passDescription.InputAssemblerInputSignature, passDescription.InputAssemblerInputSignatureSize)) { // set vertex layout this.manager.device.IA.InputLayout = inputLayout; // draw part this.manager.device.Draw((uint)part.vertexCount, 0); // Note: In Direct3D 10, the device will not retain a reference // to the input layout, so it's important to reset the device's // input layout before disposing the object. Were this code // using Direct3D 11, the device would in fact retain a reference // and so it would be safe to go ahead and dispose the input // layout without resetting it; in that case, there could be just // a single assignment to null outside the 'for' loop, or even // no assignment at all. this.manager.device.IA.InputLayout = null; } } } foreach (Part childPart in part.parts) { RenderPart(childPart, parentMatrix, parentTextureOverride); } }
/// <summary> /// Loads a mesh and creates the vertex/index buffers for the part /// </summary> /// <param name="part"></param> /// <param name="meshData"></param> void LoadMesh( ref Part part, string meshData ) { // load vertex data int dataOffset = 0; Match vertexCount = findArrayCount.Match( meshData ); if( !vertexCount.Success ) throw new System.IO.InvalidDataException( "problem reading vertex count" ); List<Vector4F> vertexList = new List<Vector4F>(); int verticies = int.Parse(vertexCount.Groups[1].Value, CultureInfo.InvariantCulture); dataOffset = vertexCount.Index + vertexCount.Length; for( int vertexIndex = 0; vertexIndex < verticies; vertexIndex++ ) { Match vertex = findVector3F.Match( meshData, dataOffset ); if( !vertex.Success ) throw new System.IO.InvalidDataException( "problem reading vertex" ); else dataOffset = vertex.Index + vertex.Length; vertexList.Add( new Vector4F( float.Parse(vertex.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(vertex.Groups[2].Value, CultureInfo.InvariantCulture), float.Parse(vertex.Groups[3].Value, CultureInfo.InvariantCulture), 1.0f) ); } // load triangle index data Match triangleIndexCount = findArrayCount.Match( meshData, dataOffset ); dataOffset = triangleIndexCount.Index + triangleIndexCount.Length; if( !triangleIndexCount.Success ) throw new System.IO.InvalidDataException( "problem reading index count" ); List<Int32> triangleIndiciesList = new List<Int32>( ); int triangleIndexListCount = int.Parse(triangleIndexCount.Groups[1].Value, CultureInfo.InvariantCulture); dataOffset = triangleIndexCount.Index + triangleIndexCount.Length; for( int triangleIndicyIndex = 0; triangleIndicyIndex < triangleIndexListCount; triangleIndicyIndex++ ) { Match indexEntry = findVertexIndex.Match( meshData, dataOffset ); if( !indexEntry.Success ) throw new System.IO.InvalidDataException( "problem reading vertex index entry" ); else dataOffset = indexEntry.Index + indexEntry.Length; int indexEntryCount = int.Parse(indexEntry.Groups[1].Value, CultureInfo.InvariantCulture); string[ ] vertexIndexes = indexEntry.Groups[ 2 ].Value.Split( new char[ ] { ',' } ); if( indexEntryCount != vertexIndexes.Length ) throw new System.IO.InvalidDataException( "vertex index count does not equal count of indicies found" ); for( int entryIndex = 0; entryIndex <= indexEntryCount - 3; entryIndex++ ) { triangleIndiciesList.Add(int.Parse(vertexIndexes[0], CultureInfo.InvariantCulture)); triangleIndiciesList.Add(int.Parse(vertexIndexes[1 + entryIndex].ToString(), CultureInfo.InvariantCulture)); triangleIndiciesList.Add(int.Parse(vertexIndexes[2 + entryIndex].ToString(), CultureInfo.InvariantCulture)); } } // load mesh colors string vertexColorData = GetTagContent( new Regex( @"MeshVertexColors[\s]+{" ), meshData ); Dictionary<int,Vector4F> colorDictionary = null; if( vertexColorData != "" ) colorDictionary = LoadMeshColors( vertexColorData ); // load mesh normals string meshNormalData = GetTagContent( new Regex( @"MeshNormals[\s]+{" ), meshData ); IndexedMeshNormals meshNormals = null; if( meshNormalData != "" ) { meshNormals = LoadMeshNormals( meshNormalData ); } // load mesh texture coordinates string meshTextureCoordsData = GetTagContent( new Regex( @"MeshTextureCoords[\s]+{" ), meshData ); List<Vector2F> meshTextureCoords = null; if( meshTextureCoordsData != "" ) { meshTextureCoords = LoadMeshTextureCoordinates( meshTextureCoordsData ); } // load mesh material string meshMaterialsData = GetTagContent( new Regex( @"MeshMaterialList[\s]+{" ), meshData ); List<MaterialSpecification> meshMaterials = null; if( meshMaterialsData != "" ) { meshMaterials = LoadMeshMaterialList( meshMaterialsData ); } // copy vertex data to HGLOBAL int byteLength = Marshal.SizeOf( typeof( XMeshVertex ) ) * triangleIndiciesList.Count; IntPtr nativeVertex = Marshal.AllocHGlobal( byteLength ); byte[ ] byteBuffer = new byte[ byteLength ]; XMeshVertex[ ] varray = new XMeshVertex[ triangleIndiciesList.Count ]; for( int n = 0; n < triangleIndiciesList.Count; n++ ) { XMeshVertex vertex = new XMeshVertex( ) { Vertex = vertexList[ triangleIndiciesList[ n ] ], Normal = (meshNormals == null) ? new Vector4F( 0, 0, 0, 1.0f ) : meshNormals.normalVectors[ meshNormals.normalIndexMap[ n ] ], Color = ((colorDictionary == null) ? new Vector4F( 0, 0, 0, 0 ) : colorDictionary[ triangleIndiciesList[ n ] ]), Texture = ((meshTextureCoords == null) ? new Vector2F( 0, 0 ) : meshTextureCoords[ triangleIndiciesList[ n ] ]) }; byte[ ] vertexData = RawSerialize( vertex ); Buffer.BlockCopy( vertexData, 0, byteBuffer, vertexData.Length * n, vertexData.Length ); } Marshal.Copy( byteBuffer, 0, nativeVertex, byteLength ); // build vertex buffer BufferDescription bdv = new BufferDescription( ) { Usage = Usage.Default, ByteWidth = (uint)(Marshal.SizeOf( typeof( XMeshVertex ) ) * triangleIndiciesList.Count), BindFlags = BindFlag.VertexBuffer, CpuAccessFlags = 0, MiscFlags = 0 }; SubresourceData vertexInit = new SubresourceData( ) { SysMem = nativeVertex }; part.vertexBuffer = device.CreateBuffer( bdv, vertexInit ); Debug.Assert( part.vertexBuffer != null ); part.vertexCount = triangleIndiciesList.Count; if( meshMaterials != null ) { // only a single material is currently supported MaterialSpecification m = meshMaterials[ 0 ]; part.material = new Material() { emissiveColor = m.emissiveColor, specularColor = m.specularColor, materialColor = m.materialColor, specularPower = m.specularPower }; string texturePath = ""; if( File.Exists( m.textureFileName ) ) texturePath = m.textureFileName; if( File.Exists( meshDirectory + "\\" + m.textureFileName ) ) texturePath = meshDirectory + "\\" + m.textureFileName; if( File.Exists( meshDirectory + "\\..\\" + m.textureFileName ) ) texturePath = meshDirectory + "\\..\\" + m.textureFileName; if( texturePath.Length == 0 ) { part.material.textureResource = null; } else { part.material.textureResource = D3D10XHelpers.CreateShaderResourceViewFromFile( device, texturePath ); } } Marshal.FreeHGlobal( nativeVertex ); }
/// <summary> /// Extracts the vertex, normal, and texture data for a part /// </summary> /// <param name="partData"></param> /// <param name="partName"></param> /// <returns></returns> private Part BuildPart( string partData, string partName ) { Part part = new Part( ); part.dataDescription = description; part.name = partName; part.partTransform = ExtractFrameTransformation( partData ); // extract mesh (vertex, index, and colors) string meshContents = GetTagContent( new Regex( @"Mesh[\s]?([\w\d_]+)?[\s]+{" ), partData ); if( meshContents.Length > 0 ) LoadMesh( ref part, meshContents ); return part; }
private Part PartFromDataObject(IXDataObject dataObject) { Part part = new Part(); part.parts = new List<Part>(); part.name = dataObject.Name; switch (dataObject.DataObjectType) { case "Frame": // Frame data objects translate to parts with only a transform, // and no vertices, materials, etc. part.partTransform = ExtractFrameTransformation(dataObject); foreach (IXDataObject childObject in dataObject.Children.Where(obj => obj.IsVisualObject)) { part.parts.Add(PartFromDataObject(childObject)); } break; case "Mesh": // Mesh data objects inherit transform from their parent, // but do have vertices, materials, etc. part.partTransform = Matrix4x4F.Identity; part.dataDescription = description; LoadMesh(ref part, dataObject); break; default: throw new ArgumentException( string.Format(CultureInfo.InvariantCulture, "Object type \"{0}\" is incorrect. Only Frame or Mesh data objects can be converted to Part instances", dataObject.DataObjectType)); } return part; }