working on visual mode

This commit is contained in:
codeimp 2008-12-09 22:51:27 +00:00
parent fe5d5a2001
commit 22d5b88baf
4 changed files with 194 additions and 55 deletions

View file

@ -54,7 +54,8 @@ namespace CodeImp.DoomBuilder.Rendering
void FinishGeometry();
// Rendering methods
void AddGeometry(VisualGeometry g);
void AddSectorGeometry(VisualGeometry g);
void AddThingGeometry(VisualThing t);
void RenderCrosshair();
void SetFogMode(bool usefog);
void SetCrosshairBusy(bool busy);

View file

@ -73,7 +73,12 @@ namespace CodeImp.DoomBuilder.Rendering
// 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;
#endregion
#region ================== Properties
@ -210,9 +215,12 @@ namespace CodeImp.DoomBuilder.Rendering
view3d = Matrix.LookAtRH(D3DDevice.V3(pos), D3DDevice.V3(lookat), new Vector3(0f, 0f, 1f));
// Make the billboard matrix
billboard = Matrix.RotationYawPitchRoll(0f, anglexy, anglez - Angle2D.PI);
Vector3D lookat2d = new Vector3D(lookat.x, lookat.y, 0.0f);
Vector3D campos2d = new Vector3D(pos.x, pos.y, 0.0f);
Vector3D delta2d = lookat2d - campos2d;
billboard = Matrix.Billboard(D3DDevice.V3(lookat2d), D3DDevice.V3(campos2d), new Vector3(0f, 0f, 1f), D3DDevice.V3(delta2d.GetNormal()));
}
// This creates 2D view matrix
private void CreateMatrices2D()
{
@ -287,7 +295,12 @@ namespace CodeImp.DoomBuilder.Rendering
{
// Make collection
geometry = new Dictionary<ImageData, BinaryHeap<VisualGeometry>>[RENDER_PASSES];
for(int i = 0; i < RENDER_PASSES; i++) geometry[i] = new Dictionary<ImageData, BinaryHeap<VisualGeometry>>();
things = new Dictionary<ImageData, List<VisualThing>>[RENDER_PASSES];
for(int i = 0; i < RENDER_PASSES; i++)
{
geometry[i] = new Dictionary<ImageData, BinaryHeap<VisualGeometry>>();
things[i] = new Dictionary<ImageData, List<VisualThing>>();
}
}
// This ends rendering world geometry
@ -307,17 +320,20 @@ namespace CodeImp.DoomBuilder.Rendering
ApplyMatrices3D();
// SOLID PASS
graphics.Device.SetTransform(TransformState.World, Matrix.Identity);
graphics.Shaders.World3D.BeginPass(0);
RenderSinglePass((int)RenderPass.Solid);
graphics.Shaders.World3D.EndPass();
// MASK PASS
graphics.Device.SetTransform(TransformState.World, Matrix.Identity);
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, true);
graphics.Shaders.World3D.BeginPass(0);
RenderSinglePass((int)RenderPass.Mask);
graphics.Shaders.World3D.EndPass();
// ALPHA PASS
graphics.Device.SetTransform(TransformState.World, Matrix.Identity);
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, true);
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, false);
graphics.Device.SetRenderState(RenderState.ZWriteEnable, false);
@ -328,6 +344,7 @@ namespace CodeImp.DoomBuilder.Rendering
graphics.Shaders.World3D.EndPass();
// ADDITIVE PASS
graphics.Device.SetTransform(TransformState.World, Matrix.Identity);
graphics.Device.SetRenderState(RenderState.DestinationBlend, Blend.One);
graphics.Shaders.World3D.BeginPass(0);
RenderSinglePass((int)RenderPass.Additive);
@ -345,10 +362,10 @@ namespace CodeImp.DoomBuilder.Rendering
private void RenderSinglePass(int pass)
{
// Get geometry for this pass
Dictionary<ImageData, BinaryHeap<VisualGeometry>> geo = geometry[pass];
Dictionary<ImageData, BinaryHeap<VisualGeometry>> geopass = geometry[pass];
// Render the geometry collected
foreach(KeyValuePair<ImageData, BinaryHeap<VisualGeometry>> group in geo)
foreach(KeyValuePair<ImageData, BinaryHeap<VisualGeometry>> group in geopass)
{
ImageData curtexture;
@ -399,6 +416,54 @@ namespace CodeImp.DoomBuilder.Rendering
}
}
}
// Get things for this pass
Dictionary<ImageData, List<VisualThing>> thingspass = things[pass];
// Render things collected
foreach(KeyValuePair<ImageData, List<VisualThing>> group in thingspass)
{
ImageData curtexture;
// What texture to use?
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
graphics.Device.SetTexture(0, curtexture.Texture);
graphics.Shaders.World3D.Texture1 = curtexture.Texture;
graphics.Shaders.World3D.ApplySettings();
// Render all things with this texture
foreach(VisualThing t in group.Value)
{
// Update buffer if needed
if(t.NeedsUpdateGeo) t.Update();
// Only do this sector when a vertexbuffer is created
if(t.GeometryBuffer != null)
{
// Create the matrix for positioning / rotation
Matrix transform = t.Orientation;
if(t.Billboard) transform = Matrix.Multiply(transform, billboard);
transform = Matrix.Multiply(transform, t.Position);
graphics.Device.SetTransform(TransformState.World, transform);
graphics.Shaders.World3D.ApplySettings();
// Apply buffer
graphics.Device.SetStreamSource(0, t.GeometryBuffer, 0, WorldVertex.Stride);
// Render!
graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, 0, t.Triangles);
}
}
}
}
// This finishes rendering
@ -414,7 +479,7 @@ namespace CodeImp.DoomBuilder.Rendering
#region ================== Rendering
// This collects a visual sector's geometry for rendering
public void AddGeometry(VisualGeometry g)
public void AddSectorGeometry(VisualGeometry g)
{
// Must have a texture!
if(g.Texture != null)
@ -425,12 +490,30 @@ namespace CodeImp.DoomBuilder.Rendering
// 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)
{
// Must have a texture!
if(t.Texture != null)
{
// 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);
}
}
// This renders the crosshair
public void RenderCrosshair()
{

View file

@ -648,43 +648,71 @@ namespace CodeImp.DoomBuilder.VisualModes
#region ================== Processing
// This creates a visual sector
/// <summary>
/// Implement this to create an instance of your VisualSector implementation.
/// </summary>
protected abstract VisualSector CreateVisualSector(Sector s);
// This creates a visual thing
/// <summary>
/// Implement this to create an instance of your VisualThing implementation.
/// </summary>
protected abstract VisualThing CreateVisualThing(Thing t);
// This returns a visual sector
/// <summary>
/// This returns the VisualSector for the given Sector.
/// </summary>
protected VisualSector GetVisualSector(Sector s)
{
return allsectors[s];
}
/// <summary>
/// This returns the VisualThing for the given Thing.
/// </summary>
protected VisualThing GetVisualThing(Thing t)
{
return allthings[t];
}
// This returns true when a visual sector has been created for the specified sector
/// <summary>
/// Returns True when a VisualSector has been created for the specified Sector.
/// </summary>
protected bool VisualSectorExists(Sector s)
{
return allsectors.ContainsKey(s);
}
// This fills the blockmap
/// <summary>
/// Returns True when a VisualThing has been created for the specified Thing.
/// </summary>
protected bool VisualThingExists(Thing t)
{
return allthings.ContainsKey(t);
}
/// <summary>
/// This is called when the blockmap needs to be refilled, because it was invalidated.
/// This usually happens when geometry is changed by undo, redo, cut or paste actions.
/// Lines and Things are added to the block map by the base implementation.
/// </summary>
protected virtual void FillBlockMap()
{
blockmap.AddLinedefsSet(General.Map.Map.Linedefs);
blockmap.AddThingsSet(General.Map.Map.Things);
}
// Processing
/// <summary>
/// While this mode is active, this is called continuously to process whatever needs processing.
/// </summary>
public override void OnProcess(double deltatime)
{
Vector3D camvec;
Vector3D camvecstrafe;
double multiplier;
base.OnProcess(deltatime);
// Calculate camera direction vectors
camvec = Vector3D.FromAngleXYZ(camanglexy, camanglez);
camvecstrafe = Vector3D.FromAngleXY(camanglexy + Angle2D.PIHALF);
Vector3D camvec = Vector3D.FromAngleXYZ(camanglexy, camanglez);
Vector3D camvecstrafe = Vector3D.FromAngleXY(camanglexy + Angle2D.PIHALF);
// Move the camera
if(doublespeed) multiplier = MOVE_SPEED_MULTIPLIER * 2.0f; else multiplier = MOVE_SPEED_MULTIPLIER;
@ -715,7 +743,7 @@ namespace CodeImp.DoomBuilder.VisualModes
{
// Render all visible sectors
foreach(VisualGeometry g in visiblegeometry)
renderer.AddGeometry(g);
renderer.AddSectorGeometry(g);
}
#endregion

View file

@ -40,7 +40,7 @@ using CodeImp.DoomBuilder.Rendering;
namespace CodeImp.DoomBuilder.VisualModes
{
public abstract class VisualThing : IVisualPickable, ID3DResource, IComparable<VisualThing>
public abstract class VisualThing : IVisualPickable, ID3DResource
{
#region ================== Constants
@ -55,12 +55,16 @@ namespace CodeImp.DoomBuilder.VisualModes
private ImageData texture;
// Geometry
private WorldVertex[] spritevertices;
private WorldVertex[] cagevertices;
private WorldVertex[] vertices;
private VertexBuffer geobuffer;
private bool updategeo;
private int spritetriangles;
private int cagetriangles;
private int triangles;
// Rendering
private int renderpass;
private Matrix orientation;
private Matrix position;
private bool billboard;
// Disposing
private bool isdisposed = false;
@ -71,11 +75,35 @@ namespace CodeImp.DoomBuilder.VisualModes
internal VertexBuffer GeometryBuffer { get { return geobuffer; } }
internal bool NeedsUpdateGeo { get { return updategeo; } }
internal int SpriteTriangles { get { return spritetriangles; } }
internal int CageTriangles { get { return cagetriangles; } }
internal int CageOffset { get { return spritevertices.Length; } }
internal int Triangles { get { return triangles; } }
internal int RenderPassInt { get { return renderpass; } }
internal Matrix Orientation { get { return orientation; } }
internal Matrix Position { get { return position; } }
/// <summary>
/// Set to True to use billboarding for this thing. When using billboarding,
/// the geometry will be rotated on the XY plane to face the camera.
/// </summary>
public bool Billboard { get { return billboard; } set { billboard = value; } }
/// <summary>
/// Returns the Thing that this VisualThing is created for.
/// </summary>
public Thing Thing { get { return thing; } }
/// <summary>
/// Render pass in which this geometry must be rendered. Default is Solid.
/// </summary>
public RenderPass RenderPass { get { return (RenderPass)renderpass; } set { renderpass = (int)value; } }
/// <summary>
/// Image to use as texture on the geometry.
/// </summary>
public ImageData Texture { get { return texture; } set { texture = value; } }
/// <summary>
/// Disposed or not?
/// </summary>
public bool IsDisposed { get { return isdisposed; } }
#endregion
@ -87,6 +115,9 @@ namespace CodeImp.DoomBuilder.VisualModes
{
// Initialize
this.thing = t;
this.renderpass = (int)RenderPass.Mask;
this.billboard = true;
this.orientation = Matrix.Identity;
// Register as resource
General.Map.Graphics.RegisterResource(this);
@ -131,30 +162,30 @@ namespace CodeImp.DoomBuilder.VisualModes
// Make new geometry
//Update();
}
// This compares for sorting by sprite
public int CompareTo(VisualThing other)
/// <summary>
/// This sets the position to use for the thing geometry.
/// </summary>
public void SetPosition(Vector3D pos)
{
return Math.Sign(this.texture.LongName - other.texture.LongName);
position = Matrix.Translation(D3DDevice.V3(pos));
}
/// <summary>
/// This sets the orientation to use for the thing geometry. When using this, you may want to turn off billboarding.
/// </summary>
public void SetOrientation(Vector3D angles)
{
orientation = Matrix.RotationYawPitchRoll(angles.z, angles.y, angles.x);
}
// This sets the vertices for the thing sprite
protected void SetSpriteVertices(ICollection<WorldVertex> verts)
protected void SetVertices(ICollection<WorldVertex> verts)
{
// Copy vertices
spritevertices = new WorldVertex[verts.Count];
verts.CopyTo(spritevertices, 0);
spritetriangles = spritevertices.Length / 3;
updategeo = true;
}
// This sets the vertices for the thing cage
protected void SetCageVertices(ICollection<WorldVertex> verts)
{
// Copy vertices
cagevertices = new WorldVertex[verts.Count];
verts.CopyTo(cagevertices, 0);
cagetriangles = cagevertices.Length / 3;
vertices = new WorldVertex[verts.Count];
verts.CopyTo(vertices, 0);
triangles = vertices.Length / 3;
updategeo = true;
}
@ -165,20 +196,16 @@ namespace CodeImp.DoomBuilder.VisualModes
if(geobuffer != null) geobuffer.Dispose();
geobuffer = null;
// Count the number of vertices there are
int numverts = spritevertices.Length + cagevertices.Length;
// Any vertics?
if(numverts > 0)
if(vertices.Length > 0)
{
// Make a new buffer
geobuffer = new VertexBuffer(General.Map.Graphics.Device, WorldVertex.Stride * numverts,
geobuffer = new VertexBuffer(General.Map.Graphics.Device, WorldVertex.Stride * vertices.Length,
Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);
// Fill the buffer
DataStream bufferstream = geobuffer.Lock(0, WorldVertex.Stride * numverts, LockFlags.Discard);
bufferstream.WriteRange<WorldVertex>(spritevertices);
bufferstream.WriteRange<WorldVertex>(cagevertices);
DataStream bufferstream = geobuffer.Lock(0, WorldVertex.Stride * vertices.Length, LockFlags.Discard);
bufferstream.WriteRange<WorldVertex>(vertices);
geobuffer.Unlock();
bufferstream.Dispose();
}