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

  1. //-----------------------------------------------------------------------------
  2. // File: BasicHLSL.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 BasicHLSLSample
  19. {
  20.     /// <summary>Class for rendering a 3d scene using basic HLSL</summary>
  21.     public class BasicHLSL : IFrameworkCallback, IDeviceCreation
  22.     {
  23.         #region Creation
  24.         /// <summary>Create a new instance of the class</summary>
  25.         public BasicHLSL(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.         // constants
  36.         private static readonly ColorValue WhiteColor = new ColorValue(1.0f,1.0f,1.0f,1.0f);
  37.         private static readonly ColorValue YellowColor = new ColorValue(1.0f,1.0f,0.0f,1.0f);
  38.  
  39.         // Variables
  40.         private Framework sampleFramework = null; // Framework for samples
  41.         private Font statsFont = null; // Font for drawing text
  42.         private Sprite textSprite = null; // Sprite for batching text calls
  43.         private Effect effect = null; // D3DX Effect Interface
  44.         private ModelViewerCamera camera = new ModelViewerCamera(); // A model viewing camera
  45.         private Mesh mesh = null; // The mesh object
  46.         private Texture meshTexture = null; // The meshes texture
  47.         private bool isHelpShowing = true; // If true, renders the UI help text
  48.         private bool isUsingPreshader; // If false, the NoPreshader flag is used when compiling the shader
  49.         private Dialog hud; // dialog for standard controls
  50.         private Dialog sampleUi; // dialog for sample specific controls
  51.         private Matrix worldFix;
  52.         
  53.         // Light stuff
  54.         DirectionWidget[] lightControl = new DirectionWidget[MaxNumberLights];
  55.         private const int MaxNumberLights = 3;
  56.         private float lightScale;
  57.         private int numberActiveLights;
  58.         private int activeLight;
  59.  
  60.         // HUD Ui Control constants
  61.         private const int ToggleFullscreen = 1;
  62.         private const int ToggleReference = 3;
  63.         private const int ChangeDevice = 4;
  64.         private const int EnablePreshader = 5;
  65.         private const int NumberLights = 6;
  66.         private const int NumberLightsStatic = 7;
  67.         private const int ActiveLightControl = 8;
  68.         private const int LightScaleControl = 9;
  69.         private const int LightScaleStatic = 10;
  70.  
  71.         /// <summary>
  72.         /// Called during device initialization, this code checks the device for some 
  73.         /// minimum set of capabilities, and rejects those that don't pass by returning false.
  74.         /// </summary>
  75.         public bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool windowed)
  76.         {
  77.             // No fallback defined by this app, so reject any device that 
  78.             // doesn't support at least ps1.1
  79.             if (caps.PixelShaderVersion < new Version(1,1))
  80.                 return false;
  81.  
  82.             // Skip back buffer formats that don't support alpha blending
  83.             if (!Manager.CheckDeviceFormat(caps.AdapterOrdinal, caps.DeviceType, adapterFormat, 
  84.                 Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backBufferFormat))
  85.                 return false;
  86.  
  87.             return true;
  88.         }
  89.  
  90.         /// <summary>
  91.         /// This callback function is called immediately before a device is created to allow the 
  92.         /// application to modify the device settings. The supplied settings parameter 
  93.         /// contains the settings that the framework has selected for the new device, and the 
  94.         /// application can make any desired changes directly to this structure.  Note however that 
  95.         /// the sample framework will not correct invalid device settings so care must be taken 
  96.         /// to return valid device settings, otherwise creating the Device will fail.  
  97.         /// </summary>
  98.         public void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
  99.         {
  100.             // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  101.             // then switch to SWVP.
  102.             if ( (!caps.DeviceCaps.SupportsHardwareTransformAndLight) ||
  103.                 (caps.VertexShaderVersion < new Version(1,1)) )
  104.             {
  105.                 settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing;
  106.             }
  107.             else
  108.             {
  109.                 settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
  110.             }
  111.  
  112.             // This application is designed to work on a pure device by not using 
  113.             // any get methods, so create a pure device if supported and using HWVP.
  114.             if ( (caps.DeviceCaps.SupportsPureDevice) && 
  115.                 ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) )
  116.                 settings.BehaviorFlags |= CreateFlags.PureDevice;
  117.  
  118.             // Debugging vertex shaders requires either REF or software vertex processing 
  119.             // and debugging pixel shaders requires REF.  
  120. #if(DEBUG_VS)
  121.             if (settings.DeviceType != DeviceType.Reference )
  122.             {
  123.                 settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing;
  124.                 settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
  125.             }
  126. #endif
  127. #if(DEBUG_PS)
  128.             settings.DeviceType = DeviceType.Reference;
  129. #endif
  130.  
  131.         }
  132.  
  133.         /// <summary>
  134.         /// This event will be fired immediately after the Direct3D device has been 
  135.         /// created, which will happen during application initialization and windowed/full screen 
  136.         /// toggles. This is the best location to create Pool.Managed resources since these 
  137.         /// resources need to be reloaded whenever the device is destroyed. Resources created  
  138.         /// here should be released in the Disposing event. 
  139.         /// </summary>
  140.         private void OnCreateDevice(object sender, DeviceEventArgs e)
  141.         {
  142.             // Initialize the stats font
  143.             statsFont = ResourceCache.GetGlobalInstance().CreateFont(e.Device, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default,
  144.                 Precision.Default, FontQuality.Default, PitchAndFamily.FamilyDoNotCare | PitchAndFamily.DefaultPitch
  145.                 , "Arial");
  146.  
  147.             // Load the mesh
  148.             mesh = LoadMesh(e.Device, "tiny\\tiny.x");
  149.  
  150.             // Calculate a bounding sphere
  151.             float radius = 0.0f;
  152.             using (GraphicsStream data = mesh.LockVertexBuffer(LockFlags.None))
  153.             {
  154.                 Vector3 center;
  155.                 radius = Geometry.ComputeBoundingSphere(data, mesh.NumberVertices, mesh.VertexFormat, out center);
  156.  
  157.                 worldFix = Matrix.Translation(-center);
  158.                 worldFix *= Matrix.RotationY((float)Math.PI);
  159.                 worldFix *= Matrix.RotationX((float)Math.PI / 2.0f);
  160.  
  161.                 // Setup direction widget
  162.                 DirectionWidget.OnCreateDevice(e.Device);
  163.                 for(int i = 0; i < MaxNumberLights; i++)
  164.                     lightControl[i].Radius = radius;
  165.                 
  166.                 // Finally unlock the vertex buffer
  167.                 mesh.UnlockVertexBuffer();
  168.             }
  169.  
  170.             // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  171.             // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  172.             // processing, and debugging pixel shaders requires REF.  The 
  173.             // ShaderFlags.Force*SoftwareNoOptimizations flag improves the debug experience in the 
  174.             // shader debugger.  It enables source level debugging, prevents instruction 
  175.             // reordering, prevents dead code elimination, and forces the compiler to compile 
  176.             // against the next higher available software target, which ensures that the 
  177.             // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  178.             // flags will cause slower rendering since the shaders will be unoptimized and 
  179.             // forced into software.  See the DirectX documentation for more information about 
  180.             // using the shader debugger.
  181.             ShaderFlags shaderFlags = ShaderFlags.None;
  182. #if(DEBUG_VS)
  183.             shaderFlags |= ShaderFlags.ForceVertexShaderSoftwareNoOptimizations;
  184. #endif
  185. #if(DEBUG_PS)
  186.             shaderFlags |= ShaderFlags.ForcePixelShaderSoftwareNoOptimizations;
  187. #endif
  188.             // Preshaders are parts of the shader that the effect system pulls out of the 
  189.             // shader and runs on the host CPU. They should be used if you are GPU limited. 
  190.             // The ShaderFlags.NoPreShader flag disables preshaders.
  191.             if (!isUsingPreshader)
  192.                 shaderFlags |= ShaderFlags.NoPreShader;
  193.  
  194.             // Read the D3DX effect file
  195.             string path = Utility.FindMediaFile("BasicHLSL.fx");
  196.             effect = ResourceCache.GetGlobalInstance().CreateEffectFromFile(e.Device,
  197.                 path, null, null, shaderFlags, null);
  198.  
  199.             // Create the mesh texture from a file
  200.             path = Utility.FindMediaFile("tiny\\tiny_skin.bmp");
  201.             meshTexture = ResourceCache.GetGlobalInstance().CreateTextureFromFile(e.Device, path);
  202.  
  203.             // Set effect variables as needed
  204.             effect.SetValue("g_MaterialAmbientColor", new ColorValue(0.35f, 0.35f, 0.35f, 0));
  205.             effect.SetValue("g_MaterialDiffuseColor", WhiteColor);
  206.             effect.SetValue("g_MeshTexture", meshTexture);
  207.  
  208.             // Setup the camera's view parameters
  209.             camera.SetViewParameters(new Vector3(0.0f, 0.0f, -15.0f), Vector3.Empty);
  210.             camera.SetRadius(radius * 3.0f, radius * 0.5f, radius * 10.0f);
  211.         }
  212.         
  213.         /// <summary>
  214.         /// This event will be fired immediately after the Direct3D device has been 
  215.         /// reset, which will happen after a lost device scenario. This is the best location to 
  216.         /// create Pool.Default resources since these resources need to be reloaded whenever 
  217.         /// the device is lost. Resources created here should be released in the OnLostDevice 
  218.         /// event. 
  219.         /// </summary>
  220.         private void OnResetDevice(object sender, DeviceEventArgs e)
  221.         {
  222.             SurfaceDescription desc = e.BackBufferDescription;
  223.             // Create a sprite to help batch calls when drawing many lines of text
  224.             textSprite = new Sprite(e.Device);
  225.  
  226.             // Reset items
  227.             for (int i = 0; i < MaxNumberLights; i++)
  228.                 lightControl[i].OnResetDevice(desc);
  229.  
  230.             // Setup the camera's projection parameters
  231.             float aspectRatio = (float)desc.Width / (float)desc.Height;
  232.             camera.SetProjectionParameters((float)Math.PI / 4, aspectRatio, 0.1f, 5000.0f);
  233.             camera.SetWindow(desc.Width, desc.Height);
  234.             camera.SetButtonMasks((int)MouseButtonMask.Left, (int)MouseButtonMask.Wheel, (int)MouseButtonMask.Middle);
  235.  
  236.             // Setup UI locations
  237.             hud.SetLocation(desc.Width-170, 0);
  238.             hud.SetSize(170,170);
  239.             sampleUi.SetLocation(desc.Width - 170, desc.Height - 300);
  240.             sampleUi.SetSize(170,300);
  241.         }
  242.  
  243.         /// <summary>
  244.         /// This event function will be called fired after the Direct3D device has 
  245.         /// entered a lost state and before Device.Reset() is called. Resources created
  246.         /// in the OnResetDevice callback should be released here, which generally includes all 
  247.         /// Pool.Default resources. See the "Lost Devices" section of the documentation for 
  248.         /// information about lost devices.
  249.         /// </summary>
  250.         private void OnLostDevice(object sender, EventArgs e)
  251.         {
  252.             if (textSprite != null)
  253.             {
  254.                 textSprite.Dispose();
  255.                 textSprite = null;
  256.             }
  257.  
  258.             // Update the direction widget
  259.             DirectionWidget.OnLostDevice();
  260.         }
  261.  
  262.         /// <summary>
  263.         /// This event will be fired immediately after the Direct3D device has 
  264.         /// been destroyed, which generally happens as a result of application termination or 
  265.         /// windowed/full screen toggles. Resources created in the OnCreateDevice event 
  266.         /// should be released here, which generally includes all Pool.Managed resources. 
  267.         /// </summary>
  268.         private void OnDestroyDevice(object sender, EventArgs e)
  269.         {
  270.             // Update the direction widget
  271.             DirectionWidget.OnDestroyDevice();
  272.             if (mesh != null)
  273.                 mesh.Dispose();
  274.         }
  275.  
  276.         /// <summary>
  277.         /// This callback function will be called once at the beginning of every frame. This is the
  278.         /// best location for your application to handle updates to the scene, but is not 
  279.         /// intended to contain actual rendering calls, which should instead be placed in the 
  280.         /// OnFrameRender callback.  
  281.         /// </summary>
  282.         public void OnFrameMove(Device device, double appTime, float elapsedTime)
  283.         {
  284.             // Update the camera's position based on user input 
  285.             camera.FrameMove(elapsedTime);
  286.         }
  287.  
  288.         /// <summary>
  289.         /// This callback function will be called at the end of every frame to perform all the 
  290.         /// rendering calls for the scene, and it will also be called if the window needs to be 
  291.         /// repainted. After this function has returned, the sample framework will call 
  292.         /// Device.Present to display the contents of the next buffer in the swap chain
  293.         /// </summary>
  294.         public unsafe void OnFrameRender(Device device, double appTime, float elapsedTime)
  295.         {
  296.             bool beginSceneCalled = false;
  297.  
  298.             // Clear the render target and the zbuffer 
  299.             device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, unchecked((int)0x8C003F3F), 1.0f, 0);
  300.             try
  301.             {
  302.                 device.BeginScene();
  303.                 beginSceneCalled = true;
  304.  
  305.                 Vector3* pLightDir = stackalloc Vector3[MaxNumberLights];
  306.                 ColorValue* pLightDiffuse = stackalloc ColorValue[MaxNumberLights];
  307.  
  308.                 // Render the arrows so the user can visually see the light direction
  309.                 for (int i = 0; i < numberActiveLights; i++)
  310.                 {
  311.                     ColorValue arrowColor = (i == activeLight) ? YellowColor : WhiteColor;
  312.                     lightControl[i].OnRender(arrowColor, camera.ViewMatrix, camera.ProjectionMatrix, camera.EyeLocation);
  313.                     // Get the light direction and color
  314.                     pLightDir[i] = lightControl[i].LightDirection;
  315.                     pLightDiffuse[i] = ColorOperator.Scale(WhiteColor, lightScale);
  316.                 }
  317.  
  318.                 Matrix worldMatrix = worldFix * camera.WorldMatrix;
  319.                 // Update the effects now
  320.                 effect.SetValue("g_LightDir", pLightDir, sizeof(Vector3) * MaxNumberLights);
  321.                 effect.SetValue("g_LightDiffuse", pLightDiffuse, sizeof(ColorValue) * MaxNumberLights);
  322.  
  323.                 // Update the effect's variables.  Instead of using strings, it would 
  324.                 // be more efficient to cache a handle to the parameter by calling 
  325.                 // Effect.GetParameter
  326.                 effect.SetValue("worldViewProjection", worldMatrix * camera.ViewMatrix * camera.ProjectionMatrix);
  327.                 effect.SetValue("worldMatrix", worldMatrix);
  328.                 effect.SetValue("appTime", (float)appTime);
  329.  
  330.                 effect.SetValue("g_MaterialDiffuseColor", WhiteColor);
  331.                 effect.SetValue("g_nNumLights", numberActiveLights);
  332.  
  333.                 // Render the scene with this technique as defined in the .fx file
  334.                 switch(numberActiveLights)
  335.                 {
  336.                     case 1: effect.Technique = "RenderSceneWithTexture1Light"; break;
  337.                     case 2: effect.Technique = "RenderSceneWithTexture2Light"; break;
  338.                     case 3: effect.Technique = "RenderSceneWithTexture3Light"; break;
  339.                 }
  340.  
  341.                 // Apply the technique contained in the effect 
  342.                 int passes = effect.Begin(0);
  343.                 for (int pass = 0; pass < passes; pass++)
  344.                 {
  345.                     effect.BeginPass(pass);
  346.  
  347.                     // The effect interface queues up the changes and performs them 
  348.                     // with the CommitChanges call. You do not need to call CommitChanges if 
  349.                     // you are not setting any parameters between the BeginPass and EndPass.
  350.                     // effect.CommitChanges() );
  351.  
  352.                     // Render the mesh with the applied technique
  353.                     mesh.DrawSubset(0);
  354.                     effect.EndPass();
  355.                 }
  356.                 effect.End();
  357.  
  358.                 // Show frame rate and help, etc
  359.                 RenderText(appTime);
  360.  
  361.                 // Show UI
  362.                 hud.OnRender(elapsedTime);
  363.                 sampleUi.OnRender(elapsedTime);
  364.             }
  365.             finally
  366.             {
  367.                 if (beginSceneCalled)
  368.                     device.EndScene();
  369.             }
  370.         }
  371.  
  372.         /// <summary>
  373.         /// Render the help and statistics text. This function uses the Font object for 
  374.         /// efficient text rendering.
  375.         /// </summary>
  376.         private void RenderText(double appTime)
  377.         {
  378.             TextHelper txtHelper = new TextHelper(statsFont, textSprite, 15);
  379.  
  380.             // Output statistics
  381.             txtHelper.Begin();
  382.             txtHelper.SetInsertionPoint(2,0);
  383.             txtHelper.SetForegroundColor(unchecked((int)0xffffff00));
  384.             txtHelper.DrawTextLine(sampleFramework.FrameStats);
  385.             txtHelper.DrawTextLine(sampleFramework.DeviceStats);
  386.  
  387.             txtHelper.SetForegroundColor(unchecked((int)0xffffffff));
  388.             txtHelper.DrawTextLine("appTime: {0} sin(appTime): {1}", appTime.ToString("f2",
  389.                 System.Globalization.CultureInfo.CurrentUICulture), Math.Sin(appTime).ToString("f4",
  390.                 System.Globalization.CultureInfo.CurrentUICulture));
  391.  
  392.             // Draw help
  393.             if (isHelpShowing)
  394.             {
  395.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*6);
  396.                 txtHelper.SetForegroundColor(System.Drawing.Color.DarkOrange);
  397.                 txtHelper.DrawTextLine("Controls (F1 to hide):");
  398.  
  399.                 txtHelper.SetInsertionPoint(20, sampleFramework.BackBufferSurfaceDescription.Height-15*5);
  400.                 txtHelper.DrawTextLine("Rotate model: Left mouse button");
  401.                 txtHelper.DrawTextLine("Rotate light: Right mouse button");
  402.                 txtHelper.DrawTextLine("Rotate camera: Middle mouse button");
  403.                 txtHelper.DrawTextLine("Zoom camera: Mouse wheel scroll");
  404.  
  405.                 txtHelper.SetInsertionPoint(250, sampleFramework.BackBufferSurfaceDescription.Height-15*5);
  406.                 txtHelper.DrawTextLine("Hide help: F1");
  407.                 txtHelper.DrawTextLine("Quit: Esc");
  408.             }
  409.             else
  410.             {
  411.                 txtHelper.SetForegroundColor(unchecked((int)0xffffffff));
  412.                 txtHelper.DrawTextLine("Press F1 for help");
  413.             }
  414.  
  415.             txtHelper.End();
  416.         }
  417.  
  418.         /// <summary>
  419.         /// As a convenience, the sample framework inspects the incoming windows messages for
  420.         /// keystroke messages and decodes the message parameters to pass relevant keyboard
  421.         /// messages to the application.  The framework does not remove the underlying keystroke 
  422.         /// messages, which are still passed to the application's MsgProc callback.
  423.         /// </summary>
  424.         private void OnKeyEvent(System.Windows.Forms.Keys key, bool isKeyDown, bool isKeyUp)
  425.         {
  426.             if (isKeyDown)
  427.             {
  428.                 switch(key)
  429.                 {
  430.                     case System.Windows.Forms.Keys.F1:
  431.                         isHelpShowing = !isHelpShowing;
  432.                         break;
  433.                 }
  434.             }
  435.         }
  436.  
  437.         /// <summary>
  438.         /// Before handling window messages, the sample framework passes incoming windows 
  439.         /// messages to the application through this callback function. If the application sets 
  440.         /// noFurtherProcessing to true, the sample framework will not process the message
  441.         /// </summary>
  442.         public IntPtr OnMsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool noFurtherProcessing)
  443.         {
  444.             // Give the dialog a chance to handle the message first
  445.             noFurtherProcessing = hud.MessageProc(hWnd, msg, wParam, lParam);
  446.             if (noFurtherProcessing)
  447.                 return IntPtr.Zero;
  448.  
  449.             noFurtherProcessing = sampleUi.MessageProc(hWnd, msg, wParam, lParam);
  450.             if (noFurtherProcessing)
  451.                 return IntPtr.Zero;
  452.  
  453.             // Give the light control a chance now
  454.             lightControl[activeLight].HandleMessages(hWnd, msg, wParam, lParam);
  455.  
  456.             // Pass all remaining windows messages to camera so it can respond to user input
  457.             camera.HandleMessages(hWnd, msg, wParam, lParam);
  458.  
  459.             return IntPtr.Zero;
  460.         }
  461.  
  462.         /// <summary>
  463.         /// This function loads the mesh and ensures the mesh has normals; it also optimizes the 
  464.         /// mesh for the graphics card's vertex cache, which improves performance by organizing 
  465.         /// the internal triangle list for less cache misses.
  466.         /// </summary>
  467.         private Mesh LoadMesh(Device device, string filename)
  468.         {
  469.             // Load the mesh with D3DX and get back a Mesh.  For this
  470.             // sample we'll ignore the X file's embedded materials since we know 
  471.             // exactly the model we're loading.  See the mesh samples such as
  472.             // "OptimizedMesh" for a more generic mesh loading example.
  473.             string path = Utility.FindMediaFile(filename);
  474.             Mesh m = Mesh.FromFile(path, MeshFlags.Managed, device);
  475.  
  476.             // Make sure there are normals which are required for lighting
  477.             if ((m.VertexFormat & VertexFormats.Normal) == 0)
  478.             {
  479.                 // Clone the mesh
  480.                 Mesh tempMesh = null;
  481.                 using(m)
  482.                 {
  483.                     tempMesh = m.Clone(m.Options.Value, m.VertexFormat | VertexFormats.Normal,
  484.                         device);
  485.                     // Compute the normals
  486.                     tempMesh.ComputeNormals();
  487.                 }
  488.                 m = tempMesh;
  489.             }
  490.  
  491.             // Optimize the mesh for this graphics card's vertex cache 
  492.             // so when rendering the mesh's triangle list the vertices will 
  493.             // cache hit more often so it won't have to re-execute the vertex shader 
  494.             // on those vertices so it will improve perf.     
  495.             int[] adj = m.ConvertPointRepsToAdjacency(null as GraphicsStream);
  496.             m.OptimizeInPlace(MeshFlags.OptimizeVertexCache, adj);
  497.  
  498.             // return the mesh
  499.             return m;
  500.         }
  501.  
  502.         /// <summary>Initializes the application</summary>
  503.         public void InitializeApplication()
  504.         {
  505.             isUsingPreshader = true;
  506.  
  507.             for (int i = 0; i < MaxNumberLights; i++)
  508.             {
  509.                 lightControl[i] = new DirectionWidget();
  510.                 lightControl[i].LightDirection = new Vector3((float)Math.Sin((float)Math.PI
  511.                     * 2 * i / MaxNumberLights-(float)Math.PI/6), 0, -(float)Math.Cos((float)Math.PI
  512.                     * 2 * i / MaxNumberLights-(float)Math.PI/6));
  513.             }
  514.  
  515.             activeLight = 0;
  516.             numberActiveLights = 1;
  517.             lightScale = 1.0f;
  518.  
  519.             int y = 10;
  520.             // Initialize the dialogs
  521.             Button fullScreen = hud.AddButton(ToggleFullscreen,"Toggle full screen", 35, y, 125,22);
  522.             Button toggleRef = hud.AddButton(ToggleReference,"Toggle reference (F3)", 35, y += 24, 125,22);
  523.             Button changeDevice = hud.AddButton(ChangeDevice,"Change Device (F2)", 35, y += 24, 125,22);
  524.             // Hook the button events for when these items are clicked
  525.             fullScreen.Click += new EventHandler(OnFullscreenClicked);
  526.             toggleRef.Click += new EventHandler(OnRefClicked);
  527.             changeDevice.Click += new EventHandler(OnChangeDevicClicked);
  528.  
  529.             // Now add the sample specific UI
  530.             y = 10;
  531.             sampleUi.AddStatic(NumberLightsStatic, string.Format("# Lights: {0}", numberActiveLights), 35, y += 24, 125, 22);
  532.             Slider lightSlider = sampleUi.AddSlider(NumberLights,50, y += 24, 100, 22, 1, MaxNumberLights, numberActiveLights, false);
  533.             
  534.             y += 24;
  535.             sampleUi.AddStatic(LightScaleStatic, string.Format("Light scale: {0}", lightScale.ToString("f2", 
  536.                 System.Globalization.CultureInfo.CurrentUICulture)), 35, y += 24, 125, 22);
  537.             Slider scaleSlider = sampleUi.AddSlider(LightScaleControl,50, y += 24, 100, 22, 0, 20, (int)(lightScale * 10.0f), false);
  538.             
  539.             y += 24;
  540.             Button activeLightControl = sampleUi.AddButton(ActiveLightControl, "Change active light (K)", 35, y += 24, 125, 22,
  541.                 System.Windows.Forms.Keys.K, false);
  542.             Checkbox preShader = sampleUi.AddCheckBox(EnablePreshader, "Enable preshaders", 35, y += 24, 125, 22, isUsingPreshader);
  543.  
  544.             // Hook the events
  545.             preShader.Changed += new EventHandler(OnPreshaderClick);
  546.             lightSlider.ValueChanged += new EventHandler(OnNumberLightsChanged);
  547.             activeLightControl.Click += new EventHandler(OnActiveLightClick);
  548.             scaleSlider.ValueChanged += new EventHandler(OnLightScaleChanged);
  549.         }
  550.  
  551.         /// <summary>Called when the light scale has changed</summary>
  552.         private void OnLightScaleChanged(object sender, EventArgs e)
  553.         {
  554.             Slider sl = sender as Slider;
  555.             lightScale = (float)(sl.Value * 0.10f);
  556.  
  557.             StaticText text = sampleUi.GetStaticText(LightScaleStatic);
  558.             text.SetText(string.Format("Light scale: {0}", lightScale.ToString("f2",
  559.                 System.Globalization.CultureInfo.CurrentUICulture)));
  560.         }
  561.  
  562.         /// <summary>Called when active light button has been clicked</summary>
  563.         private void OnActiveLightClick(object sender, EventArgs e)
  564.         {
  565.             if (!lightControl[activeLight].IsBeingDragged)
  566.             {
  567.                 activeLight++;
  568.                 activeLight %= numberActiveLights;
  569.             }
  570.         }
  571.  
  572.         /// <summary>Called when the number of lights has changed</summary>
  573.         private void OnNumberLightsChanged(object sender, EventArgs e)
  574.         {
  575.             if (!lightControl[activeLight].IsBeingDragged)
  576.             {
  577.                 StaticText text = sampleUi.GetStaticText(NumberLightsStatic);
  578.                 Slider lights = sampleUi.GetSlider(NumberLights);
  579.  
  580.                 numberActiveLights = lights.Value;
  581.  
  582.                 text.SetText(string.Format("# Lights: {0}", numberActiveLights));
  583.  
  584.                 activeLight %= numberActiveLights;
  585.             }
  586.         }
  587.  
  588.         /// <summary>Called when the pre-shader button is changed</summary>
  589.         private void OnPreshaderClick(object sender, EventArgs e)
  590.         {
  591.             Checkbox cb = sender as Checkbox;
  592.             isUsingPreshader = cb.IsChecked;
  593.  
  594.             if (sampleFramework.Device != null)
  595.             {
  596.                 // Destroy and recreate the objects to update the preshader stuff
  597.                 OnLostDevice(null, EventArgs.Empty);
  598.                 OnDestroyDevice(null, EventArgs.Empty);
  599.                 OnCreateDevice(null, new DeviceEventArgs(sampleFramework.Device, sampleFramework.BackBufferSurfaceDescription));
  600.                 OnResetDevice(null, new DeviceEventArgs(sampleFramework.Device, sampleFramework.BackBufferSurfaceDescription));
  601.             }
  602.         }
  603.  
  604.         /// <summary>Called when the change device button is clicked</summary>
  605.         private void OnChangeDevicClicked(object sender, EventArgs e)
  606.         {
  607.             sampleFramework.ShowSettingsDialog(!sampleFramework.IsD3DSettingsDialogShowing);
  608.         }
  609.  
  610.         /// <summary>Called when the full screen button is clicked</summary>
  611.         private void OnFullscreenClicked(object sender, EventArgs e)
  612.         {
  613.             sampleFramework.ToggleFullscreen();
  614.         }
  615.  
  616.         /// <summary>Called when the ref button is clicked</summary>
  617.         private void OnRefClicked(object sender, EventArgs e)
  618.         {
  619.             sampleFramework.ToggleReference();
  620.         }
  621.  
  622.         /// <summary>
  623.         /// Entry point to the program. Initializes everything and goes into a message processing 
  624.         /// loop. Idle time is used to render the scene.
  625.         /// </summary>
  626.         static int Main() 
  627.         {
  628.             using(Framework sampleFramework = new Framework())
  629.             {
  630.                 BasicHLSL sample = new BasicHLSL(sampleFramework);
  631.                 // Set the callback functions. These functions allow the sample framework to notify
  632.                 // the application about device changes, user input, and windows messages.  The 
  633.                 // callbacks are optional so you need only set callbacks for events you're interested 
  634.                 // in. However, if you don't handle the device reset/lost callbacks then the sample 
  635.                 // framework won't be able to reset your device since the application must first 
  636.                 // release all device resources before resetting.  Likewise, if you don't handle the 
  637.                 // device created/destroyed callbacks then the sample framework won't be able to 
  638.                 // recreate your device resources.
  639.                 sampleFramework.Disposing += new EventHandler(sample.OnDestroyDevice);
  640.                 sampleFramework.DeviceLost += new EventHandler(sample.OnLostDevice);
  641.                 sampleFramework.DeviceCreated += new DeviceEventHandler(sample.OnCreateDevice);
  642.                 sampleFramework.DeviceReset += new DeviceEventHandler(sample.OnResetDevice);
  643.  
  644.                 sampleFramework.SetKeyboardCallback(new KeyboardCallback(sample.OnKeyEvent));
  645.                 sampleFramework.SetWndProcCallback(new WndProcCallback(sample.OnMsgProc));
  646.  
  647.                 sampleFramework.SetCallbackInterface(sample);
  648.                 try
  649.                 {
  650.  
  651.                     // Show the cursor and clip it when in full screen
  652.                     sampleFramework.SetCursorSettings(true, true);
  653.  
  654.                     // Initialize
  655.                     sample.InitializeApplication();
  656.  
  657.                     // Initialize the sample framework and create the desired window and Direct3D 
  658.                     // device for the application. Calling each of these functions is optional, but they
  659.                     // allow you to set several options which control the behavior of the sampleFramework.
  660.                     sampleFramework.Initialize( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  661.                     sampleFramework.CreateWindow("BasicHLSL");
  662.                     sampleFramework.CreateDevice( 0, true, Framework.DefaultSizeWidth, Framework.DefaultSizeHeight, 
  663.                         sample);
  664.  
  665.                     // Pass control to the sample framework for handling the message pump and 
  666.                     // dispatching render calls. The sample framework will call your FrameMove 
  667.                     // and FrameRender callback when there is idle time between handling window messages.
  668.                     sampleFramework.MainLoop();
  669.  
  670.                 }
  671. #if(DEBUG)
  672.                 catch (Exception e)
  673.                 {
  674.                     // In debug mode show this error (maybe - depending on settings)
  675.                     sampleFramework.DisplayErrorMessage(e);
  676. #else
  677.             catch
  678.             {
  679.                 // In release mode fail silently
  680. #endif
  681.                     // Ignore any exceptions here, they would have been handled by other areas
  682.                     return (sampleFramework.ExitCode == 0) ? 1 : sampleFramework.ExitCode; // Return an error code here
  683.                 }
  684.  
  685.                 // Perform any application-level cleanup here. Direct3D device resources are released within the
  686.                 // appropriate callback functions and therefore don't require any cleanup code here.
  687.                 return sampleFramework.ExitCode;
  688.             }
  689.         }
  690.     }
  691. }
  692.