mirror of
https://github.com/crskycode/GARbro.git
synced 2026-07-08 01:30:18 +08:00
(Legacy): added formats, mostly PC-98.
This commit is contained in:
221
Legacy/AyPio/PdtBitmap.cs
Normal file
221
Legacy/AyPio/PdtBitmap.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
//! \file PdtBitmap.cs
|
||||
//! \date 2023 Oct 19
|
||||
//! \brief UK2 engine compressed bitmap.
|
||||
//
|
||||
// Copyright (C) 2023 by morkt
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using GameRes.Utility;
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
// [971031][AyPio] Satyr 95
|
||||
|
||||
namespace GameRes.Formats.AyPio
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class PdtBmpFormat : ImageFormat
|
||||
{
|
||||
public override string Tag => "PDT/BMP";
|
||||
public override string Description => "UK2 engine compressed bitmap";
|
||||
public override uint Signature => 0x544450; // 'PDT'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (8);
|
||||
if (header.ToInt32 (4) != 0x118)
|
||||
return null;
|
||||
return new ImageMetaData { Width = 640, Height = 480, BPP = 32 };
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var decoder = new PdtBmpDecoder (file, info);
|
||||
return decoder.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("PdtFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class PdtBmpDecoder
|
||||
{
|
||||
IBinaryStream m_input;
|
||||
ImageMetaData m_info;
|
||||
|
||||
public PdtBmpDecoder (IBinaryStream input, ImageMetaData info)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = info;
|
||||
}
|
||||
|
||||
int m_unpacked_size;
|
||||
int m_packed_size;
|
||||
|
||||
public ImageData Unpack ()
|
||||
{
|
||||
long offset = 0;
|
||||
var bitmap = UnpackBitmap (offset);
|
||||
m_info.Width = (uint)bitmap.PixelWidth;
|
||||
m_info.Height = (uint)bitmap.PixelHeight;
|
||||
m_info.BPP = bitmap.Format.BitsPerPixel;
|
||||
offset += m_packed_size;
|
||||
var signature = m_input.ReadBytes (4);
|
||||
if (signature.Length != 4 || !signature.AsciiEqual ("PDT\0"))
|
||||
return new ImageData (bitmap, m_info);
|
||||
var alpha = UnpackBitmap (offset);
|
||||
if (alpha.Format != PixelFormats.Gray8)
|
||||
alpha = new FormatConvertedBitmap (alpha, PixelFormats.Gray8, null, 0);
|
||||
if (m_info.BPP != 32)
|
||||
bitmap = new FormatConvertedBitmap (bitmap, PixelFormats.Bgr32, null, 0);
|
||||
|
||||
int stride = m_info.iWidth * 4;
|
||||
var pixels = new byte[stride * m_info.iHeight];
|
||||
bitmap.CopyPixels (pixels, stride, 0);
|
||||
var rect = new Int32Rect (0, 0, Math.Min (m_info.iWidth, alpha.PixelWidth),
|
||||
Math.Min (m_info.iHeight, alpha.PixelHeight));
|
||||
var a = new byte[m_info.iWidth * m_info.iHeight];
|
||||
alpha.CopyPixels (rect, a, m_info.iWidth, 0);
|
||||
int src = 0;
|
||||
for (int dst = 3; dst < pixels.Length; dst += 4)
|
||||
{
|
||||
pixels[dst] = a[src++];
|
||||
}
|
||||
return ImageData.Create (m_info, PixelFormats.Bgra32, null, pixels, stride);
|
||||
}
|
||||
|
||||
byte[] m_bits;
|
||||
byte[] m_output;
|
||||
|
||||
BitmapSource UnpackBitmap (long offset)
|
||||
{
|
||||
m_input.Position = offset+8;
|
||||
m_unpacked_size = m_input.ReadInt32();
|
||||
m_packed_size = m_input.ReadInt32();
|
||||
long data_offset = m_input.ReadUInt32() + offset;
|
||||
long bits_offset = m_input.ReadUInt32() + offset;
|
||||
string name = m_input.ReadCString (0x100);
|
||||
|
||||
if (null == m_output || m_unpacked_size > m_output.Length)
|
||||
m_output = new byte[m_unpacked_size];
|
||||
int bits_length = (int)(data_offset - bits_offset);
|
||||
if (null == m_bits || bits_length > m_bits.Length)
|
||||
m_bits = new byte[bits_length+4];
|
||||
|
||||
m_input.Position = bits_offset;
|
||||
m_input.Read (m_bits, 0, bits_length);
|
||||
|
||||
m_input.Position = data_offset;
|
||||
UnpackBits();
|
||||
|
||||
using (var bmp_input = new BinMemoryStream (m_output, name))
|
||||
{
|
||||
var decoder = new BmpBitmapDecoder (bmp_input, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||
return decoder.Frames[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void UnpackBits ()
|
||||
{
|
||||
InitBitReader();
|
||||
int dst = 0;
|
||||
byte last_byte = 0;
|
||||
while (dst < m_unpacked_size)
|
||||
{
|
||||
int ctl = 0;
|
||||
while (GetNextBit() != 0)
|
||||
++ctl;
|
||||
switch (ctl)
|
||||
{
|
||||
case 0:
|
||||
last_byte = m_output[dst++] = m_input.ReadUInt8();
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
int off = GetInteger();
|
||||
int count = GetInteger();
|
||||
Binary.CopyOverlapped (m_output, dst - off, dst, count);
|
||||
dst += count;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
int count = GetInteger();
|
||||
int step = GetInteger();
|
||||
int pos = 0;
|
||||
for (int i = 0; i < step; i += count)
|
||||
{
|
||||
Binary.CopyOverlapped (m_output, dst - count, dst + pos, count);
|
||||
pos += count * count;
|
||||
}
|
||||
dst += count * step;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
m_output[dst++] = last_byte;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int GetInteger ()
|
||||
{
|
||||
int i = 0;
|
||||
while (GetNextBit() != 0)
|
||||
++i;
|
||||
int n = 0;
|
||||
for (int j = i; j > 0; --j)
|
||||
{
|
||||
n = n << 1 | GetNextBit();
|
||||
}
|
||||
return n + (1 << i);
|
||||
}
|
||||
|
||||
uint m_current_bits;
|
||||
int m_bit_count;
|
||||
int m_bit_pos;
|
||||
|
||||
void InitBitReader ()
|
||||
{
|
||||
m_bit_pos = 0;
|
||||
m_bit_count = 0;
|
||||
}
|
||||
|
||||
byte GetNextBit ()
|
||||
{
|
||||
if (0 == m_bit_count--)
|
||||
{
|
||||
m_current_bits = m_bits.ToUInt32 (m_bit_pos);
|
||||
m_bit_pos += 4;
|
||||
m_bit_count = 31;
|
||||
}
|
||||
uint bit = m_current_bits >> 31;
|
||||
m_current_bits <<= 1;
|
||||
return (byte)bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user