diff --git a/Braver/Field/Background.cs b/Braver/Field/Background.cs index c5e6178..f67cd46 100644 --- a/Braver/Field/Background.cs +++ b/Braver/Field/Background.cs @@ -49,9 +49,6 @@ namespace Braver.Field { private Dictionary _parameters = new(); private VertexPositionColor[] _blankingVerts; - public float AutoDetectZFrom { get; private set; } - public float AutoDetectZTo { get; private set; } - private Dictionary> _layersByPalette = new(); private List _palettes; private PluginInstances _plugins; @@ -104,32 +101,19 @@ namespace Braver.Field { MinX = bg.AllSprites.Min(s => s.DestX); MinY = bg.AllSprites.Min(s => s.DestY); - var zCoords = bg.AllSprites - .Where(spr => spr.State == 0) - .Select(spr => spr.ID) - .Where(z => z > 1 && z < DEPTH_CUTOFF) - ; - if (zCoords.Any()) { - AutoDetectZFrom = zCoords.Min() * 0.75f; - AutoDetectZTo = zCoords.Max() * 1.25f; - } else { - AutoDetectZFrom = 1f; - AutoDetectZTo = 4095f; - } - + int layerNum = 0; foreach (var layer in bg.Layers.Where(L => L.Any())) { - - int DepthGroup(int id) { - if (id >= DEPTH_CUTOFF) - return 1; - else if (id <= 2) - return -1; - else - return 0; + layerNum++; +/* + System.Diagnostics.Debug.WriteLine($"LAYER {layerNum} TILES"); + int spriteNum = 0; + foreach(var sprite in layer) { + System.Diagnostics.Debug.WriteLine($"Tile {spriteNum++} at {sprite.DestX}/{sprite.DestY}/{sprite.CalculatedZ(layerNum, 9999)}, image {sprite.SrcX}/{sprite.SrcY}, UV {sprite.UParam / 10000000f}/{sprite.VParam / 10000000f} flags {sprite.Flags}"); } - +*/ + var groups = layer - .GroupBy(s => new { SortKey = s.SortKeyHigh, Depth = DepthGroup(s.ID) }) + .GroupBy(s => new { SortKey = s.SortKeyHigh }) .OrderByDescending(group => group.Key.SortKey); foreach (var group in groups) { @@ -149,13 +133,17 @@ namespace Braver.Field { float zcoord; bool isFixedZ; bool hasBlend = (blend != Ficedula.FF7.BlendType.None0) && (blend != Ficedula.FF7.BlendType.None1); + + /* if ((group.First().ID >= DEPTH_CUTOFF) || hasBlend) { zcoord = 1f; isFixedZ = true; } else if (group.First().ID <= 2) { zcoord = 0f; isFixedZ = true; } else { zcoord = group.First().ID; isFixedZ = false; - } + }*/ + + isFixedZ = true; TexLayer tl = new TexLayer { Tex = new Texture2D(graphics, texWidth, texHeight, false, SurfaceFormat.Color), @@ -174,6 +162,7 @@ namespace Braver.Field { List verts = new(); foreach(var sprite in group) { + zcoord = sprite.CalculatedZ(layerNum, 9999); //TODO float destX = sprite.DestX + tl.OffsetX, destY = sprite.DestY + tl.OffsetY; verts.Add(new VertexPositionTexture { Position = new Vector3(sprite.DestX, -sprite.DestY, zcoord), @@ -323,7 +312,7 @@ namespace Braver.Field { public void Step() { } - public void Render(Viewer viewer, float zFrom, float zTo, bool blendLayers) { + public void Render(Viewer viewer, bool blendLayers) { var depth = blendLayers ? DepthStencilState.None : DepthStencilState.Default; @@ -359,9 +348,10 @@ namespace Braver.Field { break; } - float zs = layer.FixedZ ? 1f : 1f / (zTo - zFrom); + float zs = 1f; // layer.FixedZ ? 1f : 1f / (zTo - zFrom); + float zOffset = 0; // layer.FixedZ ? 0 : -zFrom - _effect.World = Matrix.CreateTranslation(ScrollX, ScrollY, layer.FixedZ ? 0 : -zFrom) + _effect.World = Matrix.CreateTranslation(ScrollX, ScrollY, zOffset) * Matrix.CreateScale(3f, 3f, zs); _effect.Texture = layer.Tex; diff --git a/Braver/Field/FieldScreen.cs b/Braver/Field/FieldScreen.cs index 41d7553..d81519f 100644 --- a/Braver/Field/FieldScreen.cs +++ b/Braver/Field/FieldScreen.cs @@ -48,7 +48,6 @@ namespace Braver.Field { private View2D _view2D; private FieldDebug _debug; private FieldInfo _info; - private float _bgZFrom = 1025f, _bgZTo = 1092f; private string _file; private bool _debugMode = false; @@ -128,19 +127,25 @@ namespace Braver.Field { if (cam == null) return null; double fovy = (2 * Math.Atan(240.0 / (2.0 * cam.Zoom))) * 57.29577951; + //This produces a FOV that's about 7% higher than FF7 (PC at least) uses - but that's because + //FF7 PC doesn't use the full screen height, it has black bars that reduce the usable height + //by around 7% - so this gives correct results for the resolution we want to render at. var camPosition = cam.CameraPosition.ToX() * 4096f; - + /* var camDistances = _walkmesh .SelectMany(tri => new[] { tri.V0.ToX(), tri.V1.ToX(), tri.V2.ToX() }) .Select(v => (camPosition - v).Length()); float nearest = camDistances.Min(), furthest = camDistances.Max(); + */ + + //Seems like FF7 uses near/far clipping planes of 50/32000 on most (all?!?) field locations return new PerspView3D { FOV = (float)fovy, - ZNear = nearest * 0.75f, - ZFar = furthest * 1.25f, + ZNear = 50, //nearest * 0.75f, + ZFar = 32000, //furthest,// * 1.25f, CameraPosition = camPosition, CameraForwards = cam.Forwards.ToX(), CameraUp = cam.Up.ToX(), @@ -342,14 +347,6 @@ namespace Braver.Field { System.Diagnostics.Trace.WriteLine($"Walkmesh Z varies from {minZ}-{maxZ} (recip {1f / minZ} to {1f / maxZ}"); _debug = new FieldDebug(graphics, field); - if (_info.BGZFrom != 0) { - _bgZFrom = _info.BGZFrom; - _bgZTo = _info.BGZTo; - } else { - _bgZFrom = Background.AutoDetectZFrom; - _bgZTo = Background.AutoDetectZTo; - } - Dialog = new Dialog(g, _dialogPlugins, graphics); FieldUI = new FieldUI(g, graphics); @@ -429,7 +426,7 @@ namespace Braver.Field { if (Movie.Active) Movie.Render(); else - Background.Render(view2D, _bgZFrom, _bgZTo, false); + Background.Render(view2D, false); } if (_renderDebug) @@ -446,7 +443,7 @@ namespace Braver.Field { //Now render blend layers over actual background + models if (_renderBG && !Movie.Active) - Background.Render(view2D, _bgZFrom, _bgZTo, true); + Background.Render(view2D, true); Overlay.Render(); @@ -687,6 +684,7 @@ namespace Braver.Field { Game.PushScreen(new UI.Layout.LayoutScreen("FieldDebugger", parm: this)); if (input.IsDown(InputKey.Debug4)) { + /* if (input.IsDown(InputKey.Up)) _bgZFrom++; else if (input.IsDown(InputKey.Down)) @@ -709,6 +707,7 @@ namespace Braver.Field { System.Diagnostics.Trace.WriteLine($"BGZFrom {_bgZFrom} ZTo {_bgZTo}"); return; + */ } if (_debugMode) { diff --git a/Braver/Net/Server.cs b/Braver/Net/Server.cs index b5e4055..4d955d2 100644 --- a/Braver/Net/Server.cs +++ b/Braver/Net/Server.cs @@ -73,7 +73,7 @@ namespace Braver.Net { } } - private void Listener_NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) { + private void Listener_NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod) { var id = _connectedPlayers .SingleOrDefault(kv => kv.Value == peer) .Key; diff --git a/Braver/Viewer.cs b/Braver/Viewer.cs index 8b28f38..450a482 100644 --- a/Braver/Viewer.cs +++ b/Braver/Viewer.cs @@ -76,6 +76,85 @@ namespace Braver { } } + public class FieldView3D : View3D { + public float FOV { get; set; } = 90f; + public Vector2 ScreenOffset { get; set; } + public Vector2 ScreenSize { get; set; } = new Vector2(1280f, 720f); + + public override Matrix Projection { + get { + Matrix m1 = Matrix.Identity, m2 = Matrix.Identity; + + float left = 0 * (ScreenOffset.X * ScreenSize.X) - ScreenSize.X / 2; + float top = 0 * (ScreenOffset.Y * ScreenSize.Y) - ScreenSize.Y / 2; + + m2[0] = 1f / AspectRatio; + m2[5] = -1f; + m2[10] = 1f; + m2[12] = left * 2f / ScreenSize.X; + m2[13] = -(top * AspectRatio) / ScreenSize.Y; + + /* + fVar2 = ConvertToRadians(fov); + fVar1 = FUN_007aff60((float10)fVar2 / (float10)2.0); + fVar2 = (float)(fVar1 * zNear); + local_94[10] = (float)((fVar1 * extraout_ST1 * (float10)z_far) / + (((float10)z_far - (float10)z_near) * (float10)z_near)); + local_94[0xb] = fVar2 / z_near; + local_94[0xe] = (-fVar2 * z_far) / (z_far - z_near); + local_94[0xf] = 0.0; +*/ + float fovRadians = (FOV * (float)Math.PI / 180) / 2f; + float fovNear = fovRadians * ZNear; + m1[10] = (fovNear * ZFar) / ((ZFar - ZNear) * ZNear); + m1[11] = fovRadians; + m1[14] = (-fovNear * ZFar) / (ZFar - ZNear); + m1[15] = 0f; + + return m1 * m2; + } + } + + public FieldView3D Clone() { + return new FieldView3D { + AspectRatio = AspectRatio, + ZNear = ZNear, + ZFar = ZFar, + CameraPosition = CameraPosition, + CameraUp = CameraUp, + CameraForwards = CameraForwards, + FOV = FOV, + ScreenOffset = ScreenOffset, + ScreenSize = ScreenSize, + }; + } + + public FieldView3D Blend(FieldView3D other, float factor) { + return new FieldView3D { + AspectRatio = other.AspectRatio, //not going to change anyway...? + ZNear = ZNear * (1 - factor) + other.ZNear * factor, + ZFar = ZFar * (1 - factor) + other.ZFar * factor, + CameraPosition = CameraPosition * (1 - factor) + other.CameraPosition * factor, + CameraUp = CameraUp * (1 - factor) + other.CameraUp * factor, + CameraForwards = CameraForwards * (1 - factor) + other.CameraForwards * factor, + }; + } + + public Vector3 ProjectTo2D(Vector3 pos3D) { + var pos = Vector4.Transform(pos3D, View * Projection); + pos /= pos.W; + return new Vector3( + (pos.X + 1) * 1280f / 2f, + 720f - (pos.Y + 1) * 720f / 2f, + pos.Z + ); + } + + public override string ToString() { + return $"Persp Z-range {ZNear}:{ZFar} Pos {CameraPosition} Fwd {CameraForwards} Up {CameraUp}"; + } + } + public class PerspView3D : View3D { public float FOV { get; set; } = 90f; diff --git a/Ficedula.FF7.Exporters/Field.cs b/Ficedula.FF7.Exporters/Field.cs index 70027d3..f78b255 100644 --- a/Ficedula.FF7.Exporters/Field.cs +++ b/Ficedula.FF7.Exporters/Field.cs @@ -14,7 +14,7 @@ foreach (var layer in new[] { background.Layer1, background.Layer2 }) { foreach (var tiles in layer.GroupBy(s => s.Blending)) { var bmp = new SkiaSharp.SKBitmap(background.Width, background.Height, SkiaSharp.SKColorType.Rgba8888, SkiaSharp.SKAlphaType.Premul); - foreach (var tile in tiles.OrderBy(t => t.ID)) { + foreach (var tile in tiles.OrderBy(t => t.Flags)) { int destX = tile.DestX + offsetX, destY = tile.DestY + offsetY; var src = background.Pages[tile.TextureID].Data; var pal = background.Palettes[tile.PaletteID].Colours; diff --git a/Ficedula.FF7/Field/Background.cs b/Ficedula.FF7/Field/Background.cs index ec6618a..5801578 100644 --- a/Ficedula.FF7/Field/Background.cs +++ b/Ficedula.FF7/Field/Background.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Xml.XPath; namespace Ficedula.FF7.Field { public class TileGroup { @@ -23,16 +24,29 @@ namespace Ficedula.FF7.Field { public struct Sprite { public short DestX, DestY, ZZ2a, ZZ2b, SrcX, SrcY; - public short SrcX2, SrcY2, Width, Height, PaletteID, ID; + public short SrcX2, SrcY2, Width, Height, PaletteID, Flags; public byte Param, State, Blending, ZZ3, TypeTrans, ZZ4; public short TextureID, TextureID2, Depth; - public int IDBig; - public int ZZ5, ZZ6, ZZ7; + public int ZParam, UParam, VParam; + public int ZZ7; - public long SortKey => ((long)TypeTrans << 48) | ((long)Param << 40) | ((long)State << 32) | ID; + public long SortKey => ((long)TypeTrans << 48) | ((long)Param << 40) | ((long)State << 32) | Flags; public int SortKeyHigh => (TypeTrans << 16) | (Param << 8) | State; + public float CalculatedZ(int layer, int fieldID) { + switch (layer) { + case 1: + return 0.9997f; + case 2: //Some special cases in original code?! e.g. FieldID 0x43, 0xcc, or 0x75 + case 3: //No, extra logic + case 4: //No, extra logic + return ZParam / 10000000f; + default: + throw new NotImplementedException(); + } + } + public Sprite(Stream source, int layer) { DestX = source.ReadI16(); DestY = source.ReadI16(); @@ -45,7 +59,7 @@ namespace Ficedula.FF7.Field { Width = source.ReadI16(); Height = source.ReadI16(); PaletteID = source.ReadI16(); - ID = source.ReadI16(); + Flags = source.ReadI16(); Param = (byte)source.ReadByte(); State = (byte)source.ReadByte(); Blending = (byte)source.ReadByte(); @@ -55,10 +69,10 @@ namespace Ficedula.FF7.Field { TextureID = source.ReadI16(); TextureID2 = source.ReadI16(); Depth = source.ReadI16(); - IDBig = source.ReadI32(); + ZParam = source.ReadI32(); - ZZ5 = source.ReadI32(); - ZZ6 = source.ReadI32(); + UParam = source.ReadI32(); + VParam = source.ReadI32(); ZZ7 = source.ReadI32(); FixUp(layer);