UltimateZoneBuilder/Source/Rendering/D3DDevice.cs

541 lines
16 KiB
C#
Raw Normal View History

2007-06-15 18:30:55 +00:00
#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using System.Drawing;
using SlimDX.Direct3D9;
2007-06-15 18:30:55 +00:00
using System.ComponentModel;
2007-06-24 18:56:43 +00:00
using CodeImp.DoomBuilder.Geometry;
using SlimDX;
using CodeImp.DoomBuilder.Windows;
using CodeImp.DoomBuilder.Data;
using Configuration = CodeImp.DoomBuilder.IO.Configuration;
using CodeImp.DoomBuilder.Controls;
2007-06-15 18:30:55 +00:00
#endregion
namespace CodeImp.DoomBuilder.Rendering
{
2008-01-02 21:49:43 +00:00
internal class D3DDevice
2007-06-15 18:30:55 +00:00
{
#region ================== Constants
// NVPerfHUD device name
public const string NVPERFHUD_ADAPTER = "NVPerfHUD";
#endregion
#region ================== Variables
// Settings
private int adapter;
private Filter postfilter;
2007-06-15 18:30:55 +00:00
// Main objects
private static Direct3D d3d;
private RenderTargetControl rendertarget;
private Capabilities devicecaps;
2007-06-24 18:56:43 +00:00
private Device device;
private Viewport viewport;
private Dictionary<ID3DResource, ID3DResource> resources;
2007-10-19 17:05:21 +00:00
private ShaderManager shaders;
private Surface backbuffer;
private Surface depthbuffer;
private TextFont font;
private ResourceImage fonttexture;
2007-06-15 18:30:55 +00:00
// Disposing
private bool isdisposed = false;
#endregion
#region ================== Properties
2008-01-02 21:49:43 +00:00
internal Device Device { get { return device; } }
2007-06-15 18:30:55 +00:00
public bool IsDisposed { get { return isdisposed; } }
2008-01-02 21:49:43 +00:00
internal RenderTargetControl RenderTarget { get { return rendertarget; } }
internal Viewport Viewport { get { return viewport; } }
internal ShaderManager Shaders { get { return shaders; } }
internal Surface BackBuffer { get { return backbuffer; } }
internal Surface DepthBuffer { get { return depthbuffer; } }
internal TextFont Font { get { return font; } }
internal Texture FontTexture { get { return fonttexture.Texture; } }
internal Filter PostFilter { get { return postfilter; } }
2007-10-19 17:05:21 +00:00
2007-06-15 18:30:55 +00:00
#endregion
#region ================== Constructor / Disposer
// Constructor
2008-01-02 21:49:43 +00:00
internal D3DDevice(RenderTargetControl rendertarget)
2007-06-15 18:30:55 +00:00
{
// Set render target
this.rendertarget = rendertarget;
// Create resources list
resources = new Dictionary<ID3DResource, ID3DResource>();
2007-06-15 18:30:55 +00:00
// We have no destructor
GC.SuppressFinalize(this);
}
2008-01-02 21:49:43 +00:00
// Disposer
internal void Dispose()
2007-06-15 18:30:55 +00:00
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
foreach(ID3DResource res in resources.Values) res.UnloadResource();
2007-10-26 18:04:54 +00:00
if(shaders != null) shaders.Dispose();
2007-06-15 18:30:55 +00:00
rendertarget = null;
2007-10-26 18:04:54 +00:00
if(backbuffer != null) backbuffer.Dispose();
if(depthbuffer != null) depthbuffer.Dispose();
device.Dispose();
if(font != null) font.Dispose();
if(fonttexture != null) fonttexture.Dispose();
2007-06-15 18:30:55 +00:00
// Done
isdisposed = true;
}
}
#endregion
#region ================== Renderstates
// This completes initialization after the device has started or has been reset
2008-02-24 21:52:18 +00:00
public void SetupSettings()
2007-06-15 18:30:55 +00:00
{
// Setup renderstates
device.SetRenderState(RenderState.AlphaRef, 0x0000007E);
2007-11-10 19:24:52 +00:00
device.SetRenderState(RenderState.AlphaFunc, Compare.GreaterEqual);
device.SetRenderState(RenderState.AntialiasedLineEnable, false);
device.SetRenderState(RenderState.Ambient, Color.White.ToArgb());
device.SetRenderState(RenderState.AmbientMaterialSource, ColorSource.Material);
device.SetRenderState(RenderState.ColorWriteEnable, ColorWriteEnable.Red | ColorWriteEnable.Green | ColorWriteEnable.Blue | ColorWriteEnable.Alpha);
device.SetRenderState(RenderState.ColorVertex, false);
device.SetRenderState(RenderState.DiffuseMaterialSource, ColorSource.Color1);
device.SetRenderState(RenderState.FillMode, FillMode.Solid);
device.SetRenderState(RenderState.FogEnable, false);
device.SetRenderState(RenderState.Lighting, false);
device.SetRenderState(RenderState.LocalViewer, false);
device.SetRenderState(RenderState.NormalizeNormals, false);
device.SetRenderState(RenderState.SpecularEnable, false);
device.SetRenderState(RenderState.StencilEnable, false);
device.SetRenderState(RenderState.PointSpriteEnable, false);
device.SetRenderState(RenderState.DitherEnable, true);
device.SetRenderState(RenderState.AlphaBlendEnable, false);
device.SetRenderState(RenderState.ZEnable, false);
device.SetRenderState(RenderState.ZWriteEnable, false);
device.SetRenderState(RenderState.Clipping, true);
device.SetRenderState(RenderState.CullMode, Cull.None);
device.PixelShader = null;
device.VertexShader = null;
2007-06-15 18:30:55 +00:00
2008-05-18 11:43:28 +00:00
// Matrices
device.SetTransform(TransformState.World, Matrix.Identity);
device.SetTransform(TransformState.View, Matrix.Identity);
device.SetTransform(TransformState.Projection, Matrix.Identity);
2007-06-15 18:30:55 +00:00
// Sampler settings
if(General.Settings.ClassicBilinear)
{
device.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Linear);
device.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Linear);
device.SetSamplerState(0, SamplerState.MipFilter, TextureFilter.Linear);
device.SetSamplerState(0, SamplerState.MipMapLodBias, 0f);
}
else
{
device.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Point);
device.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Point);
device.SetSamplerState(0, SamplerState.MipFilter, TextureFilter.Point);
device.SetSamplerState(0, SamplerState.MipMapLodBias, 0f);
}
2007-10-21 04:07:36 +00:00
2007-06-15 18:30:55 +00:00
// Texture addressing
device.SetSamplerState(0, SamplerState.AddressU, TextureAddress.Wrap);
device.SetSamplerState(0, SamplerState.AddressV, TextureAddress.Wrap);
device.SetSamplerState(0, SamplerState.AddressW, TextureAddress.Wrap);
2007-06-15 18:30:55 +00:00
// First texture stage
2007-10-21 04:07:36 +00:00
device.SetTextureStageState(0, TextureStage.ColorOperation, TextureOperation.Modulate);
device.SetTextureStageState(0, TextureStage.ColorArg1, TextureArgument.Texture);
device.SetTextureStageState(0, TextureStage.ColorArg2, TextureArgument.Diffuse);
device.SetTextureStageState(0, TextureStage.ResultArg, TextureArgument.Current);
device.SetTextureStageState(0, TextureStage.TexCoordIndex, 0);
2007-06-15 18:30:55 +00:00
2008-02-24 21:52:18 +00:00
// Second texture stage
device.SetTextureStageState(1, TextureStage.ColorOperation, TextureOperation.Modulate);
device.SetTextureStageState(1, TextureStage.ColorArg1, TextureArgument.Current);
device.SetTextureStageState(1, TextureStage.ColorArg2, TextureArgument.TFactor);
device.SetTextureStageState(1, TextureStage.ResultArg, TextureArgument.Current);
device.SetTextureStageState(1, TextureStage.TexCoordIndex, 0);
2007-06-15 18:30:55 +00:00
// No more further stages
2008-02-24 21:52:18 +00:00
device.SetTextureStageState(2, TextureStage.ColorOperation, TextureOperation.Disable);
2007-06-15 18:30:55 +00:00
// First alpha stage
2007-10-21 04:07:36 +00:00
device.SetTextureStageState(0, TextureStage.AlphaOperation, TextureOperation.Modulate);
device.SetTextureStageState(0, TextureStage.AlphaArg1, TextureArgument.Texture);
device.SetTextureStageState(0, TextureStage.AlphaArg2, TextureArgument.Diffuse);
2008-02-24 21:52:18 +00:00
// Second alpha stage
device.SetTextureStageState(1, TextureStage.AlphaOperation, TextureOperation.Modulate);
device.SetTextureStageState(1, TextureStage.AlphaArg1, TextureArgument.Current);
device.SetTextureStageState(1, TextureStage.AlphaArg2, TextureArgument.TFactor);
2007-10-21 04:07:36 +00:00
2007-06-15 18:30:55 +00:00
// No more further stages
2008-02-24 21:52:18 +00:00
device.SetTextureStageState(2, TextureStage.AlphaOperation, TextureOperation.Disable);
2007-06-15 18:30:55 +00:00
// Setup material
Material material = new Material();
material.Ambient = new Color4(Color.White);
material.Diffuse = new Color4(Color.White);
material.Specular = new Color4(Color.White);
2007-06-24 18:56:43 +00:00
device.Material = material;
// Shader settings
shaders.World3D.SetConstants(General.Settings.VisualBilinear, true);
// Texture loading filter
if(General.Settings.QualityDisplay)
postfilter = Filter.Box;
else
postfilter = Filter.Linear;
// Initialize presentations
Presentation.Initialize();
2007-06-15 18:30:55 +00:00
}
#endregion
#region ================== Initialization
// This starts up Direct3D
public static void Startup()
{
d3d = new Direct3D();
}
// This terminates Direct3D
public static void Terminate()
{
if(d3d != null)
{
d3d.Dispose();
d3d = null;
}
}
2007-06-15 18:30:55 +00:00
// This initializes the graphics
public bool Initialize()
{
PresentParameters displaypp;
DeviceType devtype;
2007-06-15 18:30:55 +00:00
// Use default adapter
this.adapter = 0; // Manager.Adapters.Default.Adapter;
2007-06-15 18:30:55 +00:00
// Make present parameters
displaypp = CreatePresentParameters(adapter);
// Determine device type for compatability with NVPerfHUD
if(d3d.Adapters[adapter].Details.Description.EndsWith(NVPERFHUD_ADAPTER))
2007-06-15 18:30:55 +00:00
devtype = DeviceType.Reference;
else
devtype = DeviceType.Hardware;
// Get the device capabilities
devicecaps = d3d.GetDeviceCaps(adapter, devtype);
2007-06-15 18:30:55 +00:00
try
{
// Check if this adapter supports TnL
if((devicecaps.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0)
2007-06-15 18:30:55 +00:00
{
// Initialize with hardware TnL
device = new Device(d3d, adapter, devtype, rendertarget.Handle,
2007-06-15 18:30:55 +00:00
CreateFlags.HardwareVertexProcessing, displaypp);
}
else
{
// Initialize with software TnL
device = new Device(d3d, adapter, devtype, rendertarget.Handle,
2007-06-15 18:30:55 +00:00
CreateFlags.SoftwareVertexProcessing, displaypp);
}
}
catch(Exception)
{
// Failed
MessageBox.Show(General.MainWindow, "Unable to initialize the Direct3D video device. Another application may have taken exclusive mode on this video device.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
// Add event to cancel resize event
//device.DeviceResizing += new CancelEventHandler(CancelResize);
2008-02-24 21:52:18 +00:00
// Keep a reference to the original buffers
backbuffer = device.GetBackBuffer(0, 0);
depthbuffer = device.DepthStencilSurface;
2008-02-24 21:52:18 +00:00
// Get the viewport
viewport = device.Viewport;
// Create shader manager
shaders = new ShaderManager(this);
// Font
postfilter = Filter.Box;
font = new TextFont();
fonttexture = new ResourceImage("Font.png");
fonttexture.LoadImage();
fonttexture.MipMapLevels = 2;
fonttexture.CreateTexture();
2007-06-15 18:30:55 +00:00
// Initialize settings
SetupSettings();
// Done
return true;
}
// This is to disable the automatic resize reset
private static void CancelResize(object sender, CancelEventArgs e)
{
// Cancel resize event
e.Cancel = true;
}
// This creates present parameters
private PresentParameters CreatePresentParameters(int adapter)
{
PresentParameters displaypp = new PresentParameters();
DisplayMode currentmode;
// Get current display mode
currentmode = d3d.Adapters[adapter].CurrentDisplayMode;
2007-06-15 18:30:55 +00:00
// Make present parameters
displaypp.Windowed = true;
displaypp.SwapEffect = SwapEffect.Discard;
displaypp.BackBufferCount = 1;
displaypp.BackBufferFormat = currentmode.Format;
displaypp.BackBufferWidth = rendertarget.ClientSize.Width;
displaypp.BackBufferHeight = rendertarget.ClientSize.Height;
displaypp.EnableAutoDepthStencil = true;
displaypp.AutoDepthStencilFormat = Format.D16;
displaypp.Multisample = MultisampleType.None;
2007-06-15 18:30:55 +00:00
displaypp.PresentationInterval = PresentInterval.Immediate;
// Return result
return displaypp;
}
#endregion
#region ================== Resetting
// This registers a resource
2008-01-02 21:49:43 +00:00
internal void RegisterResource(ID3DResource res)
{
// Add resource
resources.Add(res, res);
}
// This unregisters a resource
2008-01-02 21:49:43 +00:00
internal void UnregisterResource(ID3DResource res)
{
// Remove resource
resources.Remove(res);
}
2007-06-15 18:30:55 +00:00
// This resets the device and returns true on success
2008-01-02 21:49:43 +00:00
internal bool Reset()
2007-06-15 18:30:55 +00:00
{
PresentParameters displaypp;
// Test the cooperative level
Result coopresult = device.TestCooperativeLevel();
2007-06-15 18:30:55 +00:00
// Can we reset?
//if(coopresult.Name != "D3DERR_DEVICENOTRESET")
2007-06-15 18:30:55 +00:00
{
// Unload all Direct3D resources
foreach(ID3DResource res in resources.Values) res.UnloadResource();
2007-06-15 18:30:55 +00:00
// Lose backbuffers
if(backbuffer != null) backbuffer.Dispose();
if(depthbuffer != null) depthbuffer.Dispose();
backbuffer = null;
depthbuffer = null;
2008-02-24 21:52:18 +00:00
// Make present parameters
displaypp = CreatePresentParameters(adapter);
2008-04-17 05:36:48 +00:00
try
{
// Reset the device
device.Reset(displaypp);
}
catch(Exception)
{
// Failed to re-initialize
return false;
}
2007-06-15 18:30:55 +00:00
// Keep a reference to the original buffers
backbuffer = device.GetBackBuffer(0, 0);
depthbuffer = device.DepthStencilSurface;
// Get the viewport
viewport = device.Viewport;
// Reload all Direct3D resources
foreach(ID3DResource res in resources.Values) res.ReloadResource();
// Re-apply settings
SetupSettings();
// Success
return true;
}
/*
else
{
// Failed
return false;
}
*/
2007-06-15 18:30:55 +00:00
}
#endregion
2007-06-24 18:56:43 +00:00
#region ================== Rendering
// This begins a drawing session
public bool StartRendering(bool clear, Color4 backcolor, Surface target, Surface depthbuffer)
2007-06-24 18:56:43 +00:00
{
// When minimized, do not render anything
if(General.MainWindow.WindowState != FormWindowState.Minimized)
{
// Test the cooperative level
Result coopresult = device.TestCooperativeLevel();
2007-06-24 18:56:43 +00:00
// Check if device must be reset
if(!coopresult.IsSuccess)
2007-06-24 18:56:43 +00:00
{
// Should we reset?
if(coopresult.Name == "D3DERR_DEVICENOTRESET")
{
// Device is lost and must be reset now
Reset();
}
// Impossible to render at this point
return false;
2007-06-24 18:56:43 +00:00
}
// Set rendertarget
device.DepthStencilSurface = depthbuffer;
device.SetRenderTarget(0, target);
2007-06-24 18:56:43 +00:00
// Clear the screen
if(clear)
{
if(depthbuffer != null)
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, backcolor, 1f, 0);
else
device.Clear(ClearFlags.Target, backcolor, 1f, 0);
}
2007-06-24 18:56:43 +00:00
// Ready to render
device.BeginScene();
return true;
}
else
{
// Minimized, you cannot see anything
return false;
}
}
// This ends a drawing session
public void FinishRendering()
2007-06-24 18:56:43 +00:00
{
try
{
// Done
device.EndScene();
}
// Errors are not a problem here
catch(Exception) { }
}
// This presents what has been drawn
public void Present()
{
try
{
device.Present();
}
// Errors are not a problem here
catch(Exception) { }
}
2007-06-24 18:56:43 +00:00
#endregion
#region ================== Tools
// Make a color from ARGB
public static int ARGB(float a, float r, float g, float b)
{
return Color.FromArgb((int)(a * 255f), (int)(r * 255f), (int)(g * 255f), (int)(b * 255f)).ToArgb();
}
// Make a color from RGB
public static int RGB(int r, int g, int b)
{
return Color.FromArgb(255, r, g, b).ToArgb();
}
// This makes a Vector3 from Vector3D
public static Vector3 V3(Vector3D v3d)
{
return new Vector3(v3d.x, v3d.y, v3d.z);
}
// This makes a Vector3D from Vector3
public static Vector3D V3D(Vector3 v3)
{
return new Vector3D(v3.X, v3.Y, v3.Z);
}
#endregion
2007-06-15 18:30:55 +00:00
}
}