home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / Managed / Common / dxmutmesh.cs < prev    next >
Encoding:
Text File  |  2004-09-27  |  15.6 KB  |  386 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: DXMUTMesh.cs
  3. //
  4. // Support code for loading DirectX .X files.
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. using System;
  9. using Microsoft.DirectX;
  10. using Microsoft.DirectX.Direct3D;
  11.  
  12. namespace Microsoft.Samples.DirectX.UtilityToolkit
  13. {
  14.     /// <summary>Class for loading and rendering file-based meshes</summary>
  15.     public sealed class FrameworkMesh : IDisposable
  16.     {
  17.         #region Instance Data
  18.         private string meshFileName;
  19.         private Mesh systemMemoryMesh = null; // System Memory mesh, lives through a resize
  20.         private Mesh localMemoryMesh = null; // Local mesh, rebuilt on resize
  21.  
  22.         private Material[] meshMaterials = null; // Materials for the mesh
  23.         private BaseTexture[] meshTextures = null; // Textures for the mesh
  24.         private bool isUsingMeshMaterials = true; // Should the mesh be rendered with the materials
  25.  
  26.         /// <summary>Returns the system memory mesh</summary>
  27.         public Mesh SystemMesh { get { return systemMemoryMesh; } }
  28.         /// <summary>Returns the local memory mesh</summary>
  29.         public Mesh LocalMesh { get { return localMemoryMesh; } }
  30.         /// <summary>Should the mesh be rendered with materials</summary>
  31.         public bool IsUsingMaterials{ get { return isUsingMeshMaterials; } set { isUsingMeshMaterials = value; } }
  32.         /// <summary>Number of materials in mesh</summary>
  33.         public int NumberMaterials { get { return meshMaterials.Length; } }
  34.         /// <summary>Gets a texture from the mesh</summary>
  35.         public BaseTexture GetTexture(int index) { return meshTextures[index]; }
  36.         /// <summary>Gets a material from the mesh</summary>
  37.         public Material GetMaterial(int index) { return meshMaterials[index]; }
  38.         #endregion
  39.  
  40.         #region Creation
  41.         /// <summary>Create a new mesh using this file</summary>
  42.         public FrameworkMesh(Device device, string name)
  43.         {
  44.             meshFileName = name;
  45.             Create(device, meshFileName);
  46.         }
  47.         /// <summary>Create a new mesh</summary>
  48.         public FrameworkMesh() : this(null, "FrameworkMeshFile_Mesh") {}
  49.         
  50.         /// <summary>Create the mesh data</summary>
  51.         public void Create(Device device, string name)
  52.         {
  53.             // Hook the device events
  54.             System.Diagnostics.Debug.Assert(device != null, "Device should not be null.");
  55.             device.DeviceLost += new EventHandler(OnLostDevice);
  56.             device.DeviceReset += new EventHandler(OnResetDevice);
  57.             device.Disposing += new EventHandler(OnDeviceDisposing);
  58.  
  59.             GraphicsStream adjacency; // Adjacency information
  60.             ExtendedMaterial[] materials; // Mesh material information
  61.  
  62.             // First try to find the filename
  63.             string path = string.Empty;
  64.             try
  65.             {
  66.                 path = Utility.FindMediaFile(name);
  67.             }
  68.             catch(MediaNotFoundException)
  69.             {
  70.                 // The media was not found, maybe a full path was passed in?
  71.                 if (System.IO.File.Exists(name))
  72.                 {
  73.                     path = name;
  74.                 }
  75.                 else
  76.                 {
  77.                     // No idea what this is trying to find
  78.                     throw new MediaNotFoundException();
  79.                 }
  80.             }
  81.  
  82.             // Now load the mesh
  83.             systemMemoryMesh = Mesh.FromFile(path, MeshFlags.SystemMemory, device, out adjacency, 
  84.                 out materials);
  85.  
  86.             using (adjacency)
  87.             {
  88.                 // Optimize the mesh for performance
  89.                 systemMemoryMesh.OptimizeInPlace(MeshFlags.OptimizeVertexCache | MeshFlags.OptimizeCompact | 
  90.                     MeshFlags.OptimizeAttributeSort, adjacency);
  91.  
  92.                 // Find the folder of where the mesh file is located
  93.                 string folder = Utility.AppendDirectorySeparator(new System.IO.FileInfo(path).DirectoryName);
  94.  
  95.                 // Create the materials
  96.                 CreateMaterials(folder, device, adjacency, materials);
  97.             }
  98.  
  99.             // Finally call reset
  100.             OnResetDevice(device, EventArgs.Empty);
  101.         }
  102.         // TODO: Create with XOF
  103.  
  104.         /// <summary>Create the materials for the mesh</summary>
  105.         public void CreateMaterials(string folder, Device device, GraphicsStream adjacency, ExtendedMaterial[] materials)
  106.         {
  107.             // Does the mesh have materials?
  108.             if ((materials != null) && (materials.Length > 0))
  109.             {
  110.                 // Allocate the arrays for the materials
  111.                 meshMaterials = new Material[materials.Length];
  112.                 meshTextures = new BaseTexture[materials.Length];
  113.  
  114.                 // Copy each material and create it's texture
  115.                 for(int i = 0; i < materials.Length; i++)
  116.                 {
  117.                     // Copy the material first
  118.                     meshMaterials[i] = materials[i].Material3D;
  119.                     
  120.                     // Is there a texture for this material?
  121.                     if ((materials[i].TextureFilename == null) || (materials[i].TextureFilename.Length == 0) )
  122.                         continue; // No, just continue now
  123.  
  124.                     ImageInformation info = new ImageInformation();
  125.                     string textureFile = folder + materials[i].TextureFilename;
  126.                     try
  127.                     {
  128.                         // First look for the texture in the same folder as the input folder
  129.                         info = TextureLoader.ImageInformationFromFile(textureFile);
  130.                     }
  131.                     catch
  132.                     {
  133.                         try
  134.                         {
  135.                             // Couldn't find it, look in the media folder
  136.                             textureFile = Utility.FindMediaFile(materials[i].TextureFilename);
  137.                             info = TextureLoader.ImageInformationFromFile(textureFile);
  138.                         }
  139.                         catch (MediaNotFoundException)
  140.                         {
  141.                             // Couldn't find it anywhere, skip it
  142.                             continue;
  143.                         }
  144.                     }
  145.                     switch (info.ResourceType)
  146.                     {
  147.                         case ResourceType.Textures:
  148.                             meshTextures[i] = TextureLoader.FromFile(device, textureFile);
  149.                             break;
  150.                         case ResourceType.CubeTexture:
  151.                             meshTextures[i] = TextureLoader.FromCubeFile(device, textureFile);
  152.                             break;
  153.                         case ResourceType.VolumeTexture:
  154.                             meshTextures[i] = TextureLoader.FromVolumeFile(device, textureFile);
  155.                             break;
  156.                     }
  157.                 }
  158.             }
  159.         }
  160.         #endregion
  161.  
  162.         #region Class Methods
  163.         /// <summary>Updates the mesh to a new vertex format</summary>
  164.         public void SetVertexFormat(Device device, VertexFormats format)
  165.         {
  166.             Mesh tempSystemMesh = null;
  167.             Mesh tempLocalMesh = null;
  168.             VertexFormats oldFormat = VertexFormats.None;
  169.             using(systemMemoryMesh)
  170.             {
  171.                 using (localMemoryMesh)
  172.                 {
  173.                     // Clone the meshes
  174.                     if (systemMemoryMesh != null)
  175.                     {
  176.                         oldFormat = systemMemoryMesh.VertexFormat;
  177.                         tempSystemMesh = systemMemoryMesh.Clone(systemMemoryMesh.Options.Value,
  178.                             format, device);
  179.                     }
  180.                     if (localMemoryMesh != null)
  181.                     {
  182.                         tempLocalMesh = localMemoryMesh.Clone(localMemoryMesh.Options.Value,
  183.                             format, device); 
  184.                     }
  185.                 }
  186.             }
  187.  
  188.             // Store the new meshes
  189.             systemMemoryMesh = tempSystemMesh;
  190.             localMemoryMesh = tempLocalMesh;
  191.  
  192.             // Compute normals if they are being requested and the old mesh didn't have them
  193.             if ( ((oldFormat & VertexFormats.Normal) == 0) && ((format & VertexFormats.None) != 0) )
  194.             {
  195.                 if (systemMemoryMesh != null)
  196.                     systemMemoryMesh.ComputeNormals();
  197.                 if (localMemoryMesh != null)
  198.                     localMemoryMesh.ComputeNormals();
  199.             }
  200.         }
  201.         /// <summary>Updates the mesh to a new vertex declaration</summary>
  202.         public void SetVertexDeclaration(Device device, VertexElement[] decl)
  203.         {
  204.             Mesh tempSystemMesh = null;
  205.             Mesh tempLocalMesh = null;
  206.             VertexElement[] oldDecl = null;
  207.             using(systemMemoryMesh)
  208.             {
  209.                 using (localMemoryMesh)
  210.                 {
  211.                     // Clone the meshes
  212.                     if (systemMemoryMesh != null)
  213.                     {
  214.                         oldDecl = systemMemoryMesh.Declaration;
  215.                         tempSystemMesh = systemMemoryMesh.Clone(systemMemoryMesh.Options.Value,
  216.                             decl, device);
  217.                     }
  218.                     if (localMemoryMesh != null)
  219.                     {
  220.                         tempLocalMesh = localMemoryMesh.Clone(localMemoryMesh.Options.Value,
  221.                             decl, device); 
  222.                     }
  223.                 }
  224.             }
  225.  
  226.             // Store the new meshes
  227.             systemMemoryMesh = tempSystemMesh;
  228.             localMemoryMesh = tempLocalMesh;
  229.             
  230.             bool hadNormal = false;
  231.             // Check if the old declaration contains a normal.
  232.             for(int i = 0; i < oldDecl.Length; i++)
  233.             {
  234.                 if (oldDecl[i].DeclarationUsage == DeclarationUsage.Normal)
  235.                 {
  236.                     hadNormal = true;
  237.                     break;
  238.                 }
  239.             }
  240.             // Check to see if the new declaration has a normal
  241.             bool hasNormalNow = false;
  242.             for(int i = 0; i < decl.Length; i++)
  243.             {
  244.                 if (decl[i].DeclarationUsage == DeclarationUsage.Normal)
  245.                 {
  246.                     hasNormalNow = true;
  247.                     break;
  248.                 }
  249.             }
  250.  
  251.             // Compute normals if they are being requested and the old mesh didn't have them
  252.             if ( !hadNormal && hasNormalNow )
  253.             {
  254.                 if (systemMemoryMesh != null)
  255.                     systemMemoryMesh.ComputeNormals();
  256.                 if (localMemoryMesh != null)
  257.                     localMemoryMesh.ComputeNormals();
  258.             }
  259.         }
  260.  
  261.         /// <summary>Occurs after the device has been reset</summary>
  262.         private void OnResetDevice(object sender, EventArgs e)
  263.         {
  264.             Device device = sender as Device;
  265.             if (systemMemoryMesh == null)
  266.                 throw new InvalidOperationException("There is no system memory mesh.  Nothing to do here.");
  267.  
  268.             // Make a local memory version of the mesh. Note: because we are passing in
  269.             // no flags, the default behavior is to clone into local memory.
  270.             localMemoryMesh = systemMemoryMesh.Clone((systemMemoryMesh.Options.Value & ~MeshFlags.SystemMemory), 
  271.                 systemMemoryMesh.VertexFormat, device);
  272.         }
  273.  
  274.         /// <summary>Occurs before the device is going to be reset</summary>
  275.         private void OnLostDevice(object sender, EventArgs e)
  276.         {
  277.             if (localMemoryMesh != null)
  278.                 localMemoryMesh.Dispose();
  279.  
  280.             localMemoryMesh = null;
  281.         }
  282.         /// <summary>Renders this mesh</summary>
  283.         public void Render(Device device, bool canDrawOpaque, bool canDrawAlpha)
  284.         {
  285.             if (localMemoryMesh == null)
  286.                 throw new InvalidOperationException("No local memory mesh.");
  287.  
  288.             // Frist, draw the subsets without alpha
  289.             if (canDrawOpaque)
  290.             {
  291.                 for (int i = 0; i < meshMaterials.Length; i++)
  292.                 {
  293.                     if (isUsingMeshMaterials)
  294.                     {
  295.                         if (meshMaterials[i].DiffuseColor.Alpha < 1.0f)
  296.                             continue; // Only drawing opaque right now
  297.  
  298.                         // set the device material and texture
  299.                         device.Material = meshMaterials[i];
  300.                         device.SetTexture(0, meshTextures[i]);
  301.                     }
  302.                     localMemoryMesh.DrawSubset(i);
  303.                 }
  304.             }
  305.  
  306.             // Then, draw the subsets with alpha
  307.             if (canDrawAlpha)
  308.             {
  309.                 for (int i = 0; i < meshMaterials.Length; i++)
  310.                 {
  311.                     if (meshMaterials[i].DiffuseColor.Alpha == 1.0f)
  312.                         continue; // Only drawing non-opaque right now
  313.  
  314.                     // set the device material and texture
  315.                     device.Material = meshMaterials[i];
  316.                     device.SetTexture(0, meshTextures[i]);
  317.                     localMemoryMesh.DrawSubset(i);
  318.                 }
  319.             }
  320.         }
  321.         /// <summary>Renders this mesh</summary>
  322.         public void Render(Device device) { Render(device, true, true); }
  323.  
  324.         // TODO: Render with effect
  325.  
  326.         /// <summary>Compute a bounding sphere for this mesh</summary>
  327.         public float ComputeBoundingSphere(out Vector3 center)
  328.         {
  329.             if (systemMemoryMesh == null)
  330.                 throw new InvalidOperationException("There is no system memory mesh.  Nothing to do here.");
  331.  
  332.             // Get the object declaration
  333.             int strideSize = VertexInformation.GetFormatSize(systemMemoryMesh.VertexFormat);
  334.  
  335.             // Lock the vertex buffer
  336.             GraphicsStream data = null;
  337.             try
  338.             {
  339.                 data = systemMemoryMesh.LockVertexBuffer(LockFlags.ReadOnly);
  340.                 // Now compute the bounding sphere
  341.                 return Geometry.ComputeBoundingSphere(data, systemMemoryMesh.NumberVertices, 
  342.                     systemMemoryMesh.VertexFormat, out center);
  343.             }
  344.             finally
  345.             {
  346.                 // Make sure to unlock the vertex buffer
  347.                 if (data != null)
  348.                     systemMemoryMesh.UnlockVertexBuffer();
  349.             }
  350.         }
  351.         #endregion
  352.  
  353.         #region IDisposable Members
  354.  
  355.         /// <summary>Cleans up any resources required when this object is disposed</summary>
  356.         public void Dispose()
  357.         {
  358.             OnLostDevice(null, EventArgs.Empty);
  359.             if (meshTextures != null)
  360.             {
  361.                 for(int i = 0; i < meshTextures.Length; i++)
  362.                 {
  363.                     if (meshTextures[i] != null)
  364.                         meshTextures[i].Dispose();
  365.                 }
  366.             }
  367.             meshTextures = null;
  368.             meshMaterials = null;
  369.  
  370.             if (systemMemoryMesh != null)
  371.                 systemMemoryMesh.Dispose();
  372.  
  373.             systemMemoryMesh = null;
  374.  
  375.         }
  376.  
  377.         /// <summary>Cleans up any resources required when this object is disposed</summary>
  378.         private void OnDeviceDisposing(object sender, EventArgs e)
  379.         {
  380.             // Just dispose of our class
  381.             Dispose();
  382.         }
  383.         #endregion
  384.  
  385.     }
  386. }