using System; using System.Collections.Generic; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Ultima.XNA.IO; using System.IO; using Ultima.XNA.Input; using Ultima.XNA.Collections; using Microsoft.Xna.Framework.Input; namespace Ultima.XNA { public enum DrawType { Texture, Land, Static, Animation } public struct DrawSet { public int Id; public DrawType DrawType; } public class MapRendererComponent : DrawableClientComponent { private VertexPositionTexture[] vertices; private VertexBuffer vertexBuffer; private TileMatrix tileMatrix; private VertexDeclaration vertexDeclaration; private PrimitiveType primitiveType = PrimitiveType.TriangleStrip; private Vector3 PlayerLocation = new Vector3(1410, 1660, 0); private int displaySize = 34; private int count = 0; private DrawSet[] drawSets; public MapRendererComponent(Game game) : base(game) { } protected override void LoadGraphicsContent(bool loadAllContent) { base.LoadGraphicsContent(loadAllContent); vertices = new VertexPositionTexture[0x10000]; //textureBuffer = new Texture2D[0x3FFF]; drawSets = new DrawSet[0x3FFF]; vertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionTexture.SizeInBytes * vertices.Length, ResourceUsage.None); tileMatrix = new TileMatrix(0, 0, 6144, 4096); vertexDeclaration = new VertexDeclaration(GraphicsDevice, VertexPositionTexture.VertexElements); } public override void Update(GameTime gameTime) { base.Update(gameTime); PlayerLocation.Z = tileMatrix.GetLandTile((int)PlayerLocation.X, (int)PlayerLocation.Y).Z; if (InputState.Keyboard.IsKeyDown(Keys.OemPlus) && displaySize < 96) { displaySize += 1; //vertices = new VertexPositionTexture[0x10000]; //textureBuffer = new Texture2D[0x10000]; //vertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionTexture.SizeInBytes * vertices.Length, ResourceUsage.None); } if (InputState.Keyboard.IsKeyDown(Keys.OemMinus) && displaySize > 1) { displaySize -= 1; //vertices = new VertexPositionTexture[0x10000]; //textureBuffer = new Texture2D[0x10000]; //vertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionTexture.SizeInBytes * vertices.Length, ResourceUsage.None); } float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; int dispSizeOver2 = displaySize / 2; int startX = (int)PlayerLocation.X - dispSizeOver2; int startY = (int)PlayerLocation.Y - dispSizeOver2; int maxX = (int)PlayerLocation.X + dispSizeOver2; int maxY = (int)PlayerLocation.Y + dispSizeOver2; int offset = 0; if (displaySize % 2 != 0) { maxX++; maxY++; } for (int y = startY; y < maxY; y++) { for (int x = startX; x < maxX; x++) { Vector3 drawOffset = new Vector3(); int xIndex = x - startX; int yIndex = y - startY; drawOffset.X = xIndex * 44; drawOffset.Y = yIndex * 44; int heightOffset = 0; object[] objs = SortObjects(tileMatrix.GetObjects(x, y)); for (int i = 0; i < objs.Length; i++, offset++, count++) { int vertexIndex = ((offset) * 6); int textureIndex = offset; object obj = objs[i]; if (obj is Tile) { Tile tile = (Tile)obj; int z = (tile.Z << 2); drawSets[textureIndex].Id = tile.ID; drawSets[textureIndex].DrawType = DrawType.Texture; Artwork.EnsureTextmap(GraphicsDevice, tile.ID); Tile eastTile = tileMatrix.GetLandTile(x + 1, y);//right Tile southTile = tileMatrix.GetLandTile(x, y + 1);//bottom Tile downTile = tileMatrix.GetLandTile(x + 1, y + 1);//bottom right int east = (eastTile.Z - tile.Z) << 2; int south = (southTile.Z - tile.Z) << 2; int down = (downTile.Z - tile.Z) << 2; vertices[vertexIndex].Position = drawOffset + new Vector3(0 - z, 0 - z, 0); vertices[vertexIndex].TextureCoordinate = new Vector2(0, 0); vertices[vertexIndex + 1].Position = drawOffset + new Vector3(44 - z - east, 0 - z - east, 0); vertices[vertexIndex + 1].TextureCoordinate = new Vector2(1, 0); vertices[vertexIndex + 2].Position = drawOffset + new Vector3(44 - z - down, 44 - z - down, 0); vertices[vertexIndex + 2].TextureCoordinate = new Vector2(1, 1); vertices[vertexIndex + 3].Position = drawOffset + new Vector3(0 - z - south, 44 - z - south, 0); vertices[vertexIndex + 3].TextureCoordinate = new Vector2(0, 1); vertices[vertexIndex + 4] = vertices[vertexIndex]; vertices[vertexIndex + 5] = vertices[vertexIndex + 2]; } else if (obj is HuedTile) { HuedTile stc = (HuedTile)obj; for (int a = 0; a < i; a++) { if (obj is HuedTile) { heightOffset = TileData.ItemTable[((HuedTile)obj).ID & 0x3FFF].CalcHeight; } } drawSets[textureIndex].Id = stc.ID; drawSets[textureIndex].DrawType = DrawType.Static; Artwork.EnsureStatic(GraphicsDevice, stc.ID); Texture2D texture = Artwork.GetTexture(stc.ID, DrawType.Static); int z = (stc.Z) << 2; Vector3[] srcVectors = new Vector3[4]; float width = texture.Width * 1.40f; float height = texture.Height * 1.40f; Vector3 rotationPoint = new Vector3(-width / 2, -height / 2, 0); Matrix rotationMatrix = Matrix.CreateTranslation(rotationPoint) * Matrix.CreateRotationZ(MathHelper.ToRadians(-45)); srcVectors[0] = Vector3.Transform(new Vector3(0, 0 - z, 0), rotationMatrix); srcVectors[1] = Vector3.Transform(new Vector3(width, 0 - z, 0), rotationMatrix); srcVectors[2] = Vector3.Transform(new Vector3(width, height - z, 0), rotationMatrix); srcVectors[3] = Vector3.Transform(new Vector3(0, height - z, 0), rotationMatrix); vertices[vertexIndex + 0].Position = drawOffset + srcVectors[0]; vertices[vertexIndex + 1].Position = drawOffset + srcVectors[1]; vertices[vertexIndex + 2].Position = drawOffset + srcVectors[2]; vertices[vertexIndex + 3].Position = drawOffset + srcVectors[3]; vertices[vertexIndex + 0].TextureCoordinate = new Vector2(0, 0); vertices[vertexIndex + 1].TextureCoordinate = new Vector2(1, 0); vertices[vertexIndex + 2].TextureCoordinate = new Vector2(1, 1); vertices[vertexIndex + 3].TextureCoordinate = new Vector2(0, 1); vertices[vertexIndex + 4] = vertices[vertexIndex + 0]; vertices[vertexIndex + 5] = vertices[vertexIndex + 2]; } } } } vertexBuffer.SetData(vertices); if (InputState.Keyboard.IsKeyDown(Keys.A)) { PlayerLocation.X -= 1; } if (InputState.Keyboard.IsKeyDown(Keys.D)) { PlayerLocation.X += 1; } if (InputState.Keyboard.IsKeyDown(Keys.W)) { PlayerLocation.Y -= 1; } if (InputState.Keyboard.IsKeyDown(Keys.S)) { PlayerLocation.Y += 1; } if (InputState.KeyboardSpaceJustPressed) { if (primitiveType == PrimitiveType.TriangleStrip) { primitiveType = PrimitiveType.LineStrip; } else { primitiveType = PrimitiveType.TriangleStrip; } } } private object[] SortObjects(object[] objs) { List objList = new List(objs); objList.Sort( new Comparison(Compare)); return objList.ToArray(); } private int Compare(object a, object b) { int az; int bz; int athreshhold; int bthreshhold; int atype; int btype; int atiebreaker; int btiebreaker; GetStats(a, out az, out athreshhold, out atype, out atiebreaker); GetStats(b, out bz, out bthreshhold, out btype, out btiebreaker); az += athreshhold; bz += bthreshhold; int compare = az - bz; if (compare == 0) { compare = atype - btype; } if (compare == 0) { compare = athreshhold - bthreshhold; } if (compare == 0) { compare = atiebreaker - btiebreaker; } return compare; } public void GetStats(object obj, out int z, out int treshold, out int type, out int tiebreaker) { /*if (obj is MobileCell) { MobileCell cell = (MobileCell)obj; z = cell.Z; treshold = 2; type = 3; if (cell.m_Mobile.Player) { tiebreaker = 0x40000000; } else { tiebreaker = cell.Serial; } } else*/ if (obj is Tile) { Tile tile = (Tile)obj; z = tile.Z; treshold = 0; type = 0; tiebreaker = 0; } /*else if (obj is DynamicItem) { int num; DynamicItem item = (DynamicItem)obj; z = item.Z; if (Map.m_ItemFlags[item.ID & 0x3fff][TileFlag.Background]) { num = 0; } else { num = 1; } treshold = (item.Height == 0) ? num : (num + 1); type = ((item.ID & 0x3fff) == 0x2006) ? 4 : 2; tiebreaker = item.Serial; }*/ else if (obj is HuedTile) { int tresh; HuedTile item2 = (HuedTile)obj; z = item2.Z; if ((TileData.ItemTable[item2.ID & 0x3FFF].Flags & TileFlag.Background) != TileFlag.None) { tresh = 0; } else { tresh = 1; } treshold = (TileData.ItemTable[item2.ID & 0x3FFF].Height == 0) ? tresh : (tresh + 1); type = 1; tiebreaker = 1; } else { z = 0; treshold = 0; type = 0; tiebreaker = 0; } } public override void Draw(GameTime gameTime) { base.Draw(gameTime); Viewport viewport = GraphicsDevice.Viewport; int vertPos = 0; GraphicsDevice.VertexDeclaration = vertexDeclaration; GraphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionTexture.SizeInBytes); GraphicsDevice.Viewport = Engine.GameViewport; GraphicsDevice.RenderState.AlphaBlendEnable = true; GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Add; GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha; GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha; GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = false; GraphicsDevice.RenderState.AlphaTestEnable = true; GraphicsDevice.RenderState.AlphaFunction = CompareFunction.Greater; GraphicsDevice.RenderState.ReferenceAlpha = 0; GraphicsDevice.SamplerStates[0].MagFilter = TextureFilter.None; GraphicsDevice.SamplerStates[0].MinFilter = TextureFilter.None; BasicEffect.Projection = Matrix.CreateRotationZ(MathHelper.ToRadians(45)) * Matrix.CreateTranslation(new Vector3(512, 352 - ((displaySize / 2) * (62.25f)), 0)) * Matrix.CreateOrthographicOffCenter(0, Engine.Width, Engine.Height, 0, 0, 1); BasicEffect.TextureEnabled = true; BasicEffect.Begin(); BasicEffect.CurrentTechnique.Passes[0].Begin(); for (int i = 0; i < count; i++, vertPos += 6) { BasicEffect.Texture = Artwork.GetTexture(drawSets[i].Id, drawSets[i].DrawType); BasicEffect.CommitChanges(); GraphicsDevice.DrawPrimitives(primitiveType, vertPos, 4); } BasicEffect.CurrentTechnique.Passes[0].End(); BasicEffect.End(); GraphicsDevice.Viewport = viewport; count = 0; } } }