mirror of
https://git.do.srb2.org/STJr/ZoneBuilder.git
synced 2024-11-15 00:51:39 +00:00
175 lines
4.7 KiB
C#
175 lines
4.7 KiB
C#
#region === Copyright (c) 2010 Pascal van der Heiden ===
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.Plugins.VisplaneExplorer
|
|
{
|
|
// This is a 64x64 tile in map space which holds the point data results.
|
|
internal class Tile
|
|
{
|
|
// Constants
|
|
public const int TILE_SIZE = 64;
|
|
public static readonly int[] STATS_COMPRESSOR = new[] { 1, 2, 1, 160 };
|
|
public static readonly int[] STATS_LIMITS = new[] { 128, 256, 32, 320 * 64 };
|
|
public const uint POINT_MAXRANGE = 254;
|
|
public const uint POINT_OVERFLOW = 0xFEFEFEFE;
|
|
public const uint POINT_VOID = 0xFFFFFFFF;
|
|
public const byte POINT_OVERFLOW_B = 0xFE;
|
|
public const byte POINT_VOID_B = 0xFF;
|
|
|
|
// Members
|
|
private Point position;
|
|
private uint[][] points;
|
|
private int nextindex;
|
|
|
|
// Properties
|
|
public Point Position { get { return position; } }
|
|
public bool IsComplete { get { return nextindex == (TILE_SIZE * TILE_SIZE); } }
|
|
|
|
// Constructor
|
|
public Tile(Point lefttoppos)
|
|
{
|
|
// Make the jagged array
|
|
// I use a jagged array because, allegedly, it performs better than a multidimensional array.
|
|
points = new uint[TILE_SIZE][];
|
|
for(int y = 0; y < TILE_SIZE; y++)
|
|
points[y] = new uint[TILE_SIZE];
|
|
|
|
position = lefttoppos;
|
|
}
|
|
|
|
// This receives a processed point
|
|
public void StorePointData(PointData pd)
|
|
{
|
|
uint t;
|
|
switch(pd.result)
|
|
{
|
|
case PointResult.OK:
|
|
uint vp = (uint)Math.Min((pd.visplanes + (STATS_COMPRESSOR[(int)ViewStats.Visplanes] - 1)) / STATS_COMPRESSOR[(int)ViewStats.Visplanes], POINT_MAXRANGE);
|
|
uint ds = (uint)Math.Min((pd.drawsegs + (STATS_COMPRESSOR[(int)ViewStats.Drawsegs] - 1)) / STATS_COMPRESSOR[(int)ViewStats.Drawsegs], POINT_MAXRANGE);
|
|
uint ss = (uint)Math.Min((pd.solidsegs + (STATS_COMPRESSOR[(int)ViewStats.Solidsegs] - 1)) / STATS_COMPRESSOR[(int)ViewStats.Solidsegs], POINT_MAXRANGE);
|
|
uint op = (uint)Math.Min((pd.openings + (STATS_COMPRESSOR[(int)ViewStats.Openings] - 1)) / STATS_COMPRESSOR[(int)ViewStats.Openings], POINT_MAXRANGE);
|
|
t = MakePointValue(vp, ds, ss, op);
|
|
break;
|
|
|
|
case PointResult.BadZ:
|
|
t = MakePointValue(1, 0, 0, 0);
|
|
break;
|
|
|
|
case PointResult.Void:
|
|
t = POINT_VOID;
|
|
break;
|
|
|
|
case PointResult.Overflow:
|
|
default:
|
|
t = POINT_OVERFLOW;
|
|
break;
|
|
}
|
|
|
|
FillPoints(ref pd.point, t);
|
|
}
|
|
|
|
// This fills points with the given tile data over the specified granularity
|
|
private void FillPoints(ref TilePoint p, uint t)
|
|
{
|
|
int xs = p.x - position.X;
|
|
int ys = p.y - position.Y;
|
|
int xe = xs + p.granularity;
|
|
int ye = ys + p.granularity;
|
|
for(int x = xs; x < xe; x++)
|
|
for(int y = ys; y < ye; y++)
|
|
points[y][x] = t;
|
|
}
|
|
|
|
// This composes point values
|
|
private static uint MakePointValue(uint vp, uint ds, uint ss, uint op)
|
|
{
|
|
unchecked
|
|
{
|
|
return vp + (ds << 8) + (ss << 16) + (op << 24);
|
|
}
|
|
}
|
|
|
|
// This returns a point value
|
|
public byte GetPointByte(int x, int y, int stat)
|
|
{
|
|
unchecked
|
|
{
|
|
uint v = points[y][x];
|
|
return (byte)((v >> (stat * 8)) & 0xFF);
|
|
}
|
|
}
|
|
|
|
// This returns a point value
|
|
public int GetPointValue(int x, int y, int stat)
|
|
{
|
|
byte b = GetPointByte(x, y, stat);
|
|
return b * STATS_COMPRESSOR[stat];
|
|
}
|
|
|
|
// This returns the next point to process
|
|
public TilePoint GetNextPoint()
|
|
{
|
|
TilePoint p = PointByIndex(nextindex++);
|
|
p.x += position.X;
|
|
p.y += position.Y;
|
|
return p;
|
|
}
|
|
|
|
// Returns a position by index
|
|
private static TilePoint PointByIndex(int index)
|
|
{
|
|
#if DEBUG
|
|
if(index > (TILE_SIZE * TILE_SIZE))
|
|
throw new IndexOutOfRangeException();
|
|
#endif
|
|
|
|
TilePoint p;
|
|
|
|
// Would be nicer if this could be done without branching or looping...
|
|
if(index == 0) p.granularity = 64;
|
|
else if(index < 4) p.granularity = 32;
|
|
else if(index < 16) p.granularity = 16;
|
|
else if(index < 64) p.granularity = 8;
|
|
else if(index < 256) p.granularity = 4;
|
|
else if(index < 1024) p.granularity = 2;
|
|
else p.granularity = 1;
|
|
|
|
// this is a "butterfly" style sequence, which begins like:
|
|
// ( 0 0) (32 32) ( 0 32) (32 0)
|
|
// (16 16) (48 48) (16 48) (48 16)
|
|
// ( 0 16) (32 48) ( 0 48) (32 16)
|
|
// (16 0) (48 32) (16 32) (48 0)
|
|
// ( 8 8) (40 40) ( 8 40) (40 8)
|
|
// etc....
|
|
|
|
p.x = (index & 1) << 5;
|
|
p.y = (((index >> 1) ^ index) & 1) << 5;
|
|
|
|
index >>= 2;
|
|
p.x += (index & 1) << 4;
|
|
p.y += (((index >> 1) ^ index) & 1) << 4;
|
|
|
|
index >>= 2;
|
|
p.x |= (index & 1) << 3;
|
|
p.y |= (((index >> 1) ^ index) & 1) << 3;
|
|
|
|
index >>= 2;
|
|
p.x |= (index & 1) << 2;
|
|
p.y |= (((index >> 1) ^ index) & 1) << 2;
|
|
|
|
index >>= 2;
|
|
p.x |= (index & 1) << 1;
|
|
p.y |= (((index >> 1) ^ index) & 1) << 1;
|
|
|
|
index >>= 2;
|
|
p.x |= index & 1;
|
|
p.y |= ((index >> 1) ^ index) & 1;
|
|
|
|
return p;
|
|
}
|
|
}
|
|
}
|