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.Generic ;
using CodeImp.DoomBuilder.Data ;
2015-05-27 12:38:03 +00:00
using CodeImp.DoomBuilder.Geometry ;
2013-04-11 11:04:16 +00:00
using CodeImp.DoomBuilder.GZBuilder.Data ; //mxd
2015-05-27 12:38:03 +00:00
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Rendering ;
using SlimDX ;
2012-04-23 21:35:48 +00:00
2009-04-19 18:07:22 +00:00
#endregion
namespace CodeImp.DoomBuilder.VisualModes
{
2015-09-27 21:09:14 +00:00
public abstract class VisualGeometry : IVisualPickable
2009-04-19 18:07:22 +00:00
{
2015-10-02 14:47:34 +00:00
#region = = = = = = = = = = = = = = = = = = Constants
2016-03-23 21:26:26 +00:00
private const float FOG_DENSITY_SCALER = - 1.442692f / 512000f ; //mxd. It's -1.442692f / 64000f in GZDoom...;
private const int FADE_MULTIPLIER = 4 ; //mxd
2015-10-02 14:47:34 +00:00
#endregion
2009-04-19 18:07:22 +00:00
#region = = = = = = = = = = = = = = = = = = Variables
// Texture
private ImageData texture ;
// Vertices
private WorldVertex [ ] vertices ;
private int triangles ;
2009-05-01 20:31:17 +00:00
// Selected?
protected bool selected ;
2009-04-19 18:07:22 +00:00
// Elements that this geometry is bound to
// Only the sector is required, sidedef is only for walls
private VisualSector sector ;
private Sidedef sidedef ;
/// <summary>
/// Absolute intersecting coordinates are set during object picking. This is not set if the geometry is not bound to a sidedef.
/// </summary>
protected Vector3D pickintersect ;
/// <summary>
/// Distance unit along the object picking ray is set during object picking. (0.0 is at camera, 1.0f is at far plane) This is not set if the geometry is not bound to a sidedef.
/// </summary>
protected float pickrayu ;
// Rendering
2015-09-27 21:09:14 +00:00
private RenderPass renderpass = RenderPass . Solid ;
2015-10-02 14:47:34 +00:00
protected float fogfactor ;
2009-04-19 18:07:22 +00:00
// Sector buffer info
private int vertexoffset ;
2012-04-18 19:34:11 +00:00
2013-09-11 09:47:53 +00:00
//mxd
2015-09-27 21:09:14 +00:00
private Vector3D [ ] boundingBox ;
2014-12-22 21:36:49 +00:00
protected VisualGeometryType geometrytype ;
protected string partname ; //UDMF part name
2016-01-11 13:00:52 +00:00
protected bool renderassky ;
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
// Internal properties
2012-07-05 13:48:08 +00:00
public WorldVertex [ ] Vertices { get { return vertices ; } } //mxd
2009-04-19 18:07:22 +00:00
internal int VertexOffset { get { return vertexoffset ; } set { vertexoffset = value ; } }
2016-01-14 11:39:52 +00:00
public int Triangles { get { return triangles ; } }
2009-04-19 18:07:22 +00:00
2013-09-11 09:47:53 +00:00
//mxd
2015-09-27 21:09:14 +00:00
public Vector3D [ ] BoundingBox { get { return boundingBox ; } }
2014-12-22 21:36:49 +00:00
public VisualGeometryType GeometryType { get { return geometrytype ; } }
2015-12-04 12:29:22 +00:00
public float FogFactor { get { return fogfactor ; } set { fogfactor = value ; } }
2016-01-11 13:00:52 +00:00
public bool RenderAsSky { get { return renderassky ; } }
2012-04-18 19:34:11 +00:00
2009-04-19 18:07:22 +00:00
/// <summary>
/// Render pass in which this geometry must be rendered. Default is Solid.
/// </summary>
2015-09-27 21:09:14 +00:00
public RenderPass RenderPass { get { return renderpass ; } set { renderpass = value ; } }
2009-04-19 18:07:22 +00:00
/// <summary>
/// Image to use as texture on this geometry.
/// </summary>
public ImageData Texture { get { return texture ; } set { texture = value ; } }
/// <summary>
/// Returns the VisualSector this geometry has been added to.
/// </summary>
public VisualSector Sector { get { return sector ; } internal set { sector = value ; } }
/// <summary>
/// Returns the Sidedef that this geometry is created for. Null for geometry that is sector-wide.
/// </summary>
public Sidedef Sidedef { get { return sidedef ; } }
2009-05-01 20:31:17 +00:00
/// <summary>
/// Selected or not? This is only used by the core to determine what color to draw it with.
/// </summary>
public bool Selected { get { return selected ; } set { selected = value ; } }
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Destructor
/// <summary>
/// This creates sector-global visual geometry. This geometry is always visible when any of the sector is visible.
/// </summary>
2015-05-27 12:38:03 +00:00
protected VisualGeometry ( VisualSector vs )
2009-04-19 18:07:22 +00:00
{
this . sector = vs ;
2014-12-22 21:36:49 +00:00
this . geometrytype = VisualGeometryType . UNKNOWN ; //mxd
2009-04-19 18:07:22 +00:00
}
/// <summary>
/// This creates visual geometry that is bound to a sidedef. This geometry is only visible when the sidedef is visible. It is automatically back-face culled during rendering and automatically XY intersection tested as well as back-face culled during object picking.
/// </summary>
2015-05-27 12:38:03 +00:00
protected VisualGeometry ( VisualSector vs , Sidedef sd )
2009-04-19 18:07:22 +00:00
{
this . sector = vs ;
this . sidedef = sd ;
2014-12-22 21:36:49 +00:00
this . geometrytype = VisualGeometryType . UNKNOWN ; //mxd
2009-04-19 18:07:22 +00:00
}
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
// This sets the vertices for this geometry
protected void SetVertices ( ICollection < WorldVertex > verts )
{
// Copy vertices
2014-10-28 09:23:21 +00:00
if ( verts ! = null ) //mxd
{
2013-09-26 12:43:39 +00:00
vertices = new WorldVertex [ verts . Count ] ;
verts . CopyTo ( vertices , 0 ) ;
triangles = vertices . Length / 3 ;
2014-10-28 09:23:21 +00:00
CalculateNormals ( ) ; //mxd
2016-01-16 12:46:44 +00:00
PerformAutoSelection ( ) ; //mxd
2014-10-28 09:23:21 +00:00
}
else
{
vertices = null ;
2013-09-26 12:43:39 +00:00
triangles = 0 ;
}
2012-04-23 21:35:48 +00:00
2009-04-19 18:07:22 +00:00
if ( sector ! = null ) sector . NeedsUpdateGeo = true ;
}
2012-04-17 19:13:47 +00:00
2013-09-11 09:47:53 +00:00
//mxd. Normals calculation algorithm taken from OpenGl wiki
2015-12-04 12:29:22 +00:00
private void CalculateNormals ( )
2014-10-28 09:23:21 +00:00
{
2015-12-04 12:29:22 +00:00
if ( triangles = = 0 ) return ;
2014-10-28 09:23:21 +00:00
BoundingBoxSizes bbs = new BoundingBoxSizes ( vertices [ 0 ] ) ;
for ( int i = 0 ; i < triangles ; i + + )
{
2015-12-28 15:01:53 +00:00
int startindex = i * 3 ;
WorldVertex p1 = vertices [ startindex ] ;
WorldVertex p2 = vertices [ startindex + 1 ] ;
WorldVertex p3 = vertices [ startindex + 2 ] ;
2014-10-28 09:23:21 +00:00
2015-12-28 15:01:53 +00:00
Vector3 U = new Vector3 ( p2 . x - p1 . x , p2 . y - p1 . y , p2 . z - p1 . z ) ;
Vector3 V = new Vector3 ( p3 . x - p1 . x , p3 . y - p1 . y , p3 . z - p1 . z ) ;
2014-10-28 09:23:21 +00:00
p1 . nx = p2 . nx = p3 . nx = - ( U . Y * V . Z - U . Z * V . Y ) ;
p1 . ny = p2 . ny = p3 . ny = - ( U . Z * V . X - U . X * V . Z ) ;
p1 . nz = p2 . nz = p3 . nz = - ( U . X * V . Y - U . Y * V . X ) ;
2015-12-28 15:01:53 +00:00
vertices [ startindex ] = p1 ;
vertices [ startindex + 1 ] = p2 ;
vertices [ startindex + 2 ] = p3 ;
2014-10-28 09:23:21 +00:00
BoundingBoxTools . UpdateBoundingBoxSizes ( ref bbs , p1 ) ;
BoundingBoxTools . UpdateBoundingBoxSizes ( ref bbs , p2 ) ;
BoundingBoxTools . UpdateBoundingBoxSizes ( ref bbs , p3 ) ;
2013-09-11 09:47:53 +00:00
}
2014-10-28 09:23:21 +00:00
boundingBox = BoundingBoxTools . CalculateBoundingPlane ( bbs ) ;
2013-09-11 09:47:53 +00:00
}
2015-10-02 14:47:34 +00:00
//mxd. Calculate fogdistance
//TODO: this doesn't match any GZDoom light mode...
//GZDoom: gl_renderstate.h, SetFog();
//GZDoom: gl_lightlevel.cpp gl_SetFog();
Fixed, Visual mode: in some cases ceiling glow effect was interfering with Transfer Brightness effect resulting in incorrectly lit sidedef geometry.
Fixed, Visual mode: UDMF sidedef brightness should be ignored when a wall section is affected by Transfer Brightness effect.
Fixed, Visual mode: any custom fog should be rendered regardless of sector brightness.
Fixed, Visual mode: "fogdensity" and "outsidefogdensity" MAPINFO values were processed incorrectly.
Fixed, Visual mode: in some cases Things were rendered twice during a render pass.
Fixed, Visual mode: floor glow effect should affect thing brightness only when applied to floor of the sector thing is in.
Fixed, TEXTURES parser: TEXTURES group was named incorrectly in the Textures Browser window when parsed from a WAD file.
Fixed, MAPINFO, GLDEFS, DECORATE parsers: "//$GZDB_SKIP" special comment was processed incorrectly.
Fixed, MAPINFO parser: "fogdensity" and "outsidefogdensity" properties are now initialized using GZDoom default value (255) instead of 0.
2016-01-25 13:42:53 +00:00
protected float CalculateFogFactor ( int brightness ) { return CalculateFogFactor ( Sector . Sector . FogMode , brightness ) ; }
public static float CalculateFogFactor ( SectorFogMode mode , int brightness )
2015-10-02 14:47:34 +00:00
{
float density ;
Fixed, Visual mode: in some cases ceiling glow effect was interfering with Transfer Brightness effect resulting in incorrectly lit sidedef geometry.
Fixed, Visual mode: UDMF sidedef brightness should be ignored when a wall section is affected by Transfer Brightness effect.
Fixed, Visual mode: any custom fog should be rendered regardless of sector brightness.
Fixed, Visual mode: "fogdensity" and "outsidefogdensity" MAPINFO values were processed incorrectly.
Fixed, Visual mode: in some cases Things were rendered twice during a render pass.
Fixed, Visual mode: floor glow effect should affect thing brightness only when applied to floor of the sector thing is in.
Fixed, TEXTURES parser: TEXTURES group was named incorrectly in the Textures Browser window when parsed from a WAD file.
Fixed, MAPINFO, GLDEFS, DECORATE parsers: "//$GZDB_SKIP" special comment was processed incorrectly.
Fixed, MAPINFO parser: "fogdensity" and "outsidefogdensity" properties are now initialized using GZDoom default value (255) instead of 0.
2016-01-25 13:42:53 +00:00
switch ( mode )
2015-10-02 14:47:34 +00:00
{
Fixed, Visual mode: in some cases ceiling glow effect was interfering with Transfer Brightness effect resulting in incorrectly lit sidedef geometry.
Fixed, Visual mode: UDMF sidedef brightness should be ignored when a wall section is affected by Transfer Brightness effect.
Fixed, Visual mode: any custom fog should be rendered regardless of sector brightness.
Fixed, Visual mode: "fogdensity" and "outsidefogdensity" MAPINFO values were processed incorrectly.
Fixed, Visual mode: in some cases Things were rendered twice during a render pass.
Fixed, Visual mode: floor glow effect should affect thing brightness only when applied to floor of the sector thing is in.
Fixed, TEXTURES parser: TEXTURES group was named incorrectly in the Textures Browser window when parsed from a WAD file.
Fixed, MAPINFO, GLDEFS, DECORATE parsers: "//$GZDB_SKIP" special comment was processed incorrectly.
Fixed, MAPINFO parser: "fogdensity" and "outsidefogdensity" properties are now initialized using GZDoom default value (255) instead of 0.
2016-01-25 13:42:53 +00:00
case SectorFogMode . OUTSIDEFOGDENSITY :
2016-03-23 21:26:26 +00:00
density = General . Map . Data . MapInfo . OutsideFogDensity * FADE_MULTIPLIER ;
Fixed, Visual mode: in some cases ceiling glow effect was interfering with Transfer Brightness effect resulting in incorrectly lit sidedef geometry.
Fixed, Visual mode: UDMF sidedef brightness should be ignored when a wall section is affected by Transfer Brightness effect.
Fixed, Visual mode: any custom fog should be rendered regardless of sector brightness.
Fixed, Visual mode: "fogdensity" and "outsidefogdensity" MAPINFO values were processed incorrectly.
Fixed, Visual mode: in some cases Things were rendered twice during a render pass.
Fixed, Visual mode: floor glow effect should affect thing brightness only when applied to floor of the sector thing is in.
Fixed, TEXTURES parser: TEXTURES group was named incorrectly in the Textures Browser window when parsed from a WAD file.
Fixed, MAPINFO, GLDEFS, DECORATE parsers: "//$GZDB_SKIP" special comment was processed incorrectly.
Fixed, MAPINFO parser: "fogdensity" and "outsidefogdensity" properties are now initialized using GZDoom default value (255) instead of 0.
2016-01-25 13:42:53 +00:00
break ;
2015-10-02 14:47:34 +00:00
Fixed, Visual mode: in some cases ceiling glow effect was interfering with Transfer Brightness effect resulting in incorrectly lit sidedef geometry.
Fixed, Visual mode: UDMF sidedef brightness should be ignored when a wall section is affected by Transfer Brightness effect.
Fixed, Visual mode: any custom fog should be rendered regardless of sector brightness.
Fixed, Visual mode: "fogdensity" and "outsidefogdensity" MAPINFO values were processed incorrectly.
Fixed, Visual mode: in some cases Things were rendered twice during a render pass.
Fixed, Visual mode: floor glow effect should affect thing brightness only when applied to floor of the sector thing is in.
Fixed, TEXTURES parser: TEXTURES group was named incorrectly in the Textures Browser window when parsed from a WAD file.
Fixed, MAPINFO, GLDEFS, DECORATE parsers: "//$GZDB_SKIP" special comment was processed incorrectly.
Fixed, MAPINFO parser: "fogdensity" and "outsidefogdensity" properties are now initialized using GZDoom default value (255) instead of 0.
2016-01-25 13:42:53 +00:00
case SectorFogMode . FOGDENSITY :
2016-03-23 21:26:26 +00:00
density = General . Map . Data . MapInfo . FogDensity * FADE_MULTIPLIER ;
Fixed, Visual mode: in some cases ceiling glow effect was interfering with Transfer Brightness effect resulting in incorrectly lit sidedef geometry.
Fixed, Visual mode: UDMF sidedef brightness should be ignored when a wall section is affected by Transfer Brightness effect.
Fixed, Visual mode: any custom fog should be rendered regardless of sector brightness.
Fixed, Visual mode: "fogdensity" and "outsidefogdensity" MAPINFO values were processed incorrectly.
Fixed, Visual mode: in some cases Things were rendered twice during a render pass.
Fixed, Visual mode: floor glow effect should affect thing brightness only when applied to floor of the sector thing is in.
Fixed, TEXTURES parser: TEXTURES group was named incorrectly in the Textures Browser window when parsed from a WAD file.
Fixed, MAPINFO, GLDEFS, DECORATE parsers: "//$GZDB_SKIP" special comment was processed incorrectly.
Fixed, MAPINFO parser: "fogdensity" and "outsidefogdensity" properties are now initialized using GZDoom default value (255) instead of 0.
2016-01-25 13:42:53 +00:00
break ;
case SectorFogMode . FADE :
2016-03-23 21:26:26 +00:00
density = General . Clamp ( 255 - brightness , 30 , 255 ) * FADE_MULTIPLIER ;
Fixed, Visual mode: in some cases ceiling glow effect was interfering with Transfer Brightness effect resulting in incorrectly lit sidedef geometry.
Fixed, Visual mode: UDMF sidedef brightness should be ignored when a wall section is affected by Transfer Brightness effect.
Fixed, Visual mode: any custom fog should be rendered regardless of sector brightness.
Fixed, Visual mode: "fogdensity" and "outsidefogdensity" MAPINFO values were processed incorrectly.
Fixed, Visual mode: in some cases Things were rendered twice during a render pass.
Fixed, Visual mode: floor glow effect should affect thing brightness only when applied to floor of the sector thing is in.
Fixed, TEXTURES parser: TEXTURES group was named incorrectly in the Textures Browser window when parsed from a WAD file.
Fixed, MAPINFO, GLDEFS, DECORATE parsers: "//$GZDB_SKIP" special comment was processed incorrectly.
Fixed, MAPINFO parser: "fogdensity" and "outsidefogdensity" properties are now initialized using GZDoom default value (255) instead of 0.
2016-01-25 13:42:53 +00:00
break ;
case SectorFogMode . CLASSIC :
density = General . Clamp ( 255 - brightness , 30 , 255 ) ;
break ;
case SectorFogMode . NONE :
density = 0f ;
break ;
default : throw new NotImplementedException ( "Unknown SectorFogMode!" ) ;
2015-10-02 14:47:34 +00:00
}
return density * FOG_DENSITY_SCALER ;
}
2013-09-11 09:47:53 +00:00
//mxd. Used to get proper sector from 3d-floors
2014-10-28 09:23:21 +00:00
public virtual Sector GetControlSector ( )
{
2013-09-11 09:47:53 +00:00
return sector . Sector ;
}
//mxd. Used to get proper linedef from 3d-floors
2014-10-28 09:23:21 +00:00
public virtual Linedef GetControlLinedef ( )
{
2013-09-11 09:47:53 +00:00
return sidedef . Line ;
}
2009-04-19 18:07:22 +00:00
// This keeps the results for a sidedef intersection
internal void SetPickResults ( Vector3D intersect , float u )
{
this . pickintersect = intersect ;
this . pickrayu = u ;
}
/// <summary>
/// This is called when the geometry must be tested for line intersection. This should reject
/// as fast as possible to rule out all geometry that certainly does not touch the line.
/// </summary>
public virtual bool PickFastReject ( Vector3D from , Vector3D to , Vector3D dir )
{
return false ;
}
/// <summary>
/// This is called when the geometry must be tested for line intersection. This should perform
/// accurate hit detection and set u_ray to the position on the ray where this hits the geometry.
/// </summary>
public virtual bool PickAccurate ( Vector3D from , Vector3D to , Vector3D dir , ref float u_ray )
{
return false ;
}
2016-01-16 12:46:44 +00:00
//mxd
protected abstract void PerformAutoSelection ( ) ;
2009-04-19 18:07:22 +00:00
#endregion
}
2012-06-26 08:54:25 +00:00
2013-09-11 09:47:53 +00:00
//mxd
2014-09-18 22:06:35 +00:00
public enum VisualGeometryType
{
2013-09-11 09:47:53 +00:00
FLOOR ,
CEILING ,
WALL_UPPER ,
WALL_MIDDLE ,
WALL_MIDDLE_3D ,
WALL_LOWER ,
2015-12-04 12:29:22 +00:00
FOG_BOUNDARY ,
2013-09-11 09:47:53 +00:00
UNKNOWN ,
}
2009-04-19 18:07:22 +00:00
}