private unsafe void BlitVoxelToSurface(DrawingSurface ds, DrawingSurface vxl_ds, GameObject obj, DrawProperties props) { Point d = new Point(obj.Tile.Dx * TileWidth / 2, (obj.Tile.Dy - obj.Tile.Z) * TileHeight / 2); d.Offset(props.GetOffset(obj)); d.Offset(-vxl_ds.BitmapData.Width / 2, -vxl_ds.BitmapData.Height / 2); // rows inverted! var w_low = (byte*)ds.BitmapData.Scan0; byte* w_high = w_low + ds.BitmapData.Stride * ds.BitmapData.Height; var zBuffer = ds.GetZBuffer(); var shadowBufVxl = vxl_ds.GetShadows(); var shadowBuf = ds.GetShadows(); // int rowsTouched = 0; // short firstRowTouched = short.MaxValue; for (int y = 0; y < vxl_ds.Height; y++) { byte* src_row = (byte*)vxl_ds.BitmapData.Scan0 + vxl_ds.BitmapData.Stride * (vxl_ds.Height - y - 1); byte* dst_row = ((byte*)ds.BitmapData.Scan0 + (d.Y + y) * ds.BitmapData.Stride + d.X * 3); int zIdx = (d.Y + y) * ds.Width + d.X; if (dst_row < w_low || dst_row >= w_high) continue; for (int x = 0; x < vxl_ds.Width; x++) { // only non-transparent pixels if (*(src_row + x * 4 + 3) > 0) { *(dst_row + x * 3) = *(src_row + x * 4); *(dst_row + x * 3 + 1) = *(src_row + x * 4 + 1); *(dst_row + x * 3 + 2) = *(src_row + x * 4 + 2); // if (y < firstRowTouched) // firstRowTouched = (short)y; short zBufVal = (short)((obj.Tile.Rx + obj.Tile.Ry + obj.Tile.Z) * TileHeight / 2); if (zBufVal >= zBuffer[zIdx]) zBuffer[zIdx] = zBufVal; } // or shadows else if (shadowBufVxl[x + y * vxl_ds.Height]) { int shadIdx = (d.Y + y) * ds.Width + d.X + x; if (!shadowBuf[shadIdx]) { *(dst_row + x * 3) /= 2; *(dst_row + x * 3 + 1) /= 2; *(dst_row + x * 3 + 2) /= 2; shadowBuf[shadIdx] = true; } } zIdx++; } } }
unsafe public static 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; } }
unsafe public static 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; } }
private void canvas_MouseMove(object sender, MouseEventArgs e) { StringBuilder sb = new StringBuilder(); var canvas = sender as ZoomableCanvas; var pixelLocationF = canvas.PointToImagePixel(e.Location); var location = new Point((int)Math.Round(pixelLocationF.X, 0), (int)Math.Round(pixelLocationF.Y, 0)); if (location.X < 0 || location.Y < 0 || location.X >= canvas.ImageSize.Width || location.Y >= canvas.ImageSize.Height) { return; } int rIdx = location.X + location.Y * _drawingSurface.Width; var tile = _tiles.GetTileScreen(location); if (tile == null || !(tile.Drawable is TileDrawable)) { sb.Append("No valid tile under mouse"); } else { sb.AppendFormat("Cells: {0} Coords (X, Y / H): {1}, {2} / {3}", _cells, tile.Rx, tile.Ry, tile.Z); var objs = _map.GetObjectsAt(tile.Dx, tile.Dy / 2); if (objs.Any()) { sb.Append(" Objects:"); foreach (var obj in objs) { sb.Append(" " + obj); if (obj is OverlayObject) { var ovl = (obj as OverlayObject); if (ovl.IsGeneratedVeins) { sb.Append("(gen)"); } } sb.Append(" "); } } var tileFile = (tile.Drawable as TileDrawable).GetTileFile(tile); if (tileFile != null) { sb.AppendFormat("\nTile: {0}", (tileFile?.FileName ?? "").ToLower()); sb.AppendFormat(" TileNum: {0} SubTile: {1}", tile.TileNum, tile.SubTile); if (tileFile.Images[tile.SubTile].RampType != 0) { sb.AppendFormat(" Ramp: {0}", tileFile.Images[tile.SubTile].RampType); } if (tileFile.Images[tile.SubTile].TerrainType != 0) { sb.AppendFormat(" Terrain: {0}", tileFile.Images[tile.SubTile].TerrainType); } if (tile.IceGrowth > 0) { sb.Append(" IceGrowth"); } } #if DEBUG sb.AppendFormat("\nMouse: ({0},{1}) ", location.X, location.Y); sb.AppendFormat(": d({0},{1}) ", tile.Dx, tile.Dy); var gridTilenoZ = _tiles.GetTileScreen(location, true, true); sb.AppendFormat(" Touched: {0}", _tiles.GridTouched[gridTilenoZ.Dx, gridTilenoZ.Dy / 2]); if (_tiles.GridTouchedBy[gridTilenoZ.Dx, gridTilenoZ.Dy / 2] != null) { sb.AppendFormat(" by {0} ", _tiles.GridTouchedBy[gridTilenoZ.Dx, gridTilenoZ.Dy / 2]); } sb.AppendFormat(" Z-buf: {0}", _drawingSurface.GetZBuffer()[rIdx]); sb.AppendFormat(" S-buf: {0}", _drawingSurface.GetShadows()[rIdx]); #endif } toolStripStatusLabel1.Text = sb.ToString(); if (e.Button == MouseButtons.Right) { Point newPoint = new Point(location.X - _oldPoint.X, location.Y - _oldPoint.Y); panel1.AutoScrollPosition = new Point(-panel1.AutoScrollPosition.X - newPoint.X, -panel1.AutoScrollPosition.Y - newPoint.Y); } }
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { StringBuilder sb = new StringBuilder(); int rIdx = e.Location.X + e.Location.Y * _drawingSurface.Width; sb.AppendFormat("Mouse: ({0},{1})", e.Location.X, e.Location.Y); var tile = _tiles.GetTileScreen(e.Location); if (tile == null || !(tile.Drawable is TileDrawable)) { sb.Append("No valid tile under mouse"); } else { var tileFile = (tile.Drawable as TileDrawable).GetTileFile(tile); sb.AppendFormat(" Tile {4}: d({0},{1}) r({2},{3})", tile.Dx, tile.Dy, tile.Rx, tile.Ry, (tileFile?.FileName ?? "").ToUpper()); if (tileFile != null) { if (tileFile.Images[tile.SubTile].RampType != 0) { sb.AppendFormat(" ramp {0}", tileFile.Images[tile.SubTile].RampType); } if (tileFile.Images[tile.SubTile].TerrainType != 0) { sb.AppendFormat(" terrain {0}", tileFile.Images[tile.SubTile].TerrainType); } } var gridTilenoZ = _tiles.GetTileScreen(e.Location, true, true); sb.AppendFormat(" Touched: {0}", _tiles.GridTouched[gridTilenoZ.Dx, gridTilenoZ.Dy / 2]); if (_tiles.GridTouchedBy[gridTilenoZ.Dx, gridTilenoZ.Dy / 2] != null) { sb.AppendFormat(" by {0} ", _tiles.GridTouchedBy[gridTilenoZ.Dx, gridTilenoZ.Dy / 2]); } sb.AppendFormat(" Z-buf: {0}", _drawingSurface.GetZBuffer()[rIdx]); sb.AppendFormat(" S-buf: {0}", _drawingSurface.GetShadows()[rIdx]); var objs = _map.GetObjectsAt(tile.Dx, tile.Dy / 2); if (objs.Any()) { sb.Append(" Objects: "); foreach (var obj in objs) { sb.Append(obj); if (obj is OverlayObject) { var ovl = (obj as OverlayObject); if (ovl.IsGeneratedVeins) { sb.Append("(gen)"); } } sb.Append(" "); } } } toolStripStatusLabel1.Text = sb.ToString(); }
public unsafe void Draw(ShpFile shp, GameObject obj, Drawable dr, DrawProperties props, DrawingSurface ds, int transLucency = 0) { shp.Initialize(); Palette p = props.PaletteOverride ?? obj.Palette; int frameIndex = props.FrameDecider(obj); if (obj.Drawable.IsActualWall) { frameIndex = ((StructureObject)obj).WallBuildingFrame; } frameIndex = DecideFrameIndex(frameIndex, shp.NumImages); if (frameIndex >= shp.Images.Count) { return; } var img = shp.GetImage(frameIndex); var imgData = img.GetImageData(); if (imgData == null || img.Width * img.Height != imgData.Length) { return; } Point offset = props.GetOffset(obj); offset.X += obj.Tile.Dx * _config.TileWidth / 2 - shp.Width / 2 + img.X; offset.Y += (obj.Tile.Dy - obj.Tile.Z) * _config.TileHeight / 2 - shp.Height / 2 + img.Y; Logger.Trace("Drawing SHP file {0} (Frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y); int stride = ds.BitmapData.Stride; var heightBuffer = ds.GetHeightBuffer(); var zBuffer = ds.GetZBuffer(); var w_low = (byte *)ds.BitmapData.Scan0; byte *w_high = (byte *)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height; byte *w = (byte *)ds.BitmapData.Scan0 + offset.X * 3 + stride * offset.Y; // clip to 25-50-75-100 transLucency = (transLucency / 25) * 25; float a = transLucency / 100f; float b = 1 - a; int rIdx = 0; // image pixel index int zIdx = offset.X + offset.Y * ds.Width; // z-buffer pixel index short hBufVal = (short)(obj.Tile.Z * _config.TileHeight / 2); short zOffset = (short)((obj.BottomTile.Rx + obj.BottomTile.Ry) * _config.TileHeight / 2 + props.ZAdjust); if (!dr.Flat) { hBufVal += shp.Height; } for (int y = 0; y < img.Height; y++) { if (offset.Y + y < 0) { w += stride; rIdx += img.Width; zIdx += ds.Width; continue; // out of bounds } for (int x = 0; x < img.Width; x++) { byte paletteValue = imgData[rIdx]; short zshapeOffset = obj is StructureObject ? (GetBuildingZ(x, y, shp, img, obj)) : (short)0; if (paletteValue != 0) { short zBufVal = zOffset; if (dr.Flat) { zBufVal += (short)(y - img.Height); } else if (dr.IsBuildingPart) { // nonflat building zBufVal += zshapeOffset; } else { zBufVal += img.Height; } if (w_low <= w && w < w_high /*&& zBufVal >= zBuffer[zIdx]*/) { if (transLucency != 0) { *(w + 0) = (byte)(a * *(w + 0) + b * p.Colors[paletteValue].B); *(w + 1) = (byte)(a * *(w + 1) + b * p.Colors[paletteValue].G); *(w + 2) = (byte)(a * *(w + 2) + b * p.Colors[paletteValue].R); } else { *(w + 0) = p.Colors[paletteValue].B; *(w + 1) = p.Colors[paletteValue].G; *(w + 2) = p.Colors[paletteValue].R; //var pal = Theater.Active.GetPalettes().UnitPalette.Colors; //*(w + 0) = pal[zshapeOffset].R; //*(w + 1) = pal[zshapeOffset].G; //*(w + 2) = pal[zshapeOffset].B; } zBuffer[zIdx] = zBufVal; heightBuffer[zIdx] = hBufVal; } } //else { // *(w + 0) = 0; // *(w + 1) = 0; // *(w + 2) = 255; //} // Up to the next pixel rIdx++; zIdx++; w += 3; } w += stride - 3 * img.Width; zIdx += ds.Width - img.Width; } }
public unsafe void DrawShadow(GameObject obj, ShpFile shp, DrawProperties props, DrawingSurface ds) { shp.Initialize(); int frameIndex = props.FrameDecider(obj); if (obj.Drawable.IsActualWall) { frameIndex = ((StructureObject)obj).WallBuildingFrame; } frameIndex = DecideFrameIndex(frameIndex, shp.NumImages); frameIndex += shp.Images.Count / 2; // latter half are shadow Images if (frameIndex >= shp.Images.Count) { return; } var img = shp.GetImage(frameIndex); var imgData = img.GetImageData(); if (imgData == null || img.Width * img.Height != imgData.Length) { return; } Point offset = props.GetShadowOffset(obj); offset.X += obj.Tile.Dx * _config.TileWidth / 2 - shp.Width / 2 + img.X; offset.Y += (obj.Tile.Dy - obj.Tile.Z) * _config.TileHeight / 2 - shp.Height / 2 + img.Y; Logger.Trace("Drawing SHP shadow {0} (frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y); int stride = ds.BitmapData.Stride; var shadows = ds.GetShadows(); var zBuffer = ds.GetZBuffer(); var heightBuffer = ds.GetHeightBuffer(); var w_low = (byte *)ds.BitmapData.Scan0; byte *w_high = (byte *)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height; byte *w = (byte *)ds.BitmapData.Scan0 + offset.X * 3 + stride * offset.Y; int zIdx = offset.X + offset.Y * ds.Width; int rIdx = 0; short zOffset = (short)((obj.Tile.Rx + obj.Tile.Ry) * _config.TileHeight / 2 - shp.Height / 2 + img.Y); int castHeight = obj.Tile.Z * _config.TileHeight / 2; if (obj.Drawable != null && !obj.Drawable.Flat) { castHeight += shp.Height; castHeight += obj.Drawable.TileElevation * _config.TileHeight / 2; } for (int y = 0; y < img.Height; y++) { if (offset.Y + y < 0) { w += stride; rIdx += img.Width; zIdx += ds.Width; continue; // out of bounds } short zBufVal = zOffset; if (obj.Drawable.Flat) { zBufVal += (short)y; } else { zBufVal += img.Height; } for (int x = 0; x < img.Width; x++) { if (0 <= offset.X + x && offset.X + x < ds.Width && 0 <= y + offset.Y && y + offset.Y < ds.Height && imgData[rIdx] != 0 && !shadows[zIdx] && // zBufVal >= zBuffer[zIdx] && castHeight >= heightBuffer[zIdx]) { *(w + 0) /= 2; *(w + 1) /= 2; *(w + 2) /= 2; shadows[zIdx] = true; } // Up to the next pixel rIdx++; zIdx++; w += 3; } w += stride - 3 * img.Width; // ... and if we're no more on the same row, zIdx += ds.Width - img.Width; // adjust the writing pointer accordingy } }
unsafe public static void Draw(ShpFile shp, GameObject obj, Drawable dr, DrawProperties props, DrawingSurface ds, int transLucency = 0) { shp.Initialize(); int frameIndex = props.FrameDecider(obj); Palette p = props.PaletteOverride ?? obj.Palette; frameIndex = DecideFrameIndex(frameIndex, shp.NumImages); if (frameIndex >= shp.Images.Count) return; var img = shp.GetImage(frameIndex); var imgData = img.GetImageData(); if (imgData == null || img.Width * img.Height != imgData.Length) return; Point offset = props.GetOffset(obj); offset.X += obj.Tile.Dx * Drawable.TileWidth / 2 - shp.Width / 2 + img.X; offset.Y += (obj.Tile.Dy - obj.Tile.Z) * Drawable.TileHeight / 2 - shp.Height / 2 + img.Y; Logger.Trace("Drawing SHP file {0} (Frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y); int stride = ds.BitmapData.Stride; var heightBuffer = ds.GetHeightBuffer(); var zBuffer = ds.GetZBuffer(); var w_low = (byte*)ds.BitmapData.Scan0; byte* w_high = (byte*)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height; byte* w = (byte*)ds.BitmapData.Scan0 + offset.X * 3 + stride * offset.Y; // clip to 25-50-75-100 transLucency = (transLucency / 25) * 25; float a = transLucency / 100f; float b = 1 - a; int rIdx = 0; // image pixel index int zIdx = offset.X + offset.Y * ds.Width; // z-buffer pixel index short hBufVal = (short)(obj.Tile.Z * Drawable.TileHeight / 2); short zOffset = (short)((obj.BottomTile.Rx + obj.BottomTile.Ry) * Drawable.TileHeight / 2); if (!dr.Flat) hBufVal += shp.Height; for (int y = 0; y < img.Height; y++) { if (offset.Y + y < 0) { w += stride; rIdx += img.Width; zIdx += ds.Width; continue; // out of bounds } for (int x = 0; x < img.Width; x++) { byte paletteValue = imgData[rIdx]; short zshapeOffset = obj is StructureObject ? (GetBuildingZ(x, y, shp, img, obj)) : (short)0; if (paletteValue != 0) { short zBufVal = zOffset; if (dr.Flat) zBufVal += (short)(y - img.Height); else if (dr.IsBuildingPart) { // nonflat building zBufVal += zshapeOffset; } else zBufVal += img.Height; if (w_low <= w && w < w_high /*&& zBufVal >= zBuffer[zIdx]*/) { if (transLucency != 0) { *(w + 0) = (byte)(a * *(w + 0) + b * p.Colors[paletteValue].B); *(w + 1) = (byte)(a * *(w + 1) + b * p.Colors[paletteValue].G); *(w + 2) = (byte)(a * *(w + 2) + b * p.Colors[paletteValue].R); } else { *(w + 0) = p.Colors[paletteValue].B; *(w + 1) = p.Colors[paletteValue].G; *(w + 2) = p.Colors[paletteValue].R; //var pal = Theater.Active.GetPalettes().UnitPalette.Colors; //*(w + 0) = pal[zshapeOffset].R; //*(w + 1) = pal[zshapeOffset].G; //*(w + 2) = pal[zshapeOffset].B; } zBuffer[zIdx] = zBufVal; heightBuffer[zIdx] = hBufVal; } } //else { // *(w + 0) = 0; // *(w + 1) = 0; // *(w + 2) = 255; //} // Up to the next pixel rIdx++; zIdx++; w += 3; } w += stride - 3 * img.Width; zIdx += ds.Width - img.Width; } }
unsafe public static void DrawShadow(GameObject obj, ShpFile shp, DrawProperties props, DrawingSurface ds) { int frameIndex = props.FrameDecider(obj); frameIndex = DecideFrameIndex(frameIndex, shp.NumImages); frameIndex += shp.Images.Count / 2; // latter half are shadow Images if (frameIndex >= shp.Images.Count) return; var img = shp.GetImage(frameIndex); var imgData = img.GetImageData(); if (imgData == null || img.Width * img.Height != imgData.Length) return; Point offset = props.GetShadowOffset(obj); offset.X += obj.Tile.Dx * Drawable.TileWidth / 2 - shp.Width / 2 + img.X; offset.Y += (obj.Tile.Dy - obj.Tile.Z) * Drawable.TileHeight / 2 - shp.Height / 2 + img.Y; Logger.Trace("Drawing SHP shadow {0} (frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y); int stride = ds.BitmapData.Stride; var shadows = ds.GetShadows(); var zBuffer = ds.GetZBuffer(); var heightBuffer = ds.GetHeightBuffer(); var w_low = (byte*)ds.BitmapData.Scan0; byte* w_high = (byte*)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height; byte* w = (byte*)ds.BitmapData.Scan0 + offset.X * 3 + stride * offset.Y; int zIdx = offset.X + offset.Y * ds.Width; int rIdx = 0; short zOffset = (short)((obj.Tile.Rx + obj.Tile.Ry) * Drawable.TileHeight / 2 - shp.Height / 2 + img.Y); int castHeight = obj.Tile.Z * Drawable.TileHeight / 2; if (obj.Drawable != null && !obj.Drawable.Flat) { castHeight += shp.Height; castHeight += obj.Drawable.TileElevation * Drawable.TileHeight / 2; } for (int y = 0; y < img.Height; y++) { if (offset.Y + y < 0) { w += stride; rIdx += img.Width; zIdx += ds.Width; continue; // out of bounds } short zBufVal = zOffset; if (obj.Drawable.Flat) zBufVal += (short)y; else zBufVal += img.Height; for (int x = 0; x < img.Width; x++) { if (w_low <= w && w < w_high && imgData[rIdx] != 0 && !shadows[zIdx] //&& zBufVal >= zBuffer[zIdx] && castHeight >= heightBuffer[zIdx] ) { *(w + 0) /= 2; *(w + 1) /= 2; *(w + 2) /= 2; shadows[zIdx] = true; } // Up to the next pixel rIdx++; zIdx++; w += 3; } w += stride - 3 * img.Width; // ... and if we're no more on the same row, zIdx += ds.Width - img.Width; // adjust the writing pointer accordingy } }