mirror of
https://github.com/ficed/Braver.git
synced 2024-11-23 05:10:08 +00:00
Get field tile Z ordering/clipping working much closer to what FF7 does - fixes a lot of locations
This commit is contained in:
parent
2a89e2f58d
commit
9656695db3
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user