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 VertexPositionColor[] _blankingVerts;
public float AutoDetectZFrom { get; private set; }
public float AutoDetectZTo { get; private set; }
private Dictionary<int, List<TexLayer>> _layersByPalette = new();
private List<Ficedula.FF7.Field.BackgroundPalette> _palettes;
private PluginInstances<IBackground> _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<VertexPositionTexture> 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;

View File

@ -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) {

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
.SingleOrDefault(kv => kv.Value == peer)
.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 float FOV { get; set; } = 90f;

View File

@ -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;

View File

@ -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);