From 1ee8a20a15347321722f72e97ff0ee028fc01a1c Mon Sep 17 00:00:00 2001 From: Sharivan Date: Wed, 15 Mar 2023 14:01:15 -0300 Subject: [PATCH] - Added support to render using bilinear filter and changed the config tu use it as default. This filter will draw stretched smoothly, like some actual emulators does. - Changed the render loop to use passive waiting instead active waiting again, this time using a more accurate wait technique. This will reduce the cpu usage of program by about 8 times. - Added the class layout to store informations about separated layouts from the game. World class now have two Layout fields, one for foreground and other for background. --- .../Engine/Collision/PixelCollisionChecker.cs | 20 +- .../Collision/TracerCollisionChecker.cs | 40 +- XSharp/Engine/Consts.cs | 17 +- XSharp/Engine/Entities/Camera.cs | 4 +- XSharp/Engine/Entities/Enemies/Bosses/Boss.cs | 18 +- XSharp/Engine/Entities/Player.cs | 2 +- XSharp/Engine/Entities/Sprite.cs | 2 +- XSharp/Engine/GameEngine.cs | 346 +++++---- XSharp/Engine/World/BackgroundLayout.cs | 71 ++ XSharp/Engine/World/Block.cs | 2 +- XSharp/Engine/World/ForegroundLayout.cs | 58 ++ XSharp/Engine/World/Layout.cs | 503 ++++++++++++ XSharp/Engine/World/Scene.cs | 14 +- XSharp/Engine/World/World.cs | 730 ++---------------- XSharp/MegaEDX/MMXCore.cs | 16 +- 15 files changed, 978 insertions(+), 865 deletions(-) create mode 100644 XSharp/Engine/World/BackgroundLayout.cs create mode 100644 XSharp/Engine/World/ForegroundLayout.cs create mode 100644 XSharp/Engine/World/Layout.cs diff --git a/XSharp/Engine/Collision/PixelCollisionChecker.cs b/XSharp/Engine/Collision/PixelCollisionChecker.cs index 26accc4..57371dd 100644 --- a/XSharp/Engine/Collision/PixelCollisionChecker.cs +++ b/XSharp/Engine/Collision/PixelCollisionChecker.cs @@ -21,7 +21,7 @@ protected override CollisionFlags GetCollisionVectorFlags() if (CheckWithWorld) { - Map map = World.GetMapFrom(vec); + Map map = World.ForegroundLayout.GetMapFrom(vec); if (map != null) { Box mapBox = GetMapBoundingBox(GetMapCellFromPos(vec)); @@ -67,14 +67,14 @@ protected override CollisionFlags GetCollisionBoxFlags() if (startRow < 0) startRow = 0; - if (startRow >= World.MapRowCount) - startRow = World.MapRowCount - 1; + if (startRow >= World.ForegroundLayout.MapRowCount) + startRow = World.ForegroundLayout.MapRowCount - 1; if (startCol < 0) startCol = 0; - if (startCol >= World.MapColCount) - startCol = World.MapColCount - 1; + if (startCol >= World.ForegroundLayout.MapColCount) + startCol = World.ForegroundLayout.MapColCount - 1; int endRow = end.Row; int endCol = end.Col; @@ -82,14 +82,14 @@ protected override CollisionFlags GetCollisionBoxFlags() if (endRow < 0) endRow = 0; - if (endRow >= World.MapRowCount) - endRow = World.MapRowCount - 1; + if (endRow >= World.ForegroundLayout.MapRowCount) + endRow = World.ForegroundLayout.MapRowCount - 1; if (endCol < 0) endCol = 0; - if (endCol >= World.MapColCount) - endCol = World.MapColCount - 1; + if (endCol >= World.ForegroundLayout.MapColCount) + endCol = World.ForegroundLayout.MapColCount - 1; CollisionFlags result = CollisionFlags.NONE; @@ -100,7 +100,7 @@ protected override CollisionFlags GetCollisionBoxFlags() for (int col = startCol; col <= endCol; col++) { var mapPos = GetMapLeftTop(row, col); - Map map = World.GetMapFrom(mapPos); + Map map = World.ForegroundLayout.GetMapFrom(mapPos); if (map != null) { Box mapBox = GetMapBoundingBox(row, col); diff --git a/XSharp/Engine/Collision/TracerCollisionChecker.cs b/XSharp/Engine/Collision/TracerCollisionChecker.cs index c469485..603af6b 100644 --- a/XSharp/Engine/Collision/TracerCollisionChecker.cs +++ b/XSharp/Engine/Collision/TracerCollisionChecker.cs @@ -271,7 +271,7 @@ protected override CollisionFlags GetCollisionVectorFlags() for (FixedSingle distance = 0; distance <= maxDistance; distance += MAP_SIZE, TestVector += stepVector) { - Map map = World.GetMapFrom(TestVector); + Map map = World.ForegroundLayout.GetMapFrom(TestVector); if (map != null) { Box mapBox = GetMapBoundingBox(GetMapCellFromPos(TestVector)); @@ -288,7 +288,7 @@ protected override CollisionFlags GetCollisionVectorFlags() } else { - Map map = World.GetMapFrom(TestVector); + Map map = World.ForegroundLayout.GetMapFrom(TestVector); if (map != null) { Box mapBox = GetMapBoundingBox(GetMapCellFromPos(TestVector)); @@ -368,14 +368,14 @@ protected override CollisionFlags GetCollisionBoxFlags() if (startRow < 0) startRow = 0; - if (startRow >= World.MapRowCount) - startRow = World.MapRowCount - 1; + if (startRow >= World.ForegroundLayout.MapRowCount) + startRow = World.ForegroundLayout.MapRowCount - 1; if (startCol < 0) startCol = 0; - if (startCol >= World.MapColCount) - startCol = World.MapColCount - 1; + if (startCol >= World.ForegroundLayout.MapColCount) + startCol = World.ForegroundLayout.MapColCount - 1; int endRow = end.Row; int endCol = end.Col; @@ -383,21 +383,21 @@ protected override CollisionFlags GetCollisionBoxFlags() if (endRow < 0) endRow = 0; - if (endRow >= World.MapRowCount) - endRow = World.MapRowCount - 1; + if (endRow >= World.ForegroundLayout.MapRowCount) + endRow = World.ForegroundLayout.MapRowCount - 1; if (endCol < 0) endCol = 0; - if (endCol >= World.MapColCount) - endCol = World.MapColCount - 1; + if (endCol >= World.ForegroundLayout.MapColCount) + endCol = World.ForegroundLayout.MapColCount - 1; for (int row = startRow; row <= endRow; row++) { for (int col = startCol; col <= endCol; col++) { var mapPos = GetMapLeftTop(row, col); - Map map = World.GetMapFrom(mapPos); + Map map = World.ForegroundLayout.GetMapFrom(mapPos); if (map != null) { Box mapBox = GetMapBoundingBox(row, col); @@ -425,14 +425,14 @@ protected override CollisionFlags GetCollisionBoxFlags() if (startRow < 0) startRow = 0; - if (startRow >= World.MapRowCount) - startRow = World.MapRowCount - 1; + if (startRow >= World.ForegroundLayout.MapRowCount) + startRow = World.ForegroundLayout.MapRowCount - 1; if (startCol < 0) startCol = 0; - if (startCol >= World.MapColCount) - startCol = World.MapColCount - 1; + if (startCol >= World.ForegroundLayout.MapColCount) + startCol = World.ForegroundLayout.MapColCount - 1; int endRow = end.Row; int endCol = end.Col; @@ -440,21 +440,21 @@ protected override CollisionFlags GetCollisionBoxFlags() if (endRow < 0) endRow = 0; - if (endRow >= World.MapRowCount) - endRow = World.MapRowCount - 1; + if (endRow >= World.ForegroundLayout.MapRowCount) + endRow = World.ForegroundLayout.MapRowCount - 1; if (endCol < 0) endCol = 0; - if (endCol >= World.MapColCount) - endCol = World.MapColCount - 1; + if (endCol >= World.ForegroundLayout.MapColCount) + endCol = World.ForegroundLayout.MapColCount - 1; for (int row = startRow; row <= endRow; row++) { for (int col = startCol; col <= endCol; col++) { var mapPos = GetMapLeftTop(row, col); - Map map = World.GetMapFrom(mapPos); + Map map = World.ForegroundLayout.GetMapFrom(mapPos); if (map != null) { Box mapBox = GetMapBoundingBox(row, col); diff --git a/XSharp/Engine/Consts.cs b/XSharp/Engine/Consts.cs index 4fee96e..4638806 100644 --- a/XSharp/Engine/Consts.cs +++ b/XSharp/Engine/Consts.cs @@ -16,11 +16,16 @@ public class Consts { public const int SAVE_SLOT_COUNT = 100; public const int KEY_BUFFER_COUNT = 60; + public static readonly bool ENABLE_BACKGROUND_INPUT = true; - // Tick rate + // Device params - public static readonly FixedSingle TICKRATE = 60; - public static readonly FixedSingle TICK = 1D / TICKRATE; + public const int TICKRATE = 60; + public const double TICK = 1D / TICKRATE; + public static readonly bool DOUBLE_BUFFERED = false; + public static readonly bool VSYNC = true; // TODO : When false the refresh rate doesn't work fine, taking about half of frames. Please fix it! + public static readonly bool SAMPLER_STATE_LINEAR = true; + public static readonly bool FULL_SCREEN = false; // TODO : When true the app crash on device creating. Please fix it! // Sprite @@ -273,8 +278,6 @@ public class Consts public static readonly FixedSingle DEFAULT_CLIENT_HEIGHT = DEFAULT_DRAW_SCALE * SCREEN_HEIGHT; public static readonly Vector DEFAULT_CLIENT_SIZE = (DEFAULT_CLIENT_WIDTH, DEFAULT_CLIENT_HEIGHT); public static readonly Box DEFAULT_CLIENT_BOX = (DEFAULT_DRAW_ORIGIN.X, DEFAULT_DRAW_ORIGIN.Y, DEFAULT_CLIENT_WIDTH, DEFAULT_CLIENT_HEIGHT); - public const bool VSYNC = false; - public const bool SPRITE_SAMPLER_STATE_LINEAR = false; // Debug @@ -508,9 +511,9 @@ public class Consts public static readonly bool ENABLE_OST = true; public static readonly bool LOAD_ROM = true; - public const string ROM_NAME = "BestGame.mmx"; + public const string ROM_NAME = "ShittyDash.mmx"; public static readonly bool SKIP_MENU = false; public static readonly bool SKIP_INTRO = false; - public const int INITIAL_LEVEL = 11; + public const int INITIAL_LEVEL = 8; public const int INITIAL_CHECKPOINT = 0; } \ No newline at end of file diff --git a/XSharp/Engine/Entities/Camera.cs b/XSharp/Engine/Entities/Camera.cs index 4d7eff4..cd350f4 100644 --- a/XSharp/Engine/Entities/Camera.cs +++ b/XSharp/Engine/Entities/Camera.cs @@ -215,8 +215,8 @@ public Vector ClampToBounds(FixedSingle x, FixedSingle y) FixedSingle minX = minCameraPos.X + w2; FixedSingle minY = minCameraPos.Y + h2; - FixedSingle maxX = FixedSingle.Min(maxCameraPos.X, World.Width) - w2; - FixedSingle maxY = FixedSingle.Min(maxCameraPos.Y, World.Height) - h2; + FixedSingle maxX = FixedSingle.Min(maxCameraPos.X, World.ForegroundLayout.Width) - w2; + FixedSingle maxY = FixedSingle.Min(maxCameraPos.Y, World.ForegroundLayout.Height) - h2; if (x < minX) x = minX; diff --git a/XSharp/Engine/Entities/Enemies/Bosses/Boss.cs b/XSharp/Engine/Entities/Enemies/Bosses/Boss.cs index f7fde33..8c37796 100644 --- a/XSharp/Engine/Entities/Enemies/Bosses/Boss.cs +++ b/XSharp/Engine/Entities/Enemies/Bosses/Boss.cs @@ -286,8 +286,13 @@ protected override void Think() { float fadingLevel = (ExplodingFrameCounter - 33 * 5) / 59f; - Engine.World.FadingControl.FadingLevel = new Vector4(fadingLevel, fadingLevel, fadingLevel, 0); - Engine.World.FadingControl.FadingColor = Color.White; + var level = new Vector4(fadingLevel, fadingLevel, fadingLevel, 0); + + Engine.World.ForegroundLayout.FadingControl.FadingLevel = level; + Engine.World.ForegroundLayout.FadingControl.FadingColor = Color.White; + + Engine.World.BackgroundLayout.FadingControl.FadingLevel = level; + Engine.World.BackgroundLayout.FadingControl.FadingColor = Color.White; FadingControl.FadingLevel = new Vector4(fadingLevel, fadingLevel, fadingLevel, 0); FadingControl.FadingColor = Color.Black; @@ -301,8 +306,13 @@ protected override void Think() else if (ExplodingFrameCounter is >= (78 * 5) and < (78 * 5 + 32)) // On frame 390, fade in the tilemaps { float fadingLevel = 1 - (ExplodingFrameCounter - 78 * 5) / 31f; - Engine.World.FadingControl.FadingLevel = new Vector4(fadingLevel, fadingLevel, fadingLevel, 0); - Engine.World.FadingControl.FadingColor = Color.White; + var level = new Vector4(fadingLevel, fadingLevel, fadingLevel, 0); + + Engine.World.ForegroundLayout.FadingControl.FadingLevel = level; + Engine.World.ForegroundLayout.FadingControl.FadingColor = Color.White; + + Engine.World.BackgroundLayout.FadingControl.FadingLevel = level; + Engine.World.BackgroundLayout.FadingControl.FadingColor = Color.White; } else if (ExplodingFrameCounter >= 78 * 5 + 32 + 2 * 60) { diff --git a/XSharp/Engine/Entities/Player.cs b/XSharp/Engine/Entities/Player.cs index d559179..1f9db0a 100644 --- a/XSharp/Engine/Entities/Player.cs +++ b/XSharp/Engine/Entities/Player.cs @@ -838,7 +838,7 @@ internal void PlaySound(string name, bool ignoreUpdatesUntilFinished = false) protected override void OnBeforeMove(ref Vector origin) { - Box limit = Engine.World.BoundingBox; + Box limit = Engine.World.ForegroundLayout.BoundingBox; if (!CanGoOutOfCameraBounds && !CrossingBossDoor && !Engine.NoCameraConstraints && !Engine.Camera.NoConstraints) limit &= Engine.CameraConstraintsBox; diff --git a/XSharp/Engine/Entities/Sprite.cs b/XSharp/Engine/Entities/Sprite.cs index 7e908b8..98f2f30 100644 --- a/XSharp/Engine/Entities/Sprite.cs +++ b/XSharp/Engine/Entities/Sprite.cs @@ -1618,7 +1618,7 @@ private Vector DoPhysics(Sprite physicsParent, Vector delta) var newOrigin = Origin + delta; if (!CanGoOutOfMapBounds) - Clamp(Engine.World.BoundingBox.ClipTop(-2 * BLOCK_SIZE).ClipBottom(-2 * BLOCK_SIZE), ref newOrigin); + Clamp(Engine.World.ForegroundLayout.BoundingBox.ClipTop(-2 * BLOCK_SIZE).ClipBottom(-2 * BLOCK_SIZE), ref newOrigin); OnBeforeMove(ref newOrigin); Origin = newOrigin; diff --git a/XSharp/Engine/GameEngine.cs b/XSharp/Engine/GameEngine.cs index 9a4b68c..24dc88d 100644 --- a/XSharp/Engine/GameEngine.cs +++ b/XSharp/Engine/GameEngine.cs @@ -43,13 +43,14 @@ using DeviceType = SharpDX.Direct3D9.DeviceType; using DXSprite = SharpDX.Direct3D9.Sprite; using Font = SharpDX.Direct3D9.Font; -using MMXBox = XSharp.Math.Geometry.Box; +using Box = XSharp.Math.Geometry.Box; using MMXWorld = XSharp.Engine.World.World; using Point = SharpDX.Point; using Rectangle = SharpDX.Rectangle; using RectangleF = SharpDX.RectangleF; using ResultCode = SharpDX.Direct3D9.ResultCode; using Sprite = XSharp.Engine.Entities.Sprite; +using System.Threading; namespace XSharp.Engine; @@ -303,7 +304,7 @@ public static void Dispose() private bool paused; private long lastCurrentMemoryUsage; - private MMXBox drawBox; + private Box drawBox; private EntityReference currentCheckpoint; private readonly List cameraConstraints; @@ -360,11 +361,11 @@ public static void Dispose() // Create Clock and FPS counters private readonly Stopwatch clock = new(); - private readonly double clockFrequency = Stopwatch.Frequency; - private readonly Stopwatch fpsTimer = new(); - private int fpsFrames = 0; - private double nextTick = 0; - private readonly double tick = 1000D / TICKRATE; + private long previousElapsedTicks; + private long lastMeasuringFPSElapsedTicks; + private long targetElapsedTime; + private long renderFrameCounter; + private long lastRenderFrameCounter; private string infoMessage = null; private long infoMessageStartTime; @@ -429,7 +430,7 @@ public FixedSingle HealthCapacity set; } = X_INITIAL_HEALT_CAPACITY; - public MMXBox CameraConstraintsBox + public Box CameraConstraintsBox { get; set; @@ -449,9 +450,9 @@ public bool NoCameraConstraints set; } - public Vector MinCameraPos => NoCameraConstraints || Camera.NoConstraints ? World.BoundingBox.LeftTop : CameraConstraintsBox.LeftTop; + public Vector MinCameraPos => NoCameraConstraints || Camera.NoConstraints ? World.ForegroundLayout.BoundingBox.LeftTop : CameraConstraintsBox.LeftTop; - public Vector MaxCameraPos => NoCameraConstraints || Camera.NoConstraints ? World.BoundingBox.RightBottom : CameraConstraintsBox.RightBottom; + public Vector MaxCameraPos => NoCameraConstraints || Camera.NoConstraints ? World.ForegroundLayout.BoundingBox.RightBottom : CameraConstraintsBox.RightBottom; public bool Paused { @@ -796,9 +797,6 @@ private GameEngine(Control control) { Control = control; - clock.Start(); - fpsTimer.Start(); - Entities = new EntityFactory(); freezingSpriteExceptions = new EntitySet(); @@ -835,14 +833,17 @@ private GameEngine(Control control) presentationParams = new PresentParameters { - Windowed = true, + Windowed = !FULL_SCREEN, SwapEffect = SwapEffect.Discard, - PresentationInterval = PresentInterval.One, + PresentationInterval = VSYNC ? PresentInterval.One : PresentInterval.Immediate, + FullScreenRefreshRateInHz = FULL_SCREEN ? TICKRATE : 0, AutoDepthStencilFormat = Format.D16, EnableAutoDepthStencil = true, - BackBufferFormat = Format.X8R8G8B8, - BackBufferHeight = Control.ClientSize.Height, - BackBufferWidth = Control.ClientSize.Width, + BackBufferCount = DOUBLE_BUFFERED ? 2 : 1, + BackBufferFormat = FULL_SCREEN ? Format.X8R8G8B8 : Format.Unknown, + BackBufferHeight = FULL_SCREEN ? Control.ClientSize.Height : 0, + BackBufferWidth = FULL_SCREEN ? Control.ClientSize.Width : 0, + PresentFlags = PresentFlags.LockableBackBuffer }; Direct3D = new Direct3D(); @@ -1012,7 +1013,10 @@ private void ResetDevice() device.SetRenderState(RenderState.AlphaBlendEnable, true); device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha); device.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha); - device.SetTextureStageState(0, TextureStage.AlphaOperation, TextureOperation.Modulate); + device.SetTextureStageState(0, TextureStage.AlphaOperation, TextureOperation.SelectArg1); + device.SetTextureStageState(0, TextureStage.ColorArg1, TextureArgument.Texture); + device.SetTextureStageState(1, TextureStage.ColorOperation, TextureOperation.Disable); + device.SetTextureStageState(1, TextureStage.AlphaOperation, TextureOperation.Disable); device.SetSamplerState(0, SamplerState.AddressU, TextureAddress.Clamp); device.SetSamplerState(0, SamplerState.AddressV, TextureAddress.Clamp); @@ -1524,7 +1528,7 @@ private void ResetDevice() sequence.AddFrame(496, 432, 32, 32); sequence.AddFrame(532, 432, 32, 32); - var smallHealthRecoverDroppingCollisionBox = new MMXBox(Vector.NULL_VECTOR, (-4, -8), (4, 0)); + var smallHealthRecoverDroppingCollisionBox = new Box(Vector.NULL_VECTOR, (-4, -8), (4, 0)); sequence = xWeaponsSpriteSheet.AddFrameSquence("SmallHealthRecoverDropping"); sequence.OriginOffset = -smallHealthRecoverDroppingCollisionBox.Mins; @@ -1533,7 +1537,7 @@ private void ResetDevice() sequence.AddFrame(0, 0, 24, 114, 8, 8); sequence.AddFrame(0, 0, 6, 138, 8, 8, 1, true); - var smallHealthRecoverIdleCollisionBox = new MMXBox(Vector.NULL_VECTOR, (-5, -8), (5, 0)); + var smallHealthRecoverIdleCollisionBox = new Box(Vector.NULL_VECTOR, (-5, -8), (5, 0)); sequence = xWeaponsSpriteSheet.AddFrameSquence("SmallHealthRecoverIdle"); sequence.OriginOffset = -smallHealthRecoverIdleCollisionBox.Mins; @@ -1544,7 +1548,7 @@ private void ResetDevice() sequence.AddFrame(0, 0, 40, 138, 10, 8, 2); sequence.AddFrame(0, 0, 22, 138, 10, 8, 1); - var bigHealthRecoverDroppingCollisionBox = new MMXBox(Vector.NULL_VECTOR, (-7, -12), (7, 0)); + var bigHealthRecoverDroppingCollisionBox = new Box(Vector.NULL_VECTOR, (-7, -12), (7, 0)); sequence = xWeaponsSpriteSheet.AddFrameSquence("BigHealthRecoverDropping"); sequence.OriginOffset = -bigHealthRecoverDroppingCollisionBox.Mins; @@ -1553,7 +1557,7 @@ private void ResetDevice() sequence.AddFrame(0, 0, 24, 114, 14, 12); sequence.AddFrame(0, 0, 3, 150, 14, 12, 1, true); - var bigHealthRecoverIdleCollisionBox = new MMXBox(Vector.NULL_VECTOR, (-8, -12), (8, 0)); + var bigHealthRecoverIdleCollisionBox = new Box(Vector.NULL_VECTOR, (-8, -12), (8, 0)); sequence = xWeaponsSpriteSheet.AddFrameSquence("BigHealthRecoverIdle"); sequence.OriginOffset = -bigHealthRecoverIdleCollisionBox.Mins; @@ -1564,7 +1568,7 @@ private void ResetDevice() sequence.AddFrame(0, 0, 37, 150, 16, 12, 2); sequence.AddFrame(0, 0, 19, 150, 16, 12, 1); - var smallAmmoRecoverCollisionBox = new MMXBox(Vector.NULL_VECTOR, (-4, -8), (4, 0)); + var smallAmmoRecoverCollisionBox = new Box(Vector.NULL_VECTOR, (-4, -8), (4, 0)); sequence = xWeaponsSpriteSheet.AddFrameSquence("SmallAmmoRecover"); sequence.OriginOffset = -smallAmmoRecoverCollisionBox.Mins; @@ -1574,7 +1578,7 @@ private void ResetDevice() sequence.AddFrame(0, 0, 116, 138, 8, 8, 2); sequence.AddFrame(0, 0, 100, 138, 8, 8, 2); - var bigAmmoRecoverCollisionBox = new MMXBox(Vector.NULL_VECTOR, (-7, -14), (7, 0)); + var bigAmmoRecoverCollisionBox = new Box(Vector.NULL_VECTOR, (-7, -14), (7, 0)); sequence = xWeaponsSpriteSheet.AddFrameSquence("BigAmmoRecover"); sequence.OriginOffset = -bigAmmoRecoverCollisionBox.Mins; @@ -1584,7 +1588,7 @@ private void ResetDevice() sequence.AddFrame(0, 0, 113, 148, 14, 14, 2); sequence.AddFrame(0, 0, 97, 148, 14, 14, 2); - var lifeUpCollisionBox = new MMXBox(Vector.NULL_VECTOR, (-8, -16), (8, 0)); + var lifeUpCollisionBox = new Box(Vector.NULL_VECTOR, (-8, -16), (8, 0)); sequence = xWeaponsSpriteSheet.AddFrameSquence("LifeUp"); sequence.OriginOffset = -lifeUpCollisionBox.Mins; @@ -1592,7 +1596,7 @@ private void ResetDevice() sequence.AddFrame(0, 0, 137, 146, 16, 16, 4, true); sequence.AddFrame(0, 0, 157, 146, 16, 16, 4); - var heartTankCollisionBox = new MMXBox(Vector.NULL_VECTOR, (-8, -17), (8, 0)); + var heartTankCollisionBox = new Box(Vector.NULL_VECTOR, (-8, -17), (8, 0)); sequence = xWeaponsSpriteSheet.AddFrameSquence("HeartTank"); sequence.OriginOffset = -heartTankCollisionBox.Mins; @@ -1602,7 +1606,7 @@ private void ResetDevice() sequence.AddFrame(-3, -2, 213, 147, 10, 15, 11); sequence.AddFrame(-2, -1, 225, 147, 12, 15, 11); - var subTankCollisionBox = new MMXBox(Vector.NULL_VECTOR, (-8, -19), (8, 0)); + var subTankCollisionBox = new Box(Vector.NULL_VECTOR, (-8, -19), (8, 0)); sequence = xWeaponsSpriteSheet.AddFrameSquence("SubTank"); sequence.OriginOffset = -subTankCollisionBox.Mins; @@ -1712,8 +1716,8 @@ private void ResetDevice() battonBoneGSpriteSheet.CurrentPalette = battonBoneGPalette; - var battonBoneGIdleHitbox = new MMXBox(Vector.NULL_VECTOR, new Vector(-6, -18), new Vector(6, 0)); - var battonBoneGAttackingHitbox = new MMXBox(Vector.NULL_VECTOR, new Vector(-8, -14), new Vector(8, 0)); + var battonBoneGIdleHitbox = new Box(Vector.NULL_VECTOR, new Vector(-6, -18), new Vector(6, 0)); + var battonBoneGAttackingHitbox = new Box(Vector.NULL_VECTOR, new Vector(-8, -14), new Vector(8, 0)); // 0 sequence = battonBoneGSpriteSheet.AddFrameSquence("Idle"); @@ -1841,7 +1845,7 @@ private void ResetDevice() bossDoorSpriteSheet.CurrentTexture = texture; } - var bossDoorHitbox = new MMXBox(Vector.NULL_VECTOR, (-8, -23), (24, 25)); + var bossDoorHitbox = new Box(Vector.NULL_VECTOR, (-8, -23), (24, 25)); sequence = bossDoorSpriteSheet.AddFrameSquence("Closed"); sequence.OriginOffset = -bossDoorHitbox.Mins; @@ -2219,7 +2223,7 @@ public void SetCheckpoint(Checkpoint value, int objectTile = -1, int backgroundT } else { - CameraConstraintsBox = World.BoundingBox; + CameraConstraintsBox = World.ForegroundLayout.BoundingBox; } } } @@ -2317,7 +2321,7 @@ private static void ZeroDataRect(DataRectangle dataRect, int length) } } - private static void FillRegion(DataRectangle dataRect, int length, MMXBox box, int paletteIndex) + private static void FillRegion(DataRectangle dataRect, int length, Box box, int paletteIndex) { int dstX = (int) box.Left; int dstY = (int) box.Top; @@ -2337,47 +2341,47 @@ private static void FillRegion(DataRectangle dataRect, int length, MMXBox box, i private static void DrawChargingPointLevel1Small(DataRectangle dataRect, int length, Vector point) { - FillRegion(dataRect, length, new MMXBox(point.X, point.Y, 1, 1), 1); + FillRegion(dataRect, length, new Box(point.X, point.Y, 1, 1), 1); } private static void DrawChargingPointLevel1Large(DataRectangle dataRect, int length, Vector point) { - FillRegion(dataRect, length, new MMXBox(point.X, point.Y, 2, 2), 1); + FillRegion(dataRect, length, new Box(point.X, point.Y, 2, 2), 1); } private static void DrawChargingPointLevel2Small1(DataRectangle dataRect, int length, Vector point) { - FillRegion(dataRect, length, new MMXBox(point.X, point.Y, 1, 1), 2); + FillRegion(dataRect, length, new Box(point.X, point.Y, 1, 1), 2); } private static void DrawChargingPointLevel2Small2(DataRectangle dataRect, int length, Vector point) { - FillRegion(dataRect, length, new MMXBox(point.X, point.Y, 1, 1), 3); + FillRegion(dataRect, length, new Box(point.X, point.Y, 1, 1), 3); - FillRegion(dataRect, length, new MMXBox(point.X, point.Y - 1, 1, 1), 4); - FillRegion(dataRect, length, new MMXBox(point.X, point.Y + 1, 1, 1), 4); - FillRegion(dataRect, length, new MMXBox(point.X - 1, point.Y, 1, 1), 4); - FillRegion(dataRect, length, new MMXBox(point.X + 1, point.Y, 1, 1), 4); + FillRegion(dataRect, length, new Box(point.X, point.Y - 1, 1, 1), 4); + FillRegion(dataRect, length, new Box(point.X, point.Y + 1, 1, 1), 4); + FillRegion(dataRect, length, new Box(point.X - 1, point.Y, 1, 1), 4); + FillRegion(dataRect, length, new Box(point.X + 1, point.Y, 1, 1), 4); - FillRegion(dataRect, length, new MMXBox(point.X - 1, point.Y - 1, 1, 1), 5); - FillRegion(dataRect, length, new MMXBox(point.X + 1, point.Y - 1, 1, 1), 5); - FillRegion(dataRect, length, new MMXBox(point.X - 1, point.Y + 1, 1, 1), 5); - FillRegion(dataRect, length, new MMXBox(point.X + 1, point.Y + 1, 1, 1), 5); + FillRegion(dataRect, length, new Box(point.X - 1, point.Y - 1, 1, 1), 5); + FillRegion(dataRect, length, new Box(point.X + 1, point.Y - 1, 1, 1), 5); + FillRegion(dataRect, length, new Box(point.X - 1, point.Y + 1, 1, 1), 5); + FillRegion(dataRect, length, new Box(point.X + 1, point.Y + 1, 1, 1), 5); } private static void DrawChargingPointLevel2Large1(DataRectangle dataRect, int length, Vector point) { - FillRegion(dataRect, length, new MMXBox(point.X, point.Y, 2, 2), 2); + FillRegion(dataRect, length, new Box(point.X, point.Y, 2, 2), 2); } private static void DrawChargingPointLevel2Large2(DataRectangle dataRect, int length, Vector point) { - FillRegion(dataRect, length, new MMXBox(point.X, point.Y, 2, 2), 3); + FillRegion(dataRect, length, new Box(point.X, point.Y, 2, 2), 3); - FillRegion(dataRect, length, new MMXBox(point.X, point.Y - 1, 2, 1), 4); - FillRegion(dataRect, length, new MMXBox(point.X, point.Y + 2, 2, 1), 4); - FillRegion(dataRect, length, new MMXBox(point.X - 1, point.Y, 1, 2), 4); - FillRegion(dataRect, length, new MMXBox(point.X + 2, point.Y, 1, 2), 4); + FillRegion(dataRect, length, new Box(point.X, point.Y - 1, 2, 1), 4); + FillRegion(dataRect, length, new Box(point.X, point.Y + 2, 2, 1), 4); + FillRegion(dataRect, length, new Box(point.X - 1, point.Y, 1, 2), 4); + FillRegion(dataRect, length, new Box(point.X + 2, point.Y, 1, 2), 4); } private static void DrawChargingPointSmall(DataRectangle dataRect, int length, Vector point, int level, int type) @@ -2512,7 +2516,7 @@ public static void SetupQuad(VertexBuffer vb) vb.Unlock(); } - public void RenderSprite(Texture texture, Palette palette, FadingControl fadingControl, MMXBox box, Matrix transform, int repeatX = 1, int repeatY = 1) + public void RenderSprite(Texture texture, Palette palette, FadingControl fadingControl, Box box, Matrix transform, int repeatX = 1, int repeatY = 1) { RectangleF rDest = WorldBoxToScreen(box); @@ -2571,7 +2575,7 @@ public void RenderSprite(Texture texture, Palette palette, FadingControl fadingC sprite.End(); } - public void RenderSprite(Texture texture, FadingControl fadingControl, MMXBox box, Matrix transform, int repeatX = 1, int repeatY = 1) + public void RenderSprite(Texture texture, FadingControl fadingControl, Box box, Matrix transform, int repeatX = 1, int repeatY = 1) { RenderSprite(texture, null, fadingControl, box, transform, repeatX, repeatY); } @@ -2579,25 +2583,25 @@ public void RenderSprite(Texture texture, FadingControl fadingControl, MMXBox bo public void RenderSprite(Texture texture, FadingControl fadingControl, Vector v, Matrix transform, int repeatX = 1, int repeatY = 1) { var description = texture.GetLevelDescription(0); - RenderSprite(texture, null, fadingControl, new MMXBox(v.X, v.Y, description.Width, description.Height), transform, repeatX, repeatY); + RenderSprite(texture, null, fadingControl, new Box(v.X, v.Y, description.Width, description.Height), transform, repeatX, repeatY); } public void RenderSprite(Texture texture, FadingControl fadingControl, FixedSingle x, FixedSingle y, Matrix transform, int repeatX = 1, int repeatY = 1) { var description = texture.GetLevelDescription(0); - RenderSprite(texture, null, fadingControl, new MMXBox(x, y, description.Width, description.Height), transform, repeatX, repeatY); + RenderSprite(texture, null, fadingControl, new Box(x, y, description.Width, description.Height), transform, repeatX, repeatY); } public void RenderSprite(Texture texture, Palette palette, FadingControl fadingControl, Vector v, Matrix transform, int repeatX = 1, int repeatY = 1) { var description = texture.GetLevelDescription(0); - RenderSprite(texture, palette, fadingControl, new MMXBox(v.X, v.Y, description.Width, description.Height), transform, repeatX, repeatY); + RenderSprite(texture, palette, fadingControl, new Box(v.X, v.Y, description.Width, description.Height), transform, repeatX, repeatY); } public void RenderSprite(Texture texture, Palette palette, FadingControl fadingControl, FixedSingle x, FixedSingle y, Matrix transform, int repeatX = 1, int repeatY = 1) { var description = texture.GetLevelDescription(0); - RenderSprite(texture, palette, fadingControl, new MMXBox(x, y, description.Width, description.Height), transform, repeatX, repeatY); + RenderSprite(texture, palette, fadingControl, new Box(x, y, description.Width, description.Height), transform, repeatX, repeatY); } private void ClearEntities() @@ -2638,7 +2642,7 @@ private Keys HandleInput(out bool nextFrame) Keys keys = Keys.NONE; nextFrame = !frameAdvance; - if (Control.Focused) + if (ENABLE_BACKGROUND_INPUT || Control.Focused) { keyboard.Poll(); var state = keyboard.GetCurrentState(); @@ -3302,12 +3306,12 @@ public static Vector3 ToVector3(Vector v) return new((float) v.X, (float) v.Y, 0); } - public static Rectangle ToRectangle(MMXBox box) + public static Rectangle ToRectangle(Box box) { return new((int) box.Left, (int) box.Top, (int) box.Width, (int) box.Height); } - public static RectangleF ToRectangleF(MMXBox box) + public static RectangleF ToRectangleF(Box box) { return new((float) box.Left, (float) box.Top, (float) box.Width, (float) box.Height); } @@ -3337,7 +3341,7 @@ public Vector ScreenVector2ToWorld(Vector2 v) return (new Vector(v.X, v.Y) - drawBox.LeftTop) / DrawScale + Camera.LeftTop; } - public RectangleF WorldBoxToScreen(MMXBox box) + public RectangleF WorldBoxToScreen(Box box) { return ToRectangleF((box.LeftTopOrigin().RoundOriginToFloor() - Camera.LeftTop.RoundToFloor()) * DrawScale + drawBox.LeftTop); } @@ -3470,7 +3474,7 @@ public void LoadLevel(ushort level, ushort checkpoint = 0) } else { - CameraConstraintsBox = World.BoundingBox; + CameraConstraintsBox = World.ForegroundLayout.BoundingBox; } World.Tessellate(); @@ -3537,10 +3541,10 @@ internal void UpdateScale() }*/ drawOrigin = Vector.NULL_VECTOR; - drawBox = new MMXBox(drawOrigin.X, drawOrigin.Y, width, height); + drawBox = new Box(drawOrigin.X, drawOrigin.Y, width, height); } - private void DrawSlopeMap(MMXBox box, RightTriangle triangle, Color color, float strokeWidth) + private void DrawSlopeMap(Box box, RightTriangle triangle, Color color, float strokeWidth) { Vector tv1 = triangle.Origin; Vector tv2 = triangle.VCathetusOpositeVertex; @@ -3574,7 +3578,7 @@ private void DrawSlopeMap(MMXBox box, RightTriangle triangle, Color color, float private void DrawHighlightMap(int row, int col, CollisionData collisionData, Color color) { - MMXBox mapBox = GetMapBoundingBox(row, col); + Box mapBox = GetMapBoundingBox(row, col); if (collisionData.IsSolidBlock()) { DrawRectangle(mapBox, 4, color); @@ -3586,12 +3590,12 @@ private void DrawHighlightMap(int row, int col, CollisionData collisionData, Col } } - private void CheckAndDrawTouchingMap(int row, int col, CollisionData collisionData, MMXBox collisionBox, Color color, bool ignoreSlopes = false) + private void CheckAndDrawTouchingMap(int row, int col, CollisionData collisionData, Box collisionBox, Color color, bool ignoreSlopes = false) { - MMXBox halfCollisionBox1 = (collisionBox.Left, collisionBox.Top, collisionBox.Width * 0.5, collisionBox.Height); - MMXBox halfCollisionBox2 = (collisionBox.Left + collisionBox.Width * 0.5, collisionBox.Top, collisionBox.Width * 0.5, collisionBox.Height); + Box halfCollisionBox1 = (collisionBox.Left, collisionBox.Top, collisionBox.Width * 0.5, collisionBox.Height); + Box halfCollisionBox2 = (collisionBox.Left + collisionBox.Width * 0.5, collisionBox.Top, collisionBox.Width * 0.5, collisionBox.Height); - MMXBox mapBox = GetMapBoundingBox(row, col); + Box mapBox = GetMapBoundingBox(row, col); if (collisionData.IsSolidBlock() && CollisionChecker.HasIntersection(mapBox, collisionBox)) { DrawRectangle(mapBox, 4, color); @@ -3605,7 +3609,7 @@ private void CheckAndDrawTouchingMap(int row, int col, CollisionData collisionDa } } - private void CheckAndDrawTouchingMaps(MMXBox collisionBox, Color color, bool ignoreSlopes = false) + private void CheckAndDrawTouchingMaps(Box collisionBox, Color color, bool ignoreSlopes = false) { Cell start = GetMapCellFromPos(collisionBox.LeftTop); Cell end = GetMapCellFromPos(collisionBox.RightBottom); @@ -3616,14 +3620,14 @@ private void CheckAndDrawTouchingMaps(MMXBox collisionBox, Color color, bool ign if (startRow < 0) startRow = 0; - if (startRow >= World.MapRowCount) - startRow = World.MapRowCount - 1; + if (startRow >= World.ForegroundLayout.MapRowCount) + startRow = World.ForegroundLayout.MapRowCount - 1; if (startCol < 0) startCol = 0; - if (startCol >= World.MapColCount) - startCol = World.MapColCount - 1; + if (startCol >= World.ForegroundLayout.MapColCount) + startCol = World.ForegroundLayout.MapColCount - 1; int endRow = end.Row; int endCol = end.Col; @@ -3631,21 +3635,21 @@ private void CheckAndDrawTouchingMaps(MMXBox collisionBox, Color color, bool ign if (endRow < 0) endRow = 0; - if (endRow >= World.MapRowCount) - endRow = World.MapRowCount - 1; + if (endRow >= World.ForegroundLayout.MapRowCount) + endRow = World.ForegroundLayout.MapRowCount - 1; if (endCol < 0) endCol = 0; - if (endCol >= World.MapColCount) - endCol = World.MapColCount - 1; + if (endCol >= World.ForegroundLayout.MapColCount) + endCol = World.ForegroundLayout.MapColCount - 1; for (int row = startRow; row <= endRow; row++) { for (int col = startCol; col <= endCol; col++) { var v = new Vector(col * MAP_SIZE, row * MAP_SIZE); - Map map = World.GetMapFrom(v); + Map map = World.ForegroundLayout.GetMapFrom(v); if (map != null) CheckAndDrawTouchingMap(row, col, map.CollisionData, collisionBox, color, ignoreSlopes); } @@ -3684,7 +3688,7 @@ public void DrawLine(Vector2 from, Vector2 to, float width, Color color, FadingC line.End(); } - public void DrawRectangle(MMXBox box, float borderWith, Color color, FadingControl fadingControl = null) + public void DrawRectangle(Box box, float borderWith, Color color, FadingControl fadingControl = null) { DrawRectangle(WorldBoxToScreen(box), borderWith, color, fadingControl); } @@ -3715,7 +3719,7 @@ public void DrawRectangle(RectangleF rect, float borderWith, Color color, Fading line.End(); } - public void FillRectangle(MMXBox box, Color color, FadingControl fadingControl = null) + public void FillRectangle(Box box, Color color, FadingControl fadingControl = null) { FillRectangle(WorldBoxToScreen(box), color, fadingControl); } @@ -3917,34 +3921,41 @@ private void DrawTexture(Texture texture, bool linear = false) public void Render() { Render(this); - } + renderFrameCounter++; - public void Render(IRenderTarget target) - { - // Time in milliseconds - var totalMillis = clock.ElapsedTicks / clockFrequency * 1000; - if (totalMillis < nextTick) - return; + long elapsedTicks = clock.ElapsedTicks; + long remainingTicks = targetElapsedTime - (elapsedTicks - previousElapsedTicks); - bool nextFrame = OnFrame(); - fpsFrames++; - nextTick = totalMillis + tick; + if (remainingTicks > 0) + { + long msRemaining = 1000 * remainingTicks / Stopwatch.Frequency; + if (msRemaining > 0) + Thread.Sleep((int) msRemaining); + } - #region FPS and title update + elapsedTicks = clock.ElapsedTicks; + previousElapsedTicks = elapsedTicks; - if (fpsTimer.ElapsedMilliseconds > 1000) + #region FPS and title update + var deltaMilliseconds = 1000 * (elapsedTicks - lastMeasuringFPSElapsedTicks) / Stopwatch.Frequency; + if (deltaMilliseconds >= 1000) { - var fps = 1000.0 * fpsFrames / fpsTimer.ElapsedMilliseconds; + lastMeasuringFPSElapsedTicks = elapsedTicks; - // Update window title with FPS once every second - Control.Text = $"X# - FPS: {fps:F2} ({fpsTimer.ElapsedMilliseconds / fpsFrames:F2}ms/frame)"; + var deltaFrames = renderFrameCounter - lastRenderFrameCounter; + lastRenderFrameCounter = renderFrameCounter; - // Restart the FPS counter - fpsTimer.Reset(); - fpsTimer.Start(); - fpsFrames = 0; + var fps = 1000.0 * deltaFrames / deltaMilliseconds; + + // Update window title with FPS once every second + Control.Text = $"X# - FPS: {fps:F2} ({(float) deltaMilliseconds / deltaFrames:F2}ms/frame)"; } #endregion + } + + public void Render(IRenderTarget target) + { + bool nextFrame = OnFrame(); if (Device == null) return; @@ -3974,7 +3985,7 @@ public void Render(IRenderTarget target) World.RenderForeground(0); Device.SetRenderTarget(0, backBuffer); - DrawTexture(worldTexture); + DrawTexture(worldTexture, SAMPLER_STATE_LINEAR); if (drawSprites) { @@ -3999,7 +4010,7 @@ public void Render(IRenderTarget target) } Device.SetRenderTarget(0, backBuffer); - DrawTexture(spritesTexture, SPRITE_SAMPLER_STATE_LINEAR); + DrawTexture(spritesTexture, SAMPLER_STATE_LINEAR); } if (drawUpLayer) @@ -4010,7 +4021,7 @@ public void Render(IRenderTarget target) World.RenderForeground(1); Device.SetRenderTarget(0, backBuffer); - DrawTexture(worldTexture); + DrawTexture(worldTexture, SAMPLER_STATE_LINEAR); } if (drawSprites) @@ -4036,7 +4047,7 @@ public void Render(IRenderTarget target) } Device.SetRenderTarget(0, backBuffer); - DrawTexture(spritesTexture, SPRITE_SAMPLER_STATE_LINEAR); + DrawTexture(spritesTexture, SAMPLER_STATE_LINEAR); } Device.SetRenderTarget(0, spritesSurface); @@ -4049,7 +4060,7 @@ public void Render(IRenderTarget target) } Device.SetRenderTarget(0, backBuffer); - DrawTexture(spritesTexture, SPRITE_SAMPLER_STATE_LINEAR); + DrawTexture(spritesTexture, SAMPLER_STATE_LINEAR); if (nextFrame) { @@ -4092,7 +4103,7 @@ public void Render(IRenderTarget target) if (drawHitbox || showColliders || showDrawBox || showTriggerBounds) { resultSet.Clear(); - partition.Query(resultSet, World.BoundingBox, false); + partition.Query(resultSet, World.ForegroundLayout.BoundingBox, false); foreach (Entity entity in resultSet) { if (entity == Player) @@ -4104,7 +4115,7 @@ public void Render(IRenderTarget target) { if (drawHitbox) { - MMXBox hitbox = sprite.Hitbox; + Box hitbox = sprite.Hitbox; var rect = WorldBoxToScreen(hitbox); if (!entity.Alive) @@ -4134,7 +4145,7 @@ public void Render(IRenderTarget target) if (showDrawBox) { - MMXBox drawBox = sprite.DrawBox; + Box drawBox = sprite.DrawBox; var rect = WorldBoxToScreen(drawBox); FillRectangle(rect, BOUNDING_BOX_COLOR); } @@ -4227,7 +4238,7 @@ public void Render(IRenderTarget target) if (drawHitbox) { - MMXBox hitbox = Player.Hitbox; + Box hitbox = Player.Hitbox; var rect = WorldBoxToScreen(hitbox); FillRectangle(rect, HITBOX_COLOR); @@ -4246,7 +4257,7 @@ public void Render(IRenderTarget target) if (showDrawBox) { - MMXBox drawBox = Player.DrawBox; + Box drawBox = Player.DrawBox; var rect = WorldBoxToScreen(drawBox); FillRectangle(rect, BOUNDING_BOX_COLOR); } @@ -4270,35 +4281,35 @@ public void Render(IRenderTarget target) Vector v = ScreenPointToVector(cursorPos.X / 4, cursorPos.Y / 4); DrawText($"Mouse Pos: X: {v.X} Y: {v.Y}", highlightMapTextFont, new RectangleF(0, 0, 400, 50), FontDrawFlags.Left | FontDrawFlags.Top, TOUCHING_MAP_COLOR); - Scene scene = World.GetSceneFrom(v, false); + Scene scene = World.ForegroundLayout.GetSceneFrom(v); if (scene != null) { Cell sceneCell = GetSceneCellFromPos(v); - MMXBox sceneBox = GetSceneBoundingBox(sceneCell); + Box sceneBox = GetSceneBoundingBox(sceneCell); DrawRectangle(WorldBoxToScreen(sceneBox), 4, TOUCHING_MAP_COLOR); DrawText($"Scene: ID: {scene.ID} Row: {sceneCell.Row} Col: {sceneCell.Col}", highlightMapTextFont, new RectangleF(0, 50, 400, 50), FontDrawFlags.Left | FontDrawFlags.Top, TOUCHING_MAP_COLOR); - Block block = World.GetBlockFrom(v, false); + Block block = World.ForegroundLayout.GetBlockFrom(v); if (block != null) { Cell blockCell = GetBlockCellFromPos(v); - MMXBox blockBox = GetBlockBoundingBox(blockCell); + Box blockBox = GetBlockBoundingBox(blockCell); DrawRectangle(WorldBoxToScreen(blockBox), 4, TOUCHING_MAP_COLOR); DrawText($"Block: ID: {block.ID} Row: {blockCell.Row} Col: {blockCell.Col}", highlightMapTextFont, new RectangleF(0, 100, 400, 50), FontDrawFlags.Left | FontDrawFlags.Top, TOUCHING_MAP_COLOR); - Map map = World.GetMapFrom(v, false); + Map map = World.ForegroundLayout.GetMapFrom(v); if (map != null) { Cell mapCell = GetMapCellFromPos(v); - MMXBox mapBox = GetMapBoundingBox(mapCell); + Box mapBox = GetMapBoundingBox(mapCell); DrawRectangle(WorldBoxToScreen(mapBox), 4, TOUCHING_MAP_COLOR); DrawText($"Map: ID: {map.ID} Row: {mapCell.Row} Col: {mapCell.Col}", highlightMapTextFont, new RectangleF(0, 150, 400, 50), FontDrawFlags.Left | FontDrawFlags.Top, TOUCHING_MAP_COLOR); - Tile tile = World.GetTileFrom(v, false); + Tile tile = World.ForegroundLayout.GetTileFrom(v); if (tile != null) { Cell tileCell = GetTileCellFromPos(v); - MMXBox tileBox = GetTileBoundingBox(tileCell); + Box tileBox = GetTileBoundingBox(tileCell); DrawRectangle(WorldBoxToScreen(tileBox), 4, TOUCHING_MAP_COLOR); DrawText($"Tile: ID: {tile.ID} Row: {tileCell.Row} Col: {tileCell.Col}", highlightMapTextFont, new RectangleF(0, 200, 400, 50), FontDrawFlags.Left | FontDrawFlags.Top, TOUCHING_MAP_COLOR); } @@ -4543,7 +4554,8 @@ public void Deserialize(BinaryReader reader) boss = serializer.ReadEntityReference(); FadingControl.Deserialize(serializer); - World.FadingControl.Deserialize(serializer); + World.ForegroundLayout.FadingControl.Deserialize(serializer); + World.BackgroundLayout.FadingControl.Deserialize(serializer); FadingOSTLevel = serializer.ReadFloat(); FadingOSTInitialVolume = serializer.ReadFloat(); @@ -4661,7 +4673,8 @@ public void Serialize(BinaryWriter writer) serializer.WriteEntityReference(boss); FadingControl.Serialize(serializer); - World.FadingControl.Serialize(serializer); + World.ForegroundLayout.FadingControl.Serialize(serializer); + World.BackgroundLayout.FadingControl.Serialize(serializer); serializer.WriteFloat(FadingOSTLevel); serializer.WriteFloat(FadingOSTInitialVolume); @@ -4751,7 +4764,7 @@ public ChangeDynamicPropertyTrigger AddChangeDynamicPropertyTrigger(Vector origi return trigger; } - public Checkpoint AddCheckpoint(ushort index, MMXBox boundingBox, Vector characterPos, Vector cameraPos, Vector backgroundPos, Vector forceBackground, uint scroll) + public Checkpoint AddCheckpoint(ushort index, Box boundingBox, Vector characterPos, Vector cameraPos, Vector backgroundPos, Vector forceBackground, uint scroll) { Checkpoint checkpoint = Entities.Create(new { @@ -4849,7 +4862,7 @@ private Sprite AddCapsule(ushort subid, Vector origin) return null; } - public CameraLockTrigger AddCameraLockTrigger(MMXBox boundingBox, IEnumerable extensions) + public CameraLockTrigger AddCameraLockTrigger(Box boundingBox, IEnumerable extensions) { CameraLockTrigger trigger = Entities.Create(new { @@ -4865,7 +4878,7 @@ public CameraLockTrigger AddCameraLockTrigger(MMXBox boundingBox, IEnumerable extensions) @@ -5162,7 +5175,7 @@ public static void WriteSquare(DataStream vbData, Vector vSource, Vector vDest, } } - public void RenderVertexBuffer(VertexBuffer vb, int vertexSize, int primitiveCount, Texture texture, Texture palette, FadingControl fadingControl, MMXBox box) + public void RenderVertexBuffer(VertexBuffer vb, int vertexSize, int primitiveCount, Texture texture, Texture palette, FadingControl fadingControl, Box box) { Device.SetStreamSource(0, vb, 0, vertexSize); @@ -5420,12 +5433,21 @@ internal void UpdateSoundChannelName(SoundChannel channel, string name) private void Execute() { World = new MMXWorld(32, 32); - partition = new Partition(World.BoundingBox, World.SceneRowCount, World.SceneColCount); + partition = new Partition(World.ForegroundLayout.BoundingBox, World.ForegroundLayout.SceneRowCount, World.ForegroundLayout.SceneColCount); resultSet = new EntitySet(); ResetDevice(); LoadLevel(@"resources\roms\" + ROM_NAME, INITIAL_LEVEL, INITIAL_CHECKPOINT); + FrameCounter = 0; + renderFrameCounter = 0; + lastRenderFrameCounter = 0; + previousElapsedTicks = 0; + targetElapsedTime = Stopwatch.Frequency / TICKRATE; + + clock.Start(); + lastMeasuringFPSElapsedTicks = clock.ElapsedTicks; + while (Running) { // Main loop @@ -5769,27 +5791,27 @@ private void DoorOpening(bool secondDoor) { if (secondDoor) { - Scene scene = World.GetSceneFrom(1, 29); - scene.SetMap(new Cell(7, 15), World.GetMapByID(0x176)); - scene.SetMap(new Cell(8, 15), World.GetMapByID(0x207)); - scene.SetMap(new Cell(9, 15), World.GetMapByID(0x20f)); - - scene = World.GetSceneFrom(1, 30); - scene.SetMap(new Cell(7, 0), World.GetMapByID(0x177)); - scene.SetMap(new Cell(8, 0), World.GetMapByID(0x1b0)); - scene.SetMap(new Cell(9, 0), World.GetMapByID(0x20b)); + Scene scene = World.ForegroundLayout.GetSceneFrom(1, 29); + scene.SetMap(new Cell(7, 15), World.ForegroundLayout.GetMapByID(0x176)); + scene.SetMap(new Cell(8, 15), World.ForegroundLayout.GetMapByID(0x207)); + scene.SetMap(new Cell(9, 15), World.ForegroundLayout.GetMapByID(0x20f)); + + scene = World.ForegroundLayout.GetSceneFrom(1, 30); + scene.SetMap(new Cell(7, 0), World.ForegroundLayout.GetMapByID(0x177)); + scene.SetMap(new Cell(8, 0), World.ForegroundLayout.GetMapByID(0x1b0)); + scene.SetMap(new Cell(9, 0), World.ForegroundLayout.GetMapByID(0x20b)); } else { - Scene scene = World.GetSceneFrom(1, 28); - scene.SetMap(new Cell(7, 15), World.GetMapByID(0x177)); - scene.SetMap(new Cell(8, 15), World.GetMapByID(0x1b0)); - scene.SetMap(new Cell(9, 15), World.GetMapByID(0x20b)); - - scene = World.GetSceneFrom(1, 29); - scene.SetMap(new Cell(7, 0), World.GetMapByID(0x177)); - scene.SetMap(new Cell(8, 0), World.GetMapByID(0x1b0)); - scene.SetMap(new Cell(9, 0), World.GetMapByID(0x20b)); + Scene scene = World.ForegroundLayout.GetSceneFrom(1, 28); + scene.SetMap(new Cell(7, 15), World.ForegroundLayout.GetMapByID(0x177)); + scene.SetMap(new Cell(8, 15), World.ForegroundLayout.GetMapByID(0x1b0)); + scene.SetMap(new Cell(9, 15), World.ForegroundLayout.GetMapByID(0x20b)); + + scene = World.ForegroundLayout.GetSceneFrom(1, 29); + scene.SetMap(new Cell(7, 0), World.ForegroundLayout.GetMapByID(0x177)); + scene.SetMap(new Cell(8, 0), World.ForegroundLayout.GetMapByID(0x1b0)); + scene.SetMap(new Cell(9, 0), World.ForegroundLayout.GetMapByID(0x20b)); } } } @@ -5800,27 +5822,27 @@ private void DoorClosing(bool secondDoor) { if (secondDoor) { - Scene scene = World.GetSceneFrom(1, 29); - scene.SetMap(new Cell(7, 15), World.GetMapByID(0x172)); - scene.SetMap(new Cell(8, 15), World.GetMapByID(0x173)); - scene.SetMap(new Cell(9, 15), World.GetMapByID(0x174)); - - scene = World.GetSceneFrom(1, 30); - scene.SetMap(new Cell(7, 0), World.GetMapByID(0x172)); - scene.SetMap(new Cell(8, 0), World.GetMapByID(0x173)); - scene.SetMap(new Cell(9, 0), World.GetMapByID(0x174)); + Scene scene = World.ForegroundLayout.GetSceneFrom(1, 29); + scene.SetMap(new Cell(7, 15), World.ForegroundLayout.GetMapByID(0x172)); + scene.SetMap(new Cell(8, 15), World.ForegroundLayout.GetMapByID(0x173)); + scene.SetMap(new Cell(9, 15), World.ForegroundLayout.GetMapByID(0x174)); + + scene = World.ForegroundLayout.GetSceneFrom(1, 30); + scene.SetMap(new Cell(7, 0), World.ForegroundLayout.GetMapByID(0x172)); + scene.SetMap(new Cell(8, 0), World.ForegroundLayout.GetMapByID(0x173)); + scene.SetMap(new Cell(9, 0), World.ForegroundLayout.GetMapByID(0x174)); } else { - Scene scene = World.GetSceneFrom(1, 28); - scene.SetMap(new Cell(7, 15), World.GetMapByID(0x172)); - scene.SetMap(new Cell(8, 15), World.GetMapByID(0x173)); - scene.SetMap(new Cell(9, 15), World.GetMapByID(0x174)); - - scene = World.GetSceneFrom(1, 29); - scene.SetMap(new Cell(7, 0), World.GetMapByID(0x172)); - scene.SetMap(new Cell(8, 0), World.GetMapByID(0x173)); - scene.SetMap(new Cell(9, 0), World.GetMapByID(0x174)); + Scene scene = World.ForegroundLayout.GetSceneFrom(1, 28); + scene.SetMap(new Cell(7, 15), World.ForegroundLayout.GetMapByID(0x172)); + scene.SetMap(new Cell(8, 15), World.ForegroundLayout.GetMapByID(0x173)); + scene.SetMap(new Cell(9, 15), World.ForegroundLayout.GetMapByID(0x174)); + + scene = World.ForegroundLayout.GetSceneFrom(1, 29); + scene.SetMap(new Cell(7, 0), World.ForegroundLayout.GetMapByID(0x172)); + scene.SetMap(new Cell(8, 0), World.ForegroundLayout.GetMapByID(0x173)); + scene.SetMap(new Cell(9, 0), World.ForegroundLayout.GetMapByID(0x174)); } } } diff --git a/XSharp/Engine/World/BackgroundLayout.cs b/XSharp/Engine/World/BackgroundLayout.cs new file mode 100644 index 0000000..0a7b64f --- /dev/null +++ b/XSharp/Engine/World/BackgroundLayout.cs @@ -0,0 +1,71 @@ +using SharpDX.Direct3D9; + +using XSharp.Engine.Entities; +using XSharp.Engine.Graphics; +using XSharp.Math.Geometry; + +using static XSharp.Engine.World.World; + +using Box = XSharp.Math.Geometry.Box; + +namespace XSharp.Engine.World; + +public class BackgroundLayout : Layout +{ + public override Texture Palette => Engine.BackgroundPalette; + + public override Texture Tilemap => Engine.BackgroundTilemap; + + internal BackgroundLayout(int sceneRowCount, int sceneColCount) : base(sceneRowCount, sceneColCount) + { + } + + public override void Render(IRenderTarget target) + { + } + + public void Render(int layer) + { + Checkpoint checkpoint = Engine.CurrentCheckpoint; + if (checkpoint == null) + return; + + var camera = Engine.Camera; + if (camera == null) + return; + + Vector screenLT = camera.LeftTop; + Vector screenRB = camera.RightBottom; + Vector backgroundPos = checkpoint.BackgroundPos; + + Vector screenDelta = (checkpoint.Scroll & 0x2) != 0 ? Vector.NULL_VECTOR : (screenLT + checkpoint.CameraPos).Scale(0.5f) - backgroundPos; + + Cell start = GetSceneCellFromPos(screenLT - screenDelta); + Cell end = GetSceneCellFromPos(screenRB - screenDelta); + + for (int col = start.Col; col <= end.Col + 1; col++) + { + if (col < 0) + continue; + + if ((checkpoint.Scroll & 0x10) == 0 && col >= SceneColCount) + continue; + + int bkgCol = (checkpoint.Scroll & 0x10) != 0 ? col % 2 : col; + + for (int row = start.Row; row <= end.Row + 1; row++) + { + if (row < 0 || row >= SceneRowCount) + continue; + + Scene scene = scenes[row, bkgCol]; + if (scene != null) + { + Vector sceneLT = GetSceneLeftTop(row, col); + Box sceneBox = GetSceneBoundingBoxFromPos(sceneLT); + Engine.RenderVertexBuffer(scene.layers[layer], GameEngine.VERTEX_SIZE, Scene.PRIMITIVE_COUNT, Tilemap, Palette, FadingControl, sceneBox + screenDelta); + } + } + } + } +} \ No newline at end of file diff --git a/XSharp/Engine/World/Block.cs b/XSharp/Engine/World/Block.cs index 52ff51e..fb1b4e1 100644 --- a/XSharp/Engine/World/Block.cs +++ b/XSharp/Engine/World/Block.cs @@ -82,7 +82,7 @@ public void SetTile(Vector pos, Tile tile) Map map = maps[cell.Row, cell.Col]; if (map == null) { - map = GameEngine.Engine.World.AddMap(); + map = GameEngine.Engine.World.ForegroundLayout.AddMap(); maps[cell.Row, cell.Col] = map; } diff --git a/XSharp/Engine/World/ForegroundLayout.cs b/XSharp/Engine/World/ForegroundLayout.cs new file mode 100644 index 0000000..fd76d72 --- /dev/null +++ b/XSharp/Engine/World/ForegroundLayout.cs @@ -0,0 +1,58 @@ +using SharpDX.Direct3D9; + +using XSharp.Engine.Graphics; +using XSharp.Math.Geometry; + +using static XSharp.Engine.World.World; + +using Box = XSharp.Math.Geometry.Box; + +namespace XSharp.Engine.World; + +public class ForegroundLayout : Layout +{ + public override Texture Palette => Engine.ForegroundPalette; + + public override Texture Tilemap => Engine.ForegroundTilemap; + + internal ForegroundLayout(int sceneRowCount, int sceneColCount) : base(sceneRowCount, sceneColCount) + { + } + + public override void Render(IRenderTarget target) + { + } + + public void Render(int layer) + { + var camera = Engine.Camera; + if (camera == null) + return; + + Vector screenLT = camera.LeftTop; + Vector screenRB = camera.RightBottom; + + Cell start = GetSceneCellFromPos(screenLT); + Cell end = GetSceneCellFromPos(screenRB); + + for (int col = start.Col; col <= end.Col + 1; col++) + { + if (col < 0 || col >= SceneColCount) + continue; + + for (int row = start.Row; row <= end.Row + 1; row++) + { + if (row < 0 || row >= SceneRowCount) + continue; + + Scene scene = scenes[row, col]; + if (scene != null) + { + var sceneLT = GetSceneLeftTop(row, col); + Box sceneBox = GetSceneBoundingBoxFromPos(sceneLT); + Engine.RenderVertexBuffer(scene.layers[layer], GameEngine.VERTEX_SIZE, Scene.PRIMITIVE_COUNT, Tilemap, Palette, FadingControl, sceneBox); + } + } + } + } +} \ No newline at end of file diff --git a/XSharp/Engine/World/Layout.cs b/XSharp/Engine/World/Layout.cs new file mode 100644 index 0000000..ca941c2 --- /dev/null +++ b/XSharp/Engine/World/Layout.cs @@ -0,0 +1,503 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +using SharpDX.Direct3D9; + +using XSharp.Engine.Collision; +using XSharp.Engine.Graphics; +using XSharp.Math.Geometry; + +using static XSharp.Engine.Consts; +using static XSharp.Engine.World.World; + +using Box = XSharp.Math.Geometry.Box; + +namespace XSharp.Engine.World; + +public abstract class Layout : IRenderable, IEnumerable, IDisposable +{ + public static GameEngine Engine => GameEngine.Engine; + + public static World World => Engine.World; + + private class LayoutEnumerator : IEnumerator + { + private Layout layout; + private int row = -1; + private int col = -1; + + public Scene Current => row >= 0 && row < layout.SceneRowCount && col >= 0 && col < layout.SceneColCount ? layout.scenes[row, col] : null; + + object IEnumerator.Current => Current; + + public LayoutEnumerator(Layout layout) + { + this.layout = layout; + } + + public void Dispose() + { + } + + public bool MoveNext() + { + if (row == -1) + { + row = 0; + col = 0; + } + else if (col == layout.SceneColCount) + { + row++; + col = 0; + } + else + col++; + + return row < layout.SceneRowCount; + } + + public void Reset() + { + row = -1; + col = -1; + } + } + + private readonly List tileList; + private readonly List mapList; + private readonly List blockList; + private readonly List sceneList; + + protected Scene[,] scenes; + + public Scene this[int row, int col] => scenes[row, col]; + + public int TileRowCount => Height / TILE_SIZE; + + public int TileColCount => Width / TILE_SIZE; + + public int MapRowCount => Height / MAP_SIZE; + + public int MapColCount => Width / MAP_SIZE; + + public int BlockRowCount => Height / BLOCK_SIZE; + + public int BlockColCount => Width / BLOCK_SIZE; + + public int SceneRowCount + { + get; + private set; + } + + public int SceneColCount + { + get; + private set; + } + + public int Width => SceneColCount * SCENE_SIZE; + + public int Height => SceneRowCount * SCENE_SIZE; + + public Box BoundingBox => new(0, 0, Width, Height); + + public Vector Size => new(Width, Height); + + public Vector LayoutSize => new(SceneRowCount, SceneColCount); + + public FadingControl FadingControl + { + get; + private set; + } + + public abstract Texture Palette + { + get; + } + + public abstract Texture Tilemap + { + get; + } + + protected Layout(int sceneRowCount, int sceneColCount) + { + SceneRowCount = sceneRowCount; + SceneColCount = sceneColCount; + + tileList = new List(); + mapList = new List(); + blockList = new List(); + sceneList = new List(); + + scenes = new Scene[sceneRowCount, sceneColCount]; + + FadingControl = new FadingControl(); + } + + public Tile GetTileFrom(Vector pos) + { + Cell tsp = GetSceneCellFromPos(pos); + int row = tsp.Row; + int col = tsp.Col; + + if (row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount) + return null; + + Scene scene = scenes[row, col]; + return scene?.GetTileFrom(pos - GetSceneLeftTop(row, col)); + } + + public Map GetMapFrom(Vector pos) + { + Cell tsp = GetSceneCellFromPos(pos); + int row = tsp.Row; + int col = tsp.Col; + + if (row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount) + return null; + + Scene scene = scenes[row, col]; + return scene?.GetMapFrom(pos - GetSceneLeftTop(row, col)); + } + + public Block GetBlockFrom(Vector pos) + { + Cell tsp = GetSceneCellFromPos(pos); + int row = tsp.Row; + int col = tsp.Col; + + if (row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount) + return null; + + Scene scene = scenes[row, col]; + return scene?.GetBlockFrom(pos - GetSceneLeftTop(row, col)); + } + + public Scene GetSceneFrom(Vector pos) + { + Cell tsp = GetSceneCellFromPos(pos); + int row = tsp.Row; + int col = tsp.Col; + + return row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount + ? null + : scenes[row, col]; + } + + public Scene GetSceneFrom(Cell cell) + { + return GetSceneFrom(cell.Row, cell.Col); + } + + public Scene GetSceneFrom(int row, int col) + { + return row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount + ? null + : scenes[row, col]; + } + + public Tile AddTile() + { + int id = tileList.Count; + var result = new Tile(id); + tileList.Add(result); + + return result; + } + + public Tile AddTile(byte[] source) + { + int id = tileList.Count; + var result = new Tile(id, source); + tileList.Add(result); + + return result; + } + + public Map AddMap(CollisionData collisionData = CollisionData.NONE) + { + int id = mapList.Count; + var result = new Map(id, collisionData); + mapList.Add(result); + + return result; + } + + public Block AddBlock() + { + int id = blockList.Count; + var result = new Block(id); + blockList.Add(result); + + return result; + } + + public Scene AddScene() + { + int id = sceneList.Count; + var result = new Scene(id); + sceneList.Add(result); + + return result; + } + + public Scene AddScene(int row, int col) + { + Scene result = AddScene(); + scenes[row, col] = result; + + return result; + } + + public Scene AddScene(Vector pos) + { + Scene result = AddScene(); + + Cell cell = GetSceneCellFromPos(pos); + scenes[cell.Row, cell.Col] = result; + + return result; + } + + public Map AddMap(Vector pos, CollisionData collisionData = CollisionData.NONE) + { + Map result = AddMap(collisionData); + SetMap(pos, result); + + return result; + } + + public void SetMap(Vector pos, Map map) + { + Cell cell = GetSceneCellFromPos(pos); + Scene scene = scenes[cell.Row, cell.Col]; + scene ??= AddScene(pos); + + scene.SetMap(pos - GetSceneLeftTop(cell), map); + } + + public void SetBlock(Vector pos, Block block) + { + Cell cell = GetSceneCellFromPos(pos); + Scene scene = scenes[cell.Row, cell.Col]; + scene ??= AddScene(pos); + + scene.SetBlock(pos - GetSceneLeftTop(cell), block); + } + + public void SetScene(Vector pos, Scene scene) + { + Cell cell = GetSceneCellFromPos(pos); + scenes[cell.Row, cell.Col] = scene; + } + + public Tile GetTileByID(int id) + { + return id < 0 || id >= tileList.Count ? null : tileList[id]; + } + + public Map GetMapByID(int id) + { + return id < 0 || id >= mapList.Count ? null : mapList[id]; + } + + public Block GetBlockByID(int id) + { + return id < 0 || id >= blockList.Count ? null : blockList[id]; + } + + public Scene GetSceneByID(int id) + { + return id < 0 || id >= sceneList.Count ? null : sceneList[id]; + } + + public void RemoveTile(Tile tile) + { + if (tile == null) + return; + + tileList.Remove(tile); + + foreach (Map map in mapList) + map.RemoveTile(tile); + } + + public void RemoveMap(Map map) + { + if (map == null) + return; + + mapList.Remove(map); + + foreach (Block block in blockList) + block.RemoveMap(map); + } + + public void RemoveBlock(Block block) + { + if (block == null) + return; + + blockList.Remove(block); + + foreach (Scene scene in sceneList) + scene.RemoveBlock(block); + } + + public void RemoveScene(Scene scene) + { + if (scene == null) + return; + + sceneList.Remove(scene); + + for (int col = 0; col < SceneColCount; col++) + { + for (int row = 0; row < SceneRowCount; row++) + { + if (scenes[row, col] == scene) + scenes[row, col] = null; + } + } + } + + public void Resize(int rowCount, int colCount) + { + if (rowCount == SceneRowCount && colCount == SceneColCount) + return; + + var newScenes = new Scene[rowCount, colCount]; + + int minRows = System.Math.Min(rowCount, SceneRowCount); + int minCols = System.Math.Min(colCount, SceneColCount); + + for (int col = 0; col < minCols; col++) + { + for (int row = 0; row < minRows; row++) + newScenes[row, col] = scenes[row, col]; + } + + SceneRowCount = rowCount; + SceneColCount = colCount; + + scenes = newScenes; + } + + public IEnumerator GetEnumerator() + { + return new LayoutEnumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new LayoutEnumerator(this); + } + + public abstract void Render(IRenderTarget target); + + internal void Tesselate() + { + foreach (Scene scene in sceneList) + scene.Tessellate(); + } + + internal void OnDisposeDevice() + { + foreach (Scene scene in sceneList) + scene.OnDisposeDevice(); + } + + public void Clear() + { + for (int col = 0; col < SceneColCount; col++) + { + for (int row = 0; row < SceneRowCount; row++) + scenes[row, col] = null; + } + + tileList.Clear(); + blockList.Clear(); + mapList.Clear(); + + foreach (Scene scene in sceneList) + scene.Dispose(); + + sceneList.Clear(); + } + + public void FillRectangle(Box box, Map map) + { + Vector boxLT = box.LeftTop; + Vector boxSize = box.DiagonalVector; + + Cell cell = GetMapCellFromPos(boxLT); + int col = cell.Col; + int row = cell.Row; + int cols = (int) (boxSize.X / MAP_SIZE); + int rows = (int) (boxSize.Y / MAP_SIZE); + + for (int c = 0; c < cols; c++) + { + for (int r = 0; r < rows; r++) + SetMap(GetMapLeftTop(row + r, col + c), map); + } + } + + public void FillRectangle(Box box, Block block) + { + Vector boxLT = box.LeftTop; + Vector boxSize = box.DiagonalVector; + + Cell cell = GetBlockCellFromPos(boxLT); + int col = cell.Col; + int row = cell.Row; + int cols = (int) (boxSize.X / BLOCK_SIZE); + int rows = (int) (boxSize.Y / BLOCK_SIZE); + + for (int c = 0; c < cols; c++) + { + for (int r = 0; r < rows; r++) + SetBlock(GetBlockLeftTop(row + r, col + c), block); + } + } + + public void FillRectangle(Box box, Scene scene) + { + Vector boxLT = box.LeftTop; + Vector boxSize = box.DiagonalVector; + + Cell cell = GetSceneCellFromPos(boxLT); + int col = cell.Col; + int row = cell.Row; + int cols = (int) (boxSize.X / SCENE_SIZE); + int rows = (int) (boxSize.Y / SCENE_SIZE); + + for (int c = 0; c < cols; c++) + { + for (int r = 0; r < rows; r++) + SetScene(GetSceneLeftTop(row + r, col + c), scene); + } + } + + public void Dispose() + { + try + { + Clear(); + } + finally + { + GC.SuppressFinalize(this); + } + } + + public void OnFrame() + { + FadingControl.OnFrame(); + } +} \ No newline at end of file diff --git a/XSharp/Engine/World/Scene.cs b/XSharp/Engine/World/Scene.cs index 8c30091..c2db05f 100644 --- a/XSharp/Engine/World/Scene.cs +++ b/XSharp/Engine/World/Scene.cs @@ -4,11 +4,12 @@ using SharpDX; using SharpDX.Direct3D9; +using XSharp.Engine.Graphics; using XSharp.Math.Geometry; using static XSharp.Engine.Consts; -using MMXBox = XSharp.Math.Geometry.Box; +using Box = XSharp.Math.Geometry.Box; namespace XSharp.Engine.World; @@ -30,6 +31,7 @@ public static Cell GetBlockCellFromPos(Vector pos) internal Block[,] blocks; internal VertexBuffer[] layers; + internal List tilemaps; public int ID { @@ -54,6 +56,8 @@ internal Scene(int id) blocks = new Block[SIDE_BLOCKS_PER_SCENE, SIDE_BLOCKS_PER_SCENE]; layers = new VertexBuffer[3]; + + tilemaps = new List(); } public Tile GetTileFrom(Vector pos) @@ -123,7 +127,7 @@ public void SetMap(Vector pos, Map map) Block block = blocks[cell.Row, cell.Col]; if (block == null) { - block = GameEngine.Engine.World.AddBlock(); + block = GameEngine.Engine.World.ForegroundLayout.AddBlock(); blocks[cell.Row, cell.Col] = block; } @@ -152,7 +156,7 @@ public void SetBlock(Cell cell, Block block) SetBlock(new Vector(cell.Col * BLOCK_SIZE, cell.Row * BLOCK_SIZE), block); } - public void FillRectangle(MMXBox box, Map map) + public void FillRectangle(Box box, Map map) { Vector boxLT = box.LeftTop; Vector boxSize = box.DiagonalVector; @@ -172,7 +176,7 @@ public void FillRectangle(MMXBox box, Map map) RefreshLayers(box); } - public void FillRectangle(MMXBox box, Block block) + public void FillRectangle(Box box, Block block) { Vector boxLT = box.LeftTop; Vector boxSize = box.DiagonalVector; @@ -192,7 +196,7 @@ public void FillRectangle(MMXBox box, Block block) RefreshLayers(box); } - private void RefreshLayers(MMXBox box) + private void RefreshLayers(Box box) { Cell start = GetBlockCellFromPos(box.LeftTop); int startCol = start.Col; diff --git a/XSharp/Engine/World/World.cs b/XSharp/Engine/World/World.cs index 28636b3..eef4559 100644 --- a/XSharp/Engine/World/World.cs +++ b/XSharp/Engine/World/World.cs @@ -10,7 +10,7 @@ using static XSharp.Engine.Consts; -using MMXBox = XSharp.Math.Geometry.Box; +using Box = XSharp.Math.Geometry.Box; namespace XSharp.Engine.World; @@ -24,567 +24,10 @@ public class World : IDisposable public static readonly Vector TILE_SIZE_VECTOR = new(TILE_SIZE, TILE_SIZE); public static readonly Vector TILE_FRAC_SIZE_VECTOR = new(TILE_FRAC_SIZE, TILE_FRAC_SIZE); - private int backgroundSceneRowCount; - private int backgroundSceneColCount; - - private readonly List tileList; - private readonly List backgroundTileList; - private readonly List mapList; - private readonly List backgroundMapList; - private readonly List blockList; - private readonly List backgroundBlockList; - private readonly List sceneList; - private readonly List backgroundSceneList; - - private Scene[,] scenes; - private Scene[,] backgroundScenes; - - private PixelCollisionChecker collisionChecker; - - public FadingControl FadingControl - { - get; - } - public static GameEngine Engine => GameEngine.Engine; public Device Device => GameEngine.Engine.Device; - public int Width => SceneColCount * SCENE_SIZE; - - public int Height => SceneRowCount * SCENE_SIZE; - - public int BackgroundWidth => backgroundSceneColCount * SCENE_SIZE; - - public int BackgroundHeight => backgroundSceneRowCount * SCENE_SIZE; - - public int TileRowCount => Height / TILE_SIZE; - - public int TileColCount => Width / TILE_SIZE; - - public int MapRowCount => Height / MAP_SIZE; - - public int MapColCount => Width / MAP_SIZE; - - public int BlockRowCount => Height / BLOCK_SIZE; - - public int BlockColCount => Width / BLOCK_SIZE; - - public int SceneRowCount - { - get; - private set; - } - - public int SceneColCount - { - get; - private set; - } - - public MMXBox BoundingBox => new(0, 0, Width, Height); - - public Vector Size => new(Width, Height); - - public Vector LayoutSize => new(SceneRowCount, SceneColCount); - - public Vector LayoutBackgroundtSize => new(backgroundSceneRowCount, backgroundSceneColCount); - - public Texture ForegroundPalette => Engine.ForegroundPalette; - - public Texture BackgroundPalette => Engine.BackgroundPalette; - - public Texture ForegroundTilemap => Engine.ForegroundTilemap; - - public Texture BackgroundTilemap => Engine.BackgroundTilemap; - - internal World(int sceneRowCount, int sceneColCount) - : this(sceneRowCount, sceneColCount, sceneRowCount, sceneColCount) - { - } - - internal World(int sceneRowCount, int sceneColCount, int backgroundSceneRowCount, int backgroundSceneColCount) - { - SceneRowCount = sceneRowCount; - SceneColCount = sceneColCount; - this.backgroundSceneRowCount = backgroundSceneRowCount; - this.backgroundSceneColCount = backgroundSceneColCount; - - FadingControl = new FadingControl(); - - tileList = new List(); - backgroundTileList = new List(); - mapList = new List(); - backgroundMapList = new List(); - blockList = new List(); - backgroundBlockList = new List(); - sceneList = new List(); - backgroundSceneList = new List(); - - scenes = new Scene[sceneRowCount, sceneColCount]; - backgroundScenes = new Scene[backgroundSceneRowCount, backgroundSceneColCount]; - - collisionChecker = new PixelCollisionChecker(); - } - - public Tile AddTile(bool background = false) - { - int id = background ? backgroundTileList.Count : tileList.Count; - var result = new Tile(id); - - if (background) - backgroundTileList.Add(result); - else - tileList.Add(result); - - return result; - } - - public Tile AddTile(byte[] source, bool background = false) - { - int id = background ? backgroundTileList.Count : tileList.Count; - var result = new Tile(id, source); - - if (background) - backgroundTileList.Add(result); - else - tileList.Add(result); - - return result; - } - - public Map AddMap(CollisionData collisionData = CollisionData.NONE, bool background = false) - { - int id = background ? backgroundMapList.Count : mapList.Count; - var result = new Map(id, collisionData); - - if (background) - backgroundMapList.Add(result); - else - mapList.Add(result); - - return result; - } - - public Block AddBlock(bool background = false) - { - int id = background ? backgroundBlockList.Count : blockList.Count; - var result = new Block(id); - - if (background) - backgroundBlockList.Add(result); - else - blockList.Add(result); - - return result; - } - - public Scene AddScene(bool background = false) - { - int id = background ? backgroundSceneList.Count : sceneList.Count; - var result = new Scene(id); - - if (background) - backgroundSceneList.Add(result); - else - sceneList.Add(result); - - return result; - } - - public Scene AddScene(int row, int col, bool background = false) - { - Scene result = AddScene(background); - - if (background) - backgroundScenes[row, col] = result; - else - scenes[row, col] = result; - - return result; - } - - public Scene AddScene(Vector pos, bool background = false) - { - Scene result = AddScene(background); - - Cell cell = GetSceneCellFromPos(pos); - - if (background) - backgroundScenes[cell.Row, cell.Col] = result; - else - scenes[cell.Row, cell.Col] = result; - - return result; - } - - public Map AddMap(Vector pos, CollisionData collisionData = CollisionData.NONE, bool background = false) - { - Map result = AddMap(collisionData, background); - SetMap(pos, result, background); - return result; - } - - public void SetMap(Vector pos, Map map, bool background = false) - { - Cell cell = GetSceneCellFromPos(pos); - Scene scene = background ? backgroundScenes[cell.Row, cell.Col] : scenes[cell.Row, cell.Col]; - scene ??= AddScene(pos, background); - - scene.SetMap(pos - GetSceneLeftTop(cell), map); - } - - public void SetBlock(Vector pos, Block block, bool background = false) - { - Cell cell = GetSceneCellFromPos(pos); - Scene scene = background ? backgroundScenes[cell.Row, cell.Col] : scenes[cell.Row, cell.Col]; - scene ??= AddScene(pos, background); - - scene.SetBlock(pos - GetSceneLeftTop(cell), block); - } - - public void SetScene(Vector pos, Scene scene, bool background = false) - { - Cell cell = GetSceneCellFromPos(pos); - - if (background) - backgroundScenes[cell.Row, cell.Col] = scene; - else - scenes[cell.Row, cell.Col] = scene; - } - - public Tile GetTileByID(int id, bool background = false) - { - return background - ? id < 0 || id >= backgroundTileList.Count ? null : backgroundTileList[id] - : id < 0 || id >= tileList.Count ? null : tileList[id]; - } - - public Map GetMapByID(int id, bool background = false) - { - return background - ? id < 0 || id >= backgroundMapList.Count ? null : backgroundMapList[id] - : id < 0 || id >= mapList.Count ? null : mapList[id]; - } - - public Block GetBlockByID(int id, bool background = false) - { - return background - ? id < 0 || id >= backgroundBlockList.Count ? null : backgroundBlockList[id] - : id < 0 || id >= blockList.Count ? null : blockList[id]; - } - - public Scene GetSceneByID(int id, bool background = false) - { - return background - ? id < 0 || id >= backgroundSceneList.Count ? null : backgroundSceneList[id] - : id < 0 || id >= sceneList.Count ? null : sceneList[id]; - } - - public void RemoveTile(Tile tile) - { - if (tile == null) - return; - - tileList.Remove(tile); - backgroundTileList.Remove(tile); - - foreach (Map map in mapList) - map.RemoveTile(tile); - - foreach (Map map in backgroundMapList) - map.RemoveTile(tile); - } - - public void RemoveMap(Map map) - { - if (map == null) - return; - - mapList.Remove(map); - backgroundMapList.Remove(map); - - foreach (Block block in blockList) - block.RemoveMap(map); - - foreach (Block block in backgroundBlockList) - block.RemoveMap(map); - } - - public void RemoveBlock(Block block) - { - if (block == null) - return; - - blockList.Remove(block); - backgroundBlockList.Remove(block); - - foreach (Scene scene in sceneList) - scene.RemoveBlock(block); - - foreach (Scene scene in backgroundSceneList) - scene.RemoveBlock(block); - } - - public void RemoveScene(Scene scene) - { - if (scene == null) - return; - - sceneList.Remove(scene); - backgroundSceneList.Remove(scene); - - for (int col = 0; col < SceneColCount; col++) - { - for (int row = 0; row < SceneRowCount; row++) - { - if (scenes[row, col] == scene) - scenes[row, col] = null; - } - } - - for (int col = 0; col < backgroundSceneColCount; col++) - { - for (int row = 0; row < backgroundSceneRowCount; row++) - { - if (backgroundScenes[row, col] == scene) - backgroundScenes[row, col] = null; - } - } - } - - public void Resize(int rowCount, int colCount, bool background = false) - { - if (background) - ResizeBackground(rowCount, colCount); - else - ResizeForeground(rowCount, colCount); - } - - public void ResizeForeground(int rowCount, int colCount) - { - if (rowCount == SceneRowCount && colCount == SceneColCount) - return; - - var newScenes = new Scene[rowCount, colCount]; - - int minRows = System.Math.Min(rowCount, SceneRowCount); - int minCols = System.Math.Min(colCount, SceneColCount); - - for (int col = 0; col < minCols; col++) - { - for (int row = 0; row < minRows; row++) - newScenes[row, col] = scenes[row, col]; - } - - SceneRowCount = rowCount; - SceneColCount = colCount; - - scenes = newScenes; - } - - public void ResizeBackground(int rowCount, int colCount) - { - if (rowCount == backgroundSceneRowCount && colCount == backgroundSceneColCount) - return; - - var newScenes = new Scene[rowCount, colCount]; - - int minRows = System.Math.Min(rowCount, backgroundSceneRowCount); - int minCols = System.Math.Min(colCount, backgroundSceneColCount); - - for (int col = 0; col < minCols; col++) - { - for (int row = 0; row < minRows; row++) - newScenes[row, col] = backgroundScenes[row, col]; - } - - backgroundSceneRowCount = rowCount; - backgroundSceneColCount = colCount; - - backgroundScenes = newScenes; - } - - public void Clear() - { - for (int col = 0; col < SceneColCount; col++) - { - for (int row = 0; row < SceneRowCount; row++) - scenes[row, col] = null; - } - - for (int col = 0; col < backgroundSceneColCount; col++) - { - for (int row = 0; row < backgroundSceneRowCount; row++) - backgroundScenes[row, col] = null; - } - - tileList.Clear(); - backgroundTileList.Clear(); - blockList.Clear(); - backgroundBlockList.Clear(); - mapList.Clear(); - backgroundMapList.Clear(); - - foreach (Scene scene in sceneList) - scene.Dispose(); - - foreach (Scene scene in backgroundSceneList) - scene.Dispose(); - - sceneList.Clear(); - backgroundSceneList.Clear(); - } - - public void FillRectangle(MMXBox box, Map map, bool background = false) - { - Vector boxLT = box.LeftTop; - Vector boxSize = box.DiagonalVector; - - Cell cell = GetMapCellFromPos(boxLT); - int col = cell.Col; - int row = cell.Row; - int cols = (int) (boxSize.X / MAP_SIZE); - int rows = (int) (boxSize.Y / MAP_SIZE); - - for (int c = 0; c < cols; c++) - { - for (int r = 0; r < rows; r++) - SetMap(GetMapLeftTop(row + r, col + c), map, background); - } - } - - public void FillRectangle(MMXBox box, Block block, bool background = false) - { - Vector boxLT = box.LeftTop; - Vector boxSize = box.DiagonalVector; - - Cell cell = GetBlockCellFromPos(boxLT); - int col = cell.Col; - int row = cell.Row; - int cols = (int) (boxSize.X / BLOCK_SIZE); - int rows = (int) (boxSize.Y / BLOCK_SIZE); - - for (int c = 0; c < cols; c++) - { - for (int r = 0; r < rows; r++) - SetBlock(GetBlockLeftTop(row + r, col + c), block, background); - } - } - - public void FillRectangle(MMXBox box, Scene scene, bool background = false) - { - Vector boxLT = box.LeftTop; - Vector boxSize = box.DiagonalVector; - - Cell cell = GetSceneCellFromPos(boxLT); - int col = cell.Col; - int row = cell.Row; - int cols = (int) (boxSize.X / SCENE_SIZE); - int rows = (int) (boxSize.Y / SCENE_SIZE); - - for (int c = 0; c < cols; c++) - { - for (int r = 0; r < rows; r++) - SetScene(GetSceneLeftTop(row + r, col + c), scene, background); - } - } - - public void Dispose() - { - try - { - Clear(); - } - finally - { - GC.SuppressFinalize(this); - } - } - - public void RenderBackground(int layer) - { - Checkpoint checkpoint = Engine.CurrentCheckpoint; - if (checkpoint == null) - return; - - var camera = Engine.Camera; - if (camera == null) - return; - - Vector screenLT = camera.LeftTop; - Vector screenRB = camera.RightBottom; - Vector backgroundPos = checkpoint.BackgroundPos; - - Vector screenDelta = (checkpoint.Scroll & 0x2) != 0 ? Vector.NULL_VECTOR : (screenLT + checkpoint.CameraPos).Scale(0.5f) - backgroundPos; - - Cell start = GetSceneCellFromPos(screenLT - screenDelta); - Cell end = GetSceneCellFromPos(screenRB - screenDelta); - - for (int col = start.Col; col <= end.Col + 1; col++) - { - if (col < 0) - continue; - - if ((checkpoint.Scroll & 0x10) == 0 && col >= backgroundSceneColCount) - continue; - - int bkgCol = (checkpoint.Scroll & 0x10) != 0 ? col % 2 : col; - - for (int row = start.Row; row <= end.Row + 1; row++) - { - if (row < 0 || row >= backgroundSceneRowCount) - continue; - - Scene scene = backgroundScenes[row, bkgCol]; - if (scene != null) - { - Vector sceneLT = GetSceneLeftTop(row, col); - MMXBox sceneBox = GetSceneBoundingBoxFromPos(sceneLT); - Engine.RenderVertexBuffer(scene.layers[layer], GameEngine.VERTEX_SIZE, Scene.PRIMITIVE_COUNT, BackgroundTilemap, BackgroundPalette, FadingControl, sceneBox + screenDelta); - } - } - } - } - - public void RenderForeground(int layer) - { - var camera = Engine.Camera; - if (camera == null) - return; - - Vector screenLT = camera.LeftTop; - Vector screenRB = camera.RightBottom; - - Cell start = GetSceneCellFromPos(screenLT); - Cell end = GetSceneCellFromPos(screenRB); - - for (int col = start.Col; col <= end.Col + 1; col++) - { - if (col < 0 || col >= SceneColCount) - continue; - - for (int row = start.Row; row <= end.Row + 1; row++) - { - if (row < 0 || row >= SceneRowCount) - continue; - - Scene scene = scenes[row, col]; - if (scene != null) - { - var sceneLT = GetSceneLeftTop(row, col); - MMXBox sceneBox = GetSceneBoundingBoxFromPos(sceneLT); - Engine.RenderVertexBuffer(scene.layers[layer], GameEngine.VERTEX_SIZE, Scene.PRIMITIVE_COUNT, ForegroundTilemap, ForegroundPalette, FadingControl, sceneBox); - } - } - } - } - - public void OnFrame() - { - FadingControl.OnFrame(); - } - public static Cell GetTileCellFromPos(Vector pos) { int col = (int) ((pos.X - WORLD_OFFSET.X) / TILE_SIZE); @@ -617,104 +60,42 @@ public static Cell GetSceneCellFromPos(Vector pos) return new Cell(row, col); } - public Tile GetTileFrom(Vector pos, bool background = false) - { - Cell tsp = GetSceneCellFromPos(pos); - int row = tsp.Row; - int col = tsp.Col; - - if (row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount) - return null; - - Scene scene = background ? backgroundScenes[row, col] : scenes[row, col]; - return scene?.GetTileFrom(pos - GetSceneLeftTop(row, col)); - } - - public Map GetMapFrom(Vector pos, bool background = false) - { - Cell tsp = GetSceneCellFromPos(pos); - int row = tsp.Row; - int col = tsp.Col; - - if (row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount) - return null; - - Scene scene = background ? backgroundScenes[row, col] : scenes[row, col]; - return scene?.GetMapFrom(pos - GetSceneLeftTop(row, col)); - } - - public Block GetBlockFrom(Vector pos, bool background = false) - { - Cell tsp = GetSceneCellFromPos(pos); - int row = tsp.Row; - int col = tsp.Col; - - if (row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount) - return null; - - Scene scene = background ? backgroundScenes[row, col] : scenes[row, col]; - return scene?.GetBlockFrom(pos - GetSceneLeftTop(row, col)); - } - - public Scene GetSceneFrom(Vector pos, bool background = false) - { - Cell tsp = GetSceneCellFromPos(pos); - int row = tsp.Row; - int col = tsp.Col; - - return row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount - ? null - : background ? backgroundScenes[row, col] : scenes[row, col]; - } - - public Scene GetSceneFrom(Cell cell, bool background = false) - { - return GetSceneFrom(cell.Row, cell.Col, background); - } - - public Scene GetSceneFrom(int row, int col, bool background = false) - { - return row < 0 || col < 0 || row >= SceneRowCount || col >= SceneColCount - ? null - : background ? backgroundScenes[row, col] : scenes[row, col]; - } - - public static MMXBox GetTileBoundingBox(int row, int col) + public static Box GetTileBoundingBox(int row, int col) { return GetTileBoundingBox(new Cell(row, col)); } - public static MMXBox GetMapBoundingBox(int row, int col) + public static Box GetMapBoundingBox(int row, int col) { return GetMapBoundingBox(new Cell(row, col)); } - public static MMXBox GetBlockBoundingBox(int row, int col) + public static Box GetBlockBoundingBox(int row, int col) { return GetBlockBoundingBox(new Cell(row, col)); } - public static MMXBox GetSceneBoundingBox(int row, int col) + public static Box GetSceneBoundingBox(int row, int col) { return GetSceneBoundingBox(new Cell(row, col)); } - public static MMXBox GetTileBoundingBox(Cell pos) + public static Box GetTileBoundingBox(Cell pos) { return (pos.Col * TILE_SIZE + WORLD_OFFSET.X, pos.Row * TILE_SIZE + WORLD_OFFSET.Y, TILE_SIZE, TILE_SIZE); } - public static MMXBox GetMapBoundingBox(Cell pos) + public static Box GetMapBoundingBox(Cell pos) { return (pos.Col * MAP_SIZE + WORLD_OFFSET.X, pos.Row * MAP_SIZE + WORLD_OFFSET.Y, MAP_SIZE, MAP_SIZE); } - public static MMXBox GetBlockBoundingBox(Cell pos) + public static Box GetBlockBoundingBox(Cell pos) { return (pos.Col * BLOCK_SIZE + WORLD_OFFSET.X, pos.Row * BLOCK_SIZE + WORLD_OFFSET.Y, BLOCK_SIZE, BLOCK_SIZE); } - public static MMXBox GetSceneBoundingBox(Cell pos) + public static Box GetSceneBoundingBox(Cell pos) { return (pos.Col * SCENE_SIZE + WORLD_OFFSET.X, pos.Row * SCENE_SIZE + WORLD_OFFSET.Y, SCENE_SIZE, SCENE_SIZE); } @@ -759,77 +140,130 @@ public static Vector GetSceneLeftTop(Cell pos) return (pos.Col * SCENE_SIZE + WORLD_OFFSET.X, pos.Row * SCENE_SIZE + WORLD_OFFSET.Y); } - public static MMXBox GetTileBoundingBoxFromPos(Vector pos) + public static Box GetTileBoundingBoxFromPos(Vector pos) { return GetTileBoundingBox(GetTileCellFromPos(pos)); } - public static MMXBox GetMapBoundingBoxFromPos(Vector pos) + public static Box GetMapBoundingBoxFromPos(Vector pos) { return GetMapBoundingBox(GetMapCellFromPos(pos)); } - public static MMXBox GetBlockBoundingBoxFromPos(Vector pos) + public static Box GetBlockBoundingBoxFromPos(Vector pos) { return GetBlockBoundingBox(GetBlockCellFromPos(pos)); } - public static MMXBox GetSceneBoundingBoxFromPos(Vector pos) + public static Box GetSceneBoundingBoxFromPos(Vector pos) { return GetSceneBoundingBox(GetSceneCellFromPos(pos)); } - internal void Tessellate() + private PixelCollisionChecker collisionChecker; + + public ForegroundLayout ForegroundLayout { - foreach (Scene scene in sceneList) - scene.Tessellate(); + get; + } - foreach (Scene scene in backgroundSceneList) - scene.Tessellate(); + public BackgroundLayout BackgroundLayout + { + get; } - internal void OnDisposeDevice() + internal World(int sceneRowCount, int sceneColCount) + : this(sceneRowCount, sceneColCount, sceneRowCount, sceneColCount) + { + } + + internal World(int foregroundSceneRowCount, int foregroundSceneColCount, int backgroundSceneRowCount, int backgroundSceneColCount) + { + ForegroundLayout = new ForegroundLayout(foregroundSceneRowCount, foregroundSceneColCount); + BackgroundLayout = new BackgroundLayout(backgroundSceneRowCount, backgroundSceneColCount); + + collisionChecker = new PixelCollisionChecker(); + } + + public void Clear() + { + ForegroundLayout.Clear(); + BackgroundLayout.Clear(); + } + + public void Dispose() + { + try + { + Clear(); + } + finally + { + GC.SuppressFinalize(this); + } + } + + public void RenderBackground(int layer) + { + BackgroundLayout.Render(layer); + } + + public void RenderForeground(int layer) { - foreach (Scene scene in sceneList) - scene.OnDisposeDevice(); + ForegroundLayout.Render(layer); + } - foreach (Scene scene in backgroundSceneList) - scene.OnDisposeDevice(); + public void OnFrame() + { + ForegroundLayout.OnFrame(); + BackgroundLayout.OnFrame(); + } + + internal void Tessellate() + { + ForegroundLayout.Tesselate(); + BackgroundLayout.Tesselate(); + } + + internal void OnDisposeDevice() + { + ForegroundLayout.OnDisposeDevice(); + BackgroundLayout.OnDisposeDevice(); } - public CollisionFlags GetCollisionFlags(MMXBox collisionBox, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false, params Entities.Sprite[] ignoreSprites) + public CollisionFlags GetCollisionFlags(Box collisionBox, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false, params Entities.Sprite[] ignoreSprites) { collisionChecker.Setup(collisionBox, ignore, checkWithWorld, checknWithSolidSprites, false, ignoreSprites); return collisionChecker.GetCollisionFlags(); } - public CollisionFlags GetCollisionFlags(MMXBox collisionBox, EntitySet ignoreSprites, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false) + public CollisionFlags GetCollisionFlags(Box collisionBox, EntitySet ignoreSprites, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false) { collisionChecker.Setup(collisionBox, ignore, ignoreSprites, checkWithWorld, checknWithSolidSprites, false); return collisionChecker.GetCollisionFlags(); } - public CollisionFlags GetCollisionFlags(MMXBox collisionBox, BitSet ignoreSprites, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false) + public CollisionFlags GetCollisionFlags(Box collisionBox, BitSet ignoreSprites, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false) { collisionChecker.Setup(collisionBox, ignore, ignoreSprites, checkWithWorld, checknWithSolidSprites, false); return collisionChecker.GetCollisionFlags(); } - public IEnumerable GetCollisionPlacements(MMXBox collisionBox, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false, params Entities.Sprite[] ignoreSprites) + public IEnumerable GetCollisionPlacements(Box collisionBox, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false, params Entities.Sprite[] ignoreSprites) { collisionChecker.Setup(collisionBox, ignore, checkWithWorld, checknWithSolidSprites, true, ignoreSprites); collisionChecker.GetCollisionFlags(); return collisionChecker.Placements; } - public IEnumerable GetCollisionPlacements(MMXBox collisionBox, EntitySet ignoreSprites, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false) + public IEnumerable GetCollisionPlacements(Box collisionBox, EntitySet ignoreSprites, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false) { collisionChecker.Setup(collisionBox, ignore, ignoreSprites, checkWithWorld, checknWithSolidSprites, true); collisionChecker.GetCollisionFlags(); return collisionChecker.Placements; } - public IEnumerable GetCollisionPlacements(MMXBox collisionBox, BitSet ignoreSprites, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false) + public IEnumerable GetCollisionPlacements(Box collisionBox, BitSet ignoreSprites, CollisionFlags ignore = CollisionFlags.NONE, bool checkWithWorld = true, bool checknWithSolidSprites = false) { collisionChecker.Setup(collisionBox, ignore, ignoreSprites, checkWithWorld, checknWithSolidSprites, true); collisionChecker.GetCollisionFlags(); diff --git a/XSharp/MegaEDX/MMXCore.cs b/XSharp/MegaEDX/MMXCore.cs index af1b685..21e4ec5 100644 --- a/XSharp/MegaEDX/MMXCore.cs +++ b/XSharp/MegaEDX/MMXCore.cs @@ -1958,7 +1958,7 @@ private Tile AddTile(World world, uint tile, bool transparent = false, bool back } } - Tile wtile = world.AddTile(imageData, background); + Tile wtile = background ? world.BackgroundLayout.AddTile(imageData) : world.ForegroundLayout.AddTile(imageData); return wtile; } @@ -2015,7 +2015,7 @@ internal void RefreshMapCache(GameEngine engine, bool background = false) { byte colisionByte = rom[pCollisions + i]; var collisionData = (CollisionData) colisionByte; - Map wmap = engine.World.AddMap(collisionData, background); + Map wmap = background ? engine.World.BackgroundLayout.AddMap(collisionData) : engine.World.ForegroundLayout.AddMap(collisionData); uint tileData = ReadWord(map); byte palette = (byte) ((tileData >> 10) & 7); @@ -2075,7 +2075,12 @@ private void LoadMap(World world, int x, int y, ushort index, bool background = { Map map = maps[index]; if (map != null) - world.SetMap(new Vector(x * MAP_SIZE + WORLD_OFFSET.X, y * MAP_SIZE + WORLD_OFFSET.Y), map, background); + { + if (background) + world.BackgroundLayout.SetMap(new Vector(x * MAP_SIZE + WORLD_OFFSET.X, y * MAP_SIZE + WORLD_OFFSET.Y), map); + else + world.ForegroundLayout.SetMap(new Vector(x * MAP_SIZE + WORLD_OFFSET.X, y * MAP_SIZE + WORLD_OFFSET.Y), map); + } } } @@ -2120,7 +2125,10 @@ public void LoadToWorld(GameEngine engine, bool background = false) { LoadPalette(engine, background); - engine.World.Resize(levelHeight, levelWidth, background); + if (background) + engine.World.BackgroundLayout.Resize(levelHeight, levelWidth); + else + engine.World.ForegroundLayout.Resize(levelHeight, levelWidth); RefreshMapCache(engine, background);