working on visual mode

This commit is contained in:
codeimp 2008-12-02 06:53:24 +00:00
parent e0539e626b
commit 1336103adc
6 changed files with 212 additions and 8 deletions

View file

@ -112,5 +112,32 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
#endregion
#region ================== Methods
// TEST:
public override void OnMouseDown(MouseEventArgs e)
{
// Make ray
Vector3D start = CameraPosition;
Vector3D delta = CameraTarget.GetFixedLength(General.Settings.ViewDistance);
VisualPickResult pick = PickObject(start, start + delta);
// Any result?
if(pick.geometry != null)
{
if(pick.geometry is VisualMiddleSingle)
{
VisualMiddleSingle sd = (pick.geometry as VisualMiddleSingle);
General.Interface.ShowLinedefInfo(sd.Sidedef.Line);
}
}
else
{
General.Interface.HideInfo();
}
}
#endregion
}
}

View file

@ -47,6 +47,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Variables
private float top;
private float bottom;
#endregion
#region ================== Properties
@ -136,6 +139,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
verts[4] = verts[2];
verts[5] = new WorldVertex(v2.x, v2.y, geobottom, pc.ToInt(), t2.x, t2.y);
// Keep properties
this.top = geotop;
this.bottom = geobottom;
// Apply vertices
base.SetVertices(verts);
return true;
@ -151,6 +158,21 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Methods
// This performs a fast test in object picking
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
{
// We can't do any faster than the accurate pick
return true;
}
// This performs an accurate test for object picking
public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
{
// Check if point is between top and bottom
u_ray = PickRayU;
return (PickIntersect.z >= bottom) && (PickIntersect.z <= top);
}
#endregion
}
}

View file

@ -70,6 +70,11 @@ namespace CodeImp.DoomBuilder.VisualModes
internal int Triangles { get { return triangles; } }
internal int RenderPassInt { get { return renderpass; } }
// These are only here so that we can call this on all geometry
// but it is only implemented in the VisualSidedef class
internal Vector3D PickIntersect { set { } }
internal float PickRayU { set { } }
/// <summary>
/// Render pass in which this geometry must be rendered. Default is Solid.
/// </summary>
@ -110,13 +115,31 @@ namespace CodeImp.DoomBuilder.VisualModes
if(sector != null) sector.NeedsUpdateGeo = true;
}
// This compares for sorting
// This compares for sorting by sector
public int CompareTo(VisualGeometry other)
{
// Compare sectors
return this.sector.Sector.Index - other.sector.Sector.Index;
}
/// <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;
}
#endregion
}
}

View file

