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 / Direct3D / ProgressiveMesh / ProgressiveMesh.cs next >
Encoding:
Text File  |  2004-09-27  |  33.0 KB  |  696 lines

  1. //-----------------------------------------------------------------------------
  2. // File: ProgressiveMesh.cs
  3. //
  4. // Starting point for new Direct3D applications
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8.  
  9.  
  10. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  11. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  12.  
  13. using System;
  14. using Microsoft.DirectX;
  15. using Microsoft.DirectX.Direct3D;
  16. using Microsoft.Samples.DirectX.UtilityToolkit;
  17.  
  18. namespace ProgressiveMeshSample
  19. {
  20.     /// <summary>ProgressiveMesh Sample Class</summary>
  21.     public class ProgressiveMeshes : IFrameworkCallback, IDeviceCreation
  22.     {
  23.         #region Creation
  24.         /// <summary>Create a new instance of the class</summary>
  25.         public ProgressiveMeshes(Framework f) 
  26.         { 
  27.             // Store framework
  28.             sampleFramework = f; 
  29.             // Create dialogs
  30.             hud = new Dialog(sampleFramework); 
  31.             sampleUi = new Dialog(sampleFramework); 
  32.         }
  33.         #endregion
  34.  
  35.         private const string OptimizedText = "Using optimized mesh {0} of {1}\nCurrent mesh vertices range: {2} / {3}\n"  +
  36.             "Absolute vertices range: {4} / {5}\nCurrent vertices: {6}";
  37.         private const string UnoptimizedText = "Using unoptimized mesh\nMesh vertices range: {0} / {1}\n"  +
  38.             "Current vertices: {2}\n";
  39.  
  40.         // Variables
  41.         private Framework sampleFramework = null; // Framework for samples
  42.         private Font statsFont = null; // Font for drawing text
  43.         private Sprite textSprite = null; // Sprite for batching text calls
  44.         private Effect effect = null; // D3DX Effect Interface
  45.         private ModelViewerCamera camera = new ModelViewerCamera(); // A model viewing camera
  46.         private bool isHelpShowing = true; // If true, renders the UI help text
  47.         private Dialog hud = null; // dialog for standard controls
  48.         private Dialog sampleUi = null; // dialog for sample specific controls
  49.  
  50.         // Sample specific variables
  51.         private ProgressiveMesh[] meshes = null;
  52.         private ProgressiveMesh fullMesh = null;
  53.         private int currentMeshIndex = 0;
  54.         private Material[] meshMaterials = null;
  55.         private Texture[] meshTextures = null;
  56.         private Vector3 objectCenter; // Center of bounding sphere of object
  57.         private float objectRadius; // Radius of bounding sphere of object
  58.         private Matrix worldCenter; // World matrix to center the mesh
  59.         private bool isShowingOptimized = true;
  60.  
  61.         // HUD Ui Control constants
  62.         private const int ToggleFullscreen = 1;
  63.         private const int ToggleReference = 3;
  64.         private const int ChangeDevice = 4;
  65.         private const int Detail = 5;
  66.         private const int DetailLabel = 6;
  67.         private const int UseOptimizedCheckBox = 7;
  68.  
  69.         /// <summary>
  70.         /// Called during device initialization, this code checks the device for some 
  71.         /// minimum set of capabilities, and rejects those that don't pass by returning false.
  72.         /// </summary>
  73.         public bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool windowed)
  74.         {
  75.             // No fallback, need at least PS1.1
  76.             if (caps.PixelShaderVersion < new Version(1,1))
  77.                 return false;
  78.  
  79.             // Skip back buffer formats that don't support alpha blending
  80.             if (!Manager.CheckDeviceFormat(caps.AdapterOrdinal, caps.DeviceType, adapterFormat, 
  81.                 Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backBufferFormat))
  82.                 return false;
  83.  
  84.             return true;
  85.         }
  86.  
  87.         /// <summary>
  88.         /// This callback function is called immediately before a device is created to allow the 
  89.         /// application to modify the device settings. The supplied settings parameter 
  90.         /// contains the settings that the framework has selected for the new device, and the 
  91.         /// application can make any desired changes directly to this structure.  Note however that 
  92.         /// the sample framework will not correct invalid device settings so care must be taken 
  93.         /// to return valid device settings, otherwise creating the Device will fail.  
  94.         /// </summary>
  95.         public void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
  96.         {
  97.             // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  98.             // then switch to SWVP.
  99.             if ( (!caps.DeviceCaps.SupportsHardwareTransformAndLight) ||
  100.                 (caps.VertexShaderVersion < new Version(1,1)) )
  101.             {
  102.                 settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing;
  103.             }
  104.             else
  105.             {
  106.                 settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
  107.             }
  108.  
  109.             // This application is designed to work on a pure device by not using 
  110.             // any get methods, so create a pure device if supported and using HWVP.
  111.             if ( (caps.DeviceCaps.SupportsPureDevice) && 
  112.                 ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) )
  113.                 settings.BehaviorFlags |= CreateFlags.PureDevice;
  114.  
  115.             // Debugging vertex shaders requires either REF or software vertex processing 
  116.             // and debugging pixel shaders requires REF.  
  117. #if(DEBUG_VS)
  118.             if (settings.DeviceType != DeviceType.Reference )
  119.             {
  120.                 settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing;
  121.                 settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
  122.             }
  123. #endif
  124. #if(DEBUG_PS)
  125.             settings.DeviceType = DeviceType.Reference;
  126. #endif
  127.  
  128.         }
  129.  
  130.         /// <summary>
  131.         /// This event will be fired immediately after the Direct3D device has been 
  132.         /// created, which will happen during application initialization and windowed/full screen 
  133.         /// toggles. This is the best location to create Pool.Managed resources since these 
  134.         /// resources need to be reloaded whenever the device is destroyed. Resources created  
  135.         /// here should be released in the Disposing event. 
  136.         /// </summary>
  137.         private void OnCreateDevice(object sender, DeviceEventArgs e)
  138.         {
  139.             // Initialize the stats font
  140.             statsFont = ResourceCache.GetGlobalInstance().CreateFont(e.Device, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default,
  141.                 Precision.Default, FontQuality.Default, PitchAndFamily.FamilyDoNotCare | PitchAndFamily.DefaultPitch
  142.                 , "Arial");
  143.  
  144.             // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  145.             // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  146.             // processing, and debugging pixel shaders requires REF.  The 
  147.             // ShaderFlags.Force*SoftwareNoOptimizations flag improves the debug experience in the 
  148.             // shader debugger.  It enables source level debugging, prevents instruction 
  149.             // reordering, prevents dead code elimination, and forces the compiler to compile 
  150.             // against the next higher available software target, which ensures that the 
  151.             // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  152.             // flags will cause slower rendering since the shaders will be unoptimized and 
  153.             // forced into software.  See the DirectX documentation for more information about 
  154.             // using the shader debugger.
  155.             ShaderFlags shaderFlags = ShaderFlags.None;
  156. #if(DEBUG_VS)
  157.             shaderFlags |= ShaderFlags.ForceVertexShaderSoftwareNoOptimizations;
  158. #endif
  159. #if(DEBUG_PS)
  160.             shaderFlags |= ShaderFlags.ForcePixelShaderSoftwareNoOptimizations;
  161. #endif
  162.             // Read the D3DX effect file
  163.             string path = Utility.FindMediaFile("ProgressiveMesh.fx");
  164.             effect = ResourceCache.GetGlobalInstance().CreateEffectFromFile(e.Device,
  165.                 path, null, null, shaderFlags, null);
  166.  
  167.             // Set the technique now, it will never be updated
  168.             effect.Technique = "RenderScene";
  169.  
  170.             // Load the mesh
  171.             GraphicsStream adjacencyBuffer = null;
  172.             ExtendedMaterial[] materials = null;
  173.  
  174.             // Find the mesh
  175.             path = Utility.FindMediaFile("dwarf\\dwarf.x");
  176.             
  177.             // Change the current directory to the mesh's directory so we can
  178.             // find the textures.
  179.             string currentFolder = System.IO.Directory.GetCurrentDirectory();
  180.             System.IO.FileInfo info = new System.IO.FileInfo(path);
  181.             System.IO.Directory.SetCurrentDirectory(info.Directory.FullName);
  182.  
  183.             using (Mesh originalMesh = Mesh.FromFile(path, MeshFlags.Managed, e.Device,
  184.                        out adjacencyBuffer, out materials))
  185.             {
  186.                 int use32Bit = (int)(originalMesh.Options.Value & MeshFlags.Use32Bit);
  187.  
  188.                 // Perform simple cleansing operations on mesh
  189.                 using (Mesh mesh = Mesh.Clean(CleanType.Simplification, originalMesh, adjacencyBuffer, adjacencyBuffer))
  190.                 {
  191.                     // Perform a weld to try and remove excess vertices.
  192.                     // Weld the mesh using all epsilons of 0.0f.  A small epsilon like 1e-6 works well too
  193.                     WeldEpsilons epsilons = new WeldEpsilons();
  194.                     mesh.WeldVertices(0, epsilons, adjacencyBuffer, adjacencyBuffer);
  195.  
  196.                     // Verify validity of mesh for simplification
  197.                     mesh.Validate(adjacencyBuffer);
  198.  
  199.                     // Allocate a material/texture arrays
  200.                     meshMaterials = new Material[materials.Length];
  201.                     meshTextures = new Texture[materials.Length];
  202.  
  203.                     // Copy the materials and load the textures
  204.                     for(int i = 0; i < meshMaterials.Length; i++)
  205.                     {
  206.                         meshMaterials[i] = materials[i].Material3D;
  207.                         meshMaterials[i].AmbientColor = meshMaterials[i].DiffuseColor;
  208.  
  209.                         if ( (materials[i].TextureFilename != null) && (materials[i].TextureFilename.Length > 0) )
  210.                         {
  211.                             // Create the texture
  212.                             meshTextures[i] = ResourceCache.GetGlobalInstance().CreateTextureFromFile(e.Device, materials[i].TextureFilename);
  213.                         }
  214.                     }
  215.  
  216.                     // Find the mesh's center, then generate a centering matrix
  217.                     using(VertexBuffer vb = mesh.VertexBuffer)
  218.                     {
  219.                         using (GraphicsStream stm = vb.Lock(0, 0, LockFlags.NoSystemLock))
  220.                         {
  221.                             try
  222.                             {
  223.                                 objectRadius = Geometry.ComputeBoundingSphere(stm,
  224.                                     mesh.NumberVertices, mesh.VertexFormat, out objectCenter);
  225.  
  226.                                 worldCenter = Matrix.Translation(-objectCenter);
  227.                                 float scaleFactor = 2.0f / objectRadius;
  228.                                 worldCenter *= Matrix.Scaling(scaleFactor, scaleFactor, scaleFactor);
  229.                             }
  230.                             finally
  231.                             {
  232.                                 vb.Unlock();
  233.                             }
  234.                         }
  235.                     }
  236.  
  237.                     // If the mesh is missing normals, generate them.
  238.                     Mesh currentMesh = mesh;
  239.                     if ((mesh.VertexFormat & VertexFormats.Normal) == 0)
  240.                     {
  241.                         currentMesh = mesh.Clone(MeshFlags.Managed | (MeshFlags)use32Bit,
  242.                             mesh.VertexFormat | VertexFormats.Normal, e.Device);
  243.  
  244.                         // Compute normals now
  245.                         currentMesh.ComputeNormals();
  246.                     }
  247.  
  248.                     using (currentMesh)
  249.                     {
  250.                         // Generate progressive meshes
  251.                         using(ProgressiveMesh pMesh = new ProgressiveMesh(currentMesh, adjacencyBuffer, null, 1, MeshFlags.SimplifyVertex))
  252.                         {
  253.                             int minVerts = pMesh.MinVertices;
  254.                             int maxVerts = pMesh.MaxVertices;
  255.                             int vertsPerMesh = (maxVerts - minVerts + 10) / 10;
  256.  
  257.                             // How many meshes should be in the array
  258.                             int numMeshes = Math.Max(1, (int)Math.Ceiling((maxVerts - minVerts + 1) / (float)vertsPerMesh) );
  259.                             meshes = new ProgressiveMesh[numMeshes];
  260.  
  261.                             // Clone full sized pmesh
  262.                             fullMesh = pMesh.Clone(MeshFlags.Managed | MeshFlags.VbShare, pMesh.VertexFormat, e.Device);
  263.  
  264.                             // Clone all the separate pmeshes
  265.                             for (int iMesh = 0; iMesh < numMeshes; iMesh++)
  266.                             {
  267.                                 meshes[iMesh] = pMesh.Clone(MeshFlags.Managed | MeshFlags.VbShare, pMesh.VertexFormat, e.Device);
  268.  
  269.                                 // Trim to appropriate space
  270.                                 meshes[iMesh].TrimByVertices(minVerts + vertsPerMesh * iMesh, minVerts + vertsPerMesh * (iMesh + 1));
  271.                                 meshes[iMesh].OptimizeBaseLevelOfDetail(MeshFlags.OptimizeVertexCache);
  272.                             }
  273.  
  274.                             // Set the current to be max vertices
  275.                             currentMeshIndex = numMeshes - 1;
  276.                             meshes[currentMeshIndex].NumberVertices = maxVerts;
  277.                             fullMesh.NumberVertices = maxVerts;
  278.  
  279.                             // Set up the slider to reflect the vertices range the mesh has
  280.                             sampleUi.GetSlider(Detail).SetRange(meshes[0].MinVertices,
  281.                                 meshes[meshes.Length -1].MaxVertices);
  282.                             sampleUi.GetSlider(Detail).Value = (meshes[currentMeshIndex] as BaseMesh).NumberVertices;
  283.                         }
  284.                     }
  285.                 }
  286.             }
  287.  
  288.             // Restore the original folder
  289.             System.IO.Directory.SetCurrentDirectory(currentFolder);
  290.             // Setup the camera's view parameters
  291.             camera.SetViewParameters(new Vector3(0.0f, 0.0f, -5.0f), Vector3.Empty);
  292.         }
  293.         
  294.         /// <summary>
  295.         /// This event will be fired immediately after the Direct3D device has been 
  296.         /// reset, which will happen after a lost device scenario. This is the best location to 
  297.         /// create Pool.Default resources since these resources need to be reloaded whenever 
  298.         /// the device is lost. Resources created here should be released in the OnLostDevice 
  299.         /// event. 
  300.         /// </summary>
  301.         private void OnResetDevice(object sender, DeviceEventArgs e)
  302.         {
  303.             SurfaceDescription desc = e.BackBufferDescription;
  304.             // Create a sprite to help batch calls when drawing many lines of text
  305.             textSprite = new Sprite(e.Device);
  306.  
  307.             // Setup the camera's projection parameters
  308.             float aspectRatio = (float)desc.Width / (float)desc.Height;
  309.             camera.SetProjectionParameters((float)Math.PI / 4, aspectRatio, 0.1f, 1000.0f);
  310.             camera.SetWindow(desc.Width, desc.Height);
  311.  
  312.             // Setup UI locations
  313.             hud.SetLocation(desc.Width-170, 0);
  314.             hud.SetSize(170,170);
  315.             sampleUi.SetLocation(0, desc.Height - 50);
  316.             sampleUi.SetSize(desc.Width,50);
  317.  
  318.             // Update controls
  319.             sampleUi.GetControl(DetailLabel).SetLocation((desc.Width - 200) / 2, 10);
  320.             sampleUi.GetControl(UseOptimizedCheckBox).SetLocation(desc.Width - 130, 5);
  321.             sampleUi.GetControl(Detail).SetSize(desc.Width - 20, 16);
  322.         }
  323.  
  324.         /// <summary>
  325.         /// This event function will be called fired after the Direct3D device has 
  326.         /// entered a lost state and before Device.Reset() is called. Resources created
  327.         /// in the OnResetDevice callback should be released here, which generally includes all 
  328.         /// Pool.Default resources. See the "Lost Devices" section of the documentation for 
  329.         /// information about lost devices.
  330.         /// </summary>
  331.         private void OnLostDevice(object sender, EventArgs e)
  332.         {
  333.             if (textSprite != null)
  334.             {
  335.                 textSprite.Dispose();
  336.                 textSprite = null;
  337.             }
  338.         }
  339.  
  340.         /// <summary>
  341.         /// This callback function will be called immediately after the Direct3D device has 
  342.         /// been destroyed, which generally happens as a result of application termination or 
  343.         /// windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  344.         /// should be released here, which generally includes all Pool.Managed resources. 
  345.         /// </summary>
  346.         private void OnDestroyDevice(object sender, EventArgs e)
  347.         {
  348.             meshTextures = null;
  349.             meshMaterials = null;
  350.  
  351.             if (fullMesh != null)
  352.                 fullMesh.Dispose();
  353.  
  354.             if ( (meshes != null) && (meshes.Length > 0) )
  355.             {
  356.                 for (int i = 0; i < meshes.Length; i++)
  357.                 {
  358.                     if (meshes[i] != null)
  359.                         meshes[i].Dispose();
  360.                 }
  361.             }
  362.             meshes = null;
  363.         }
  364.  
  365.         /// <summary>
  366.         /// This callback function will be called once at the beginning of every frame. This is the
  367.         /// best location for your application to handle updates to the scene, but is not 
  368.         /// intended to contain actual rendering calls, which should instead be placed in the 
  369.         /// OnFrameRender callback.  
  370.         /// </summary>
  371.         public void OnFrameMove(Device device, double appTime, float elapsedTime)
  372.         {
  373.             // Update the camera's position based on user input 
  374.             camera.FrameMove(elapsedTime);
  375.         }
  376.  
  377.         /// <summary>
  378.         /// This callback function will be called at the end of every frame to perform all the 
  379.         /// rendering calls for the scene, and it will also be called if the window needs to be 
  380.         /// repainted. After this function has returned, the sample framework will call 
  381.         /// Device.Present to display the contents of the next buffer in the swap chain
  382.         /// </summary>
  383.         public void OnFrameRender(Device device, double appTime, float elapsedTime)
  384.         {
  385.             bool beginSceneCalled = false;
  386.  
  387.             // Clear the render target and the zbuffer 
  388.             device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, 0x00424B79, 1.0f, 0);
  389.             try
  390.             {
  391.                 device.BeginScene();
  392.                 beginSceneCalled = true;
  393.  
  394.                 // Get the world matrix
  395.                 Matrix worldMatrix = worldCenter * camera.WorldMatrix;
  396.  
  397.                 if ((meshes != null) && (meshes.Length > 0))
  398.                 {
  399.                     // Update the effect's variables.  Instead of using strings, it would 
  400.                     // be more efficient to cache a handle to the parameter by calling 
  401.                     // Effect.GetParameter
  402.                     effect.SetValue("g_mWorldViewProjection", worldMatrix * camera.ViewMatrix * camera.ProjectionMatrix);
  403.                     effect.SetValue("g_mWorld", worldMatrix);
  404.  
  405.                     // Set and draw each of the materials in the mesh
  406.                     for (int i = 0; i < meshMaterials.Length; i++)
  407.                     {
  408.                         effect.SetValue("g_vDiffuse", meshMaterials[i].DiffuseColor);
  409.                         effect.SetValue("g_txScene", meshTextures[i]);
  410.                         int passes = effect.Begin(0);
  411.                         for(int pass = 0; pass < passes; pass++)
  412.                         {
  413.                             effect.BeginPass(pass);
  414.                             if (isShowingOptimized)
  415.                             {
  416.                                 meshes[currentMeshIndex].DrawSubset(i);
  417.                             }
  418.                             else
  419.                             {
  420.                                 fullMesh.DrawSubset(i);
  421.                             }
  422.                             effect.EndPass();
  423.                         }
  424.                         effect.End();
  425.                     }
  426.                 }
  427.                 // Show frame rate
  428.                 RenderText();
  429.  
  430.                 // Show UI
  431.                 hud.OnRender(elapsedTime);
  432.                 sampleUi.OnRender(elapsedTime);
  433.             }
  434.             finally
  435.             {
  436.                 if (beginSceneCalled)
  437.                     device.EndScene();
  438.             }
  439.         }
  440.  
  441.         /// <summary>
  442.         /// Render the help and statistics text. This function uses the Font object for 
  443.         /// efficient text rendering.
  444.         /// </summary>
  445.         private void RenderText()
  446.         {
  447.             TextHelper txtHelper = new TextHelper(statsFont, textSprite, 15);
  448.  
  449.             // Output statistics
  450.             txtHelper.Begin();
  451.             txtHelper.SetInsertionPoint(5,5);
  452.             txtHelper.SetForegroundColor(System.Drawing.Color.Yellow);
  453.             txtHelper.DrawTextLine(sampleFramework.FrameStats);
  454.             txtHelper.DrawTextLine(sampleFramework.DeviceStats);
  455.  
  456.             txtHelper.SetForegroundColor(System.Drawing.Color.White);
  457.             if (isShowingOptimized)
  458.             {
  459.                 txtHelper.DrawTextLine(OptimizedText, currentMeshIndex + 1, meshes.Length, 
  460.                     meshes[currentMeshIndex].MinVertices, meshes[currentMeshIndex].MaxVertices, 
  461.                     meshes[0].MinVertices, meshes[meshes.Length -1].MaxVertices, 
  462.                     (meshes[currentMeshIndex] as BaseMesh).NumberVertices);
  463.             }
  464.             else
  465.             {
  466.                 txtHelper.DrawTextLine(UnoptimizedText, fullMesh.MinFaces, fullMesh.MaxFaces, 
  467.                     (fullMesh as BaseMesh).NumberVertices);
  468.            }
  469.  
  470.             // Draw help
  471.             if (isHelpShowing)
  472.             {
  473.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*7);
  474.                 txtHelper.SetForegroundColor(System.Drawing.Color.DarkOrange);
  475.                 txtHelper.DrawTextLine("Controls (F1 to hide):");
  476.  
  477.                 txtHelper.SetInsertionPoint(40, sampleFramework.BackBufferSurfaceDescription.Height-15*6);
  478.                 txtHelper.DrawTextLine("Rotate mesh: Left click drag");
  479.                 txtHelper.DrawTextLine("Zoom: mouse wheel");
  480.                 txtHelper.DrawTextLine("Quit: Esc");
  481.                 txtHelper.DrawTextLine("Hide help: F1");
  482.             }
  483.             else
  484.             {
  485.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*4);
  486.                 txtHelper.SetForegroundColor(System.Drawing.Color.White);
  487.                 txtHelper.DrawTextLine("Press F1 for help");
  488.             }
  489.  
  490.             txtHelper.End();
  491.         }
  492.  
  493.         /// <summary>
  494.         /// As a convenience, the sample framework inspects the incoming windows messages for
  495.         /// keystroke messages and decodes the message parameters to pass relevant keyboard
  496.         /// messages to the application.  The framework does not remove the underlying keystroke 
  497.         /// messages, which are still passed to the application's MsgProc callback.
  498.         /// </summary>
  499.         private void OnKeyEvent(System.Windows.Forms.Keys key, bool isKeyDown, bool isKeyUp)
  500.         {
  501.             if (isKeyDown)
  502.             {
  503.                 switch(key)
  504.                 {
  505.                     case System.Windows.Forms.Keys.F1:
  506.                         isHelpShowing = !isHelpShowing;
  507.                         break;
  508.                 }
  509.             }
  510.         }
  511.  
  512.         /// <summary>
  513.         /// Before handling window messages, the sample framework passes incoming windows 
  514.         /// messages to the application through this callback function. If the application sets 
  515.         /// noFurtherProcessing to true, the sample framework will not process the message
  516.         /// </summary>
  517.         public IntPtr OnMsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool noFurtherProcessing)
  518.         {
  519.             // Give the dialog a chance to handle the message first
  520.             noFurtherProcessing = hud.MessageProc(hWnd, msg, wParam, lParam);
  521.             if (noFurtherProcessing)
  522.                 return IntPtr.Zero;
  523.  
  524.             noFurtherProcessing = sampleUi.MessageProc(hWnd, msg, wParam, lParam);
  525.             if (noFurtherProcessing)
  526.                 return IntPtr.Zero;
  527.  
  528.             // Pass all remaining windows messages to camera so it can respond to user input
  529.             camera.HandleMessages(hWnd, msg, wParam, lParam);
  530.  
  531.             return IntPtr.Zero;
  532.         }
  533.  
  534.         /// <summary>
  535.         /// Initializes the application
  536.         /// </summary>
  537.         public void InitializeApplication()
  538.         {
  539.             int y = 10;
  540.             // Initialize the HUD
  541.             Button fullScreen = hud.AddButton(ToggleFullscreen,"Toggle full screen", 35, y, 125,22);
  542.             Button toggleRef = hud.AddButton(ToggleReference,"Toggle reference (F3)", 35, y += 24, 125,22);
  543.             Button changeDevice = hud.AddButton(ChangeDevice,"Change Device (F2)", 35, y += 24, 125,22);
  544.             // Hook the button events for when these items are clicked
  545.             fullScreen.Click += new EventHandler(OnFullscreenClicked);
  546.             toggleRef.Click += new EventHandler(OnRefClicked);
  547.             changeDevice.Click += new EventHandler(OnChangeDevicClicked);
  548.  
  549.             // Now add the sample specific UI
  550.             y = 10;
  551.             sampleUi.IsUsingKeyboardInput = true;
  552.             sampleUi.AddStatic(DetailLabel, "Level of Detail:", 0, y, 200, 16);
  553.             Checkbox opt = sampleUi.AddCheckBox(UseOptimizedCheckBox, "Use optimized mesh", 50, y, 200, 20, true);
  554.             Slider sl = sampleUi.AddSlider(Detail, 10, y += 16, 200, 16, 4, 4, 4, false);
  555.  
  556.             // Hook the sample events
  557.             opt.Changed += new EventHandler(OnOptimizedChanged);
  558.             sl.ValueChanged += new EventHandler(OnDetailChanged);
  559.  
  560.             // Set button masks
  561.             camera.SetButtonMasks((int)MouseButtonMask.Left, (int)MouseButtonMask.Wheel, 0);
  562.         }
  563.  
  564.         /// <summary>Called when the change device button is clicked</summary>
  565.         private void OnChangeDevicClicked(object sender, EventArgs e)
  566.         {
  567.             sampleFramework.ShowSettingsDialog(!sampleFramework.IsD3DSettingsDialogShowing);
  568.         }
  569.  
  570.         /// <summary>Called when the full screen button is clicked</summary>
  571.         private void OnFullscreenClicked(object sender, EventArgs e)
  572.         {
  573.             sampleFramework.ToggleFullscreen();
  574.         }
  575.  
  576.         /// <summary>Called when the ref button is clicked</summary>
  577.         private void OnRefClicked(object sender, EventArgs e)
  578.         {
  579.             sampleFramework.ToggleReference();
  580.         }
  581.  
  582.         /// <summary>Fired when the optimized checkbox is changed</summary>
  583.         private void OnOptimizedChanged(object sender, EventArgs e)
  584.         {
  585.             isShowingOptimized = (sender as Checkbox).IsChecked;
  586.         }
  587.  
  588.         /// <summary>Fired when the level of detail is changed</summary>
  589.         private void OnDetailChanged(object sender, EventArgs e)
  590.         {
  591.             SetNumberVertices((sender as Slider).Value);
  592.         }
  593.  
  594.         /// <summary>Sets the number of vertices for the progressive meshes</summary>
  595.         private void SetNumberVertices(int numberVerts)
  596.         {
  597.             // Update the full mesh first
  598.             fullMesh.NumberVertices = numberVerts;
  599.  
  600.             // If current pm valid for desired value, then set the number of vertices directly
  601.             if ( (numberVerts >= meshes[currentMeshIndex].MinVertices) &&
  602.                 (numberVerts <= meshes[currentMeshIndex].MaxVertices) )
  603.             {
  604.                 meshes[currentMeshIndex].NumberVertices = numberVerts;
  605.             }
  606.             else
  607.             {
  608.                 // Search for the right one
  609.                 currentMeshIndex = meshes.Length - 1;
  610.                 
  611.                 // Look for the correct "bin"
  612.                 while (currentMeshIndex > 0)
  613.                 {
  614.                     // If number of vertices is less than current max then we found one to fit
  615.                     if (numberVerts >= meshes[currentMeshIndex].MinVertices)
  616.                         break;
  617.  
  618.                     currentMeshIndex--;
  619.                 }
  620.  
  621.                 // Set the vertices on the newly selected mesh
  622.                 meshes[currentMeshIndex].NumberVertices = numberVerts;
  623.             }
  624.         }
  625.  
  626.         /// <summary>
  627.         /// Entry point to the program. Initializes everything and goes into a message processing 
  628.         /// loop. Idle time is used to render the scene.
  629.         /// </summary>
  630.         static int Main() 
  631.         {
  632.             using(Framework sampleFramework = new Framework())
  633.             {
  634.                 ProgressiveMeshes sample = new ProgressiveMeshes(sampleFramework);
  635.                 // Set the callback functions. These functions allow the sample framework to notify
  636.                 // the application about device changes, user input, and windows messages.  The 
  637.                 // callbacks are optional so you need only set callbacks for events you're interested 
  638.                 // in. However, if you don't handle the device reset/lost callbacks then the sample 
  639.                 // framework won't be able to reset your device since the application must first 
  640.                 // release all device resources before resetting.  Likewise, if you don't handle the 
  641.                 // device created/destroyed callbacks then the sample framework won't be able to 
  642.                 // recreate your device resources.
  643.                 sampleFramework.Disposing += new EventHandler(sample.OnDestroyDevice);
  644.                 sampleFramework.DeviceLost += new EventHandler(sample.OnLostDevice);
  645.                 sampleFramework.DeviceCreated += new DeviceEventHandler(sample.OnCreateDevice);
  646.                 sampleFramework.DeviceReset += new DeviceEventHandler(sample.OnResetDevice);
  647.  
  648.                 sampleFramework.SetKeyboardCallback(new KeyboardCallback(sample.OnKeyEvent));
  649.                 sampleFramework.SetWndProcCallback(new WndProcCallback(sample.OnMsgProc));
  650.  
  651.                 sampleFramework.SetCallbackInterface(sample);
  652.                 try
  653.                 {
  654.  
  655.                     // Show the cursor and clip it when in full screen
  656.                     sampleFramework.SetCursorSettings(true, true);
  657.  
  658.                     // Initialize
  659.                     sample.InitializeApplication();
  660.  
  661.                     // Initialize the sample framework and create the desired window and Direct3D 
  662.                     // device for the application. Calling each of these functions is optional, but they
  663.                     // allow you to set several options which control the behavior of the sampleFramework.
  664.                     sampleFramework.Initialize( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  665.                     sampleFramework.CreateWindow("ProgressiveMesh: Using Progressive Meshes in Direct3D");
  666.                     sampleFramework.CreateDevice( 0, true, Framework.DefaultSizeWidth, Framework.DefaultSizeHeight, 
  667.                         sample);
  668.  
  669.                     // Pass control to the sample framework for handling the message pump and 
  670.                     // dispatching render calls. The sample framework will call your FrameMove 
  671.                     // and FrameRender callback when there is idle time between handling window messages.
  672.                     sampleFramework.MainLoop();
  673.  
  674.                 }
  675. #if(DEBUG)
  676.                 catch (Exception e)
  677.                 {
  678.                     // In debug mode show this error (maybe - depending on settings)
  679.                     sampleFramework.DisplayErrorMessage(e);
  680. #else
  681.             catch
  682.             {
  683.                 // In release mode fail silently
  684. #endif
  685.                     // Ignore any exceptions here, they would have been handled by other areas
  686.                     return (sampleFramework.ExitCode == 0) ? 1 : sampleFramework.ExitCode; // Return an error code here
  687.                 }
  688.  
  689.                 // Perform any application-level cleanup here. Direct3D device resources are released within the
  690.                 // appropriate callback functions and therefore don't require any cleanup code here.
  691.                 return sampleFramework.ExitCode;
  692.             }
  693.         }
  694.     }
  695. }
  696.