AssetStudio/Unity Studio/Unity Studio Classes/Texture2DConverter.cs
Perfare c8393e165f Separate code
rename
2018-03-01 20:01:25 +08:00

541 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace Unity_Studio
{
partial class Texture2D
{
[DllImport("PVRTexLibWrapper.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool DecompressPVR(byte[] buffer, IntPtr bmp, int len);
[DllImport("TextureConverterWrapper.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool Ponvert(byte[] buffer, IntPtr bmp, int nWidth, int nHeight, int len, int type, int bmpsize, bool fixAlpha);
[DllImport("crunch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool DecompressCRN(byte[] pSrc_file_data, int src_file_size, out IntPtr uncompressedData, out int uncompressedSize);
[DllImport("crunchunity.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool DecompressUnityCRN(byte[] pSrc_file_data, int src_file_size, out IntPtr uncompressedData, out int uncompressedSize);
[DllImport("texgenpack.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void texgenpackdecode(int texturetype, byte[] texturedata, int width, int height, IntPtr bmp, bool fixAlpha);
public byte[] ConvertToContainer()
{
if (image_data == null || image_data.Length == 0)
return null;
switch (m_TextureFormat)
{
case TextureFormat.Alpha8:
case TextureFormat.ARGB4444:
case TextureFormat.RGB24:
case TextureFormat.RGBA32:
case TextureFormat.ARGB32:
case TextureFormat.RGB565:
case TextureFormat.R16:
case TextureFormat.DXT1:
case TextureFormat.DXT5:
case TextureFormat.RGBA4444:
case TextureFormat.BGRA32:
case TextureFormat.RG16:
case TextureFormat.R8:
return ConvertToDDS();
case TextureFormat.YUY2:
case TextureFormat.PVRTC_RGB2:
case TextureFormat.PVRTC_RGBA2:
case TextureFormat.PVRTC_RGB4:
case TextureFormat.PVRTC_RGBA4:
case TextureFormat.ETC_RGB4:
case TextureFormat.ETC2_RGB:
case TextureFormat.ETC2_RGBA1:
case TextureFormat.ETC2_RGBA8:
case TextureFormat.ASTC_RGB_4x4:
case TextureFormat.ASTC_RGB_5x5:
case TextureFormat.ASTC_RGB_6x6:
case TextureFormat.ASTC_RGB_8x8:
case TextureFormat.ASTC_RGB_10x10:
case TextureFormat.ASTC_RGB_12x12:
case TextureFormat.ASTC_RGBA_4x4:
case TextureFormat.ASTC_RGBA_5x5:
case TextureFormat.ASTC_RGBA_6x6:
case TextureFormat.ASTC_RGBA_8x8:
case TextureFormat.ASTC_RGBA_10x10:
case TextureFormat.ASTC_RGBA_12x12:
case TextureFormat.ETC_RGB4_3DS:
case TextureFormat.ETC_RGBA8_3DS:
return ConvertToPVR();
case TextureFormat.RHalf:
case TextureFormat.RGHalf:
case TextureFormat.RGBAHalf:
case TextureFormat.RFloat:
case TextureFormat.RGFloat:
case TextureFormat.RGBAFloat:
case TextureFormat.BC4:
case TextureFormat.BC5:
case TextureFormat.BC6H:
case TextureFormat.BC7:
case TextureFormat.ATC_RGB4:
case TextureFormat.ATC_RGBA8:
case TextureFormat.EAC_R:
case TextureFormat.EAC_R_SIGNED:
case TextureFormat.EAC_RG:
case TextureFormat.EAC_RG_SIGNED:
return ConvertToKTX();
default:
return image_data;
}
}
private byte[] ConvertToDDS()
{
var imageBuffer = new byte[128 + image_data_size];
dwMagic.CopyTo(imageBuffer, 0);
BitConverter.GetBytes(dwFlags).CopyTo(imageBuffer, 8);
BitConverter.GetBytes(m_Height).CopyTo(imageBuffer, 12);
BitConverter.GetBytes(m_Width).CopyTo(imageBuffer, 16);
BitConverter.GetBytes(dwPitchOrLinearSize).CopyTo(imageBuffer, 20);
BitConverter.GetBytes(dwMipMapCount).CopyTo(imageBuffer, 28);
BitConverter.GetBytes(dwSize).CopyTo(imageBuffer, 76);
BitConverter.GetBytes(dwFlags2).CopyTo(imageBuffer, 80);
BitConverter.GetBytes(dwFourCC).CopyTo(imageBuffer, 84);
BitConverter.GetBytes(dwRGBBitCount).CopyTo(imageBuffer, 88);
BitConverter.GetBytes(dwRBitMask).CopyTo(imageBuffer, 92);
BitConverter.GetBytes(dwGBitMask).CopyTo(imageBuffer, 96);
BitConverter.GetBytes(dwBBitMask).CopyTo(imageBuffer, 100);
BitConverter.GetBytes(dwABitMask).CopyTo(imageBuffer, 104);
BitConverter.GetBytes(dwCaps).CopyTo(imageBuffer, 108);
BitConverter.GetBytes(dwCaps2).CopyTo(imageBuffer, 112);
image_data.CopyTo(imageBuffer, 128);
return imageBuffer;
}
private byte[] ConvertToPVR()
{
var mstream = new MemoryStream();
using (var writer = new BinaryWriter(mstream))
{
writer.Write(pvrVersion);
writer.Write(pvrFlags);
writer.Write(pvrPixelFormat);
writer.Write(pvrColourSpace);
writer.Write(pvrChannelType);
writer.Write(m_Height);
writer.Write(m_Width);
writer.Write(pvrDepth);
writer.Write(pvrNumSurfaces);
writer.Write(pvrNumFaces);
writer.Write(dwMipMapCount);
writer.Write(pvrMetaDataSize);
writer.Write(image_data);
return mstream.ToArray();
}
}
private byte[] ConvertToKTX()
{
var mstream = new MemoryStream();
using (var writer = new BinaryWriter(mstream))
{
writer.Write(KTXHeader.IDENTIFIER);
writer.Write(KTXHeader.ENDIANESS_LE);
writer.Write(glType);
writer.Write(glTypeSize);
writer.Write(glFormat);
writer.Write(glInternalFormat);
writer.Write(glBaseInternalFormat);
writer.Write(m_Width);
writer.Write(m_Height);
writer.Write(pixelDepth);
writer.Write(numberOfArrayElements);
writer.Write(numberOfFaces);
writer.Write(numberOfMipmapLevels);
writer.Write(bytesOfKeyValueData);
writer.Write(image_data_size);
writer.Write(image_data);
return mstream.ToArray();
}
}
public Bitmap ConvertToBitmap(bool flip)
{
if (image_data == null || image_data.Length == 0)
return null;
Bitmap bitmap;
switch (m_TextureFormat)
{
case TextureFormat.Alpha8:
case TextureFormat.ARGB4444:
case TextureFormat.RGB24:
case TextureFormat.RGBA32:
case TextureFormat.ARGB32:
case TextureFormat.R16:
case TextureFormat.RGBA4444:
case TextureFormat.BGRA32:
case TextureFormat.RG16:
case TextureFormat.R8:
bitmap = BGRA32ToBitmap();
break;
case TextureFormat.RGB565:
bitmap = RGB565ToBitmap();
break;
case TextureFormat.YUY2:
case TextureFormat.PVRTC_RGB2:
case TextureFormat.PVRTC_RGBA2:
case TextureFormat.PVRTC_RGB4:
case TextureFormat.PVRTC_RGBA4:
case TextureFormat.ETC_RGB4:
case TextureFormat.ETC2_RGB:
case TextureFormat.ETC2_RGBA1:
case TextureFormat.ETC2_RGBA8:
case TextureFormat.ASTC_RGB_4x4:
case TextureFormat.ASTC_RGB_5x5:
case TextureFormat.ASTC_RGB_6x6:
case TextureFormat.ASTC_RGB_8x8:
case TextureFormat.ASTC_RGB_10x10:
case TextureFormat.ASTC_RGB_12x12:
case TextureFormat.ASTC_RGBA_4x4:
case TextureFormat.ASTC_RGBA_5x5:
case TextureFormat.ASTC_RGBA_6x6:
case TextureFormat.ASTC_RGBA_8x8:
case TextureFormat.ASTC_RGBA_10x10:
case TextureFormat.ASTC_RGBA_12x12:
case TextureFormat.ETC_RGB4_3DS:
case TextureFormat.ETC_RGBA8_3DS:
bitmap = PVRToBitmap(ConvertToPVR());
break;
case TextureFormat.DXT1:
case TextureFormat.DXT5:
case TextureFormat.RHalf:
case TextureFormat.RGHalf:
case TextureFormat.RGBAHalf:
case TextureFormat.RFloat:
case TextureFormat.RGFloat:
case TextureFormat.RGBAFloat:
case TextureFormat.RGB9e5Float:
case TextureFormat.ATC_RGB4:
case TextureFormat.ATC_RGBA8:
case TextureFormat.EAC_R:
case TextureFormat.EAC_R_SIGNED:
case TextureFormat.EAC_RG:
case TextureFormat.EAC_RG_SIGNED:
bitmap = TextureConverter();
break;
case TextureFormat.BC4:
case TextureFormat.BC5:
case TextureFormat.BC6H:
case TextureFormat.BC7:
bitmap = Texgenpack();
break;
case TextureFormat.DXT1Crunched:
case TextureFormat.DXT5Crunched:
DecompressCRN();
bitmap = TextureConverter();
break;
case TextureFormat.ETC_RGB4Crunched:
case TextureFormat.ETC2_RGBA8Crunched:
DecompressCRN();
bitmap = PVRToBitmap(ConvertToPVR());
break;
default:
return null;
}
if (bitmap != null && flip)
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
return bitmap;
}
private Bitmap BGRA32ToBitmap()
{
var hObject = GCHandle.Alloc(image_data, GCHandleType.Pinned);
var pObject = hObject.AddrOfPinnedObject();
var bitmap = new Bitmap(m_Width, m_Height, m_Width * 4, PixelFormat.Format32bppArgb, pObject);
hObject.Free();
return bitmap;
}
private Bitmap RGB565ToBitmap()
{
//stride = m_Width * 2 + m_Width * 2 % 4
//所以m_Width * 2不为4的倍数时需要在每行补上相应的像素
byte[] buff;
var padding = m_Width * 2 % 4;
var stride = m_Width * 2 + padding;
if (padding != 0)
{
buff = new byte[stride * m_Height];
for (int i = 0; i < m_Height; i++)
{
Array.Copy(image_data, i * m_Width * 2, buff, i * stride, m_Width * 2);
}
}
else
{
buff = image_data;
}
var hObject = GCHandle.Alloc(buff, GCHandleType.Pinned);
var pObject = hObject.AddrOfPinnedObject();
var bitmap = new Bitmap(m_Width, m_Height, stride, PixelFormat.Format16bppRgb565, pObject);
hObject.Free();
return bitmap;
}
private Bitmap PVRToBitmap(byte[] pvrdata)
{
var bitmap = new Bitmap(m_Width, m_Height);
var rect = new Rectangle(0, 0, m_Width, m_Height);
var bmd = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
var len = Math.Abs(bmd.Stride) * bmd.Height;
if (!DecompressPVR(pvrdata, bmd.Scan0, len))
{
bitmap.UnlockBits(bmd);
bitmap.Dispose();
return null;
}
bitmap.UnlockBits(bmd);
return bitmap;
}
private Bitmap TextureConverter()
{
var bitmap = new Bitmap(m_Width, m_Height);
var rect = new Rectangle(0, 0, m_Width, m_Height);
var bmd = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
var len = Math.Abs(bmd.Stride) * bmd.Height;
var fixAlpha = glBaseInternalFormat == KTXHeader.GL_RED || glBaseInternalFormat == KTXHeader.GL_RG;
if (!Ponvert(image_data, bmd.Scan0, m_Width, m_Height, image_data_size, (int)q_format, len, fixAlpha))
{
bitmap.UnlockBits(bmd);
bitmap.Dispose();
return null;
}
bitmap.UnlockBits(bmd);
return bitmap;
}
private void DecompressCRN()
{
IntPtr uncompressedData;
int uncompressedSize;
bool result;
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)) //2017.3 and up
{
result = DecompressUnityCRN(image_data, image_data_size, out uncompressedData, out uncompressedSize);
}
else
{
result = DecompressCRN(image_data, image_data_size, out uncompressedData, out uncompressedSize);
}
if (result)
{
var uncompressedBytes = new byte[uncompressedSize];
Marshal.Copy(uncompressedData, uncompressedBytes, 0, uncompressedSize);
Marshal.FreeHGlobal(uncompressedData);
image_data = uncompressedBytes;
image_data_size = uncompressedSize;
}
}
private Bitmap Texgenpack()
{
var bitmap = new Bitmap(m_Width, m_Height);
var rect = new Rectangle(0, 0, m_Width, m_Height);
var bmd = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
var fixAlpha = glBaseInternalFormat == KTXHeader.GL_RED || glBaseInternalFormat == KTXHeader.GL_RG;
texgenpackdecode((int)texturetype, image_data, m_Width, m_Height, bmd.Scan0, fixAlpha);
bitmap.UnlockBits(bmd);
return bitmap;
}
}
public static class KTXHeader
{
public static byte[] IDENTIFIER = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
public static byte[] ENDIANESS_LE = { 1, 2, 3, 4 };
public static byte[] ENDIANESS_BE = { 4, 3, 2, 1 };
// constants for glInternalFormat
public static int GL_ETC1_RGB8_OES = 0x8D64;
public static int GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
public static int GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01;
public static int GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
public static int GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;
public static int GL_ATC_RGB_AMD = 0x8C92;
public static int GL_ATC_RGBA_EXPLICIT_ALPHA_AMD = 0x8C93;
public static int GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE;
public static int GL_COMPRESSED_RGB8_ETC2 = 0x9274;
public static int GL_COMPRESSED_SRGB8_ETC2 = 0x9275;
public static int GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276;
public static int GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277;
public static int GL_COMPRESSED_RGBA8_ETC2_EAC = 0x9278;
public static int GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279;
public static int GL_COMPRESSED_R11_EAC = 0x9270;
public static int GL_COMPRESSED_SIGNED_R11_EAC = 0x9271;
public static int GL_COMPRESSED_RG11_EAC = 0x9272;
public static int GL_COMPRESSED_SIGNED_RG11_EAC = 0x9273;
public static int GL_COMPRESSED_RED_RGTC1 = 0x8DBB;
public static int GL_COMPRESSED_RG_RGTC2 = 0x8DBD;
public static int GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F;
public static int GL_COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C;
public static int GL_R16F = 0x822D;
public static int GL_RG16F = 0x822F;
public static int GL_RGBA16F = 0x881A;
public static int GL_R32F = 0x822E;
public static int GL_RG32F = 0x8230;
public static int GL_RGBA32F = 0x8814;
// constants for glBaseInternalFormat
public static int GL_RED = 0x1903;
public static int GL_GREEN = 0x1904;
public static int GL_BLUE = 0x1905;
public static int GL_ALPHA = 0x1906;
public static int GL_RGB = 0x1907;
public static int GL_RGBA = 0x1908;
public static int GL_RG = 0x8227;
}
//from TextureConverter.h
public enum QFORMAT
{
// General formats
Q_FORMAT_RGBA_8UI = 1,
Q_FORMAT_RGBA_8I,
Q_FORMAT_RGB5_A1UI,
Q_FORMAT_RGBA_4444,
Q_FORMAT_RGBA_16UI,
Q_FORMAT_RGBA_16I,
Q_FORMAT_RGBA_32UI,
Q_FORMAT_RGBA_32I,
Q_FORMAT_PALETTE_8_RGBA_8888,
Q_FORMAT_PALETTE_8_RGBA_5551,
Q_FORMAT_PALETTE_8_RGBA_4444,
Q_FORMAT_PALETTE_4_RGBA_8888,
Q_FORMAT_PALETTE_4_RGBA_5551,
Q_FORMAT_PALETTE_4_RGBA_4444,
Q_FORMAT_PALETTE_1_RGBA_8888,
Q_FORMAT_PALETTE_8_RGB_888,
Q_FORMAT_PALETTE_8_RGB_565,
Q_FORMAT_PALETTE_4_RGB_888,
Q_FORMAT_PALETTE_4_RGB_565,
Q_FORMAT_R2_GBA10UI,
Q_FORMAT_RGB10_A2UI,
Q_FORMAT_RGB10_A2I,
Q_FORMAT_RGBA_F,
Q_FORMAT_RGBA_HF,
Q_FORMAT_RGB9_E5, // Last five bits are exponent bits (Read following section in GLES3 spec: "3.8.17 Shared Exponent Texture Color Conversion")
Q_FORMAT_RGB_8UI,
Q_FORMAT_RGB_8I,
Q_FORMAT_RGB_565,
Q_FORMAT_RGB_16UI,
Q_FORMAT_RGB_16I,
Q_FORMAT_RGB_32UI,
Q_FORMAT_RGB_32I,
Q_FORMAT_RGB_F,
Q_FORMAT_RGB_HF,
Q_FORMAT_RGB_11_11_10_F,
Q_FORMAT_RG_F,
Q_FORMAT_RG_HF,
Q_FORMAT_RG_32UI,
Q_FORMAT_RG_32I,
Q_FORMAT_RG_16I,
Q_FORMAT_RG_16UI,
Q_FORMAT_RG_8I,
Q_FORMAT_RG_8UI,
Q_FORMAT_RG_S88,
Q_FORMAT_R_32UI,
Q_FORMAT_R_32I,
Q_FORMAT_R_F,
Q_FORMAT_R_16F,
Q_FORMAT_R_16I,
Q_FORMAT_R_16UI,
Q_FORMAT_R_8I,
Q_FORMAT_R_8UI,
Q_FORMAT_LUMINANCE_ALPHA_88,
Q_FORMAT_LUMINANCE_8,
Q_FORMAT_ALPHA_8,
Q_FORMAT_LUMINANCE_ALPHA_F,
Q_FORMAT_LUMINANCE_F,
Q_FORMAT_ALPHA_F,
Q_FORMAT_LUMINANCE_ALPHA_HF,
Q_FORMAT_LUMINANCE_HF,
Q_FORMAT_ALPHA_HF,
Q_FORMAT_DEPTH_16,
Q_FORMAT_DEPTH_24,
Q_FORMAT_DEPTH_24_STENCIL_8,
Q_FORMAT_DEPTH_32,
Q_FORMAT_BGR_565,
Q_FORMAT_BGRA_8888,
Q_FORMAT_BGRA_5551,
Q_FORMAT_BGRX_8888,
Q_FORMAT_BGRA_4444,
// Compressed formats
Q_FORMAT_ATITC_RGBA,
Q_FORMAT_ATC_RGBA_EXPLICIT_ALPHA = Q_FORMAT_ATITC_RGBA,
Q_FORMAT_ATITC_RGB,
Q_FORMAT_ATC_RGB = Q_FORMAT_ATITC_RGB,
Q_FORMAT_ATC_RGBA_INTERPOLATED_ALPHA,
Q_FORMAT_ETC1_RGB8,
Q_FORMAT_3DC_X,
Q_FORMAT_3DC_XY,
Q_FORMAT_ETC2_RGB8,
Q_FORMAT_ETC2_RGBA8,
Q_FORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1,
Q_FORMAT_ETC2_SRGB8,
Q_FORMAT_ETC2_SRGB8_ALPHA8,
Q_FORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1,
Q_FORMAT_EAC_R_SIGNED,
Q_FORMAT_EAC_R_UNSIGNED,
Q_FORMAT_EAC_RG_SIGNED,
Q_FORMAT_EAC_RG_UNSIGNED,
Q_FORMAT_S3TC_DXT1_RGB,
Q_FORMAT_S3TC_DXT1_RGBA,
Q_FORMAT_S3TC_DXT3_RGBA,
Q_FORMAT_S3TC_DXT5_RGBA,
// YUV formats
Q_FORMAT_AYUV_32,
Q_FORMAT_I444_24,
Q_FORMAT_YUYV_16,
Q_FORMAT_UYVY_16,
Q_FORMAT_I420_12,
Q_FORMAT_YV12_12,
Q_FORMAT_NV21_12,
Q_FORMAT_NV12_12,
// ASTC Format
Q_FORMAT_ASTC_8,
Q_FORMAT_ASTC_16,
};
public enum texgenpack_texturetype
{
RGTC1,
RGTC2,
BPTC_FLOAT,
BPTC
}
}