| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Graphics;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.IO;
- using System.Linq;
- using System.Runtime.InteropServices;
- namespace OpenVIII.Battle.Dat
- {
- /// <summary>
- /// Section 2f: Quad
- /// </summary>
- /// <see cref="http://wiki.ffrtt.ru/index.php?title=FF8/FileFormat_DAT#Useful_structures"/>
- [StructLayout(LayoutKind.Explicit, Pack = 1, Size = ByteSize)]
- public class Quad
- {
- #region Fields
- public const int ByteSize = 20;
- [field: FieldOffset(10)]
- public readonly ushort TexUnk;
- [field: FieldOffset(14)]
- public readonly ushort U;
- [field: FieldOffset(8)]
- public readonly UV Vta;
- [field: FieldOffset(12)]
- public readonly UV Vtb;
- [field: FieldOffset(16)]
- public readonly UV Vtc;
- [field: FieldOffset(18)]
- public readonly UV Vtd;
- [field: FieldOffset(0)]
- private readonly ushort _a;
- [field: FieldOffset(2)]
- private readonly ushort _b;
- [field: FieldOffset(4)]
- private readonly ushort _c;
- [field: FieldOffset(6)]
- private readonly ushort _d;
- #endregion Fields
- #region Constructors
- [SuppressMessage("ReSharper", "UnusedMember.Local")]
- private Quad(BinaryReader br)
- {
- _a = br.ReadUInt16();
- _b = br.ReadUInt16();
- _c = br.ReadUInt16();
- _d = br.ReadUInt16();
- Vta = UV.CreateInstance(br);
- TexUnk = br.ReadUInt16();
- Vtb = UV.CreateInstance(br);
- U = br.ReadUInt16();
- Vtc = UV.CreateInstance(br);
- Vtd = UV.CreateInstance(br);
- }
- [SuppressMessage("ReSharper", "UnusedMember.Local")]
- private Quad()
- {
- }
- #endregion Constructors
- #region Properties
- public static byte Count => 6;
- public ushort A => (ushort)(_a & 0xFFF);
- public ushort B => (ushort)(_b & 0xFFF);
- public ushort C => (ushort)(_c & 0xFFF);
- public ushort D => (ushort)(_d & 0xFFF);
- public byte TextureIndex => (byte)((TexUnk >> 6) & 0b111);
- #endregion Properties
- #region Indexers
- public byte this[int i]
- {
- get
- {
- switch (i)
- {
- case 0:
- case 3:
- return 0;
- case 1:
- return 1;
- case 2:
- case 5:
- return 3;
- case 4:
- return 2;
- }
- throw new IndexOutOfRangeException($"{this} :: 0-5 are only valid values");
- }
- }
- #endregion Indexers
- #region Methods
- public static Quad CreateInstance(BinaryReader br) => Extended.ByteArrayToClass<Quad>(br.ReadBytes(ByteSize));
- public static IReadOnlyList<Quad> CreateInstances(BinaryReader br, ushort count) =>
- Enumerable.Range(0, count).Select(_ => CreateInstance(br)).ToList().AsReadOnly();
- public VertexPositionTexture[] GenerateVPT(List<VectorBoneGRP> vertices, Quaternion rotation,
- Vector3 translationPosition, TextureHandler preVarTex)
- {
- var tempVPT = new VertexPositionTexture[Count];
- VertexPositionTexture GetVPT(Quad quad, byte i)
- {
- Vector3 GetVertex(Quad refQuad, byte j)
- {
- return DatFile.TransformVertex(vertices[refQuad.GetIndex(j)], translationPosition, rotation);
- }
- // begin stupid hacks to fix Rinoa and Ward in remaster. might break when going above 3X upscale
- // if you choose to upscale more crop off dead bottom 128 pixels from SE's render.
- // also hack adjusts aspect ratio to handle the eye closing animation frames.
- // in remaster you just need to shift all the uv's to the right when eyes close.
- var (x, y) = preVarTex.ScaleFactor;
- float height;
- if (x > y)
- height = (float)(preVarTex.Height / Math.Floor(y));
- else
- height = (float)(preVarTex.Height / Math.Floor(x));
- var (newAR, oldAR) = ((float)preVarTex.Width / preVarTex.Height,
- preVarTex.ClassicWidth / height);
- var width = Math.Abs(newAR - oldAR) < float.Epsilon ? preVarTex.ClassicWidth : height * newAR;
- // end hacks
- return new VertexPositionTexture(GetVertex(quad, i),
- quad.GetUV(i).ToVector2(width, height));
- }
- tempVPT[0] = tempVPT[3] = GetVPT(this, this[0]);
- tempVPT[1] = GetVPT(this, this[1]);
- tempVPT[4] = GetVPT(this, this[4]);
- tempVPT[2] = tempVPT[5] = GetVPT(this, this[2]);
- return tempVPT;
- }
- public ushort GetIndex(int i)
- {
- switch (i)
- {
- case 0:
- return A;
- case 1:
- return B;
- case 2:
- return C;
- case 3:
- return D;
- }
- throw new IndexOutOfRangeException($"{this} :: 0-3 are only valid values");
- }
- public UV GetUV(int i)
- {
- switch (i)
- {
- case 0:
- return Vta;
- case 1:
- return Vtb;
- case 2:
- return Vtc;
- case 3:
- return Vtd;
- }
- throw new IndexOutOfRangeException($"{this} :: 0-3 are only valid values");
- }
- #endregion Methods
- }
- }
|