public static unsafe void Draw(MapTile tile, TmpFile tmp, DrawingSurface ds)
{
tmp.Initialize();
if (tile.SubTile >= tmp.Images.Count) return;
TmpFile.TmpImage img = tmp.Images[tile.SubTile];
var zBuffer = ds.GetZBuffer();
var heightBuffer = ds.GetHeightBuffer();
Palette p = tile.Palette;
// calculate tile index -> pixel index
Point offset = new Point(tile.Dx * tmp.BlockWidth / 2, (tile.Dy - tile.Z) * tmp.BlockHeight / 2);
// make touched tiles (used for determining image cutoff)
Point center = offset + new Size(tmp.BlockWidth / 2, tmp.BlockHeight / 2);
var centerGridTile = tile.Layer.GetTileScreen(center, true, true);
if (centerGridTile != null) {
tile.Layer.GridTouched[centerGridTile.Dx, centerGridTile.Dy / 2] |= TileLayer.TouchType.ByNormalData;
tile.Layer.GridTouchedBy[centerGridTile.Dx, centerGridTile.Dy / 2] = tile;
}
Logger.Trace("Drawing TMP file {0} (subtile {1}) at ({2},{3})", tmp.FileName, tile.SubTile, offset.X, offset.Y);
int stride = ds.BitmapData.Stride;
int halfCx = tmp.BlockWidth / 2,
halfCy = tmp.BlockHeight / 2;
// writing bounds
var w_low = (byte*)ds.BitmapData.Scan0;
byte* w_high = (byte*)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height;
byte* w = (byte*)ds.BitmapData.Scan0 + stride * offset.Y + (offset.X + halfCx - 2) * 3;
int rIdx = 0, x, y = 0;
int zIdx = offset.Y * ds.Width + offset.X + halfCx - 2;
int cx = 0; // Amount of pixel to copy
for (; y < halfCy; y++) {
cx += 4;
for (ushort c = 0; c < cx; c++) {
byte paletteValue = img.TileData[rIdx];
short zBufVal = (short)((tile.Rx + tile.Ry) * tmp.BlockHeight / 2 - (img.ZData != null ? img.ZData[rIdx] : 0));
if (paletteValue != 0 && w_low <= w && w < w_high && zBufVal >= zBuffer[zIdx]) {
*(w + 0) = p.Colors[paletteValue].B;
*(w + 1) = p.Colors[paletteValue].G;
*(w + 2) = p.Colors[paletteValue].R;
zBuffer[zIdx] = zBufVal;
heightBuffer[zIdx] = (short)(tile.Z * Drawable.TileHeight / 2);
}
w += 3;
zIdx++;
rIdx++;
}
w += stride - 3 * (cx + 2);
zIdx += ds.Width - (cx + 2);
}
w += 12;
zIdx += 4;
for (; y < tmp.BlockHeight; y++) {
cx -= 4;
for (ushort c = 0; c < cx; c++) {
byte paletteValue = img.TileData[rIdx];
short zBufVal = (short)((tile.Rx + tile.Ry) * tmp.BlockHeight / 2 - (img.ZData != null ? img.ZData[rIdx] : 0));
if (paletteValue != 0 && w_low <= w && w < w_high && zBufVal >= zBuffer[zIdx]) {
*(w + 0) = p.Colors[paletteValue].B;
*(w + 1) = p.Colors[paletteValue].G;
*(w + 2) = p.Colors[paletteValue].R;
zBuffer[zIdx] = zBufVal;
heightBuffer[zIdx] = (short)(tile.Z * Drawable.TileHeight / 2);
}
w += 3;
zIdx++;
rIdx++;
}
w += stride - 3 * (cx - 2);
zIdx += ds.Width - (cx - 2);
}
if (!img.HasExtraData) return; // we're done now
offset.X += img.ExtraX - img.X;
offset.Y += img.ExtraY - img.Y;
w = w_low + stride * offset.Y + 3 * offset.X;
zIdx = offset.X + offset.Y * ds.Width;
rIdx = 0;
// identify extra-data affected tiles for cutoff
var extraScreenBounds = Rectangle.FromLTRB(
Math.Max(0, offset.X), Math.Max(0, offset.Y),
Math.Min(offset.X + img.ExtraWidth, ds.Width), Math.Min(offset.Y + img.ExtraHeight, ds.Height));
for (int by = extraScreenBounds.Top; by < extraScreenBounds.Bottom; by += tmp.BlockHeight / 2) {
for (int bx = extraScreenBounds.Left; bx < extraScreenBounds.Right; bx += tmp.BlockWidth / 2) {
var gridTileNoZ = tile.Layer.GetTileScreen(new Point(bx, by), true, true);
if (gridTileNoZ != null) {
Logger.Trace("Tile at ({0},{1}) has extradata affecting ({2},{3})", tile.Dx, tile.Dy, gridTileNoZ.Dx,
gridTileNoZ.Dy);
tile.Layer.GridTouched[gridTileNoZ.Dx, gridTileNoZ.Dy / 2] |= TileLayer.TouchType.ByExtraData;
tile.Layer.GridTouchedBy[gridTileNoZ.Dx, gridTileNoZ.Dy / 2] = tile;
}
}
}
// Extra graphics are just a square
for (y = 0; y < img.ExtraHeight; y++) {
for (x = 0; x < img.ExtraWidth; x++) {
// Checking per line is required because v needs to be checked every time
byte paletteValue = img.ExtraData[rIdx];
short zBufVal = (short)((tile.Rx + tile.Ry) * tmp.BlockHeight / 2 + (img.ExtraZData != null ? img.ExtraZData[rIdx] : 0));
if (paletteValue != 0 && w_low <= w && w < w_high && zBufVal >= zBuffer[zIdx]) {
*w++ = p.Colors[paletteValue].B;
*w++ = p.Colors[paletteValue].G;
*w++ = p.Colors[paletteValue].R;
zBuffer[zIdx] = zBufVal;
heightBuffer[zIdx] = (short)(img.ExtraHeight - y + tile.Z * Drawable.TileHeight / 2);
}
else
w += 3;
zIdx++;
rIdx++;
}
w += stride - img.ExtraWidth * 3;
zIdx += ds.Width - img.ExtraWidth;
}
}