| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- using Microsoft.Xna.Framework.Graphics;
- using System;
- using System.IO;
- namespace FF8
- {
- /// <summary>
- /// TEX file handler class. TEX files are packages of textures and Palettes.
- /// </summary>
- /// <remarks>
- /// I borrowed this from my Rinoa's toolset, but modified to aim for buffer rather than file-work
- /// </remarks>
- /// <see cref="https://github.com/MaKiPL/FF8-Rinoa-s-Toolset/blob/master/SerahToolkit_SharpGL/FF8_Core/TEX.cs"/>
- /// <seealso cref="https://github.com/myst6re/vincent-tim/blob/master/TexFile.cpp"/>
- internal class TEX
- {
- #region Fields
- /// <summary>
- /// Ratio needed to convert 16 bit to 32 bit color
- /// </summary>
- /// <seealso cref="https://github.com/myst6re/vincent-tim/blob/master/PsColor.h"/>
- public const double COEFF_COLOR = (double)255 / 31;
- /// <summary>
- /// Raw data of TEX file
- /// </summary>
- private byte[] buffer;
- private Texture texture;
- #endregion Fields
- #region Constructors
- public TEX(byte[] buffer)
- {
- texture = new Texture();
- this.buffer = buffer;
- ReadParameters();
- }
- #endregion Constructors
- #region Properties
- /// <summary>
- /// Contains header info and Palette data of TEX file.
- /// </summary>
- public Texture TextureData => texture; //added to get texturedata outside of class.
- /// <summary>
- /// start of texture section
- /// </summary>
- private int TextureLocator => Headersize + PaletteSectionSize;
- /// <summary>
- /// size of palette section
- /// </summary>
- private int PaletteSectionSize => (int)(texture.PaletteSize * 4);
- /// <summary>
- /// size of header section
- /// </summary>
- private int Headersize => texture.Version <= 1 ? 0xEC : 0xF0;
- #endregion Properties
- #region Methods
- /// <summary>
- /// Read header data from TEX file.
- /// </summary>
- /// <see cref="https://github.com/MaKiPL/FF8-Rinoa-s-Toolset/blob/master/SerahToolkit_SharpGL/FF8_Core/TEX.cs"/>
- /// <seealso cref="https://github.com/myst6re/vincent-tim/blob/master/TexFile.h"/>
- private void ReadParameters()
- {
- texture.Version = BitConverter.ToUInt32(buffer, 0x00);
- texture.Width = BitConverter.ToUInt32(buffer, 0x3C);
- texture.Height = BitConverter.ToUInt32(buffer, 0x40);
- texture.bytesPerPixel = buffer[0x68];
- texture.NumOfPalettes = buffer[0x30];
- texture.NumOfColorsPerPalette = BitConverter.ToUInt32(buffer, 0x34);
- texture.bitDepth = BitConverter.ToUInt32(buffer, 0x38);
- texture.PaletteFlag = buffer[0x4C];
- texture.PaletteSize = BitConverter.ToUInt32(buffer, 0x58);
- if (texture.PaletteFlag != 0)
- {
- texture.paletteData = new byte[PaletteSectionSize];
- Buffer.BlockCopy(buffer, 0xF0, texture.paletteData, 0, PaletteSectionSize);
- }
- }
- /// <summary>
- /// Get Texture2D converted to 32bit color
- /// </summary>
- /// <param name="forcePalette">Desired Palette, see texture.NumOfPalettes. -1 is default.</param>
- /// <returns>32bit Texture2D</returns>
- public Texture2D GetTexture(int forcePalette = -1)
- {
- uint ImageSizeBytes = texture.Width * texture.Height * 4;
- if (texture.PaletteFlag != 0)
- {
- if (forcePalette >= texture.NumOfPalettes) //prevents exception for forcing a palette that doesn't exist.
- return null;
- int localTextureLocator = TextureLocator;
- Color[] colors = new Color[texture.paletteData.Length / 4];
- int k = 0;
- for (int i = 0; i < texture.paletteData.Length; i += 4)
- {
- colors[k].Red = texture.paletteData[i];
- colors[k].Green = texture.paletteData[i + 1];
- colors[k].Blue = texture.paletteData[i + 2];
- colors[k].Alpha = texture.paletteData[i + 3];
- k++;
- }
- Texture2D bmp = new Texture2D(Memory.graphics.GraphicsDevice, (int)texture.Width, (int)texture.Height, false, SurfaceFormat.Color);
- byte[] convertBuffer = new byte[ImageSizeBytes];
- for (int i = 0; i < convertBuffer.Length; i += 4)
- {
- byte colorkey = buffer[localTextureLocator++];
- convertBuffer[i] = colors[forcePalette == -1 ? colorkey : (forcePalette * texture.NumOfColorsPerPalette) + colorkey].Blue;
- convertBuffer[i + 1] = colors[forcePalette == -1 ? colorkey : (forcePalette * texture.NumOfColorsPerPalette) + colorkey].Green;
- convertBuffer[i + 2] = colors[forcePalette == -1 ? colorkey : (forcePalette * texture.NumOfColorsPerPalette) + colorkey].Red;
- convertBuffer[i + 3] = colors[forcePalette == -1 ? colorkey : (forcePalette * texture.NumOfColorsPerPalette) + colorkey].Alpha;
- }
- bmp.SetData(convertBuffer);
- return bmp;
- }
- else
- {
- if (texture.bytesPerPixel == 2)
- {
- //working code
- Texture2D bmp = new Texture2D(Memory.graphics.GraphicsDevice, (int)texture.Width, (int)texture.Height, false, SurfaceFormat.Color);
- using (MemoryStream os = new MemoryStream((int)(ImageSizeBytes)))
- using (BinaryWriter bw = new BinaryWriter(os))
- {
- using (MemoryStream ms = new MemoryStream(buffer))
- using (BinaryReader br = new BinaryReader(ms))
- {
- ms.Seek(TextureLocator, SeekOrigin.Begin);
- while (ms.Position < ms.Length)
- bw.Write(FromPsColor(br.ReadUInt16()), 0, 4);
- }
- bmp.SetData(os.GetBuffer(), 0, (int)os.Length);
- }
- return bmp;
- }
- if (texture.bytesPerPixel == 3)
- {
- // not tested but vincent tim had support for it so i guess it's possible RGB or
- // BGR is a thing.
- Texture2D bmp = new Texture2D(Memory.graphics.GraphicsDevice, (int)texture.Width, (int)texture.Height, false, SurfaceFormat.Color);
- using (MemoryStream os = new MemoryStream((int)(ImageSizeBytes)))
- using (BinaryWriter bw = new BinaryWriter(os))
- {
- using (MemoryStream ms = new MemoryStream(buffer))
- using (BinaryReader br = new BinaryReader(ms))
- {
- ms.Seek(TextureLocator, SeekOrigin.Begin);
- while (ms.Position < ms.Length)
- {
- //RGB or BGR so might need to reorder things to RGB
- bw.Write(br.ReadBytes(3), 0, 3);
- //ALPHA
- bw.Write((byte)0xFF);
- }
- }
- bmp.SetData(os.GetBuffer(), 0, (int)os.Length);
- }
- return bmp;
- }
- return null;
- }
- }
- /// <summary>
- /// converts 16 bit color to 32bit with alpha. alpha needs to be set true manually per pixel
- /// unless you know the color value.
- /// </summary>
- /// <param name="color">16 bit color</param>
- /// <param name="useAlpha">area is visable or not</param>
- /// <returns>byte[4] red green blue alpha, i think</returns>
- /// <see cref="https://github.com/myst6re/vincent-tim/blob/master/PsColor.cpp"/>
- public static byte[] FromPsColor(ushort color, bool useAlpha = false) => new byte[] { (byte)Math.Round((color & 31) * COEFF_COLOR), (byte)Math.Round(((color >> 5) & 31) * COEFF_COLOR), (byte)Math.Round(((color >> 10) & 31) * COEFF_COLOR), (byte)(color == 0 && useAlpha ? 0 : 255) };
- #endregion Methods
- #region Structs
- /// <summary>
- /// Contains Header info and Palette data of TEX file.
- /// </summary>
- /// <see cref="https://github.com/MaKiPL/FF8-Rinoa-s-Toolset/blob/master/SerahToolkit_SharpGL/FF8_Core/TEX.cs"/>
- /// <seealso cref="https://github.com/myst6re/vincent-tim/blob/master/TexFile.h"/>
- public struct Texture
- {
- #region Fields
- /// <summary>
- /// 0x68
- /// </summary>
- public byte bytesPerPixel;
- /// <summary>
- /// 0x40
- /// </summary>
- public uint Height;
- /// <summary>
- /// 0x30
- /// </summary>
- public byte NumOfPalettes;
- /// <summary>
- /// 0xF0 for ff8;0xEC for ff7; size = PaletteSize * 4;
- /// </summary>
- public byte[] paletteData;
- /// <summary>
- /// 0x4C
- /// </summary>
- public byte PaletteFlag;
- /// <summary>
- /// 0x58
- /// </summary>
- public uint PaletteSize;
- /// <summary>
- /// 0x3C
- /// </summary>
- public uint Width;
- /// <summary>
- /// 0x38
- /// </summary>
- public uint bitDepth;
- /// <summary>
- /// 0x34
- /// </summary>
- public uint NumOfColorsPerPalette;
- /// <summary>
- /// 0x00; 1=FF7 | 2=FF8
- /// </summary>
- public uint Version;
- #endregion Fields
- }
- private struct Color
- {
- #region Fields
- public byte Alpha;
- public byte Blue;
- public byte Green;
- public byte Red;
- #endregion Fields
- }
- #endregion Structs
- }
- }
|