mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-12-25 19:46:50 -05:00
Added map caching. Improved map rendering a little bit.
This commit is contained in:
parent
256ccbc7c2
commit
04f1238f2c
@ -29,6 +29,6 @@ namespace OpenDiablo2.Common.Interfaces
|
||||
void Draw(ISprite sprite, int frame);
|
||||
void Draw(ISprite sprite, int xSegments, int ySegments, int offset);
|
||||
void Draw(ILabel label);
|
||||
void DrawMapCell(int xCell, int yCell, int xPixel, int yPixel, MPQDS1 mapData, int main_index, int sub_index, Palette palette, MPQDS1WallOrientationTileProps orientation);
|
||||
void DrawMapCell(int xCell, int yCell, int xPixel, int yPixel, MPQDS1 mapData, int main_index, int sub_index, Palette palette, int orientation = -1);
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ namespace OpenDiablo2.Common.Models
|
||||
{
|
||||
static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public Guid Id { get; } = Guid.NewGuid();
|
||||
public Int32 Version { get; internal set; }
|
||||
public Int32 Width { get; internal set; }
|
||||
public Int32 Height { get; internal set; }
|
||||
|
@ -21,6 +21,7 @@ namespace OpenDiablo2.Common.Models
|
||||
|
||||
public sealed class MPQDT1Tile
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
public Int32 Direction { get; internal set; }
|
||||
public Int16 RoofHeight { get; internal set; }
|
||||
public byte SoundIndex { get; internal set; }
|
||||
@ -40,6 +41,8 @@ namespace OpenDiablo2.Common.Models
|
||||
|
||||
public sealed class MPQDT1
|
||||
{
|
||||
public Int32 X1 { get; private set; }
|
||||
public Int32 X2 { get; private set; }
|
||||
public Int32 NumberOfTiles { get; private set; }
|
||||
public MPQDT1Tile[] Tiles { get; private set; }
|
||||
private Int32 tileHeaderOffset;
|
||||
@ -48,7 +51,11 @@ namespace OpenDiablo2.Common.Models
|
||||
{
|
||||
var br = new BinaryReader(stream);
|
||||
|
||||
X1 = br.ReadInt32();
|
||||
X2 = br.ReadInt32();
|
||||
|
||||
stream.Seek(268, SeekOrigin.Begin); // Skip useless header info
|
||||
|
||||
NumberOfTiles = br.ReadInt32();
|
||||
tileHeaderOffset = br.ReadInt32();
|
||||
|
||||
@ -62,6 +69,7 @@ namespace OpenDiablo2.Common.Models
|
||||
Tiles = new MPQDT1Tile[NumberOfTiles];
|
||||
for (int tileIndex = 0; tileIndex < NumberOfTiles; tileIndex++)
|
||||
{
|
||||
br.BaseStream.Seek(tileHeaderOffset + (tileIndex * 96), SeekOrigin.Begin);
|
||||
Tiles[tileIndex] = new MPQDT1Tile();
|
||||
var tile = Tiles[tileIndex];
|
||||
|
||||
@ -93,11 +101,12 @@ namespace OpenDiablo2.Common.Models
|
||||
for (int tileIndex = 0; tileIndex < NumberOfTiles; tileIndex++)
|
||||
{
|
||||
var tile = Tiles[tileIndex];
|
||||
br.BaseStream.Seek(tile.BlockHeadersPointer, SeekOrigin.Begin);
|
||||
tile.Blocks = new MPQDT1Block[tile.NumberOfBlocks];
|
||||
|
||||
for (int blockIndex = 0; blockIndex < tile.NumberOfBlocks; blockIndex++)
|
||||
{
|
||||
br.BaseStream.Seek(tile.BlockHeadersPointer + (blockIndex * 20), SeekOrigin.Begin);
|
||||
|
||||
tile.Blocks[blockIndex] = new MPQDT1Block();
|
||||
var block = tile.Blocks[blockIndex];
|
||||
|
||||
|
@ -10,7 +10,7 @@ namespace OpenDiablo2.Common.Models
|
||||
public struct Palette
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public UInt32[] Colors;
|
||||
public UInt32[] Colors { get; set; }
|
||||
|
||||
public static Palette LoadFromStream(Stream stream, string paletteName)
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ namespace OpenDiablo2.Core.GameState_
|
||||
Seed = random.Next();
|
||||
|
||||
sceneManager.ChangeScene("Game");
|
||||
ChangeMap(eLevelId.Act5_BaalEntrance);
|
||||
ChangeMap(eLevelId.Act3_MephistoComplex);
|
||||
}
|
||||
|
||||
public void ChangeMap(eLevelId levelId)
|
||||
@ -71,6 +71,7 @@ namespace OpenDiablo2.Core.GameState_
|
||||
MapName = level.Name;
|
||||
Act = levelType.Act;
|
||||
MapData = resourceManager.GetMPQDS1(mapName, level, levelDetails, levelType);
|
||||
|
||||
getMapEngine().NotifyMapChanged();
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using OpenDiablo2.Common;
|
||||
using OpenDiablo2.Common.Interfaces;
|
||||
using OpenDiablo2.Common.Models;
|
||||
|
||||
namespace OpenDiablo2.Core.Map_Engine
|
||||
{
|
||||
@ -65,83 +66,126 @@ namespace OpenDiablo2.Core.Map_Engine
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Render()
|
||||
{
|
||||
// Lower Walls, Floors, and Shadows
|
||||
|
||||
// Shadows of objects
|
||||
|
||||
// Objects with OrderFlag = 1
|
||||
|
||||
// Upper Walls and objects with ORderFlag = 0 or 2
|
||||
|
||||
// Roofs
|
||||
|
||||
|
||||
for (int y = 0; y < gameState.MapData.Width; y++)
|
||||
for (int x = 0; x < gameState.MapData.Height; x++)
|
||||
for (int y = 0; y < gameState.MapData.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < gameState.MapData.Width; x++)
|
||||
{
|
||||
|
||||
var visualX = ((x - y) * (cellSizeX / 2)) - cOffX;
|
||||
var visualY = ((x + y) * (cellSizeY / 2)) - cOffY;
|
||||
|
||||
if (visualX < -160 || visualX > 800 || visualY < -120 || visualY > 650)
|
||||
continue;
|
||||
|
||||
// Render the floor
|
||||
foreach (var floorLayer in gameState.MapData.FloorLayers)
|
||||
{
|
||||
var idx = x + (y * gameState.MapData.Width);
|
||||
if (idx >= floorLayer.Props.Length)
|
||||
break;
|
||||
var floor = floorLayer.Props[idx];
|
||||
|
||||
if (floor.Prop1 == 0)
|
||||
continue;
|
||||
|
||||
var sub_index = floor.Prop2;
|
||||
var main_index = (floor.Prop3 >> 4) + ((floor.Prop4 & 0x03) << 4);
|
||||
|
||||
|
||||
renderWindow.DrawMapCell(x, y, ((x - y) * 80) - cOffX, ((x + y) * 40) - cOffY, gameState.MapData, main_index, sub_index, gameState.CurrentPalette, null);
|
||||
}
|
||||
|
||||
|
||||
DrawWall(x, y, visualX, visualY, false);
|
||||
DrawFloor(x, y, visualX, visualY);
|
||||
DrawWall(x, y, visualX, visualY, true);
|
||||
DrawRoof(x, y, visualX, visualY);
|
||||
// //DrawShadow(x, y, visualX, visualY);
|
||||
}
|
||||
/*
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void DrawRoof(int x, int y, int visualX, int visualY)
|
||||
{
|
||||
var cx = ((x - y) * 80) - cOffX;
|
||||
var cy = ((x + y) * 40) - cOffY;
|
||||
|
||||
|
||||
// Render the walls
|
||||
foreach (var wallLayer in gameState.MapData.WallLayers)
|
||||
{
|
||||
var wall = wallLayer.Props[x + (y * gameState.MapData.Width)];
|
||||
var orientation = wallLayer.Orientations[x + (y * gameState.MapData.Width)].Orientation1;
|
||||
|
||||
for (int y = 0; y < gameState.MapData.Width; y++)
|
||||
for (int x = 0; x < gameState.MapData.Height; x++)
|
||||
{
|
||||
if (orientation != 15) // Only 15 (roof)
|
||||
return;
|
||||
|
||||
var visualX = ((x - y) * (cellSizeX / 2)) - cOffX;
|
||||
var visualY = ((x + y) * (cellSizeY / 2)) - cOffY;
|
||||
if (wall.Prop1 == 0)
|
||||
continue;
|
||||
|
||||
if (visualX < -160 || visualX > 800 || visualY < -120 || visualY > 650)
|
||||
continue;
|
||||
if ((wall.Prop4 & 0x80) > 0)
|
||||
{
|
||||
if (orientation != 10 && orientation != 11)
|
||||
return;
|
||||
}
|
||||
|
||||
var idx = x + (y * gameState.MapData.Width);
|
||||
if (idx >= wallLayer.Props.Length)
|
||||
continue;
|
||||
var wall = wallLayer.Props[idx];
|
||||
|
||||
if (wall.Prop1 == 0)
|
||||
continue;
|
||||
|
||||
var sub_index = wall.Prop2;
|
||||
var main_index = (wall.Prop3 >> 4) + ((wall.Prop4 & 0x03) << 4);
|
||||
|
||||
var orientation = wallLayer.Orientations[x + (y * gameState.MapData.Width)];
|
||||
renderWindow.DrawMapCell(x, y, ((x - y) * 80) - cOffX, ((x + y) * 40) - cOffY + 80, gameState.MapData, main_index, sub_index, gameState.CurrentPalette, orientation);
|
||||
|
||||
}
|
||||
var sub_index = wall.Prop2;
|
||||
var main_index = (wall.Prop3 >> 4) + ((wall.Prop4 & 0x03) << 4);
|
||||
|
||||
var lt = gameState.MapData.LookupTable.First(z => z.MainIndex == main_index && z.SubIndex == sub_index && z.Orientation == orientation);
|
||||
renderWindow.DrawMapCell(x, y, cx, cy - lt.TileRef.RoofHeight, gameState.MapData, main_index, sub_index, gameState.CurrentPalette, orientation);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private void DrawShadow(int x, int y, int visualX, int visualY)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void DrawFloor(int x, int y, int visualX, int visualY)
|
||||
{
|
||||
if (visualX < -160 || visualX > 800 || visualY < -120 || visualY > 650)
|
||||
return;
|
||||
|
||||
var cx = ((x - y) * 80) - cOffX;
|
||||
var cy = ((x + y) * 40) - cOffY;
|
||||
|
||||
// Render the floor
|
||||
foreach (var floorLayer in gameState.MapData.FloorLayers)
|
||||
{
|
||||
var idx = x + (y * gameState.MapData.Width);
|
||||
if (idx >= floorLayer.Props.Length)
|
||||
break;
|
||||
var floor = floorLayer.Props[idx];
|
||||
|
||||
if (floor.Prop1 == 0)
|
||||
continue;
|
||||
|
||||
var sub_index = floor.Prop2;
|
||||
var main_index = (floor.Prop3 >> 4) + ((floor.Prop4 & 0x03) << 4);
|
||||
|
||||
|
||||
renderWindow.DrawMapCell(x, y, cx, cy, gameState.MapData, main_index, sub_index, gameState.CurrentPalette);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawWall(int x, int y, int visualX, int visualY, bool upper)
|
||||
{
|
||||
var cx = ((x - y) * 80) - cOffX;
|
||||
var cy = ((x + y) * 40) - cOffY;
|
||||
|
||||
|
||||
foreach (var wallLayer in gameState.MapData.WallLayers)
|
||||
{
|
||||
var wall = wallLayer.Props[x + (y * gameState.MapData.Width)];
|
||||
var orientation = wallLayer.Orientations[x + (y * gameState.MapData.Width)].Orientation1;
|
||||
|
||||
|
||||
if (wall.Prop1 == 0)
|
||||
continue;
|
||||
|
||||
if (upper && orientation <= 15)
|
||||
return;
|
||||
|
||||
|
||||
if (orientation == 10 || orientation == 11)
|
||||
return; // TODO: Support special walls
|
||||
|
||||
if ((wall.Prop4 & 0x80) > 0)
|
||||
{
|
||||
if (orientation != 10 && orientation != 11)
|
||||
return;
|
||||
}
|
||||
|
||||
var sub_index = wall.Prop2;
|
||||
var main_index = (wall.Prop3 >> 4) + ((wall.Prop4 & 0x03) << 4);
|
||||
|
||||
var lt = gameState.MapData.LookupTable.First(z => z.MainIndex == main_index && z.SubIndex == sub_index && z.Orientation == orientation);
|
||||
renderWindow.DrawMapCell(x, y, cx, cy + 80, gameState.MapData, main_index, sub_index, gameState.CurrentPalette, orientation);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(long ms)
|
||||
|
@ -34,8 +34,6 @@ namespace OpenDiablo2.SDL2_
|
||||
private readonly IResourceManager resourceManager;
|
||||
private readonly IGameState gameState;
|
||||
|
||||
private IntPtr cellTexture;
|
||||
|
||||
public SDL2RenderWindow(
|
||||
IMPQProvider mpqProvider,
|
||||
IPaletteProvider paletteProvider,
|
||||
@ -64,10 +62,6 @@ namespace OpenDiablo2.SDL2_
|
||||
SDL.SDL_SetRenderDrawBlendMode(renderer, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
|
||||
SDL.SDL_ShowCursor(0);
|
||||
|
||||
cellTexture = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, 256, 1024);
|
||||
SDL.SDL_SetTextureBlendMode(cellTexture, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
|
||||
|
||||
|
||||
IsRunning = true;
|
||||
|
||||
}
|
||||
@ -280,17 +274,31 @@ namespace OpenDiablo2.SDL2_
|
||||
SDL.SDL_RenderCopy(renderer, lbl.texture, IntPtr.Zero, ref destRect);
|
||||
}
|
||||
|
||||
public unsafe void DrawMapCell(int xCell, int yCell, int xPixel, int yPixel, MPQDS1 mapData, int main_index, int sub_index, Palette palette, MPQDS1WallOrientationTileProps orientation)
|
||||
// TODO: Clean this up
|
||||
class _MapDataLookup
|
||||
{
|
||||
public Guid TileId;
|
||||
public int OffX;
|
||||
public int OffY;
|
||||
public int FrameWidth;
|
||||
public int FrameHeight;
|
||||
public SDL.SDL_Rect SrcRect;
|
||||
public IntPtr Texture;
|
||||
}
|
||||
private Dictionary<Guid, List<_MapDataLookup>> mapDataLookup = new Dictionary<Guid, List<_MapDataLookup>>();
|
||||
public unsafe void DrawMapCell(int xCell, int yCell, int xPixel, int yPixel, MPQDS1 mapData, int main_index, int sub_index, Palette palette, int orientation)
|
||||
{
|
||||
|
||||
var tiles = mapData.LookupTable.Where(x =>
|
||||
x.MainIndex == main_index &&
|
||||
x.SubIndex == sub_index &&
|
||||
(orientation == null || x.Orientation == orientation.Orientation1)).Select(x => x.TileRef);
|
||||
(orientation == -1 || x.Orientation == orientation)).Select(x => x.TileRef);
|
||||
|
||||
if (!tiles.Any())
|
||||
return; // TODO: Why does this happen....
|
||||
return;
|
||||
//throw new ApplicationException("Invalid tile id found!");
|
||||
|
||||
|
||||
// TODO: This isn't good.. should be remembered in the map engine layer
|
||||
MPQDT1Tile tile = null;
|
||||
if (tiles.Count() > 0)
|
||||
{
|
||||
@ -309,10 +317,45 @@ namespace OpenDiablo2.SDL2_
|
||||
}
|
||||
} else tile = tiles.First();
|
||||
|
||||
var frameSize = new Size(tile.Width, Math.Abs(tile.Height));
|
||||
var srcRect = new SDL.SDL_Rect { x = 0, y = 0, w = frameSize.Width, h = frameSize.Height };
|
||||
var frameSizeMax = frameSize.Width * frameSize.Height;
|
||||
if (SDL.SDL_LockTexture(cellTexture, IntPtr.Zero, out IntPtr pixels, out int pitch) != 0)
|
||||
// This WILL happen to you
|
||||
if (tile.Width == 0 || tile.Height == 0)
|
||||
return;
|
||||
|
||||
if (mapDataLookup.ContainsKey(mapData.Id))
|
||||
{
|
||||
var lookupDetails = mapDataLookup[mapData.Id].FirstOrDefault(x => x.TileId == tile.Id);
|
||||
if (lookupDetails != null)
|
||||
{
|
||||
|
||||
var dx = new SDL.SDL_Rect { x = xPixel - lookupDetails.OffX, y = yPixel - lookupDetails.OffY, w = lookupDetails.FrameWidth, h = lookupDetails.FrameHeight };
|
||||
SDL.SDL_RenderCopy(renderer, lookupDetails.Texture, ref lookupDetails.SrcRect, ref dx);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
var minX = tile.Blocks.Min(x => x.PositionX);
|
||||
var minY = tile.Blocks.Min(x => x.PositionY);
|
||||
var maxX = tile.Blocks.Max(x => x.PositionX + 32);
|
||||
var maxY = tile.Blocks.Max(x => x.PositionY + 32);
|
||||
var diffX = maxX - minX;
|
||||
var diffY = maxY - minY;
|
||||
|
||||
var offX = -minX;
|
||||
var offy = -minY;
|
||||
|
||||
var frameSize = new Size(diffX, Math.Abs(diffY));
|
||||
|
||||
var srcRect = new SDL.SDL_Rect { x = 0, y = 0, w = frameSize.Width, h = Math.Abs(frameSize.Height) };
|
||||
var frameSizeMax = diffX * Math.Abs(diffY);
|
||||
|
||||
|
||||
var texId = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, frameSize.Width, frameSize.Height);
|
||||
SDL.SDL_SetTextureBlendMode(texId, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
|
||||
|
||||
|
||||
if (SDL.SDL_LockTexture(texId, IntPtr.Zero, out IntPtr pixels, out int pitch) != 0)
|
||||
{
|
||||
log.Error("Could not lock texture for map rendering");
|
||||
return;
|
||||
@ -320,14 +363,16 @@ namespace OpenDiablo2.SDL2_
|
||||
try
|
||||
{
|
||||
UInt32* data = (UInt32*)pixels;
|
||||
for (var i = 0; i < frameSizeMax; i++)
|
||||
data[i] = 0x0;
|
||||
|
||||
var pitchChange = (pitch / 4);
|
||||
|
||||
for (var i = 0; i < frameSize.Height * pitchChange; i++)
|
||||
data[i] = 0x0;
|
||||
|
||||
|
||||
foreach (var block in tile.Blocks)
|
||||
{
|
||||
var index = block.PositionX + ((block.PositionY) * pitchChange);
|
||||
var index = block.PositionX + offX + ((block.PositionY + offy) * pitchChange);
|
||||
var xx = 0;
|
||||
var yy = 0;
|
||||
foreach (var colorIndex in block.PixelData)
|
||||
@ -338,7 +383,7 @@ namespace OpenDiablo2.SDL2_
|
||||
continue;
|
||||
var color = palette.Colors[colorIndex];
|
||||
|
||||
if ((color & 0xFFFFFF) > 0)
|
||||
if (color > 0)
|
||||
data[index] = color;
|
||||
|
||||
}
|
||||
@ -359,13 +404,30 @@ namespace OpenDiablo2.SDL2_
|
||||
}
|
||||
finally
|
||||
{
|
||||
SDL.SDL_UnlockTexture(cellTexture);
|
||||
SDL.SDL_UnlockTexture(texId);
|
||||
}
|
||||
|
||||
SDL.SDL_SetRenderDrawBlendMode(renderer, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
|
||||
SDL.SDL_SetTextureBlendMode(cellTexture, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
|
||||
var dstRect = new SDL.SDL_Rect { x = xPixel, y = yPixel - tile.RoofHeight, w = frameSize.Width, h = frameSize.Height };
|
||||
SDL.SDL_RenderCopy(renderer, cellTexture, ref srcRect, ref dstRect);
|
||||
if (!mapDataLookup.ContainsKey(mapData.Id))
|
||||
mapDataLookup[mapData.Id] = new List<_MapDataLookup>();
|
||||
|
||||
var lookup = new _MapDataLookup
|
||||
{
|
||||
FrameHeight = frameSize.Height,
|
||||
FrameWidth = frameSize.Width,
|
||||
OffX = offX,
|
||||
OffY = offy,
|
||||
SrcRect = srcRect,
|
||||
TileId = tile.Id,
|
||||
Texture = texId
|
||||
};
|
||||
|
||||
mapDataLookup[mapData.Id].Add(lookup);
|
||||
|
||||
var dr = new SDL.SDL_Rect { x = xPixel - lookup.OffX, y = yPixel - lookup.OffY, w = lookup.FrameWidth, h = lookup.FrameHeight };
|
||||
SDL.SDL_RenderCopy(renderer, lookup.Texture, ref lookup.SrcRect, ref dr);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user