/// <summary> /// Application constructor /// </summary> public BillboardForm() { // Set the window text this.Text = "Billboard: D3D Billboarding Example"; this.MinimizeBox = false; skyBoxMesh = new GraphicsMesh(); terrainMesh = new GraphicsMesh(); OnetimeSceneInitialization(); // Now let's setup our D3D parameters PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; presentParams.SwapEffect = SwapEffect.Discard; presentParams.AutoDepthStencilFormat = DepthFormat.D16; presentParams.EnableAutoDepthStencil = true; // create the device device = new Device(0, DeviceType.Default, this, CreateFlags.None, presentParams); // store the render state renderState = device.RenderState; // initialize any device resources that aren't lost on reset InitializeDeviceObjects(); // attach the reset callback device.DeviceReset += new EventHandler(RestoreDeviceObjects); // initialize any device resources that are lost on reset RestoreDeviceObjects(device, EventArgs.Empty); }
/// <summary> /// Renders the mesh /// </summary> /// <param name="canDrawOpaque">Enables drawing opaque portions /// of the mesh</param> /// <param name="canDrawAlpha">Enables drawing alpha blended portions /// of the mesh</param> public void Render(bool canDrawOpaque, bool canDrawAlpha) { RenderStateManager rs = device.RenderState; // Frist, draw the subsets without alpha if (canDrawOpaque) { for (int i = 0; i < meshMaterials.Length; i++) { if (canDrawAlpha) { if (meshMaterials[i].Diffuse.A < 0xff) { continue; } } // Set the material and texture for this subset device.Material = meshMaterials[i]; if (meshTextures[i] != null) { device.SetTexture(0, meshTextures[i]); } // Draw the mesh subset meshValue.DrawSubset(i); } } // Then, draw the subsets with alpha if (canDrawAlpha) { // Enable alpha blending rs.AlphaBlendEnable = true; rs.SourceBlend = Blend.SourceAlpha; rs.DestinationBlend = Blend.InvSourceAlpha; for (int i = 0; i < meshMaterials.Length; i++) { if (meshMaterials[i].Diffuse.A == 0xff) { continue; } // Set the material and texture for this subset device.Material = meshMaterials[i]; if (meshTextures[i] != null) { device.SetTexture(0, meshTextures[i]); } // Draw the mesh subset meshValue.DrawSubset(i); } // Restore state rs.AlphaBlendEnable = false; } }
/// <summary> /// Actually draw the mesh /// </summary> /// <param name="device">The device used to draw</param> /// <param name="canDrawOpaque">Can draw the opaque parts of the mesh</param> /// <param name="canDrawAlpha">Can draw the alpha parts of the mesh</param> public void Render(Device device, bool canDrawOpaque, bool canDrawAlpha) { if (null == localMemoryMesh) { throw new ArgumentException(); } RenderStateManager rs = device.RenderState; // Frist, draw the subsets without alpha if (canDrawOpaque) { for (int i = 0; i < materials.Length; i++) { if (isUsingMeshMaterials) { if (canDrawAlpha) { if (materials[i].DiffuseColor.Alpha < 0xff) { continue; } } device.Material = materials[i]; device.SetTexture(0, textures[i]); } localMemoryMesh.DrawSubset(i); } } // Then, draw the subsets with alpha if (canDrawAlpha && isUsingMeshMaterials) { // Enable alpha blending rs.AlphaBlendEnable = true; rs.SourceBlend = Blend.SourceAlpha; rs.DestinationBlend = Blend.InvSourceAlpha; for (int i = 0; i < materials.Length; i++) { if (materials[i].DiffuseColor.Alpha == 0xff) { continue; } // Set the material and texture device.Material = materials[i]; device.SetTexture(0, textures[i]); localMemoryMesh.DrawSubset(i); } // Restore state rs.AlphaBlendEnable = false; } }
/// <summary> /// Initialize the device objects /// </summary> /// <param name="dev">The grpahics device used to initialize</param> public void InitializeDeviceObjects(Device dev) { if (dev != null) { // Set up our events dev.DeviceReset += new System.EventHandler(this.RestoreDeviceObjects); } // Keep a local copy of the device device = dev; textureState0 = device.TextureState[0]; textureState1 = device.TextureState[1]; samplerState0 = device.SamplerState[0]; renderState = device.RenderState; // Create a bitmap on which to measure the alphabet Bitmap bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(bmp); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; g.TextContrast = 0; // Establish the font and texture size textureScale = 1.0f; // Draw fonts into texture without scaling // Calculate the dimensions for the smallest power-of-two texture which // can hold all the printable characters textureWidth = textureHeight = 128; for (;;) { try { // Measure the alphabet PaintAlphabet(g, true); } catch (System.InvalidOperationException) { // Scale up the texture size and try again textureWidth *= 2; textureHeight *= 2; continue; } break; } // If requested texture is too big, use a smaller texture and smaller font, // and scale up when rendering. Direct3D.Caps d3dCaps = device.DeviceCaps; // If the needed texture is too large for the video card... if (textureWidth > d3dCaps.MaxTextureWidth) { // Scale the font size down to fit on the largest possible texture textureScale = (float)d3dCaps.MaxTextureWidth / (float)textureWidth; textureWidth = textureHeight = d3dCaps.MaxTextureWidth; for(;;) { // Create a new, smaller font ourFontHeight = (int) Math.Floor(ourFontHeight * textureScale); systemFont = new System.Drawing.Font(systemFont.Name, ourFontHeight, systemFont.Style); try { // Measure the alphabet PaintAlphabet(g, true); } catch (System.InvalidOperationException) { // If that still doesn't fit, scale down again and continue textureScale *= 0.9F; continue; } break; } } // Release the bitmap used for measuring and create one for drawing bmp.Dispose(); bmp = new Bitmap(textureWidth, textureHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb); g = Graphics.FromImage(bmp); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; g.TextContrast = 0; // Draw the alphabet PaintAlphabet(g, false); // Create a new texture for the font from the bitmap we just created fontTexture = Texture.FromBitmap(device, bmp, 0, Pool.Managed); RestoreDeviceObjects(null, null); }
/// <summary> /// Initialize the device objects /// </summary> /// <param name="dev">The grpahics device used to initialize</param> public void InitializeDeviceObjects(Device dev) { if (dev != null) { // Set up our events dev.DeviceReset += new System.EventHandler(this.RestoreDeviceObjects); } // Keep a local copy of the device device = dev; textureState0 = device.TextureState[0]; textureState1 = device.TextureState[1]; samplerState0 = device.SamplerState[0]; renderState = device.RenderState; // Create a bitmap on which to measure the alphabet Bitmap bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(bmp); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; g.TextContrast = 0; // Establish the font and texture size textureScale = 1.0f; // Draw fonts into texture without scaling // Calculate the dimensions for the smallest power-of-two texture which // can hold all the printable characters textureWidth = textureHeight = 128; for (;;) { try { // Measure the alphabet PaintAlphabet(g, true); } catch (System.InvalidOperationException) { // Scale up the texture size and try again textureWidth *= 2; textureHeight *= 2; continue; } break; } // If requested texture is too big, use a smaller texture and smaller font, // and scale up when rendering. Direct3D.Caps d3dCaps = device.DeviceCaps; // If the needed texture is too large for the video card... if (textureWidth > d3dCaps.MaxTextureWidth) { // Scale the font size down to fit on the largest possible texture textureScale = (float)d3dCaps.MaxTextureWidth / (float)textureWidth; textureWidth = textureHeight = d3dCaps.MaxTextureWidth; for (;;) { // Create a new, smaller font ourFontHeight = (int)Math.Floor(ourFontHeight * textureScale); systemFont = new System.Drawing.Font(systemFont.Name, ourFontHeight, systemFont.Style); try { // Measure the alphabet PaintAlphabet(g, true); } catch (System.InvalidOperationException) { // If that still doesn't fit, scale down again and continue textureScale *= 0.9F; continue; } break; } } // Release the bitmap used for measuring and create one for drawing bmp.Dispose(); bmp = new Bitmap(textureWidth, textureHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb); g = Graphics.FromImage(bmp); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; g.TextContrast = 0; // Draw the alphabet PaintAlphabet(g, false); // Create a new texture for the font from the bitmap we just created fontTexture = Texture.FromBitmap(device, bmp, 0, Pool.Managed); RestoreDeviceObjects(null, null); }
/// <summary> /// Initialize the device objects /// </summary> /// <param name="dev">The grpahics device used to initialize</param> public void InitializeDeviceObjects(Device dev) { if (dev != null) { // Set up our events dev.DeviceReset += new System.EventHandler(this.RestoreDeviceObjects); } // Keep a local copy of the device device = dev; textureState0 = device.TextureState[0]; textureState1 = device.TextureState[1]; samplerState0 = device.SamplerState[0]; renderState = device.RenderState; // Establish the font and texture size textureScale = 1.0f; // Draw fonts into texture without scaling // Large fonts need larger textures if (ourFontHeight > 60) { textureWidth = textureHeight = 2048; } else if (ourFontHeight > 30) { textureWidth = textureHeight = 1024; } else if (ourFontHeight > 15) { textureWidth = textureHeight = 512; } else { textureWidth = textureHeight = 256; } // If requested texture is too big, use a smaller texture and smaller font, // and scale up when rendering. Direct3D.Caps d3dCaps = device.DeviceCaps; if (textureWidth > d3dCaps.MaxTextureWidth) { textureScale = (float)d3dCaps.MaxTextureWidth / (float)textureWidth; textureWidth = textureHeight = d3dCaps.MaxTextureWidth; } Bitmap bmp = new Bitmap(textureWidth, textureHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(bmp); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; g.TextContrast = 0; string str; float x = 0; float y = 0; Point p = new Point(0, 0); Size size = new Size(0, 0); // Calculate the spacing between characters based on line height size = g.MeasureString(" ", systemFont).ToSize(); x = spacingPerChar = (int)Math.Ceiling(size.Height * 0.3); for (char c = (char)32; c < (char)127; c++) { str = c.ToString(); // We need to do some things here to get the right sizes. The default implemententation of MeasureString // will return a resolution independant size. For our height, this is what we want. However, for our width, we // want a resolution dependant size. Size resSize = g.MeasureString(str, systemFont).ToSize(); size.Height = resSize.Height + 1; // Now the Resolution independent width if (c != ' ') // We need the special case here because a space has a 0 width in GenericTypoGraphic stringformats { resSize = g.MeasureString(str, systemFont, p, StringFormat.GenericTypographic).ToSize(); size.Width = resSize.Width; } else { size.Width = resSize.Width; } if ((x + size.Width + spacingPerChar) > textureWidth) { x = spacingPerChar; y += size.Height; } if (c != ' ') // We need the special case here because a space has a 0 width in GenericTypoGraphic stringformats { g.DrawString(str, systemFont, Brushes.White, new Point((int)x, (int)y), StringFormat.GenericTypographic); } else { g.DrawString(str, systemFont, Brushes.White, new Point((int)x, (int)y)); } textureCoords[c - 32, 0] = ((float)(x + 0 - spacingPerChar)) / textureWidth; textureCoords[c - 32, 1] = ((float)(y + 0 + 0)) / textureHeight; textureCoords[c - 32, 2] = ((float)(x + size.Width + spacingPerChar)) / textureWidth; textureCoords[c - 32, 3] = ((float)(y + size.Height + 0)) / textureHeight; x += size.Width + (2 * spacingPerChar); } // Create a new texture for the font from the bitmap we just created fontTexture = Texture.FromBitmap(device, bmp, 0, Pool.Managed); RestoreDeviceObjects(null, null); }
/// <summary> /// Initialize the graphics environment /// </summary> public void InitializeEnvironment() { GraphicsAdapterInfo adapterInfo = graphicsSettings.AdapterInfo; GraphicsDeviceInfo deviceInfo = graphicsSettings.DeviceInfo; windowed = graphicsSettings.IsWindowed; // Set up the presentation parameters BuildPresentParamsFromSettings(); if (deviceInfo.Caps.PrimitiveMiscCaps.IsNullReference) { // Warn user about null ref device that can't render anything HandleSampleException(new NullReferenceDeviceException(), ApplicationMessage.None); } CreateFlags createFlags = new CreateFlags(); if (graphicsSettings.VertexProcessingType == VertexProcessingType.Software) createFlags = CreateFlags.SoftwareVertexProcessing; else if (graphicsSettings.VertexProcessingType == VertexProcessingType.Mixed) createFlags = CreateFlags.MixedVertexProcessing; else if (graphicsSettings.VertexProcessingType == VertexProcessingType.Hardware) createFlags = CreateFlags.HardwareVertexProcessing; else if (graphicsSettings.VertexProcessingType == VertexProcessingType.PureHardware) { createFlags = CreateFlags.HardwareVertexProcessing; } else throw new ApplicationException(); #if (DX9) #else // Make sure to allow multithreaded apps if we need them presentParams.ForceNoMultiThreadedFlag = !isMultiThreaded; #endif try { // Create the device device = new Device(graphicsSettings.AdapterOrdinal, graphicsSettings.DevType, windowed ? ourRenderTarget : this , createFlags, presentParams); // Cache our local objects renderState = device.RenderState; sampleState = device.SamplerState; textureStates = device.TextureState; // When moving from fullscreen to windowed mode, it is important to // adjust the window size after recreating the device rather than // beforehand to ensure that you get the window size you want. For // example, when switching from 640x480 fullscreen to windowed with // a 1000x600 window on a 1024x768 desktop, it is impossible to set // the window size to 1000x600 until after the display mode has // changed to 1024x768, because windows cannot be larger than the // desktop. if (windowed) { // Make sure main window isn't topmost, so error message is visible System.Drawing.Size currentClientSize = this.ClientSize; this.Size = this.ClientSize; this.SendToBack(); this.BringToFront(); this.ClientSize = currentClientSize; } // Store device Caps graphicsCaps = device.DeviceCaps; behavior = createFlags; System.Text.StringBuilder sb = new System.Text.StringBuilder(); // Store device description if (deviceInfo.DevType == DeviceType.Reference) sb.Append("REF"); else if (deviceInfo.DevType == DeviceType.Hardware) sb.Append("HAL"); else if (deviceInfo.DevType == DeviceType.Software) sb.Append("SW"); BehaviorFlags behaviorFlags = new BehaviorFlags(createFlags); if ((behaviorFlags.HardwareVertexProcessing) && (behaviorFlags.PureDevice)) { if (deviceInfo.DevType == DeviceType.Hardware) sb.Append(" (pure hw vp)"); else sb.Append(" (simulated pure hw vp)"); } else if (behaviorFlags.HardwareVertexProcessing) { if (deviceInfo.DevType == DeviceType.Hardware) sb.Append(" (hw vp)"); else sb.Append(" (simulated hw vp)"); } else if (behaviorFlags.MixedVertexProcessing) { if (deviceInfo.DevType == DeviceType.Hardware) sb.Append(" (mixed vp)"); else sb.Append(" (simulated mixed vp)"); } else if (behaviorFlags.SoftwareVertexProcessing) { sb.Append(" (sw vp)"); } if (deviceInfo.DevType == DeviceType.Hardware) { sb.Append(": "); sb.Append(adapterInfo.AdapterDetails.Description); } // Set device stats string deviceStats = sb.ToString(); // Set up the fullscreen cursor if (showCursorWhenFullscreen && !windowed) { System.Windows.Forms.Cursor ourCursor = this.Cursor; device.SetCursor(ourCursor, true); device.ShowCursor(true); } // Confine cursor to fullscreen window if (clipCursorWhenFullscreen) { if (!windowed) { System.Drawing.Rectangle rcWindow = this.ClientRectangle; } } // Setup the event handlers for our device device.DeviceLost += new System.EventHandler(this.InvalidateDeviceObjects); device.DeviceReset += new System.EventHandler(this.RestoreDeviceObjects); device.Disposing += new System.EventHandler(this.DeleteDeviceObjects); device.DeviceResizing += new System.ComponentModel.CancelEventHandler(this.EnvironmentResized); // Initialize the app's device-dependent objects try { InitializeDeviceObjects(); RestoreDeviceObjects(null, null); active = true; return; } catch { // Cleanup before we try again InvalidateDeviceObjects(null, null); DeleteDeviceObjects(null, null); device.Dispose(); device = null; if (this.Disposing) return; } } catch { // If that failed, fall back to the reference rasterizer if (deviceInfo.DevType == DeviceType.Hardware) { if (FindBestWindowedMode(false, true)) { windowed = true; // Make sure main window isn't topmost, so error message is visible System.Drawing.Size currentClientSize = this.ClientSize; this.Size = this.ClientSize; this.SendToBack(); this.BringToFront(); this.ClientSize = currentClientSize; // Let the user know we are switching from HAL to the reference rasterizer HandleSampleException(null, ApplicationMessage.WarnSwitchToRef); InitializeEnvironment(); } } } }