/// <summary> /// Output 32 bit Color data for image. /// </summary> /// <param name="br">Binary reader pointing to memory stream of data.</param> /// <param name="palette">Color[] palette</param> /// <param name="bIgnoreSize"> /// If true skip size check useful for files with more than just Tim /// </param> /// <returns>Color[]</returns> /// <remarks> /// This allows null palette but it doesn't seem to handle the palette being null /// </remarks> protected unsafe TextureBuffer CreateImageBuffer(BinaryReader br, IColorData[] palette = null) { br.BaseStream.Seek(TextureDataPointer, SeekOrigin.Begin); var buffer = new TextureBuffer(Texture.Width, Texture.Height); //ARGB if (Assert((buffer.Length / BPP) <= br.BaseStream.Length - br.BaseStream.Position)) //make sure the buffer is large enough { return(null); } if (BPP == 8) { for (var i = 0; i < buffer.Length; i++) { var colorKey = br.ReadByte(); if (colorKey < Texture.NumOfColors) { buffer[i] = palette[colorKey]; //color key } //else // buffer[i] = Color.TransparentBlack; // trying something out of ordinary. } } else if (BPP == 4) { for (var i = 0; i < buffer.Length; i++) { var colorKey = br.ReadByte(); buffer[i] = palette[colorKey & 0xf]; buffer[++i] = palette[colorKey >> 4]; } } else if (BPP == 16) //copied from overture { for (var i = 0; i < buffer.Length && br.BaseStream.Position + 2 < br.BaseStream.Length; i++) { buffer[i] = new ColorABGR1555(br.ReadUInt16(), IgnoreAlpha); } } else if (BPP == 24) //could be wrong. // assuming it is BGR { for (var i = 0; i < buffer.Length && br.BaseStream.Position + 2 < br.BaseStream.Length; i++) { var pixel = br.ReadBytes(3); fixed(byte *p = pixel) { buffer[i] = *(ColorBGR888 *)p; } } } else { throw new Exception($"TIM_v2::CreateImageBuffer::TIM unsupported bits per pixel = {BPP}"); } //Then in bs debug where ReadTexture store for all cluts //data and then create Texture2D from there. (array of e.g. 15 texture2D) return(buffer); }
/// <summary> /// Get clut color palette /// </summary> /// <param name="br">Binary reader pointing to memory stream of data.</param> /// <param name="clut">Active clut data</param> /// <returns>Color[]</returns> protected IColorData[] GetClutColors(BinaryReader br, ushort clut) { if (clut >= Texture.NumOfCluts) { throw new Exception($"TIM_v2::GetClutColors::given clut {clut} is >= texture number of cluts {Texture.NumOfCluts}"); } if (!CLP) { throw new Exception($"TIM that has {BPP} bpp mode and has no clut data!"); } var colorPixels = new IColorData[Texture.NumOfColors]; br.BaseStream.Seek(TIMOffset + 20 + (Texture.NumOfColors * 2 * clut), SeekOrigin.Begin); for (var i = 0; i < Texture.NumOfColors; i++) { colorPixels[i] = new ColorABGR1555(br.ReadUInt16(), IgnoreAlpha); } return(colorPixels); }
/// <summary> /// Get Texture2D converted to 32bit color /// </summary> /// <param name="forcePalette">Desired Palette, see texture.NumOfPalettes. -1 is default.</param> /// <param name="colors">Override colors of palette; Array size must match texture.NumOfColorsPerPalette</param> /// <returns>32bit Texture2D</returns> /// <remarks> /// Some palettes are 256 but the game only uses 16 colors might need to make the restriction /// more lax and allow any size array and only throw errors if the color key is greater than /// size of array. Or we could treat any of those bad matches as transparent. /// </remarks> public Texture2D GetTexture(IColorData[] colors) { if (Memory.Graphics.GraphicsDevice == null) { return(null); } if (_texture.PaletteFlag != 0) { if (colors == null) { throw new ArgumentNullException(nameof(colors)); } //if (colors != null && colors.Length != texture.NumOfColors) //{ // //if (colors.Length > texture.NumOfColors) //truncate colors to the correct amount. in some // // colors = colors.Take(texture.NumOfColors).ToArray(); // //else // might need to expand the array the other way if we get more mismatches. // //Array.Resize(ref colors,texture.NumOfColors); // //throw new Exception($" custom colors parameter set but array size to match palette size: {texture.NumOfColors}"); //} MemoryStream ms; using (var br = new BinaryReader(ms = new MemoryStream(_buffer))) { ms.Seek(TextureLocator, SeekOrigin.Begin); var convertBuffer = new TextureBuffer(_texture.Width, _texture.Height); for (var i = 0; i < convertBuffer.Length && ms.Position < ms.Length; i++) { var colorKey = br.ReadByte(); if (colorKey > colors.Length) { continue; } convertBuffer[i] = colors[colorKey]; } return(convertBuffer.GetTexture()); } } if (_texture.BytesPerPixel == 2) { MemoryStream ms; using (var br = new BinaryReader(ms = new MemoryStream(_buffer))) { ms.Seek(TextureLocator, SeekOrigin.Begin); var convertBuffer = new TextureBuffer(_texture.Width, _texture.Height); for (var i = 0; ms.Position + 2 < ms.Length; i++) { convertBuffer[i] = new ColorABGR1555(br.ReadUInt16()); } return(convertBuffer.GetTexture()); } } if (_texture.BytesPerPixel != 3) { return(null); } { // not tested but vincent tim had support for it so i guess it's possible RGB or BGR MemoryStream ms; using (var br = new BinaryReader(ms = new MemoryStream(_buffer))) { ms.Seek(TextureLocator, SeekOrigin.Begin); var convertBuffer = new TextureBuffer(_texture.Width, _texture.Height); for (var i = 0; ms.Position + 3 < ms.Length; i++) { //RGB or BGR so might need to reorder things to RGB IColorData color = new ColorRGBA8888(b: br.ReadByte(), g: br.ReadByte(), r: br.ReadByte(), a: 0xFF); convertBuffer[i] = color; } return(convertBuffer.GetTexture()); } } }