2009-04-19 18:07:22 +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 System.ComponentModel ;
using SlimDX ;
using CodeImp.DoomBuilder.Geometry ;
using SlimDX.Direct3D9 ;
using CodeImp.DoomBuilder.Data ;
using CodeImp.DoomBuilder.VisualModes ;
using CodeImp.DoomBuilder.Map ;
2012-04-17 19:13:47 +00:00
//mxd
using ColladaDotNet.Pipeline.MD3 ;
using CodeImp.DoomBuilder.GZBuilder.Data ;
2009-04-19 18:07:22 +00:00
#endregion
namespace CodeImp.DoomBuilder.Rendering
{
internal sealed class Renderer3D : Renderer , IRenderer3D
{
#region = = = = = = = = = = = = = = = = = = Constants
private const int RENDER_PASSES = 4 ;
private const float PROJ_NEAR_PLANE = 1f ;
private const float CROSSHAIR_SCALE = 0.06f ;
private const float FOG_RANGE = 0.9f ;
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
// Matrices
private Matrix projection ;
private Matrix view3d ;
private Matrix billboard ;
private Matrix worldviewproj ;
private Matrix view2d ;
private Matrix world ;
private Vector3D cameraposition ;
private int shaderpass ;
// Options
private bool fullbrightness ;
// Window size
private Size windowsize ;
// Frustum
private ProjectedFrustum2D frustum ;
// Thing cage
2012-04-17 19:13:47 +00:00
//private VertexBuffer thingcage;
2012-04-18 19:34:11 +00:00
private bool renderthingcages ;
//mxd
private ThingBoundingBox bbox ;
private List < VisualThing > thingsWithLight ;
private int [ ] lightOffsets ;
private Dictionary < Texture , List < VisualGeometry > > litGeometry ;
private Dictionary < ModelDefEntry , List < VisualThing > > thingsWithModel ;
//dbg
2012-04-23 21:35:48 +00:00
//int geoSkipped = 0;
//int totalGeo = 0;
//int totalThings = 0;
2009-04-19 18:07:22 +00:00
// Crosshair
private FlatVertex [ ] crosshairverts ;
private bool crosshairbusy ;
// Highlighting
private IVisualPickable highlighted ;
private float highlightglow ;
2009-05-05 21:13:50 +00:00
private float highlightglowinv ;
2009-05-04 06:13:56 +00:00
private ColorImage highlightimage ;
private ColorImage selectionimage ;
2009-07-07 14:52:39 +00:00
private bool showselection ;
private bool showhighlight ;
2009-04-19 18:07:22 +00:00
// Geometry to be rendered.
// Each Dictionary in the array is a render pass.
// Each BinaryHeap in the Dictionary contains all geometry that needs
// to be rendered with the associated ImageData.
// The BinaryHeap sorts the geometry by sector to minimize stream switchs.
private Dictionary < ImageData , BinaryHeap < VisualGeometry > > [ ] geometry ;
// Things to be rendered.
// Each Dictionary in the array is a render pass.
// Each VisualThing is inserted in the Dictionary by their texture image.
private Dictionary < ImageData , List < VisualThing > > [ ] things ;
// Things to be rendered, sorted by distance from camera
private BinaryHeap < VisualThing > thingsbydistance ;
2012-04-17 19:13:47 +00:00
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
public ProjectedFrustum2D Frustum2D { get { return frustum ; } }
public bool DrawThingCages { get { return renderthingcages ; } set { renderthingcages = value ; } }
public bool FullBrightness { get { return fullbrightness ; } set { fullbrightness = value ; } }
2009-07-07 14:52:39 +00:00
public bool ShowSelection { get { return showselection ; } set { showselection = value ; } }
public bool ShowHighlight { get { return showhighlight ; } set { showhighlight = value ; } }
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// Constructor
internal Renderer3D ( D3DDevice graphics ) : base ( graphics )
{
// Initialize
CreateProjection ( ) ;
CreateMatrices2D ( ) ;
SetupThingCage ( ) ;
2009-05-04 06:13:56 +00:00
SetupTextures ( ) ;
2009-04-19 18:07:22 +00:00
renderthingcages = true ;
2009-07-07 14:52:39 +00:00
showselection = true ;
showhighlight = true ;
2009-04-19 18:07:22 +00:00
// Dummy frustum
frustum = new ProjectedFrustum2D ( new Vector2D ( ) , 0.0f , 0.0f , PROJ_NEAR_PLANE ,
General . Settings . ViewDistance , Angle2D . DegToRad ( ( float ) General . Settings . VisualFOV ) ) ;
// We have no destructor
GC . SuppressFinalize ( this ) ;
}
// Disposer
internal override void Dispose ( )
{
// Not already disposed?
if ( ! isdisposed )
{
// Clean up
2012-04-17 19:13:47 +00:00
//mxd
//if(thingcage != null) thingcage.Dispose();
if ( bbox ! = null ) bbox . Dispose ( ) ;
2009-05-04 06:13:56 +00:00
if ( selectionimage ! = null ) selectionimage . Dispose ( ) ;
if ( highlightimage ! = null ) highlightimage . Dispose ( ) ;
2012-04-17 19:13:47 +00:00
//mxd
//thingcage = null;
bbox = null ;
2009-05-04 06:13:56 +00:00
selectionimage = null ;
highlightimage = null ;
2009-04-19 18:07:22 +00:00
// Done
base . Dispose ( ) ;
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Management
// This is called before a device is reset
// (when resized or display adapter was changed)
public override void UnloadResource ( )
{
crosshairverts = null ;
2012-04-17 19:13:47 +00:00
//mxd
//if(thingcage != null) thingcage.Dispose();
if ( bbox ! = null ) bbox . Dispose ( ) ;
2009-05-04 06:13:56 +00:00
if ( selectionimage ! = null ) selectionimage . Dispose ( ) ;
if ( highlightimage ! = null ) highlightimage . Dispose ( ) ;
2012-04-17 19:13:47 +00:00
//mxd
//thingcage = null;
bbox = null ;
2009-05-04 06:13:56 +00:00
selectionimage = null ;
highlightimage = null ;
2009-04-19 18:07:22 +00:00
}
// This is called resets when the device is reset
// (when resized or display adapter was changed)
public override void ReloadResource ( )
{
CreateMatrices2D ( ) ;
SetupThingCage ( ) ;
2009-05-04 06:13:56 +00:00
SetupTextures ( ) ;
2009-04-19 18:07:22 +00:00
}
// This makes screen vertices for display
private void CreateCrosshairVerts ( Size texturesize )
{
// Determine coordinates
float width = ( float ) windowsize . Width ;
float height = ( float ) windowsize . Height ;
float size = ( float ) height * CROSSHAIR_SCALE ;
RectangleF rect = new RectangleF ( ( width - size ) / 2 , ( height - size ) / 2 , size , size ) ;
// Make vertices
crosshairverts = new FlatVertex [ 4 ] ;
crosshairverts [ 0 ] . x = rect . Left ;
crosshairverts [ 0 ] . y = rect . Top ;
crosshairverts [ 0 ] . c = - 1 ;
crosshairverts [ 0 ] . u = 1f / texturesize . Width ;
crosshairverts [ 0 ] . v = 1f / texturesize . Height ;
crosshairverts [ 1 ] . x = rect . Right ;
crosshairverts [ 1 ] . y = rect . Top ;
crosshairverts [ 1 ] . c = - 1 ;
crosshairverts [ 1 ] . u = 1f - 1f / texturesize . Width ;
crosshairverts [ 1 ] . v = 1f / texturesize . Height ;
crosshairverts [ 2 ] . x = rect . Left ;
crosshairverts [ 2 ] . y = rect . Bottom ;
crosshairverts [ 2 ] . c = - 1 ;
crosshairverts [ 2 ] . u = 1f / texturesize . Width ;
crosshairverts [ 2 ] . v = 1f - 1f / texturesize . Height ;
crosshairverts [ 3 ] . x = rect . Right ;
crosshairverts [ 3 ] . y = rect . Bottom ;
crosshairverts [ 3 ] . c = - 1 ;
crosshairverts [ 3 ] . u = 1f - 1f / texturesize . Width ;
crosshairverts [ 3 ] . v = 1f - 1f / texturesize . Height ;
}
#endregion
2009-05-04 06:13:56 +00:00
#region = = = = = = = = = = = = = = = = = = Resources
2009-04-19 18:07:22 +00:00
2009-05-04 06:13:56 +00:00
// This loads the textures for highlight and selection if we need them
private void SetupTextures ( )
{
if ( ! graphics . Shaders . Enabled )
{
highlightimage = new ColorImage ( General . Colors . Highlight , 32 , 32 ) ;
highlightimage . LoadImage ( ) ;
highlightimage . CreateTexture ( ) ;
selectionimage = new ColorImage ( General . Colors . Selection , 32 , 32 ) ;
selectionimage . LoadImage ( ) ;
selectionimage . CreateTexture ( ) ;
}
}
2009-04-19 18:07:22 +00:00
// This sets up the thing cage
2012-04-17 19:13:47 +00:00
/ * private void SetupThingCage ( )
2009-04-19 18:07:22 +00:00
{
const int totalvertices = 36 ;
WorldVertex [ ] tv = new WorldVertex [ totalvertices ] ;
float x0 = - 1.0f ;
float x1 = 1.0f ;
float y0 = - 1.0f ;
float y1 = 1.0f ;
float z0 = 0.0f ;
float z1 = 1.0f ;
float u0 = 0.0f ;
float u1 = 1.0f ;
float v0 = 0.0f ;
float v1 = 1.0f ;
int c = - 1 ;
// Front
tv [ 0 ] = new WorldVertex ( x0 , y0 , z0 , c , u0 , v0 ) ;
tv [ 1 ] = new WorldVertex ( x0 , y0 , z1 , c , u0 , v1 ) ;
tv [ 2 ] = new WorldVertex ( x1 , y0 , z0 , c , u1 , v0 ) ;
tv [ 3 ] = new WorldVertex ( x1 , y0 , z0 , c , u1 , v0 ) ;
tv [ 4 ] = new WorldVertex ( x0 , y0 , z1 , c , u0 , v1 ) ;
tv [ 5 ] = new WorldVertex ( x1 , y0 , z1 , c , u1 , v1 ) ;
// Right
tv [ 6 ] = new WorldVertex ( x1 , y0 , z0 , c , u0 , v0 ) ;
tv [ 7 ] = new WorldVertex ( x1 , y0 , z1 , c , u0 , v1 ) ;
tv [ 8 ] = new WorldVertex ( x1 , y1 , z0 , c , u1 , v0 ) ;
tv [ 9 ] = new WorldVertex ( x1 , y1 , z0 , c , u1 , v0 ) ;
tv [ 10 ] = new WorldVertex ( x1 , y0 , z1 , c , u0 , v1 ) ;
tv [ 11 ] = new WorldVertex ( x1 , y1 , z1 , c , u1 , v1 ) ;
// Back
tv [ 12 ] = new WorldVertex ( x1 , y1 , z0 , c , u0 , v0 ) ;
tv [ 13 ] = new WorldVertex ( x1 , y1 , z1 , c , u0 , v1 ) ;
tv [ 14 ] = new WorldVertex ( x0 , y1 , z0 , c , u1 , v0 ) ;
tv [ 15 ] = new WorldVertex ( x0 , y1 , z0 , c , u1 , v0 ) ;
tv [ 16 ] = new WorldVertex ( x1 , y1 , z1 , c , u0 , v1 ) ;
tv [ 17 ] = new WorldVertex ( x0 , y1 , z1 , c , u1 , v1 ) ;
// Left
tv [ 18 ] = new WorldVertex ( x0 , y1 , z0 , c , u0 , v1 ) ;
tv [ 19 ] = new WorldVertex ( x0 , y1 , z1 , c , u0 , v0 ) ;
tv [ 20 ] = new WorldVertex ( x0 , y0 , z1 , c , u1 , v0 ) ;
tv [ 21 ] = new WorldVertex ( x0 , y1 , z0 , c , u1 , v0 ) ;
tv [ 22 ] = new WorldVertex ( x0 , y0 , z1 , c , u0 , v1 ) ;
tv [ 23 ] = new WorldVertex ( x0 , y0 , z0 , c , u1 , v1 ) ;
// Top
tv [ 24 ] = new WorldVertex ( x0 , y0 , z1 , c , u0 , v0 ) ;
tv [ 25 ] = new WorldVertex ( x0 , y1 , z1 , c , u0 , v1 ) ;
tv [ 26 ] = new WorldVertex ( x1 , y0 , z1 , c , u1 , v0 ) ;
tv [ 27 ] = new WorldVertex ( x1 , y0 , z1 , c , u1 , v0 ) ;
tv [ 28 ] = new WorldVertex ( x0 , y1 , z1 , c , u0 , v1 ) ;
tv [ 29 ] = new WorldVertex ( x1 , y1 , z1 , c , u1 , v1 ) ;
// Bottom
tv [ 30 ] = new WorldVertex ( x1 , y0 , z0 , c , u1 , v0 ) ;
tv [ 31 ] = new WorldVertex ( x0 , y1 , z0 , c , u0 , v1 ) ;
tv [ 32 ] = new WorldVertex ( x0 , y0 , z0 , c , u0 , v0 ) ;
tv [ 33 ] = new WorldVertex ( x1 , y0 , z0 , c , u1 , v0 ) ;
tv [ 34 ] = new WorldVertex ( x1 , y1 , z0 , c , u1 , v1 ) ;
tv [ 35 ] = new WorldVertex ( x0 , y1 , z0 , c , u0 , v1 ) ;
// Create vertexbuffer
thingcage = new VertexBuffer ( General . Map . Graphics . Device , WorldVertex . Stride * totalvertices ,
Usage . WriteOnly | Usage . Dynamic , VertexFormat . None , Pool . Default ) ;
DataStream bufferstream = thingcage . Lock ( 0 , WorldVertex . Stride * totalvertices , LockFlags . Discard ) ;
bufferstream . WriteRange < WorldVertex > ( tv ) ;
thingcage . Unlock ( ) ;
bufferstream . Dispose ( ) ;
2012-04-17 19:13:47 +00:00
} * /
//mxd
private void SetupThingCage ( ) {
bbox = new ThingBoundingBox ( General . Map . Graphics . Device ) ;
}
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Presentation
// This creates the projection
internal void CreateProjection ( )
{
// Calculate aspect
float aspect = ( float ) General . Map . Graphics . RenderTarget . ClientSize . Width /
( float ) General . Map . Graphics . RenderTarget . ClientSize . Height ;
// The DirectX PerspectiveFovRH matrix method calculates the scaling in X and Y as follows:
// yscale = 1 / tan(fovY / 2)
// xscale = yscale / aspect
// The fov specified in the method is the FOV over Y, but we want the user to specify the FOV
// over X, so calculate what it would be over Y first;
float fov = Angle2D . DegToRad ( ( float ) General . Settings . VisualFOV ) ;
float reversefov = 1.0f / ( float ) Math . Tan ( fov / 2.0f ) ;
float reversefovy = reversefov * aspect ;
float fovy = ( float ) Math . Atan ( 1.0f / reversefovy ) * 2.0f ;
// Make the projection matrix
projection = Matrix . PerspectiveFovRH ( fovy , aspect , PROJ_NEAR_PLANE , General . Settings . ViewDistance ) ;
// Apply matrices
ApplyMatrices3D ( ) ;
}
// This creates matrices for a camera view
public void PositionAndLookAt ( Vector3D pos , Vector3D lookat )
{
Vector3D delta ;
float anglexy , anglez ;
// Calculate delta vector
cameraposition = pos ;
delta = lookat - pos ;
anglexy = delta . GetAngleXY ( ) ;
anglez = delta . GetAngleZ ( ) ;
// Create frustum
frustum = new ProjectedFrustum2D ( pos , anglexy , anglez , PROJ_NEAR_PLANE ,
General . Settings . ViewDistance , Angle2D . DegToRad ( ( float ) General . Settings . VisualFOV ) ) ;
// Make the view matrix
view3d = Matrix . LookAtRH ( D3DDevice . V3 ( pos ) , D3DDevice . V3 ( lookat ) , new Vector3 ( 0f , 0f , 1f ) ) ;
// Make the billboard matrix
billboard = Matrix . RotationZ ( anglexy + Angle2D . PI ) ;
}
// This creates 2D view matrix
private void CreateMatrices2D ( )
{
windowsize = graphics . RenderTarget . ClientSize ;
Matrix scaling = Matrix . Scaling ( ( 1f / ( float ) windowsize . Width ) * 2f , ( 1f / ( float ) windowsize . Height ) * - 2f , 1f ) ;
Matrix translate = Matrix . Translation ( - ( float ) windowsize . Width * 0.5f , - ( float ) windowsize . Height * 0.5f , 0f ) ;
view2d = Matrix . Multiply ( translate , scaling ) ;
}
// This applies the matrices
private void ApplyMatrices3D ( )
{
worldviewproj = world * view3d * projection ;
graphics . Shaders . World3D . WorldViewProj = worldviewproj ;
graphics . Device . SetTransform ( TransformState . World , world ) ;
graphics . Device . SetTransform ( TransformState . Projection , projection ) ;
graphics . Device . SetTransform ( TransformState . View , view3d ) ;
}
// This sets the appropriate view matrix
public void ApplyMatrices2D ( )
{
graphics . Device . SetTransform ( TransformState . World , world ) ;
graphics . Device . SetTransform ( TransformState . Projection , Matrix . Identity ) ;
graphics . Device . SetTransform ( TransformState . View , view2d ) ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Start / Finish
// This starts rendering
public bool Start ( )
{
2009-05-04 06:13:56 +00:00
// Create texture
2012-04-17 19:13:47 +00:00
//mxd
//if(General.Map.Data.ThingBox.Texture == null)
//General.Map.Data.ThingBox.CreateTexture();
2009-04-19 18:07:22 +00:00
// Start drawing
if ( graphics . StartRendering ( true , General . Colors . Background . ToColorValue ( ) , graphics . BackBuffer , graphics . DepthBuffer ) )
{
2012-04-17 19:13:47 +00:00
// Beginning renderstates
2009-04-19 18:07:22 +00:00
graphics . Device . SetRenderState ( RenderState . CullMode , Cull . None ) ;
graphics . Device . SetRenderState ( RenderState . ZEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . AlphaBlendEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . AlphaTestEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . SourceBlend , Blend . SourceAlpha ) ;
graphics . Device . SetRenderState ( RenderState . DestinationBlend , Blend . InverseSourceAlpha ) ;
graphics . Device . SetRenderState ( RenderState . FogEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . FogDensity , 1.0f ) ;
graphics . Device . SetRenderState ( RenderState . FogColor , General . Colors . Background . ToInt ( ) ) ;
graphics . Device . SetRenderState ( RenderState . FogStart , General . Settings . ViewDistance * FOG_RANGE ) ;
graphics . Device . SetRenderState ( RenderState . FogEnd , General . Settings . ViewDistance ) ;
graphics . Device . SetRenderState ( RenderState . FogTableMode , FogMode . Linear ) ;
graphics . Device . SetRenderState ( RenderState . RangeFogEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . TextureFactor , - 1 ) ;
graphics . Shaders . World3D . SetModulateColor ( - 1 ) ;
graphics . Shaders . World3D . SetHighlightColor ( 0 ) ;
2009-04-26 20:20:40 +00:00
// Texture addressing
graphics . Device . SetSamplerState ( 0 , SamplerState . AddressU , TextureAddress . Wrap ) ;
graphics . Device . SetSamplerState ( 0 , SamplerState . AddressV , TextureAddress . Wrap ) ;
graphics . Device . SetSamplerState ( 0 , SamplerState . AddressW , TextureAddress . Wrap ) ;
2009-04-19 18:07:22 +00:00
// Matrices
world = Matrix . Identity ;
ApplyMatrices3D ( ) ;
// Highlight
2009-05-04 06:13:56 +00:00
if ( General . Settings . AnimateVisualSelection )
{
double time = General . Clock . GetCurrentTime ( ) ;
2009-05-06 07:26:12 +00:00
highlightglow = ( float ) Math . Sin ( time / 100.0f ) * 0.1f + 0.4f ;
2012-04-17 19:13:47 +00:00
//mxd. WHY?!
//highlightglowinv = -(float)Math.Sin(time / 100.0f) * 0.1f + 0.4f;
highlightglowinv = - highlightglow + 0.8f ;
2009-05-04 06:13:56 +00:00
}
else
{
2009-05-06 07:26:12 +00:00
highlightglow = 0.4f ;
highlightglowinv = 0.3f ;
2009-05-04 06:13:56 +00:00
}
2009-04-19 18:07:22 +00:00
// Determine shader pass to use
if ( fullbrightness ) shaderpass = 1 ; else shaderpass = 0 ;
// Create crosshair vertices
if ( crosshairverts = = null )
CreateCrosshairVerts ( new Size ( General . Map . Data . Crosshair3D . Width , General . Map . Data . Crosshair3D . Height ) ) ;
// Ready
return true ;
}
else
{
// Can't render now
return false ;
}
}
// This begins rendering world geometry
public void StartGeometry ( )
{
// Make collection
geometry = new Dictionary < ImageData , BinaryHeap < VisualGeometry > > [ RENDER_PASSES ] ;
things = new Dictionary < ImageData , List < VisualThing > > [ RENDER_PASSES ] ;
thingsbydistance = new BinaryHeap < VisualThing > ( ) ;
2012-04-17 19:13:47 +00:00
//mxd
thingsWithModel = new Dictionary < ModelDefEntry , List < VisualThing > > ( ) ;
2012-04-23 21:35:48 +00:00
litGeometry = new Dictionary < Texture , List < VisualGeometry > > ( ) ;
2012-04-17 19:13:47 +00:00
2009-04-19 18:07:22 +00:00
for ( int i = 0 ; i < RENDER_PASSES ; i + + )
{
geometry [ i ] = new Dictionary < ImageData , BinaryHeap < VisualGeometry > > ( ) ;
things [ i ] = new Dictionary < ImageData , List < VisualThing > > ( ) ;
}
2012-04-17 19:13:47 +00:00
//mxd
if ( General . Settings . GZDrawLights ) {
thingsWithLight = new List < VisualThing > ( ) ;
2012-04-18 19:34:11 +00:00
//dbg
//GZBuilder.GZGeneral.ClearTrace();
//geoSkipped = 0;
2012-04-23 21:35:48 +00:00
//totalGeo = 0;
//totalThings = 0;
2012-04-17 19:13:47 +00:00
}
2009-04-19 18:07:22 +00:00
}
// This ends rendering world geometry
public void FinishGeometry ( )
{
2012-04-17 19:13:47 +00:00
//mxd. sort lights
if ( General . Settings . GZDrawLights & & ! fullbrightness & & thingsWithLight . Count > 0 )
updateLights ( ) ;
// Initial renderstates
2009-04-19 18:07:22 +00:00
graphics . Device . SetRenderState ( RenderState . CullMode , Cull . Counterclockwise ) ;
graphics . Device . SetRenderState ( RenderState . ZEnable , true ) ;
graphics . Device . SetRenderState ( RenderState . ZWriteEnable , true ) ;
graphics . Device . SetRenderState ( RenderState . AlphaBlendEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . AlphaTestEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . TextureFactor , - 1 ) ;
graphics . Shaders . World3D . Begin ( ) ;
// SOLID PASS
world = Matrix . Identity ;
ApplyMatrices3D ( ) ;
RenderSinglePass ( ( int ) RenderPass . Solid ) ;
2012-04-18 19:34:11 +00:00
//mxd. Render models
RenderModels ( ) ;
2012-04-17 19:13:47 +00:00
2009-04-19 18:07:22 +00:00
// MASK PASS
2012-04-17 19:13:47 +00:00
world = Matrix . Identity ;
ApplyMatrices3D ( ) ;
graphics . Device . SetRenderState ( RenderState . AlphaTestEnable , true ) ;
RenderSinglePass ( ( int ) RenderPass . Mask ) ;
// ALPHA PASS
world = Matrix . Identity ;
ApplyMatrices3D ( ) ;
graphics . Device . SetRenderState ( RenderState . AlphaBlendEnable , true ) ;
graphics . Device . SetRenderState ( RenderState . AlphaTestEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . ZWriteEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . SourceBlend , Blend . SourceAlpha ) ;
graphics . Device . SetRenderState ( RenderState . DestinationBlend , Blend . InverseSourceAlpha ) ;
RenderSinglePass ( ( int ) RenderPass . Alpha ) ;
// THINGS
if ( renderthingcages ) RenderThingCages ( ) ;
2009-04-19 18:07:22 +00:00
// ADDITIVE PASS
world = Matrix . Identity ;
ApplyMatrices3D ( ) ;
graphics . Device . SetRenderState ( RenderState . DestinationBlend , Blend . One ) ;
RenderSinglePass ( ( int ) RenderPass . Additive ) ;
2012-04-17 19:13:47 +00:00
2012-04-18 19:34:11 +00:00
//mxd. LIGHT PASS
if ( General . Settings . GZDrawLights & & ! fullbrightness & & thingsWithLight . Count > 0 & & litGeometry . Count > 0 )
RenderLights ( litGeometry , thingsWithLight ) ;
2009-04-19 18:07:22 +00:00
// Remove references
graphics . Shaders . World3D . Texture1 = null ;
// Done
graphics . Shaders . World3D . End ( ) ;
geometry = null ;
2012-04-18 19:34:11 +00:00
//dbg
2012-04-23 21:35:48 +00:00
//GZBuilder.GZGeneral.TraceLine("Affected by lights: "+totalGeo+"; skipped: "+geoSkipped+"; total things:"+totalThings);
2012-04-18 19:34:11 +00:00
//GZBuilder.GZGeneral.TraceInHeader("FPS:" + calculateFrameRate());
2009-04-19 18:07:22 +00:00
}
2012-04-17 19:13:47 +00:00
//mxd
private void updateLights ( ) {
thingsWithLight . Sort ( sortThingsByCameraDistance ) ;
if ( thingsWithLight . Count > General . Settings . GZMaxDynamicLights ) {
List < VisualThing > tl = new List < VisualThing > ( ) ;
for ( int i = 0 ; i < General . Settings . GZMaxDynamicLights ; i + + )
tl . Add ( thingsWithLight [ i ] ) ;
thingsWithLight = tl ;
}
thingsWithLight . Sort ( sortThingsByLightRenderStyle ) ;
lightOffsets = new int [ 3 ] ;
foreach ( VisualThing t in thingsWithLight ) {
//add light to apropriate array. can't clear lights now, since it's Count is used to check if dynamic light rendering pass is needed and I don't want to add special variable for that...
if ( t . LightRenderStyle = = ( int ) GZDoomLightRenderStyle . NORMAL )
lightOffsets [ 0 ] + + ;
else if ( t . LightRenderStyle = = ( int ) GZDoomLightRenderStyle . ADDITIVE )
lightOffsets [ 1 ] + + ;
else
lightOffsets [ 2 ] + + ;
}
}
//mxd
private int sortThingsByCameraDistance ( VisualThing t1 , VisualThing t2 ) {
if ( t1 . CameraDistance3D = = t2 . CameraDistance3D ) return 0 ;
if ( t1 . CameraDistance3D > t2 . CameraDistance3D ) return 1 ;
return - 1 ;
}
//mxd
private int sortThingsByLightRenderStyle ( VisualThing t1 , VisualThing t2 ) {
if ( t1 . LightRenderStyle = = t2 . LightRenderStyle ) return 0 ;
if ( t1 . LightRenderStyle > t2 . LightRenderStyle ) return 1 ;
return - 1 ;
}
2012-04-18 19:34:11 +00:00
//mxd.
//I never particularly liked old ThingCages, so I wrote this instead.
2012-04-17 19:13:47 +00:00
//It should render faster and it has fancy arrow! :)
private void RenderThingCages ( ) {
graphics . Device . SetRenderState ( RenderState . AlphaBlendEnable , true ) ;
graphics . Device . SetRenderState ( RenderState . AlphaTestEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . ZWriteEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . SourceBlend , Blend . SourceAlpha ) ;
graphics . Device . SetRenderState ( RenderState . DestinationBlend , Blend . SourceAlpha ) ;
2012-04-18 19:34:11 +00:00
//mxd. Doesn't look nearly as good as I expected :(
2012-04-17 19:13:47 +00:00
//graphics.Device.SetRenderState(RenderState.AntialiasedLineEnable, General.Settings.QualityDisplay);
graphics . Shaders . World3D . BeginPass ( 8 ) ;
foreach ( VisualThing t in thingsbydistance ) {
// Setup matrix
world = Matrix . Multiply ( t . CageScales , t . Position ) ;
ApplyMatrices3D ( ) ;
// Setup color
Color4 thingColor = new Color4 ( ) ;
if ( t . Selected & & showselection ) {
thingColor = General . Colors . Selection3D . ToColorValue ( ) ;
} else {
//thingColor = Color4.Modulate(t.Thing.Color.ToColorValue(), new Color4(t.VertexColor));
thingColor = t . Thing . Color . ToColorValue ( ) ;
if ( t ! = highlighted ) thingColor . Alpha = 0.6f ;
}
graphics . Shaders . World3D . VertexColor = thingColor ;
//Render cage
graphics . Shaders . World3D . ApplySettings ( ) ;
graphics . Device . SetStreamSource ( 0 , bbox . cage , 0 , WorldVertex . Stride ) ;
graphics . Device . DrawPrimitives ( PrimitiveType . LineList , 0 , 12 ) ;
//and arrow
float sx = t . CageScales . M11 ;
Matrix arrowScaler = Matrix . Scaling ( sx , sx , sx ) ; //scale arrow evenly based on thing width\depth
world = Matrix . Multiply ( arrowScaler , t . Position * Matrix . Translation ( 0.0f , 0.0f , t . CageScales . M33 / 2 ) ) ;
Matrix rot = Matrix . RotationZ ( t . Thing . Angle - Angle2D . PI / 2 ) ;
world = Matrix . Multiply ( rot , world ) ;
ApplyMatrices3D ( ) ;
graphics . Shaders . World3D . ApplySettings ( ) ;
graphics . Device . SetStreamSource ( 0 , bbox . arrow , 0 , WorldVertex . Stride ) ;
graphics . Device . DrawPrimitives ( PrimitiveType . LineList , 0 , 5 ) ;
}
// Done
graphics . Shaders . World3D . EndPass ( ) ;
graphics . Shaders . World3D . SetModulateColor ( - 1 ) ;
graphics . Device . SetRenderState ( RenderState . TextureFactor , - 1 ) ;
}
2009-04-19 18:07:22 +00:00
// This performs a single render pass
private void RenderSinglePass ( int pass )
{
2012-04-17 19:13:47 +00:00
int currentshaderpass = shaderpass ;
2009-05-01 20:31:17 +00:00
int highshaderpass = shaderpass + 2 ;
2009-04-19 18:07:22 +00:00
// Get geometry for this pass
Dictionary < ImageData , BinaryHeap < VisualGeometry > > geopass = geometry [ pass ] ;
// Begin rendering with this shader
graphics . Shaders . World3D . BeginPass ( shaderpass ) ;
2012-04-17 19:13:47 +00:00
2009-04-19 18:07:22 +00:00
// Render the geometry collected
foreach ( KeyValuePair < ImageData , BinaryHeap < VisualGeometry > > group in geopass )
{
ImageData curtexture ;
// What texture to use?
if ( group . Key is UnknownImage )
curtexture = General . Map . Data . UnknownTexture3D ;
else if ( ( group . Key ! = null ) & & group . Key . IsImageLoaded & & ! group . Key . IsDisposed )
curtexture = group . Key ;
else
curtexture = General . Map . Data . Hourglass3D ;
// Create Direct3D texture if still needed
if ( ( curtexture . Texture = = null ) | | curtexture . Texture . Disposed )
curtexture . CreateTexture ( ) ;
// Apply texture
2009-05-04 06:13:56 +00:00
if ( ! graphics . Shaders . Enabled ) graphics . Device . SetTexture ( 0 , curtexture . Texture ) ;
2009-04-19 18:07:22 +00:00
graphics . Shaders . World3D . Texture1 = curtexture . Texture ;
// Go for all geometry that uses this texture
VisualSector sector = null ;
2012-04-17 19:13:47 +00:00
2009-04-19 18:07:22 +00:00
foreach ( VisualGeometry g in group . Value )
{
// Changing sector?
if ( ! object . ReferenceEquals ( g . Sector , sector ) )
{
// Update the sector if needed
if ( g . Sector . NeedsUpdateGeo ) g . Sector . Update ( ) ;
// Only do this sector when a vertexbuffer is created
if ( g . Sector . GeometryBuffer ! = null )
{
// Change current sector
sector = g . Sector ;
// Set stream source
graphics . Device . SetStreamSource ( 0 , sector . GeometryBuffer , 0 , WorldVertex . Stride ) ;
}
else
{
sector = null ;
}
}
if ( sector ! = null )
{
2009-05-01 20:31:17 +00:00
// Determine the shader pass we want to use for this object
2009-07-07 14:52:39 +00:00
int wantedshaderpass = ( ( ( g = = highlighted ) & & showhighlight ) | | ( g . Selected & & showselection ) ) ? highshaderpass : shaderpass ;
2009-05-01 20:31:17 +00:00
2012-04-18 19:34:11 +00:00
//mxd. Seems that translucent lines aren't affected by dynamic lights in GZDoom
if ( g . RenderPass ! = RenderPass . Alpha & & General . Settings . GZDrawLights & & ! fullbrightness & & thingsWithLight . Count > 0 ) {
if ( ! litGeometry . ContainsKey ( curtexture . Texture ) )
litGeometry [ curtexture . Texture ] = new List < VisualGeometry > ( ) ;
litGeometry [ curtexture . Texture ] . Add ( g ) ;
}
2012-04-17 19:13:47 +00:00
2009-05-01 20:31:17 +00:00
// Switch shader pass?
if ( currentshaderpass ! = wantedshaderpass )
2009-04-19 18:07:22 +00:00
{
graphics . Shaders . World3D . EndPass ( ) ;
2009-05-01 20:31:17 +00:00
graphics . Shaders . World3D . BeginPass ( wantedshaderpass ) ;
currentshaderpass = wantedshaderpass ;
2009-04-19 18:07:22 +00:00
}
2009-05-04 06:13:56 +00:00
// Set the colors to use
if ( ! graphics . Shaders . Enabled )
{
2009-07-07 14:52:39 +00:00
graphics . Device . SetTexture ( 2 , ( g . Selected & & showselection ) ? selectionimage . Texture : null ) ;
graphics . Device . SetTexture ( 3 , ( ( g = = highlighted ) & & showhighlight ) ? highlightimage . Texture : null ) ;
2009-05-04 06:13:56 +00:00
}
else
{
2012-04-17 19:13:47 +00:00
graphics . Shaders . World3D . SetHighlightColor ( CalculateHighlightColor ( ( g = = highlighted ) & & showhighlight , ( g . Selected & & showselection ) ) . ToArgb ( ) ) ;
2009-05-04 06:13:56 +00:00
graphics . Shaders . World3D . ApplySettings ( ) ;
}
2009-05-01 20:31:17 +00:00
2009-04-19 18:07:22 +00:00
// Render!
graphics . Device . DrawPrimitives ( PrimitiveType . TriangleList , g . VertexOffset , g . Triangles ) ;
}
}
}
// Get things for this pass
Dictionary < ImageData , List < VisualThing > > thingspass = things [ pass ] ;
2009-04-26 20:20:40 +00:00
if ( thingspass . Count > 0 )
2009-04-19 18:07:22 +00:00
{
2009-04-26 20:20:40 +00:00
// Texture addressing
graphics . Device . SetSamplerState ( 0 , SamplerState . AddressU , TextureAddress . Clamp ) ;
graphics . Device . SetSamplerState ( 0 , SamplerState . AddressV , TextureAddress . Clamp ) ;
graphics . Device . SetSamplerState ( 0 , SamplerState . AddressW , TextureAddress . Clamp ) ;
2009-04-19 18:07:22 +00:00
2009-04-26 20:20:40 +00:00
// Render things collected
foreach ( KeyValuePair < ImageData , List < VisualThing > > group in thingspass )
2009-04-19 18:07:22 +00:00
{
2012-04-17 19:13:47 +00:00
ImageData curtexture ;
2009-04-19 18:07:22 +00:00
2009-04-26 20:20:40 +00:00
if ( ! ( group . Key is UnknownImage ) )
{
// What texture to use?
if ( ( group . Key ! = null ) & & group . Key . IsImageLoaded & & ! group . Key . IsDisposed )
curtexture = group . Key ;
else
curtexture = General . Map . Data . Hourglass3D ;
2009-04-19 18:07:22 +00:00
2009-04-26 20:20:40 +00:00
// Create Direct3D texture if still needed
if ( ( curtexture . Texture = = null ) | | curtexture . Texture . Disposed )
curtexture . CreateTexture ( ) ;
2009-04-19 18:07:22 +00:00
2009-04-26 20:20:40 +00:00
// Apply texture
2009-05-04 06:13:56 +00:00
if ( ! graphics . Shaders . Enabled ) graphics . Device . SetTexture ( 0 , curtexture . Texture ) ;
2009-04-26 20:20:40 +00:00
graphics . Shaders . World3D . Texture1 = curtexture . Texture ;
2009-04-19 18:07:22 +00:00
2009-04-26 20:20:40 +00:00
// Render all things with this texture
foreach ( VisualThing t in group . Value )
{
2012-04-17 19:13:47 +00:00
//mxd
if ( General . Settings . GZDrawModels & & ( ! General . Settings . GZDrawSelectedModelsOnly | | t . Selected ) & & t . Thing . IsModel )
continue ;
// Update buffer if needed
t . Update ( ) ;
// Only do this sector when a vertexbuffer is created
if ( t . GeometryBuffer ! = null ) {
// Determine the shader pass we want to use for this object
int wantedshaderpass = ( ( ( t = = highlighted ) & & showhighlight ) | | ( t . Selected & & showselection ) ) ? highshaderpass : shaderpass ;
//mxd. if current thing is light - set it's color to light color
if ( t . LightType ! = - 1 ) {
wantedshaderpass + = 4 ; //render using one of passes, which uses World3D.VertexColor
2012-04-18 19:34:11 +00:00
/ * Color4 c = t . LightColor ;
2012-04-17 19:13:47 +00:00
if ( t . LightRenderStyle = = ( int ) GZDoomLightRenderStyle . NEGATIVE ) {
c . Red = 1.0f - t . LightColor . Blue ;
c . Green = 1.0f - t . LightColor . Green ;
c . Blue = 1.0f - t . LightColor . Red ;
2012-04-18 19:34:11 +00:00
} * /
graphics . Shaders . World3D . VertexColor = t . LightColor ;
2012-04-17 19:13:47 +00:00
//mxd. check if Thing is affected by dynamic lights and set color accordingly
} else if ( General . Settings . GZDrawLights & & ! fullbrightness & & thingsWithLight . Count > 0 ) {
Color4 litColor = getLitColor ( t . PositionV3 ) ;
if ( litColor . ToArgb ( ) ! = 0 ) {
wantedshaderpass + = 4 ; //render using one of passes, which uses World3D.VertexColor
graphics . Shaders . World3D . VertexColor = new Color4 ( t . VertexColor ) + litColor ;
}
}
// Switch shader pass?
if ( currentshaderpass ! = wantedshaderpass ) {
graphics . Shaders . World3D . EndPass ( ) ;
graphics . Shaders . World3D . BeginPass ( wantedshaderpass ) ;
currentshaderpass = wantedshaderpass ;
}
// Set the colors to use
if ( ! graphics . Shaders . Enabled ) {
graphics . Device . SetTexture ( 2 , ( t . Selected & & showselection ) ? selectionimage . Texture : null ) ;
graphics . Device . SetTexture ( 3 , ( ( t = = highlighted ) & & showhighlight ) ? highlightimage . Texture : null ) ;
} else {
graphics . Shaders . World3D . SetHighlightColor ( CalculateHighlightColor ( ( t = = highlighted ) & & showhighlight , ( t . Selected & & showselection ) ) . ToArgb ( ) ) ;
}
// Create the matrix for positioning / rotation
world = t . Orientation ;
if ( t . Billboard ) world = Matrix . Multiply ( world , billboard ) ;
world = Matrix . Multiply ( world , t . Position ) ;
ApplyMatrices3D ( ) ;
graphics . Shaders . World3D . ApplySettings ( ) ;
// Apply buffer
graphics . Device . SetStreamSource ( 0 , t . GeometryBuffer , 0 , WorldVertex . Stride ) ;
// Render!
graphics . Device . DrawPrimitives ( PrimitiveType . TriangleList , 0 , t . Triangles ) ;
}
2009-04-19 18:07:22 +00:00
}
}
}
2012-04-17 19:13:47 +00:00
// Texture addressing
graphics . Device . SetSamplerState ( 0 , SamplerState . AddressU , TextureAddress . Wrap ) ;
graphics . Device . SetSamplerState ( 0 , SamplerState . AddressV , TextureAddress . Wrap ) ;
graphics . Device . SetSamplerState ( 0 , SamplerState . AddressW , TextureAddress . Wrap ) ;
2009-04-19 18:07:22 +00:00
}
// Done rendering with this shader
graphics . Shaders . World3D . EndPass ( ) ;
}
2009-05-05 21:13:50 +00:00
2012-04-18 19:34:11 +00:00
//mxd. Dynamic lights pass!
private void RenderLights ( Dictionary < Texture , List < VisualGeometry > > geometry_to_lit , List < VisualThing > lights ) {
graphics . Shaders . World3D . World = world ;
graphics . Shaders . World3D . BeginPass ( 9 ) ;
int i , count ;
Vector4 lpr ;
graphics . Device . SetRenderState ( RenderState . SourceBlend , Blend . One ) ;
graphics . Device . SetRenderState ( RenderState . DestinationBlend , Blend . BlendFactor ) ;
foreach ( KeyValuePair < Texture , List < VisualGeometry > > group in geometry_to_lit ) {
graphics . Shaders . World3D . Texture1 = group . Key ;
foreach ( VisualGeometry g in group . Value ) {
i = 0 ;
count = 0 ;
graphics . Device . SetStreamSource ( 0 , g . Sector . GeometryBuffer , 0 , WorldVertex . Stride ) ;
//normal lights
count = lightOffsets [ 0 ] ;
if ( lightOffsets [ 0 ] > 0 ) {
graphics . Device . SetRenderState ( RenderState . BlendOperation , BlendOperation . Add ) ;
for ( i = 0 ; i < count ; i + + ) {
2012-04-23 21:35:48 +00:00
if ( checkBBoxIntersection ( g . BoundingBox , lights [ i ] . BoundingBox ) ) {
//dbg
//totalGeo++;
lpr = lights [ i ] . LightPositionAndRadius ;
if ( lpr . W = = 0 )
continue ;
graphics . Shaders . World3D . LightColor = lights [ i ] . LightColor ;
graphics . Shaders . World3D . LightPositionAndRadius = lights [ i ] . LightPositionAndRadius ;
graphics . Shaders . World3D . ApplySettings ( ) ;
graphics . Device . DrawPrimitives ( PrimitiveType . TriangleList , g . VertexOffset , g . Triangles ) ;
}
2012-04-18 19:34:11 +00:00
}
}
//additive lights.
if ( lightOffsets [ 1 ] > 0 ) {
count + = lightOffsets [ 1 ] ;
graphics . Device . SetRenderState ( RenderState . BlendOperation , BlendOperation . Add ) ;
for ( i = lightOffsets [ 0 ] ; i < count ; i + + ) {
2012-04-23 21:35:48 +00:00
if ( checkBBoxIntersection ( g . BoundingBox , lights [ i ] . BoundingBox ) ) {
//dbg
//totalGeo++;
lpr = lights [ i ] . LightPositionAndRadius ;
if ( lpr . W = = 0 )
continue ;
graphics . Shaders . World3D . LightColor = lights [ i ] . LightColor ;
graphics . Shaders . World3D . LightPositionAndRadius = lights [ i ] . LightPositionAndRadius ;
graphics . Shaders . World3D . ApplySettings ( ) ;
graphics . Device . DrawPrimitives ( PrimitiveType . TriangleList , g . VertexOffset , g . Triangles ) ;
}
2012-04-18 19:34:11 +00:00
}
}
//negative lights
if ( lightOffsets [ 2 ] > 0 ) {
count + = lightOffsets [ 2 ] ;
graphics . Device . SetRenderState ( RenderState . BlendOperation , BlendOperation . ReverseSubtract ) ;
for ( i = lightOffsets [ 0 ] + lightOffsets [ 1 ] ; i < count ; i + + ) {
2012-04-23 21:35:48 +00:00
if ( checkBBoxIntersection ( g . BoundingBox , lights [ i ] . BoundingBox ) ) {
//dbg
//totalGeo++;
lpr = lights [ i ] . LightPositionAndRadius ;
if ( lpr . W = = 0 )
continue ;
Color4 lc = lights [ i ] . LightColor ;
graphics . Shaders . World3D . LightColor = new Color4 ( 1.0f , ( lc . Green + lc . Blue ) / 2 , ( lc . Red + lc . Blue ) / 2 , ( lc . Green + lc . Red ) / 2 ) ;
graphics . Shaders . World3D . LightPositionAndRadius = lights [ i ] . LightPositionAndRadius ;
graphics . Shaders . World3D . ApplySettings ( ) ;
graphics . Device . DrawPrimitives ( PrimitiveType . TriangleList , g . VertexOffset , g . Triangles ) ;
}
2012-04-18 19:34:11 +00:00
}
}
}
}
graphics . Shaders . World3D . EndPass ( ) ;
graphics . Device . SetRenderState ( RenderState . BlendOperation , BlendOperation . Add ) ;
//dbg
//GZBuilder.GZGeneral.TraceLine("Lit " + gcount + " geometries; Lights: [" + lightOffsets[0] + ";" + lightOffsets[1] + ";" + lightOffsets[2] + "]" + Environment.NewLine + "Models count: " + thingsWithModel.Count);
}
2012-04-17 19:13:47 +00:00
//mxd. render models
private void RenderModels ( ) {
int shaderpass = 4 ;
if ( fullbrightness ) shaderpass + + ;
int currentshaderpass = shaderpass ;
int highshaderpass = shaderpass + 2 ;
// Begin rendering with this shader
graphics . Shaders . World3D . BeginPass ( currentshaderpass ) ;
foreach ( KeyValuePair < ModelDefEntry , List < VisualThing > > group in thingsWithModel ) {
foreach ( VisualThing t in group . Value ) {
Color4 vertexColor = new Color4 ( t . VertexColor ) ;
vertexColor . Alpha = 1.0f ;
//check if model is affected by dynamic lights and set color accordingly
if ( General . Settings . GZDrawLights & & ! fullbrightness & & thingsWithLight . Count > 0 ) {
Color4 litColor = getLitColor ( t . PositionV3 ) ;
graphics . Shaders . World3D . VertexColor = vertexColor + litColor ;
} else {
graphics . Shaders . World3D . VertexColor = vertexColor ;
}
2012-04-18 19:34:11 +00:00
// Determine the shader pass we want to use for this object
int wantedshaderpass = ( ( ( ( t = = highlighted ) & & showhighlight ) | | ( t . Selected & & showselection ) ) ? highshaderpass : shaderpass ) ;
2012-04-17 19:13:47 +00:00
2012-04-18 19:34:11 +00:00
// Switch shader pass?
if ( currentshaderpass ! = wantedshaderpass ) {
graphics . Shaders . World3D . EndPass ( ) ;
graphics . Shaders . World3D . BeginPass ( wantedshaderpass ) ;
currentshaderpass = wantedshaderpass ;
}
2012-04-17 19:13:47 +00:00
2012-04-18 19:34:11 +00:00
// Set the colors to use
if ( ! graphics . Shaders . Enabled ) {
graphics . Device . SetTexture ( 2 , ( t . Selected & & showselection ) ? selectionimage . Texture : null ) ;
graphics . Device . SetTexture ( 3 , ( ( t = = highlighted ) & & showhighlight ) ? highlightimage . Texture : null ) ;
} else {
graphics . Shaders . World3D . SetHighlightColor ( CalculateHighlightColor ( ( t = = highlighted ) & & showhighlight , ( t . Selected & & showselection ) ) . ToArgb ( ) ) ;
}
2012-04-17 19:13:47 +00:00
2012-04-18 19:34:11 +00:00
// Create the matrix for positioning / rotation
world = Matrix . Multiply ( t . Orientation , Matrix . RotationZ ( t . Thing . Angle ) ) ;
world = Matrix . Multiply ( world , t . Position ) ;
ApplyMatrices3D ( ) ;
2012-04-17 19:13:47 +00:00
2012-04-18 19:34:11 +00:00
for ( int i = 0 ; i < group . Key . Model . NUM_MESHES ; i + + ) {
if ( ! graphics . Shaders . Enabled ) graphics . Device . SetTexture ( 0 , group . Key . Model . Textures [ i ] ) ;
graphics . Shaders . World3D . Texture1 = group . Key . Model . Textures [ i ] ;
2012-04-17 19:13:47 +00:00
graphics . Shaders . World3D . ApplySettings ( ) ;
// Render!
group . Key . Model . Meshes [ i ] . DrawSubset ( 0 ) ;
}
}
}
graphics . Shaders . World3D . EndPass ( ) ;
}
//mxd. This gets color from dynamic lights based on distance to thing.
//WARNING: thing position must be in absolute cordinates
2012-04-18 19:34:11 +00:00
//(thing.Position.Z value is relative to floor of the sector the thing is in)
2012-04-17 19:13:47 +00:00
//so use visualThing.PositionV3 instead
private Color4 getLitColor ( Vector3 thingPosition ) {
Color4 litColor = new Color4 ( ) ;
float distSquared , scaler ;
int radius , radiusSquared , sign ;
for ( int i = 0 ; i < thingsWithLight . Count ; i + + ) {
distSquared = Vector3 . DistanceSquared ( thingsWithLight [ i ] . Center , thingPosition ) ;
radius = thingsWithLight [ i ] . LightRadius ;
radiusSquared = radius * radius ;
if ( distSquared < radiusSquared ) {
sign = thingsWithLight [ i ] . LightRenderStyle = = ( int ) GZDoomLightRenderStyle . NEGATIVE ? - 1 : 1 ;
scaler = 1 - distSquared / radiusSquared ;
litColor . Red + = thingsWithLight [ i ] . LightColor . Red * scaler * sign ;
litColor . Green + = thingsWithLight [ i ] . LightColor . Green * scaler * sign ;
litColor . Blue + = thingsWithLight [ i ] . LightColor . Blue * scaler * sign ;
}
}
return litColor ;
}
2009-05-05 21:13:50 +00:00
// This calculates the highlight/selection color
public Color4 CalculateHighlightColor ( bool ishighlighted , bool isselected )
{
Color4 highlightcolor = isselected ? General . Colors . Selection . ToColorValue ( ) : General . Colors . Highlight . ToColorValue ( ) ;
highlightcolor . Alpha = ishighlighted ? highlightglowinv : highlightglow ;
return highlightcolor ;
}
2009-04-19 18:07:22 +00:00
// This finishes rendering
public void Finish ( )
{
2010-08-22 12:09:32 +00:00
General . Plugins . OnPresentDisplayBegin ( ) ;
2009-04-19 18:07:22 +00:00
// Done
graphics . FinishRendering ( ) ;
graphics . Present ( ) ;
highlighted = null ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Rendering
// This sets the highlighted object for the rendering
public void SetHighlightedObject ( IVisualPickable obj )
{
highlighted = obj ;
}
// This collects a visual sector's geometry for rendering
public void AddSectorGeometry ( VisualGeometry g )
{
2009-07-04 10:06:35 +00:00
// Must have a texture and vertices
if ( ( g . Texture ! = null ) & & ( g . Triangles > 0 ) )
2009-04-19 18:07:22 +00:00
{
2012-04-18 19:34:11 +00:00
// Texture group not yet collected?
2009-04-19 18:07:22 +00:00
if ( ! geometry [ g . RenderPassInt ] . ContainsKey ( g . Texture ) )
{
// Create texture group
geometry [ g . RenderPassInt ] . Add ( g . Texture , new BinaryHeap < VisualGeometry > ( ) ) ;
}
// Add geometry to texture group
geometry [ g . RenderPassInt ] [ g . Texture ] . Add ( g ) ;
}
}
// This collects a visual sector's geometry for rendering
public void AddThingGeometry ( VisualThing t )
{
2012-04-17 19:13:47 +00:00
//mxd. gater lights
if ( General . Settings . GZDrawLights & & ! fullbrightness & & t . LightType ! = - 1 ) {
t . UpdateLightRadius ( ) ;
2012-04-23 21:35:48 +00:00
2012-04-17 19:13:47 +00:00
if ( t . LightRadius > 0 ) {
t . CalculateCameraDistance3D ( D3DDevice . V3 ( cameraposition ) ) ;
//t.CameraDistance3D is actually squared distance, hence (t.LightRadius * t.LightRadius)
if ( t . CameraDistance3D < ( t . LightRadius * t . LightRadius ) | | isThingOnScreen ( t . BoundingBox ) ) { //always render light if camera is within it's radius
2012-04-23 21:35:48 +00:00
if ( t . LightType = = ( int ) GZDoomLightType . FLICKER | | t . LightType = = ( int ) GZDoomLightType . PULSE | | t . LightType = = ( int ) GZDoomLightType . RANDOM )
t . UpdateBoundingBox ( t . LightRadius , t . LightRadius * 2 ) ;
2012-04-17 19:13:47 +00:00
thingsWithLight . Add ( t ) ;
}
}
//mxd. gather models
} else if ( General . Settings . GZDrawModels & & ( ! General . Settings . GZDrawSelectedModelsOnly | | t . Selected ) & & t . Thing . IsModel ) {
ModelDefEntry mde = GZBuilder . GZGeneral . ModelDefEntries [ t . Thing . Type ] ;
2012-04-23 21:35:48 +00:00
if ( ! isThingOnScreen ( t . BoundingBox ) )
2012-04-17 19:13:47 +00:00
return ;
if ( ! thingsWithModel . ContainsKey ( mde ) )
thingsWithModel . Add ( mde , new List < VisualThing > ( ) ) ;
thingsWithModel [ mde ] . Add ( t ) ;
} else if ( ! isThingOnScreen ( t . BoundingBox ) ) {
return ;
}
// Make sure the distance to camera is calculated
t . CalculateCameraDistance ( cameraposition ) ;
thingsbydistance . Add ( t ) ;
// Must have a texture!
if ( t . Texture ! = null )
2009-04-19 18:07:22 +00:00
{
// Texture group not yet collected?
if ( ! things [ t . RenderPassInt ] . ContainsKey ( t . Texture ) )
{
// Create texture group
things [ t . RenderPassInt ] . Add ( t . Texture , new List < VisualThing > ( ) ) ;
}
// Add geometry to texture group
things [ t . RenderPassInt ] [ t . Texture ] . Add ( t ) ;
}
}
2012-04-17 19:13:47 +00:00
//mxd
private bool isThingOnScreen ( Vector3 [ ] bbox ) {
Vector3D camNormal = Vector3D . FromAngleXYZ ( General . Map . VisualCamera . AngleXY , General . Map . VisualCamera . AngleZ ) ;
Vector3D thingNormal = D3DDevice . V3D ( bbox [ 0 ] ) - cameraposition ; //bbox[0] is always thing center
2012-04-23 21:35:48 +00:00
if ( Vector3D . DotProduct ( camNormal , thingNormal ) < 0 ) { //behind camera plane
//GZBuilder.GZGeneral.TraceLine("Skipped geo. Vector3D.DotProduct(camNormal, thingNormal) < 0");
return false ;
}
2012-04-17 19:13:47 +00:00
int len = bbox . Length ;
Vector3 screenPos ;
2012-04-23 21:35:48 +00:00
int behingCount = 0 ;
int leftCount = 0 ;
int rightCount = 0 ;
int topCount = 0 ;
int bottomCount = 0 ;
2012-04-17 19:13:47 +00:00
for ( int i = 0 ; i < len ; i + + ) {
//check visibility
screenPos = Vector3 . Project ( bbox [ i ] , 0 , 0 , 1 , 1 , PROJ_NEAR_PLANE , General . Settings . ViewDistance , worldviewproj ) ;
2012-04-23 21:35:48 +00:00
2012-04-17 19:13:47 +00:00
if ( screenPos . X > 0 & & screenPos . X < 1 & & screenPos . Y > 0 & & screenPos . Y < 1 )
return true ;
2012-04-23 21:35:48 +00:00
if ( screenPos . Z < 0 )
behingCount + + ;
if ( screenPos . X < 0 )
leftCount + + ;
else if ( screenPos . X > 1 )
rightCount + + ;
if ( screenPos . Y < 0 )
topCount + + ;
else if ( screenPos . Y > 1 )
bottomCount + + ;
2012-04-17 19:13:47 +00:00
}
2012-04-23 21:35:48 +00:00
if ( behingCount = = len | | leftCount = = len | | rightCount = = len | | topCount = = len | | bottomCount = = len )
return false ; //Not on screen
return true ;
}
//mxd
private static bool checkBBoxIntersection ( Vector3 [ ] bbox1 , Vector3 [ ] bbox2 ) {
Vector3 dist = bbox1 [ 0 ] - bbox2 [ 0 ] ;
Vector3 halfSize1 = bbox1 [ 0 ] - bbox1 [ 1 ] ;
Vector3 halfSize2 = bbox2 [ 0 ] - bbox2 [ 1 ] ;
if ( halfSize1 . X + halfSize2 . X > = Math . Abs ( dist . X ) & & halfSize1 . Y + halfSize2 . Y > = Math . Abs ( dist . Y ) & & halfSize1 . Z + halfSize2 . Z > = Math . Abs ( dist . Z ) )
return true ;
2012-04-17 19:13:47 +00:00
return false ;
}
2009-04-19 18:07:22 +00:00
// This renders the crosshair
public void RenderCrosshair ( )
{
// Set renderstates
graphics . Device . SetRenderState ( RenderState . CullMode , Cull . None ) ;
graphics . Device . SetRenderState ( RenderState . ZEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . AlphaBlendEnable , true ) ;
graphics . Device . SetRenderState ( RenderState . AlphaTestEnable , false ) ;
graphics . Device . SetRenderState ( RenderState . SourceBlend , Blend . SourceAlpha ) ;
graphics . Device . SetRenderState ( RenderState . DestinationBlend , Blend . InverseSourceAlpha ) ;
graphics . Device . SetRenderState ( RenderState . TextureFactor , - 1 ) ;
graphics . Device . SetTransform ( TransformState . World , Matrix . Identity ) ;
graphics . Device . SetTransform ( TransformState . Projection , Matrix . Identity ) ;
ApplyMatrices2D ( ) ;
// Texture
if ( crosshairbusy )
{
if ( General . Map . Data . CrosshairBusy3D . Texture = = null ) General . Map . Data . CrosshairBusy3D . CreateTexture ( ) ;
graphics . Device . SetTexture ( 0 , General . Map . Data . CrosshairBusy3D . Texture ) ;
graphics . Shaders . Display2D . Texture1 = General . Map . Data . CrosshairBusy3D . Texture ;
}
else
{
if ( General . Map . Data . Crosshair3D . Texture = = null ) General . Map . Data . Crosshair3D . CreateTexture ( ) ;
graphics . Device . SetTexture ( 0 , General . Map . Data . Crosshair3D . Texture ) ;
graphics . Shaders . Display2D . Texture1 = General . Map . Data . Crosshair3D . Texture ;
}
// Draw
graphics . Shaders . Display2D . Begin ( ) ;
graphics . Shaders . Display2D . SetSettings ( 1.0f , 1.0f , 0.0f , 1.0f , true ) ;
graphics . Shaders . Display2D . BeginPass ( 1 ) ;
graphics . Device . DrawUserPrimitives < FlatVertex > ( PrimitiveType . TriangleStrip , 0 , 2 , crosshairverts ) ;
graphics . Shaders . Display2D . EndPass ( ) ;
graphics . Shaders . Display2D . End ( ) ;
}
// This switches fog on and off
public void SetFogMode ( bool usefog )
{
graphics . Device . SetRenderState ( RenderState . FogEnable , usefog ) ;
}
// This siwtches crosshair busy icon on and off
public void SetCrosshairBusy ( bool busy )
{
crosshairbusy = busy ;
}
2012-04-18 19:34:11 +00:00
//dbg
2012-04-23 21:35:48 +00:00
//private int lastTick, lastFrameRate, frameRate;
2012-04-18 19:34:11 +00:00
2012-04-23 21:35:48 +00:00
/ * private int calculateFrameRate ( ) {
2012-04-18 19:34:11 +00:00
if ( System . Environment . TickCount - lastTick > = 1000 ) {
lastFrameRate = frameRate ;
frameRate = 0 ;
lastTick = System . Environment . TickCount ;
}
frameRate + + ;
return lastFrameRate ;
2012-04-23 21:35:48 +00:00
} * /
2009-04-19 18:07:22 +00:00
#endregion
}
}