Get field tile Z ordering/clipping working much closer to what FF7 does - fixes a lot of locations

This commit is contained in:
ficedula 2023-09-10 21:25:07 +01:00
parent 2a89e2f58d
commit 9656695db3
6 changed files with 136 additions and 54 deletions

View File

@ -49,9 +49,6 @@ namespace Braver.Field {
private Dictionary<int, int> _parameters = new(); private Dictionary<int, int> _parameters = new();
private VertexPositionColor[] _blankingVerts; private VertexPositionColor[] _blankingVerts;
public float AutoDetectZFrom { get; private set; }
public float AutoDetectZTo { get; private set; }
private Dictionary<int, List<TexLayer>> _layersByPalette = new(); private Dictionary<int, List<TexLayer>> _layersByPalette = new();
private List<Ficedula.FF7.Field.BackgroundPalette> _palettes; private List<Ficedula.FF7.Field.BackgroundPalette> _palettes;
private PluginInstances<IBackground> _plugins; private PluginInstances<IBackground> _plugins;
@ -104,32 +101,19 @@ namespace Braver.Field {
MinX = bg.AllSprites.Min(s => s.DestX); MinX = bg.AllSprites.Min(s => s.DestX);
MinY = bg.AllSprites.Min(s => s.DestY); MinY = bg.AllSprites.Min(s => s.DestY);
var zCoords = bg.AllSprites int layerNum = 0;
.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;
}
foreach (var layer in bg.Layers.Where(L => L.Any())) { foreach (var layer in bg.Layers.Where(L => L.Any())) {
layerNum++;
int DepthGroup(int id) { /*
if (id >= DEPTH_CUTOFF) System.Diagnostics.Debug.WriteLine($"LAYER {layerNum} TILES");
return 1; int spriteNum = 0;
else if (id <= 2) foreach(var sprite in layer) {
return -1; 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}");
else
return 0;
} }
*/
var groups = layer var groups = layer
.GroupBy(s => new { SortKey = s.SortKeyHigh, Depth = DepthGroup(s.ID) }) .GroupBy(s => new { SortKey = s.SortKeyHigh })
.OrderByDescending(group => group.Key.SortKey); .OrderByDescending(group => group.Key.SortKey);
foreach (var group in groups) { foreach (var group in groups) {
@ -149,13 +133,17 @@ namespace Braver.Field {
float zcoord; float zcoord;
bool isFixedZ; bool isFixedZ;
bool hasBlend = (blend != Ficedula.FF7.BlendType.None0) && (blend != Ficedula.FF7.BlendType.None1); bool hasBlend = (blend != Ficedula.FF7.BlendType.None0) && (blend != Ficedula.FF7.BlendType.None1);
/*
if ((group.First().ID >= DEPTH_CUTOFF) || hasBlend) { if ((group.First().ID >= DEPTH_CUTOFF) || hasBlend) {
zcoord = 1f; isFixedZ = true; zcoord = 1f; isFixedZ = true;
} else if (group.First().ID <= 2) { } else if (group.First().ID <= 2) {
zcoord = 0f; isFixedZ = true; zcoord = 0f; isFixedZ = true;
} else { } else {
zcoord = group.First().ID; isFixedZ = false; zcoord = group.First().ID; isFixedZ = false;
} }*/
isFixedZ = true;
TexLayer tl = new TexLayer { TexLayer tl = new TexLayer {
Tex = new Texture2D(graphics, texWidth, texHeight, false, SurfaceFormat.Color), Tex = new Texture2D(graphics, texWidth, texHeight, false, SurfaceFormat.Color),
@ -174,6 +162,7 @@ namespace Braver.Field {
List<VertexPositionTexture> verts = new(); List<VertexPositionTexture> verts = new();
foreach(var sprite in group) { foreach(var sprite in group) {
zcoord = sprite.CalculatedZ(layerNum, 9999); //TODO
float destX = sprite.DestX + tl.OffsetX, destY = sprite.DestY + tl.OffsetY; float destX = sprite.DestX + tl.OffsetX, destY = sprite.DestY + tl.OffsetY;
verts.Add(new VertexPositionTexture { verts.Add(new VertexPositionTexture {
Position = new Vector3(sprite.DestX, -sprite.DestY, zcoord), Position = new Vector3(sprite.DestX, -sprite.DestY, zcoord),
@ -323,7 +312,7 @@ namespace Braver.Field {
public void Step() { 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; var depth = blendLayers ? DepthStencilState.None : DepthStencilState.Default;
@ -359,9 +348,10 @@ namespace Braver.Field {
break; 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); * Matrix.CreateScale(3f, 3f, zs);
_effect.Texture = layer.Tex; _effect.Texture = layer.Tex;

View File

@ -48,7 +48,6 @@ namespace Braver.Field {
private View2D _view2D; private View2D _view2D;
private FieldDebug _debug; private FieldDebug _debug;
private FieldInfo _info; private FieldInfo _info;
private float _bgZFrom = 1025f, _bgZTo = 1092f;
private string _file; private string _file;
private bool _debugMode = false; private bool _debugMode = false;
@ -128,19 +127,25 @@ namespace Braver.Field {
if (cam == null) return null; if (cam == null) return null;
double fovy = (2 * Math.Atan(240.0 / (2.0 * cam.Zoom))) * 57.29577951; 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 camPosition = cam.CameraPosition.ToX() * 4096f;
/*
var camDistances = _walkmesh var camDistances = _walkmesh
.SelectMany(tri => new[] { tri.V0.ToX(), tri.V1.ToX(), tri.V2.ToX() }) .SelectMany(tri => new[] { tri.V0.ToX(), tri.V1.ToX(), tri.V2.ToX() })
.Select(v => (camPosition - v).Length()); .Select(v => (camPosition - v).Length());
float nearest = camDistances.Min(), furthest = camDistances.Max(); 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 { return new PerspView3D {
FOV = (float)fovy, FOV = (float)fovy,
ZNear = nearest * 0.75f, ZNear = 50, //nearest * 0.75f,
ZFar = furthest * 1.25f, ZFar = 32000, //furthest,// * 1.25f,
CameraPosition = camPosition, CameraPosition = camPosition,
CameraForwards = cam.Forwards.ToX(), CameraForwards = cam.Forwards.ToX(),
CameraUp = cam.Up.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}"); System.Diagnostics.Trace.WriteLine($"Walkmesh Z varies from {minZ}-{maxZ} (recip {1f / minZ} to {1f / maxZ}");
_debug = new FieldDebug(graphics, field); _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); Dialog = new Dialog(g, _dialogPlugins, graphics);
FieldUI = new FieldUI(g, graphics); FieldUI = new FieldUI(g, graphics);
@ -429,7 +426,7 @@ namespace Braver.Field {
if (Movie.Active) if (Movie.Active)
Movie.Render(); Movie.Render();
else else
Background.Render(view2D, _bgZFrom, _bgZTo, false); Background.Render(view2D, false);
} }
if (_renderDebug) if (_renderDebug)
@ -446,7 +443,7 @@ namespace Braver.Field {
//Now render blend layers over actual background + models //Now render blend layers over actual background + models
if (_renderBG && !Movie.Active) if (_renderBG && !Movie.Active)
Background.Render(view2D, _bgZFrom, _bgZTo, true); Background.Render(view2D, true);
Overlay.Render(); Overlay.Render();
@ -687,6 +684,7 @@ namespace Braver.Field {
Game.PushScreen(new UI.Layout.LayoutScreen("FieldDebugger", parm: this)); Game.PushScreen(new UI.Layout.LayoutScreen("FieldDebugger", parm: this));
if (input.IsDown(InputKey.Debug4)) { if (input.IsDown(InputKey.Debug4)) {
/*
if (input.IsDown(InputKey.Up)) if (input.IsDown(InputKey.Up))
_bgZFrom++; _bgZFrom++;
else if (input.IsDown(InputKey.Down)) else if (input.IsDown(InputKey.Down))
@ -709,6 +707,7 @@ namespace Braver.Field {
System.Diagnostics.Trace.WriteLine($"BGZFrom {_bgZFrom} ZTo {_bgZTo}"); System.Diagnostics.Trace.WriteLine($"BGZFrom {_bgZFrom} ZTo {_bgZTo}");
return; return;
*/
} }
if (_debugMode) { if (_debugMode) {

View File

@ -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 var id = _connectedPlayers
.SingleOrDefault(kv => kv.Value == peer) .SingleOrDefault(kv => kv.Value == peer)
.Key; .Key;

View File

@ -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 class PerspView3D : View3D {
public float FOV { get; set; } = 90f; public float FOV { get; set; } = 90f;

View File

@ -14,7 +14,7 @@
foreach (var layer in new[] { background.Layer1, background.Layer2 }) { foreach (var layer in new[] { background.Layer1, background.Layer2 }) {
foreach (var tiles in layer.GroupBy(s => s.Blending)) { foreach (var tiles in layer.GroupBy(s => s.Blending)) {
var bmp = new SkiaSharp.SKBitmap(background.Width, background.Height, SkiaSharp.SKColorType.Rgba8888, SkiaSharp.SKAlphaType.Premul); 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; int destX = tile.DestX + offsetX, destY = tile.DestY + offsetY;
var src = background.Pages[tile.TextureID].Data; var src = background.Pages[tile.TextureID].Data;
var pal = background.Palettes[tile.PaletteID].Colours; var pal = background.Palettes[tile.PaletteID].Colours;

View File

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.XPath;
namespace Ficedula.FF7.Field { namespace Ficedula.FF7.Field {
public class TileGroup { public class TileGroup {
@ -23,16 +24,29 @@ namespace Ficedula.FF7.Field {
public struct Sprite { public struct Sprite {
public short DestX, DestY, ZZ2a, ZZ2b, SrcX, SrcY; 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 byte Param, State, Blending, ZZ3, TypeTrans, ZZ4;
public short TextureID, TextureID2, Depth; public short TextureID, TextureID2, Depth;
public int IDBig; public int ZParam, UParam, VParam;
public int ZZ5, ZZ6, ZZ7; 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 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) { public Sprite(Stream source, int layer) {
DestX = source.ReadI16(); DestX = source.ReadI16();
DestY = source.ReadI16(); DestY = source.ReadI16();
@ -45,7 +59,7 @@ namespace Ficedula.FF7.Field {
Width = source.ReadI16(); Width = source.ReadI16();
Height = source.ReadI16(); Height = source.ReadI16();
PaletteID = source.ReadI16(); PaletteID = source.ReadI16();
ID = source.ReadI16(); Flags = source.ReadI16();
Param = (byte)source.ReadByte(); Param = (byte)source.ReadByte();
State = (byte)source.ReadByte(); State = (byte)source.ReadByte();
Blending = (byte)source.ReadByte(); Blending = (byte)source.ReadByte();
@ -55,10 +69,10 @@ namespace Ficedula.FF7.Field {
TextureID = source.ReadI16(); TextureID = source.ReadI16();
TextureID2 = source.ReadI16(); TextureID2 = source.ReadI16();
Depth = source.ReadI16(); Depth = source.ReadI16();
IDBig = source.ReadI32(); ZParam = source.ReadI32();
ZZ5 = source.ReadI32(); UParam = source.ReadI32();
ZZ6 = source.ReadI32(); VParam = source.ReadI32();
ZZ7 = source.ReadI32(); ZZ7 = source.ReadI32();
FixUp(layer); FixUp(layer);