@ Modified the BlockMap class with a template for the BlockEntry class and added custom block size (must be a power of 2 greater than 1)

@ Added BlockMapMode as an example to show how the BlockMap class behaves
This commit is contained in:
codeimp 2009-08-14 10:45:22 +00:00
parent 9d6d86936d
commit d75bd6be69
10 changed files with 344 additions and 44 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

View file

@ -1343,6 +1343,42 @@ namespace CodeImp.DoomBuilder
a = b;
b = t;
}
// This calculates the bits needed for a number
public static int BitsForInt(int v)
{
int[] LOGTABLE = new int[] {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 };
int r; // r will be lg(v)
int t, tt;
if(Int2Bool(tt = v >> 16))
{
r = Int2Bool(t = tt >> 8) ? 24 + LOGTABLE[t] : 16 + LOGTABLE[tt];
}
else
{
r = Int2Bool(t = v >> 8) ? 8 + LOGTABLE[t] : LOGTABLE[v];
}
return r;
}
// This clamps a value
public static float Clamp(float value, float min, float max)

View file

@ -38,7 +38,7 @@ using CodeImp.DoomBuilder.Editing;
namespace CodeImp.DoomBuilder.Map
{
public sealed class BlockEntry
public class BlockEntry
{
#region ================== Variables
@ -60,7 +60,7 @@ namespace CodeImp.DoomBuilder.Map
#region ================== Constructor
// Constructor for empty block
internal BlockEntry()
public BlockEntry()
{
lines = new List<Linedef>(2);
things = new List<Thing>(2);

View file

@ -38,20 +38,18 @@ using CodeImp.DoomBuilder.Editing;
namespace CodeImp.DoomBuilder.Map
{
public class BlockMap
public class BlockMap<BE> where BE : BlockEntry, new()
{
#region ================== Constants
public const int BLOCK_SIZE_SHIFT = 7;
public const int BLOCK_SIZE = 1 << BLOCK_SIZE_SHIFT;
public const float BLOCK_RADIUS = BLOCK_SIZE * Angle2D.SQRT2;
#endregion
#region ================== Variables
// Blocks
protected BlockEntry[,] blockmap;
protected BE[,] blockmap;
protected int blocksizeshift;
protected int blocksize;
protected Size size;
protected RectangleF range;
protected Vector2D rangelefttop;
@ -66,7 +64,7 @@ namespace CodeImp.DoomBuilder.Map
public bool IsDisposed { get { return isdisposed; } }
public Size Size { get { return size; } }
public RectangleF Range { get { return range; } }
public int BlockSize { get { return BLOCK_SIZE; } }
public int BlockSize { get { return blocksize; } }
#endregion
@ -74,14 +72,29 @@ namespace CodeImp.DoomBuilder.Map
// Constructor
public BlockMap(RectangleF range)
{
Initialize(range, 128);
}
// Constructor
public BlockMap(RectangleF range, int blocksize)
{
Initialize(range, blocksize);
}
// This initializes the blockmap
private void Initialize(RectangleF range, int blocksize)
{
// Initialize
this.range = range;
this.blocksizeshift = General.BitsForInt(blocksize);
this.blocksize = 1 << blocksizeshift;
if((this.blocksize != blocksize) || (this.blocksize <= 1)) throw new ArgumentException("Block size must be a power of 2 greater than 1");
rangelefttop = new Vector2D(range.Left, range.Top);
Point lefttop = new Point((int)range.Left >> BLOCK_SIZE_SHIFT, (int)range.Top >> BLOCK_SIZE_SHIFT);
Point rightbottom = new Point((int)range.Right >> BLOCK_SIZE_SHIFT, (int)range.Bottom >> BLOCK_SIZE_SHIFT);
Point lefttop = new Point((int)range.Left >> blocksizeshift, (int)range.Top >> blocksizeshift);
Point rightbottom = new Point((int)range.Right >> blocksizeshift, (int)range.Bottom >> blocksizeshift);
size = new Size((rightbottom.X - lefttop.X) + 1, (rightbottom.Y - lefttop.Y) + 1);
blockmap = new BlockEntry[size.Width, size.Height];
blockmap = new BE[size.Width, size.Height];
Clear();
}
@ -106,15 +119,15 @@ namespace CodeImp.DoomBuilder.Map
// This returns the block coordinates
protected Point GetBlockCoordinates(Vector2D v)
{
return new Point((int)(v.x - range.Left) >> BLOCK_SIZE_SHIFT,
(int)(v.y - range.Top) >> BLOCK_SIZE_SHIFT);
return new Point((int)(v.x - range.Left) >> blocksizeshift,
(int)(v.y - range.Top) >> blocksizeshift);
}
// This returns the block center in world coordinates
protected Vector2D GetBlockCenter(Point p)
{
return new Vector2D((float)((p.X << BLOCK_SIZE_SHIFT) + (BLOCK_SIZE >> 1)) + range.Left,
(float)((p.Y << BLOCK_SIZE_SHIFT) + (BLOCK_SIZE >> 1)) + range.Top);
return new Vector2D((float)((p.X << blocksizeshift) + (blocksize >> 1)) + range.Left,
(float)((p.Y << blocksizeshift) + (blocksize >> 1)) + range.Top);
}
// This returns true when the given block is inside range
@ -155,13 +168,22 @@ namespace CodeImp.DoomBuilder.Map
{
for(int y = 0; y < size.Height; y++)
{
blockmap[x, y] = new BlockEntry();
blockmap[x, y] = new BE();
}
}
}
// This returns a blocks at the given coordinates, if any
// Returns null when out of range
public virtual BE GetBlockAt(Vector2D pos)
{
// Calculate block coordinates
Point p = GetBlockCoordinates(pos);
return IsInRange(p) ? blockmap[p.X, p.Y] : null;
}
// This returns a range of blocks in a square
public virtual List<BlockEntry> GetSquareRange(RectangleF rect)
public virtual List<BE> GetSquareRange(RectangleF rect)
{
// Calculate block coordinates
Point lt = GetBlockCoordinates(new Vector2D(rect.Left, rect.Top));
@ -173,7 +195,7 @@ namespace CodeImp.DoomBuilder.Map
// Go through the range to make a list
int entriescount = ((rb.X - lt.X) + 1) * ((rb.Y - lt.Y) + 1);
List<BlockEntry> entries = new List<BlockEntry>(entriescount);
List<BE> entries = new List<BE>(entriescount);
for(int x = lt.X; x <= rb.X; x++)
{
for(int y = lt.Y; y <= rb.Y; y++)
@ -187,7 +209,7 @@ namespace CodeImp.DoomBuilder.Map
}
// This returns all blocks along the given line
public virtual List<BlockEntry> GetLineBlocks(Vector2D v1, Vector2D v2)
public virtual List<BE> GetLineBlocks(Vector2D v1, Vector2D v2)
{
float deltax, deltay;
float posx, posy;
@ -195,8 +217,8 @@ namespace CodeImp.DoomBuilder.Map
int dirx, diry;
// Estimate number of blocks we will go through and create list
int entriescount = (int)(Vector2D.ManhattanDistance(v1, v2) * 2.0f) / BLOCK_SIZE;
List<BlockEntry> entries = new List<BlockEntry>(entriescount);
int entriescount = (int)(Vector2D.ManhattanDistance(v1, v2) * 2.0f) / blocksize;
List<BE> entries = new List<BE>(entriescount);
// Find start and end block
pos = GetBlockCoordinates(v1);
@ -251,10 +273,10 @@ namespace CodeImp.DoomBuilder.Map
if(pos != end)
{
// Calculate current block edges
float cl = pos.X * BLOCK_SIZE;
float cr = (pos.X + 1) * BLOCK_SIZE;
float ct = pos.Y * BLOCK_SIZE;
float cb = (pos.Y + 1) * BLOCK_SIZE;
float cl = pos.X * blocksize;
float cr = (pos.X + 1) * blocksize;
float ct = pos.Y * blocksize;
float cb = (pos.Y + 1) * blocksize;
// Line directions
dirx = Math.Sign(v2.x - v1.x);
@ -264,25 +286,25 @@ namespace CodeImp.DoomBuilder.Map
if(dirx >= 0)
{
posx = (cr - v1.x) / (v2.x - v1.x);
deltax = BLOCK_SIZE / (v2.x - v1.x);
deltax = blocksize / (v2.x - v1.x);
}
else
{
// Calculate offset and delta movement over x
posx = (v1.x - cl) / (v1.x - v2.x);
deltax = BLOCK_SIZE / (v1.x - v2.x);
deltax = blocksize / (v1.x - v2.x);
}
// Calculate offset and delta movement over y
if(diry >= 0)
{
posy = (cb - v1.y) / (v2.y - v1.y);
deltay = BLOCK_SIZE / (v2.y - v1.y);
deltay = blocksize / (v2.y - v1.y);
}
else
{
posy = (v1.y - ct) / (v1.y - v2.y);
deltay = BLOCK_SIZE / (v1.y - v2.y);
deltay = blocksize / (v1.y - v2.y);
}
// Continue while not reached the end
@ -419,10 +441,10 @@ namespace CodeImp.DoomBuilder.Map
if(pos != end)
{
// Calculate current block edges
float cl = pos.X * BLOCK_SIZE;
float cr = (pos.X + 1) * BLOCK_SIZE;
float ct = pos.Y * BLOCK_SIZE;
float cb = (pos.Y + 1) * BLOCK_SIZE;
float cl = pos.X * blocksize;
float cr = (pos.X + 1) * blocksize;
float ct = pos.Y * blocksize;
float cb = (pos.Y + 1) * blocksize;
// Line directions
dirx = Math.Sign(v2.x - v1.x);
@ -437,13 +459,13 @@ namespace CodeImp.DoomBuilder.Map
else if(dirx > 0)
{
posx = (cr - v1.x) / (v2.x - v1.x);
deltax = BLOCK_SIZE / (v2.x - v1.x);
deltax = blocksize / (v2.x - v1.x);
}
else
{
// Calculate offset and delta movement over x
posx = (v1.x - cl) / (v1.x - v2.x);
deltax = BLOCK_SIZE / (v1.x - v2.x);
deltax = blocksize / (v1.x - v2.x);
}
// Calculate offset and delta movement over y
@ -455,12 +477,12 @@ namespace CodeImp.DoomBuilder.Map
else if(diry > 0)
{
posy = (cb - v1.y) / (v2.y - v1.y);
deltay = BLOCK_SIZE / (v2.y - v1.y);
deltay = blocksize / (v2.y - v1.y);
}
else
{
posy = (v1.y - ct) / (v1.y - v2.y);
deltay = BLOCK_SIZE / (v1.y - v2.y);
deltay = blocksize / (v1.y - v2.y);
}
// Continue while not reached the end

View file

@ -0,0 +1,229 @@

#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 CodeImp.DoomBuilder.Windows;
using CodeImp.DoomBuilder.IO;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Editing;
using System.Drawing;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.Data;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "BlockMap Mode",
SwitchAction = "blockmapmode",
ButtonImage = "Blockmap.png",
ButtonOrder = 400,
ButtonGroup = "002_tools",
AllowCopyPaste = false,
UseByDefault = true,
SafeStartMode = true)]
public sealed class BlockMapMode : BaseClassicMode
{
#region ================== Constants
#endregion
#region ================== Variables
private BlockMap<BlockEntry> blockmap;
private BlockEntry highlighted;
private int hx, hy;
#endregion
#region ================== Properties
#endregion
#region ================== Constructor / Disposer
// Constructor
public BlockMapMode()
{
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Dispose base
base.Dispose();
}
}
#endregion
#region ================== Methods
#endregion
#region ================== Events
// Mode engages
public override void OnEngage()
{
base.OnEngage();
// Nothing highlighted
highlighted = null;
hx = -1;
hy = -1;
// Custom presentation to hide the grid
CustomPresentation p = new CustomPresentation();
p.AddLayer(new PresentLayer(RendererLayer.Background, BlendingMode.Mask, General.Settings.BackgroundAlpha));
p.AddLayer(new PresentLayer(RendererLayer.Surface, BlendingMode.Mask));
p.AddLayer(new PresentLayer(RendererLayer.Overlay, BlendingMode.Alpha, 1f, true));
p.AddLayer(new PresentLayer(RendererLayer.Things, BlendingMode.Alpha, 1.0f));
p.AddLayer(new PresentLayer(RendererLayer.Geometry, BlendingMode.Alpha, 1f, true));
renderer.SetPresentation(p);
// Make the blockmap
RectangleF area = MapSet.CreateArea(General.Map.Map.Vertices);
area = MapSet.IncreaseArea(area, General.Map.Map.Things);
blockmap = new BlockMap<BlockEntry>(area);
blockmap.AddLinedefsSet(General.Map.Map.Linedefs);
blockmap.AddSectorsSet(General.Map.Map.Sectors);
blockmap.AddThingsSet(General.Map.Map.Things);
}
// When disengaged
public override void OnDisengage()
{
base.OnDisengage();
}
// This redraws the display
public override void OnRedrawDisplay()
{
renderer.RedrawSurface();
// Render lines and vertices
if(renderer.StartPlotter(true))
{
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
if(highlighted != null)
{
foreach(Linedef l in highlighted.Lines)
{
renderer.PlotLinedef(l, General.Colors.Highlight);
}
}
renderer.PlotVerticesSet(General.Map.Map.Vertices);
renderer.Finish();
}
// Render things
if(renderer.StartThings(true))
{
renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, Presentation.THINGS_HIDDEN_ALPHA);
renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, 1.0f);
if(highlighted != null)
{
foreach(Thing t in highlighted.Things)
{
renderer.RenderThing(t, General.Colors.Highlight, 1.0f);
}
}
renderer.Finish();
}
// Render blocks
if(renderer.StartOverlay(true))
{
for(int x = 0; x <= blockmap.Size.Width; x++)
{
Vector2D v1 = new Vector2D(blockmap.Range.X + (float)x * blockmap.BlockSize, blockmap.Range.Y);
Vector2D v2 = new Vector2D(v1.x, blockmap.Range.Y + blockmap.Size.Height * blockmap.BlockSize);
renderer.RenderLine(v1, v2, 2.0f, General.Colors.Selection, true);
}
for(int y = 0; y <= blockmap.Size.Height; y++)
{
Vector2D v1 = new Vector2D(blockmap.Range.X, blockmap.Range.Y + (float)y * blockmap.BlockSize);
Vector2D v2 = new Vector2D(blockmap.Range.X + blockmap.Size.Width * blockmap.BlockSize, v1.y);
renderer.RenderLine(v1, v2, 2.0f, General.Colors.Selection, true);
}
if((hx > -1) && (hy > -1))
{
Vector2D v1 = new Vector2D(blockmap.Range.X + (float)hx * blockmap.BlockSize, blockmap.Range.Y + (float)hy * blockmap.BlockSize);
Vector2D v2 = new Vector2D(blockmap.Range.X + (float)(hx + 1) * blockmap.BlockSize, blockmap.Range.Y + (float)(hy + 1) * blockmap.BlockSize);
renderer.RenderRectangle(new RectangleF(v1.x, v1.y, v2.x - v1.x, v2.y - v1.y), 2.0f, General.Colors.Highlight, true);
}
renderer.Finish();
}
renderer.Present();
}
// Mouse moves over display
public override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
BlockEntry newhighlight = null;
hx = -1;
hy = -1;
// Determine highlighted block
float nhx = (mousemappos.x - blockmap.Range.Left) / (float)blockmap.BlockSize;
float nhy = (mousemappos.y - blockmap.Range.Top) / (float)blockmap.BlockSize;
if((nhx < (float)blockmap.Size.Width) && (nhy < (float)blockmap.Size.Height) && (nhx >= 0.0f) && (nhy >= 0.0f))
{
newhighlight = blockmap.GetBlockAt(mousemappos);
if(newhighlight != null)
{
hx = (int)nhx;
hy = (int)nhy;
}
}
if(newhighlight != highlighted)
{
highlighted = newhighlight;
General.Interface.RedrawDisplay();
}
}
#endregion
}
}

View file

@ -65,7 +65,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public override void Run()
{
Dictionary<Linedef, Linedef> donelines = new Dictionary<Linedef, Linedef>();
BlockMap blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap;
BlockMap<BlockEntry> blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap;
int progress = 0;
int stepprogress = 0;

View file

@ -66,7 +66,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This runs the check
public override void Run()
{
BlockMap blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap;
BlockMap<BlockEntry> blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap;
int progress = 0;
int stepprogress = 0;

View file

@ -58,14 +58,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
private volatile bool running = false;
private Thread checksthread;
private BlockMap blockmap;
private BlockMap<BlockEntry> blockmap;
#endregion
#region ================== Properties
public ErrorResult SelectedResult { get { return results.SelectedItem as ErrorResult; } }
public BlockMap BlockMap { get { return blockmap; } }
public BlockMap<BlockEntry> BlockMap { get { return blockmap; } }
#endregion
@ -194,7 +194,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Make blockmap
RectangleF area = MapSet.CreateArea(General.Map.Map.Vertices);
area = MapSet.IncreaseArea(area, General.Map.Map.Things);
blockmap = new BlockMap(area);
blockmap = new BlockMap<BlockEntry>(area);
blockmap.AddLinedefsSet(General.Map.Map.Linedefs);
blockmap.AddSectorsSet(General.Map.Map.Sectors);
blockmap.AddThingsSet(General.Map.Map.Things);

View file

@ -26,6 +26,19 @@ categories
// allowkeys and allowmouse are true by default, the others are false by default.
//
// TEMPORARY:
blockmapmode
{
title = "BlockMap Mode";
category = "modes";
description = "Switches to blockmap checking mode.";
allowkeys = true;
allowmouse = true;
allowscroll = true;
}
verticesmode
{
title = "Vertices Mode";

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B