@ -301,12 +301,12 @@ namespace CodeImp.DoomBuilder.VisualModes
if(ld.SideOfLine(campos2d) < 0)
{
// Do front of line
if(ld.Front != null) ProcessSidedef(ld.Front);
if(ld.Front != null) ProcessSidedefCulling(ld.Front);
}
else
{
// Do back of line
if(ld.Back != null) ProcessSidedef(ld.Back);
if(ld.Back != null) ProcessSidedefCulling(ld.Back);
}
}
}
@ -336,7 +336,7 @@ namespace CodeImp.DoomBuilder.VisualModes
float side = sd.Line.SideOfLine(campos2d);
if(((side < 0) && sd.IsFront) ||
((side > 0) && !sd.IsFront))
ProcessSidedef(sd);
ProcessSidedefCulling(sd);
}
}
else
@ -354,7 +354,7 @@ namespace CodeImp.DoomBuilder.VisualModes
}
// This finds and adds visible sectors
private void ProcessSidedef(Sidedef sd)
private void ProcessSidedefCulling(Sidedef sd)
{
VisualSector vs;
@ -453,16 +453,141 @@ namespace CodeImp.DoomBuilder.VisualModes
public VisualPickResult PickObject(Vector3D from, Vector3D to)
{
VisualPickResult result = new VisualPickResult();
Vector2D from2d = from;
Vector2D to2d = to;
// Setup no result
result.geometry = null;
result.hitpos = new Vector3D();
result.u_ray = float.MaxValue;
// Pick geometry
// Find all blocks we are intersecting
List<VisualBlockEntry> blocks = blockmap.GetLineBlocks(from, to);
// TODO
// Go for all lines to see which ones we intersect
// We will collect geometry from the sectors and sidedefs
Line2D ray2d = new Line2D(from2d, to2d);
Dictionary<Linedef, Linedef> lines = new Dictionary<Linedef, Linedef>(blocks.Count * 10);
Dictionary<Sector, VisualSector> sectors = new Dictionary<Sector, VisualSector>(blocks.Count * 10);
List<VisualGeometry> potentialgeometry = new List<VisualGeometry>(blocks.Count * 10);
foreach(VisualBlockEntry b in blocks)
{
foreach(Linedef ld in b.Lines)
{
// Make sure we don't test a line twice
if(!lines.ContainsKey(ld))
{
lines.Add(ld, ld);
// Intersecting?
float u;
if(ld.Line.GetIntersection(ray2d, out u))
{
// Check on which side we are
float side = ld.SideOfLine(from2d);
// Calculate intersection point
Vector3D intersect = from + to * u;
// We must add the sectors of both sides of the line
// If we wouldn't, then aiming at a sector that is just within range
// could result in an incorrect hit (because the far line of the
// sector may not be included in this loop)
if(ld.Front != null)
{
// Find the visualsector
if(allsectors.ContainsKey(ld.Front.Sector))
{
VisualSector vs = allsectors[ld.Front.Sector];
// Add sector if not already added
if(!sectors.ContainsKey(ld.Front.Sector))
{
sectors.Add(ld.Front.Sector, vs);
potentialgeometry.AddRange(vs.FixedGeometry);
}
// Add sidedef if on the front side
if(side < 0.0f)
{
int previndex = potentialgeometry.Count;
potentialgeometry.AddRange(vs.GetSidedefGeometry(ld.Front));
for(int i = previndex; i < potentialgeometry.Count; i++)
{
potentialgeometry[i].PickIntersect = intersect;
potentialgeometry[i].PickRayU = u;
}
}
}
}
// Add back side also
if(ld.Back != null)
{
// Find the visualsector
if(allsectors.ContainsKey(ld.Back.Sector))
{
VisualSector vs = allsectors[ld.Back.Sector];
// Add sector if not already added
if(!sectors.ContainsKey(ld.Back.Sector))
{
sectors.Add(ld.Back.Sector, vs);
potentialgeometry.AddRange(vs.FixedGeometry);
}
// Add sidedef if on the front side
if(side > 0.0f)
{
int previndex = potentialgeometry.Count;
potentialgeometry.AddRange(vs.GetSidedefGeometry(ld.Back));
for(int i = previndex; i < potentialgeometry.Count; i++)
{
potentialgeometry[i].PickIntersect = intersect;
potentialgeometry[i].PickRayU = u;
}
}
}
}
}
}
}
}
// Now we have a list of potential geometry that lies along the trace line.
// We still don't know what geometry actually hits, but we ruled out that which doesn't get even close.
// This is still too much for accurate intersection testing, so we do a fast reject pass first.
Vector3D direction = to - from;
direction = direction.GetNormal();
List<VisualGeometry> likelygeometry = new List<VisualGeometry>(potentialgeometry.Count);
foreach(VisualGeometry g in potentialgeometry)
{
if(g.PickFastReject(from, to, direction)) likelygeometry.Add(g);
}
// Now we do an accurate intersection test for all resulting geometry
// We keep only the closest hit!
foreach(VisualGeometry g in likelygeometry)
{
float u = result.u_ray;
if(g.PickAccurate(from, to, direction, ref u))
{
// Closer than previous find?
if(u < result.u_ray)
{
result.u_ray = u;
result.geometry = g;
}
}
}
// Setup final result
result.hitpos = from + to * result.u_ray;
// Done
return result;
}
#endregion
#region ================== Rendering

View file

@ -42,6 +42,7 @@ namespace CodeImp.DoomBuilder.VisualModes
{
// Members
public VisualGeometry geometry;
public float u_ray;
public Vector3D hitpos;
}
}

View file

@ -51,11 +51,17 @@ namespace CodeImp.DoomBuilder.VisualModes
// Original sidedef
private Sidedef sidedef;
// Intersection point for current pick test
private Vector3D pickintersect;
private float pickrayu;
#endregion
#region ================== Properties
public Sidedef Sidedef { get { return sidedef; } }
new public Vector3D PickIntersect { get { return pickintersect; } internal set { pickintersect = value; } }
new public float PickRayU { get { return pickrayu; } internal set { pickrayu = value; } }
#endregion