mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-30 15:41:30 +00:00
bafb8ed511
Texture scale controls now have "Link" button. Thing, Sector (UDMF) and Linedef edit forms now work in realtime mode. Some more fixes in Edit form realtime update stuff. Removed some unused variables and functions.
580 lines
17 KiB
C#
580 lines
17 KiB
C#
|
|
#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.Generic;
|
|
using System.Windows.Forms;
|
|
using System.Drawing;
|
|
using SlimDX.Direct3D9;
|
|
using System.ComponentModel;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using SlimDX;
|
|
using CodeImp.DoomBuilder.Data;
|
|
using CodeImp.DoomBuilder.Controls;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.Rendering
|
|
{
|
|
internal class D3DDevice
|
|
{
|
|
#region ================== Constants
|
|
|
|
// NVPerfHUD device name
|
|
public const string NVPERFHUD_ADAPTER = "NVPerfHUD";
|
|
|
|
#endregion
|
|
|
|
#region ================== Variables
|
|
|
|
// Settings
|
|
private int adapter;
|
|
private Filter postfilter;
|
|
private Filter mipgeneratefilter;
|
|
|
|
// Main objects
|
|
private static Direct3D d3d;
|
|
private RenderTargetControl rendertarget;
|
|
private Capabilities devicecaps;
|
|
private Device device;
|
|
private Viewport viewport;
|
|
private Dictionary<ID3DResource, ID3DResource> resources;
|
|
private ShaderManager shaders;
|
|
private Surface backbuffer;
|
|
private Surface depthbuffer;
|
|
private TextFont font;
|
|
private ResourceImage fonttexture;
|
|
|
|
// Disposing
|
|
private bool isdisposed = false;
|
|
|
|
#endregion
|
|
|
|
#region ================== Properties
|
|
|
|
internal Device Device { get { return device; } }
|
|
public bool IsDisposed { get { return isdisposed; } }
|
|
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; } }
|
|
internal Filter MipGenerateFilter { get { return mipgeneratefilter; } }
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
// Constructor
|
|
internal D3DDevice(RenderTargetControl rendertarget)
|
|
{
|
|
// Set render target
|
|
this.rendertarget = rendertarget;
|
|
|
|
// Create resources list
|
|
resources = new Dictionary<ID3DResource, ID3DResource>();
|
|
|
|
// We have no destructor
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
// Disposer
|
|
internal void Dispose()
|
|
{
|
|
// Not already disposed?
|
|
if(!isdisposed)
|
|
{
|
|
// Clean up
|
|
foreach(ID3DResource res in resources.Values) res.UnloadResource();
|
|
if(shaders != null) shaders.Dispose();
|
|
rendertarget = null;
|
|
if(backbuffer != null) backbuffer.Dispose();
|
|
if(depthbuffer != null) depthbuffer.Dispose();
|
|
if(device != null) device.Dispose();
|
|
if(font != null) font.Dispose();
|
|
if(fonttexture != null) fonttexture.Dispose();
|
|
|
|
// Done
|
|
isdisposed = true;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Renderstates
|
|
|
|
// This completes initialization after the device has started or has been reset
|
|
public void SetupSettings()
|
|
{
|
|
// Setup renderstates
|
|
device.SetRenderState(RenderState.AlphaBlendEnable, false);
|
|
device.SetRenderState(RenderState.AlphaBlendEnable, false);
|
|
device.SetRenderState(RenderState.AlphaFunc, Compare.GreaterEqual);
|
|
device.SetRenderState(RenderState.AlphaRef, 0x0000007E);
|
|
device.SetRenderState(RenderState.AlphaTestEnable, false);
|
|
device.SetRenderState(RenderState.Ambient, Color.White.ToArgb());
|
|
device.SetRenderState(RenderState.AmbientMaterialSource, ColorSource.Material);
|
|
device.SetRenderState(RenderState.AntialiasedLineEnable, false);
|
|
device.SetRenderState(RenderState.Clipping, true);
|
|
device.SetRenderState(RenderState.ColorVertex, false);
|
|
device.SetRenderState(RenderState.ColorWriteEnable, ColorWriteEnable.Red | ColorWriteEnable.Green | ColorWriteEnable.Blue | ColorWriteEnable.Alpha);
|
|
device.SetRenderState(RenderState.CullMode, Cull.None);
|
|
device.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha);
|
|
device.SetRenderState(RenderState.DiffuseMaterialSource, ColorSource.Color1);
|
|
device.SetRenderState(RenderState.DitherEnable, true);
|
|
device.SetRenderState(RenderState.FillMode, FillMode.Solid);
|
|
device.SetRenderState(RenderState.FogEnable, false);
|
|
device.SetRenderState(RenderState.FogTableMode, FogMode.Linear);
|
|
device.SetRenderState(RenderState.Lighting, false);
|
|
device.SetRenderState(RenderState.LocalViewer, false);
|
|
device.SetRenderState(RenderState.NormalizeNormals, false);
|
|
device.SetRenderState(RenderState.PointSpriteEnable, false);
|
|
device.SetRenderState(RenderState.RangeFogEnable, false);
|
|
device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha);
|
|
device.SetRenderState(RenderState.SpecularEnable, false);
|
|
device.SetRenderState(RenderState.StencilEnable, false);
|
|
device.SetRenderState(RenderState.TextureFactor, -1);
|
|
device.SetRenderState(RenderState.ZEnable, false);
|
|
device.SetRenderState(RenderState.ZWriteEnable, false);
|
|
device.PixelShader = null;
|
|
device.VertexShader = null;
|
|
|
|
// Matrices
|
|
device.SetTransform(TransformState.World, Matrix.Identity);
|
|
device.SetTransform(TransformState.View, Matrix.Identity);
|
|
device.SetTransform(TransformState.Projection, Matrix.Identity);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Texture addressing
|
|
device.SetSamplerState(0, SamplerState.AddressU, TextureAddress.Wrap);
|
|
device.SetSamplerState(0, SamplerState.AddressV, TextureAddress.Wrap);
|
|
device.SetSamplerState(0, SamplerState.AddressW, TextureAddress.Wrap);
|
|
|
|
// First texture stage
|
|
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);
|
|
|
|
// 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);
|
|
|
|
// No more further stages
|
|
device.SetTextureStageState(2, TextureStage.ColorOperation, TextureOperation.Disable);
|
|
|
|
// First alpha stage
|
|
device.SetTextureStageState(0, TextureStage.AlphaOperation, TextureOperation.Modulate);
|
|
device.SetTextureStageState(0, TextureStage.AlphaArg1, TextureArgument.Texture);
|
|
device.SetTextureStageState(0, TextureStage.AlphaArg2, TextureArgument.Diffuse);
|
|
|
|
// Second alpha stage
|
|
device.SetTextureStageState(1, TextureStage.AlphaOperation, TextureOperation.Modulate);
|
|
device.SetTextureStageState(1, TextureStage.AlphaArg1, TextureArgument.Current);
|
|
device.SetTextureStageState(1, TextureStage.AlphaArg2, TextureArgument.TFactor);
|
|
|
|
// No more further stages
|
|
device.SetTextureStageState(2, TextureStage.AlphaOperation, TextureOperation.Disable);
|
|
|
|
// Setup material
|
|
Material material = new Material();
|
|
material.Ambient = new Color4(Color.White);
|
|
material.Diffuse = new Color4(Color.White);
|
|
material.Specular = new Color4(Color.White);
|
|
device.Material = material;
|
|
|
|
// Shader settings
|
|
shaders.World3D.SetConstants(General.Settings.VisualBilinear, true, General.Settings.FilterAnisotropy);
|
|
|
|
// Texture filters
|
|
postfilter = Filter.Point;
|
|
mipgeneratefilter = Filter.Box;
|
|
|
|
// Initialize presentations
|
|
Presentation.Initialize();
|
|
}
|
|
|
|
#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;
|
|
}
|
|
}
|
|
|
|
// This initializes the graphics
|
|
public bool Initialize()
|
|
{
|
|
PresentParameters displaypp;
|
|
DeviceType devtype;
|
|
|
|
// Use default adapter
|
|
this.adapter = 0; // Manager.Adapters.Default.Adapter;
|
|
|
|
try
|
|
{
|
|
// Make present parameters
|
|
displaypp = CreatePresentParameters(adapter);
|
|
|
|
// Determine device type for compatability with NVPerfHUD
|
|
if(d3d.Adapters[adapter].Details.Description.EndsWith(NVPERFHUD_ADAPTER))
|
|
devtype = DeviceType.Reference;
|
|
else
|
|
devtype = DeviceType.Hardware;
|
|
|
|
// Get the device capabilities
|
|
devicecaps = d3d.GetDeviceCaps(adapter, devtype);
|
|
|
|
// Check if this adapter supports TnL
|
|
if((devicecaps.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0)
|
|
{
|
|
// Initialize with hardware TnL
|
|
device = new Device(d3d, adapter, devtype, rendertarget.Handle,
|
|
CreateFlags.HardwareVertexProcessing, displaypp);
|
|
}
|
|
else
|
|
{
|
|
// Initialize with software TnL
|
|
device = new Device(d3d, adapter, devtype, rendertarget.Handle,
|
|
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 or the device does not support Direct3D at all.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
return false;
|
|
}
|
|
|
|
// Add event to cancel resize event
|
|
//device.DeviceResizing += new CancelEventHandler(CancelResize);
|
|
|
|
// Keep a reference to the original buffers
|
|
backbuffer = device.GetBackBuffer(0, 0);
|
|
depthbuffer = device.DepthStencilSurface;
|
|
|
|
// Get the viewport
|
|
viewport = device.Viewport;
|
|
|
|
// Create shader manager
|
|
shaders = new ShaderManager(this);
|
|
|
|
// Font
|
|
postfilter = Filter.Box; // Only for the font. This will be reset in SetupSettings (see below)
|
|
font = new TextFont();
|
|
fonttexture = new ResourceImage("CodeImp.DoomBuilder.Resources.Font.png");
|
|
fonttexture.LoadImage();
|
|
fonttexture.MipMapLevels = 2;
|
|
fonttexture.CreateTexture();
|
|
|
|
// 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;
|
|
|
|
// 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;
|
|
displaypp.PresentationInterval = PresentInterval.Immediate;
|
|
|
|
// Return result
|
|
return displaypp;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Resetting
|
|
|
|
// This registers a resource
|
|
internal void RegisterResource(ID3DResource res)
|
|
{
|
|
// Add resource
|
|
resources.Add(res, res);
|
|
}
|
|
|
|
// This unregisters a resource
|
|
internal void UnregisterResource(ID3DResource res)
|
|
{
|
|
// Remove resource
|
|
resources.Remove(res);
|
|
}
|
|
|
|
// This resets the device and returns true on success
|
|
internal bool Reset()
|
|
{
|
|
// Test the cooperative level
|
|
//Result coopresult = device.TestCooperativeLevel();
|
|
|
|
// Can we reset?
|
|
//if(coopresult.Name != "D3DERR_DEVICENOTRESET")
|
|
{
|
|
// Unload all Direct3D resources
|
|
foreach(ID3DResource res in resources.Values) res.UnloadResource();
|
|
|
|
// Lose backbuffers
|
|
if(backbuffer != null) backbuffer.Dispose();
|
|
if(depthbuffer != null) depthbuffer.Dispose();
|
|
backbuffer = null;
|
|
depthbuffer = null;
|
|
|
|
// Make present parameters
|
|
PresentParameters displaypp = CreatePresentParameters(adapter);
|
|
|
|
try
|
|
{
|
|
// Reset the device
|
|
device.Reset(displaypp);
|
|
}
|
|
catch(Exception)
|
|
{
|
|
// Failed to re-initialize
|
|
return false;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
*/
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Rendering
|
|
|
|
// This begins a drawing session
|
|
public bool StartRendering(bool clear, Color4 backcolor, Surface target, Surface depthbuffer)
|
|
{
|
|
// Check if we can render
|
|
if(CheckAvailability())
|
|
{
|
|
// Set rendertarget
|
|
device.DepthStencilSurface = depthbuffer;
|
|
device.SetRenderTarget(0, target);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Ready to render
|
|
device.BeginScene();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Minimized, you cannot see anything
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// This clears a target
|
|
public void ClearRendertarget(Color4 backcolor, Surface target, Surface depthbuffer)
|
|
{
|
|
// Set rendertarget
|
|
device.DepthStencilSurface = depthbuffer;
|
|
device.SetRenderTarget(0, target);
|
|
|
|
if(depthbuffer != null)
|
|
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, backcolor, 1f, 0);
|
|
else
|
|
device.Clear(ClearFlags.Target, backcolor, 1f, 0);
|
|
}
|
|
|
|
// This ends a drawing session
|
|
public void FinishRendering()
|
|
{
|
|
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) { }
|
|
}
|
|
|
|
// This checks if we can use the hardware at this moment
|
|
public bool CheckAvailability()
|
|
{
|
|
// When minimized, the hardware is not available
|
|
if(General.MainWindow.WindowState != FormWindowState.Minimized)
|
|
{
|
|
// Test the cooperative level
|
|
Result coopresult = device.TestCooperativeLevel();
|
|
|
|
// Check if device must be reset
|
|
if(!coopresult.IsSuccess)
|
|
{
|
|
// 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;
|
|
}
|
|
else
|
|
{
|
|
// Read to go!
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Minimized
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#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);
|
|
}
|
|
|
|
// This makes a Vector2 from Vector2D
|
|
public static Vector2 V2(Vector2D v2d)
|
|
{
|
|
return new Vector2(v2d.x, v2d.y);
|
|
}
|
|
|
|
// This makes a Vector2D from Vector2
|
|
public static Vector2D V2D(Vector2 v2)
|
|
{
|
|
return new Vector2D(v2.X, v2.Y);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|