Texture_Base.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. namespace OpenVIII
  7. {
  8. public abstract class Texture_Base
  9. {
  10. #region Fields
  11. private const ushort blue_mask = 0x7C00;
  12. private const ushort green_mask = 0x3E0;
  13. /// <summary>
  14. /// all bits except the STP bit.
  15. /// </summary>
  16. private const ushort NotSTP_mask = 0x7FFF;
  17. private const ushort red_mask = 0x1F;
  18. /// <summary>
  19. /// Special Transparency Processing bit.
  20. /// </summary>
  21. /// <remarks>
  22. /// The STP (special transparency processing) bit has varying special meanings. Depending on
  23. /// the current transparency processing mode, it denotes if pixels of this color should be
  24. /// treated as transparent or not. If transparency processing is enabled, pixels of this
  25. /// color will be rendered transparent if the STP bit is set. A special case is black pixels
  26. /// (RGB 0,0,0), which by default are treated as transparent by the PlayStation unless the
  27. /// STP bit is set.
  28. /// </remarks>
  29. /// <see cref="http://www.psxdev.net/forum/viewtopic.php?t=109"/>
  30. /// <seealso cref="http://www.raphnet.net/electronique/psx_adaptor/Playstation.txt"/>
  31. private const ushort STP_mask = 0x8000;
  32. #endregion Fields
  33. //#region Enums
  34. //public enum TextureType : byte
  35. //{
  36. // TEX,
  37. // TIM,
  38. // Texture2D,
  39. // PNG
  40. //}
  41. //#endregion Enums
  42. #region Properties
  43. public abstract byte GetBytesPerPixel { get; }
  44. public abstract int GetClutCount { get; }
  45. public abstract int GetClutSize { get; }
  46. public abstract int GetColorsCountPerPalette { get; }
  47. public abstract int GetHeight { get; }
  48. public abstract int GetOrigX { get; }
  49. public abstract int GetOrigY { get; }
  50. public abstract int GetWidth { get; }
  51. #endregion Properties
  52. #region Methods
  53. /// <summary>
  54. /// Convert ABGR1555 color to RGBA 32bit color
  55. /// </summary>
  56. /// <remarks>
  57. /// FromPsColor from TEX does the same thing I think. Unsure which is better. I like the masks
  58. /// </remarks>
  59. public static Color ABGR1555toRGBA32bit(ushort pixel, bool ignoreAlpha = false)
  60. {
  61. // alert to let me know if we might need to check something.
  62. if (pixel == 0 && !ignoreAlpha) return Color.TransparentBlack;
  63. //https://docs.microsoft.com/en-us/windows/win32/directshow/working-with-16-bit-rgb
  64. // had the masks. though they were doing rgb but we are doing bgr so i switched red and blue.
  65. var ret = new Color
  66. {
  67. R = (byte)MathHelper.Clamp((pixel & red_mask) << 3, 0, 255),
  68. G = (byte)MathHelper.Clamp(((pixel & green_mask) >> 5) << 3, 0, 255),
  69. B = (byte)MathHelper.Clamp(((pixel & blue_mask) >> 10) << 3, 0, 255),
  70. A = 255
  71. };
  72. //if (GetSTP(pixel))
  73. //{
  74. // //ret.A = Transparency.GetAlpha;
  75. // Debug.WriteLine($"Special Transparency Processing bit set 16 bit color: {pixel & 0x7FFF}, 32 bit color: {ret}");
  76. // //Debug.Assert(false);
  77. //}
  78. //TDW has STP
  79. return ret;
  80. }
  81. /// <summary>
  82. /// Custom Convert 16BIT color to RGBA 32bit color
  83. /// </summary>
  84. /// <remarks>
  85. /// TEX file actually has it's own masks and shift varibles. if these are honor'ed could have
  86. /// the 16 bit color in any order. Though I think they are all the same. Unsure if these
  87. /// values also work for 32 bit. or 24 bit. (Needs testing and Tex needs to be adjusted
  88. /// to read those values, they are in the header)
  89. /// </remarks>
  90. public static Color Custom_16BITtoRGBA32bit(ushort pixel, ushort c_red_mask, ushort c_red_shift, ushort c_green_mask, ushort c_green_shift, ushort c_blue_mask, ushort c_blue_shift, bool ignoreAlpha = false)
  91. {
  92. // alert to let me know if we might need to check something.
  93. if (pixel == 0 && !ignoreAlpha) return Color.TransparentBlack;
  94. //https://docs.microsoft.com/en-us/windows/win32/directshow/working-with-16-bit-rgb
  95. // had the masks. though they were doing rgb but we are doing bgr so i switched red and blue.
  96. var ret = new Color
  97. {
  98. R = (byte)MathHelper.Clamp(((pixel & c_red_mask) >> c_red_shift) << 3, 0, 255),
  99. G = (byte)MathHelper.Clamp(((pixel & c_green_mask) >> c_green_shift) << 3, 0, 255),
  100. B = (byte)MathHelper.Clamp(((pixel & c_blue_mask) >> c_blue_shift) << 3, 0, 255),
  101. A = 255
  102. };
  103. return ret;
  104. }
  105. /// <summary>
  106. /// Get Special Transparency Processing bit.
  107. /// </summary>
  108. /// <param name="pixel">16 bit color</param>
  109. /// <returns>true if bit is set and not black, otherwise false.</returns>
  110. public static bool GetSTP(ushort pixel) =>
  111. // I set this to always return false for black. As it's transparency is handled in
  112. // conversion method.
  113. (pixel & NotSTP_mask) == 0 ? false : (pixel & STP_mask) != 0;
  114. public static Texture_Base Open(byte[] buffer, uint offset = 0)
  115. {
  116. switch (BitConverter.ToUInt32(buffer, (int)(0 + offset)))
  117. {
  118. case 0x1:
  119. case 0x2:
  120. return new TEX(buffer);
  121. case 0x10:
  122. return new TIM2(buffer, 0);
  123. default:
  124. return null;
  125. }
  126. }
  127. public abstract void ForceSetClutColors(ushort newNumOfColors);
  128. public abstract void ForceSetClutCount(ushort newClut);
  129. public abstract Color[] GetClutColors(ushort clut);
  130. public Texture2D GetTexture(Dictionary<int, Color> colorOverride, sbyte clut = -1)
  131. {
  132. if (colorOverride == null || colorOverride.Count == 0) return null;
  133. var colors = clut > 0 && clut < GetClutCount ? GetClutColors((ushort)clut) : new Color[GetColorsCountPerPalette];
  134. if (colors == null) return null;
  135. colorOverride.Where(x => x.Key < colors.Length).ForEach(x => colors[x.Key] = x.Value);
  136. return GetTexture((colors));
  137. }
  138. public abstract Texture2D GetTexture(Color[] colors);
  139. public abstract Texture2D GetTexture(ushort clut);
  140. public virtual Texture2D GetTexture() => GetTexture(GetClutColors(0));
  141. public abstract void Load(byte[] buffer, uint offset = 0);
  142. public abstract void Save(string path);
  143. public abstract void SaveCLUT(string path);
  144. public virtual void SavePNG(string path, short clut = -1)
  145. { }
  146. #endregion Methods
  147. //public static class Transparency
  148. //{
  149. // /// <summary>
  150. // /// <para>PSX Transparency Mode</para>
  151. // /// <para>
  152. // /// GPU first reads the pixel it wants to write to, and then calculates the color it will
  153. // /// write from the 2 pixels according to the semi-transparency mode selected
  154. // /// </para>
  155. // /// <para>OFF is 100% alpha</para>
  156. // /// <para>Mode 1 is 50%</para>
  157. // /// <para>Mode 2 is supposed to be existing pixel plus value of new one.</para>
  158. // /// <para>Mode 3 is supposed to be existing pixel minus value of new one.</para>
  159. // /// <para>Mode 4 is 25%</para>
  160. // /// <para>Unsure if the pixel is supposed to be 50% alpha before this</para>
  161. // /// </summary>
  162. // /// <see cref="http://www.raphnet.net/electronique/psx_adaptor/Playstation.txt"/>
  163. // //public static readonly byte[] Modes = { 0xFF 0x7F, 0xFF, 0x7F, 0x3F }; // if 100% before calculation
  164. // public static readonly byte[] Modes = { 0xFF, 0x3F, 0x7F, 0x7F, 0x1F }; // if 50% before calculation
  165. //If color is not black and STP bit on, possible semi-transparency.
  166. //http://www.raphnet.net/electronique/psx_adaptor/Playstation.txt
  167. //4 modes psx could use for Semi-Transparency. I donno which one ff8 uses or if it uses only one.
  168. //If Black is transparent when bit is off. And visible when bit is on.
  169. ///// <summary>
  170. ///// Ratio needed to convert 16 bit to 32 bit color
  171. ///// </summary>
  172. ///// <seealso cref="https://github.com/myst6re/vincent-tim/blob/master/PsColor.h"/>
  173. //public const double COEFF_COLOR = (double)255 / 31;
  174. ///// <summary>
  175. ///// converts 16 bit color to 32bit with alpha. alpha needs to be set true manually per pixel
  176. ///// unless you know the color value.
  177. ///// </summary>
  178. ///// <param name="color">16 bit color</param>
  179. ///// <param name="useAlpha">area is Visible or not</param>
  180. ///// <returns>byte[4] red green blue alpha, i think</returns>
  181. ///// <see cref="https://github.com/myst6re/vincent-tim/blob/master/PsColor.cpp"/>
  182. //public static Color FromPsColor(ushort color, bool useAlpha = false) => new Color((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));
  183. }
  184. }