mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-12-11 21:01:22 +00:00
746 lines
31 KiB
C#
Executable file
746 lines
31 KiB
C#
Executable file
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
/*
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
* This program is released under GNU General Public License
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#endregion
|
|
|
|
#region ================== Namespaces
|
|
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.IO;
|
|
using System.Drawing;
|
|
using CodeImp.DoomBuilder.Rendering;
|
|
using System.Drawing.Imaging;
|
|
using CodeImp.DoomBuilder.Data;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.IO
|
|
{
|
|
//mxd
|
|
internal struct DevilImageType
|
|
{
|
|
internal const int IL_TYPE_UNKNOWN = 0x0000;
|
|
//internal const int IL_DOOM = 0x0422; //!< DooM walls - no specific extension
|
|
//internal const int IL_DOOM_FLAT = 0x0423; //!< DooM flats - no specific extension
|
|
|
|
internal const int IL_JPG = 0x0425; //!< JPEG - .jpg, .jpe and .jpeg extensions
|
|
internal const int IL_PCX = 0x0428; //!< ZSoft PCX - .pcx extension
|
|
internal const int IL_PNG = 0x042A; //!< Portable Network Graphics - .png extension
|
|
internal const int IL_TGA = 0x042D; //!< TrueVision Targa File - .tga, .vda, .icb and .vst extensions
|
|
internal const int IL_GIF = 0x0436; //!< Graphics Interchange Format - .gif extension
|
|
internal const int IL_DDS = 0x0437; //!< DirectDraw Surface - .dds extension
|
|
}
|
|
|
|
// [ZZ]
|
|
internal enum DevilError
|
|
{
|
|
IL_NO_ERROR = 0x0000,
|
|
IL_INVALID_ENUM = 0x0501,
|
|
IL_OUT_OF_MEMORY = 0x0502,
|
|
IL_FORMAT_NOT_SUPPORTED = 0x0503,
|
|
IL_INTERNAL_ERROR = 0x0504,
|
|
IL_INVALID_VALUE = 0x0505,
|
|
IL_ILLEGAL_OPERATION = 0x0506,
|
|
IL_ILLEGAL_FILE_VALUE = 0x0507,
|
|
IL_INVALID_FILE_HEADER = 0x0508,
|
|
IL_INVALID_PARAM = 0x0509,
|
|
IL_COULD_NOT_OPEN_FILE = 0x050A,
|
|
IL_INVALID_EXTENSION = 0x050B,
|
|
IL_FILE_ALREADY_EXISTS = 0x050C,
|
|
IL_OUT_FORMAT_SAME = 0x050D,
|
|
IL_STACK_OVERFLOW = 0x050E,
|
|
IL_STACK_UNDERFLOW = 0x050F,
|
|
IL_INVALID_CONVERSION = 0x0510,
|
|
IL_BAD_DIMENSIONS = 0x0511,
|
|
IL_FILE_READ_ERROR = 0x0512, // 05/12/2002: Addition by Sam.
|
|
IL_FILE_WRITE_ERROR = 0x0512,
|
|
|
|
IL_LIB_GIF_ERROR = 0x05E1,
|
|
IL_LIB_JPEG_ERROR = 0x05E2,
|
|
IL_LIB_PNG_ERROR = 0x05E3,
|
|
IL_LIB_TIFF_ERROR = 0x05E4,
|
|
IL_LIB_MNG_ERROR = 0x05E5,
|
|
IL_UNKNOWN_ERROR = 0x05FF
|
|
}
|
|
|
|
internal unsafe class FileImageReader : IImageReader
|
|
{
|
|
#region ================== APIs
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern void ilEnable(int num);
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern void ilGenImages(int num, IntPtr images);
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern void ilBindImage(uint image);
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern void ilDeleteImages(int num, IntPtr images);
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern void ilOriginFunc(int func);
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern bool ilLoadL(uint type, IntPtr lump, uint size);
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern int ilGetInteger(uint mode);
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern int ilGetError();
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern int ilConvertImage(uint destformat, uint desttype);
|
|
|
|
[DllImport("devil.dll")]
|
|
private static extern uint ilCopyPixels(uint xoff, uint yoff, uint zoff, uint width, uint height, uint depth, uint format, uint type, IntPtr data);
|
|
|
|
//
|
|
private const int IL_ORIGIN_SET = 0x0600;
|
|
private const int IL_ORIGIN_LOWER_LEFT = 0x0601;
|
|
private const int IL_ORIGIN_UPPER_LEFT = 0x0602;
|
|
|
|
//mxd. Look's like we don't need many of those...
|
|
// Matches OpenGL's right now.
|
|
//! Data formats \link Formats Formats\endlink
|
|
//private const int IL_COLOUR_INDEX = 0x1900;
|
|
//private const int IL_COLOR_INDEX = 0x1900;
|
|
//private const int IL_ALPHA = 0x1906;
|
|
//private const int IL_RGB = 0x1907;
|
|
//private const int IL_RGBA = 0x1908;
|
|
//private const int IL_BGR = 0x80E0;
|
|
private const int IL_BGRA = 0x80E1;
|
|
//private const int IL_LUMINANCE = 0x1909;
|
|
//private const int IL_LUMINANCE_ALPHA = 0x190A;
|
|
|
|
//! Data types \link Types Types\endlink
|
|
//private const int IL_BYTE = 0x1400;
|
|
private const int IL_UNSIGNED_BYTE = 0x1401;
|
|
/*private const int IL_SHORT = 0x1402;
|
|
private const int IL_UNSIGNED_SHORT = 0x1403;
|
|
private const int IL_INT = 0x1404;
|
|
private const int IL_UNSIGNED_INT = 0x1405;
|
|
private const int IL_FLOAT = 0x1406;
|
|
private const int IL_DOUBLE = 0x140A;
|
|
private const int IL_HALF = 0x140B;*/
|
|
|
|
// Image types
|
|
//private const int IL_TYPE_UNKNOWN = 0x0000;
|
|
/*private const int IL_BMP = 0x0420; //!< Microsoft Windows Bitmap - .bmp extension
|
|
private const int IL_CUT = 0x0421; //!< Dr. Halo - .cut extension
|
|
private const int IL_DOOM = 0x0422; //!< DooM walls - no specific extension
|
|
private const int IL_DOOM_FLAT = 0x0423; //!< DooM flats - no specific extension
|
|
private const int IL_ICO = 0x0424; //!< Microsoft Windows Icons and Cursors - .ico and .cur extensions
|
|
private const int IL_JPG = 0x0425; //!< JPEG - .jpg, .jpe and .jpeg extensions
|
|
private const int IL_JFIF = 0x0425; //!<
|
|
private const int IL_ILBM = 0x0426; //!< Amiga IFF (FORM ILBM) - .iff, .ilbm, .lbm extensions
|
|
private const int IL_PCD = 0x0427; //!< Kodak PhotoCD - .pcd extension
|
|
private const int IL_PCX = 0x0428; //!< ZSoft PCX - .pcx extension
|
|
private const int IL_PIC = 0x0429; //!< PIC - .pic extension
|
|
private const int IL_PNG = 0x042A; //!< Portable Network Graphics - .png extension
|
|
private const int IL_PNM = 0x042B; //!< Portable Any Map - .pbm, .pgm, .ppm and .pnm extensions
|
|
private const int IL_SGI = 0x042C; //!< Silicon Graphics - .sgi, .bw, .rgb and .rgba extensions
|
|
private const int IL_TGA = 0x042D; //!< TrueVision Targa File - .tga, .vda, .icb and .vst extensions
|
|
private const int IL_TIF = 0x042E; //!< Tagged Image File Format - .tif and .tiff extensions
|
|
private const int IL_CHEAD = 0x042F; //!< C-Style Header - .h extension
|
|
private const int IL_RAW = 0x0430; //!< Raw Image Data - any extension
|
|
private const int IL_MDL = 0x0431; //!< Half-Life Model Texture - .mdl extension
|
|
private const int IL_WAL = 0x0432; //!< Quake 2 Texture - .wal extension
|
|
private const int IL_LIF = 0x0434; //!< Homeworld Texture - .lif extension
|
|
private const int IL_MNG = 0x0435; //!< Multiple-image Network Graphics - .mng extension
|
|
private const int IL_JNG = 0x0435; //!<
|
|
private const int IL_GIF = 0x0436; //!< Graphics Interchange Format - .gif extension
|
|
private const int IL_DDS = 0x0437; //!< DirectDraw Surface - .dds extension
|
|
private const int IL_DCX = 0x0438; //!< ZSoft Multi-PCX - .dcx extension
|
|
private const int IL_PSD = 0x0439; //!< Adobe PhotoShop - .psd extension
|
|
private const int IL_EXIF = 0x043A; //!<
|
|
private const int IL_PSP = 0x043B; //!< PaintShop Pro - .psp extension
|
|
private const int IL_PIX = 0x043C; //!< PIX - .pix extension
|
|
private const int IL_PXR = 0x043D; //!< Pixar - .pxr extension
|
|
private const int IL_XPM = 0x043E; //!< X Pixel Map - .xpm extension
|
|
private const int IL_HDR = 0x043F; //!< Radiance High Dynamic Range - .hdr extension
|
|
private const int IL_ICNS = 0x0440; //!< Macintosh Icon - .icns extension
|
|
private const int IL_JP2 = 0x0441; //!< Jpeg 2000 - .jp2 extension
|
|
private const int IL_EXR = 0x0442; //!< OpenEXR - .exr extension
|
|
private const int IL_WDP = 0x0443; //!< Microsoft HD Photo - .wdp and .hdp extension
|
|
private const int IL_VTF = 0x0444; //!< Valve Texture Format - .vtf extension
|
|
private const int IL_WBMP = 0x0445; //!< Wireless Bitmap - .wbmp extension
|
|
private const int IL_SUN = 0x0446; //!< Sun Raster - .sun, .ras, .rs, .im1, .im8, .im24 and .im32 extensions
|
|
private const int IL_IFF = 0x0447; //!< Interchange File Format - .iff extension
|
|
private const int IL_TPL = 0x0448; //!< Gamecube Texture - .tpl extension
|
|
private const int IL_FITS = 0x0449; //!< Flexible Image Transport System - .fit and .fits extensions
|
|
private const int IL_DICOM = 0x044A; //!< Digital Imaging and Communications in Medicine (DICOM) - .dcm and .dicom extensions
|
|
private const int IL_IWI = 0x044B; //!< Call of Duty Infinity Ward Image - .iwi extension
|
|
private const int IL_BLP = 0x044C; //!< Blizzard Texture Format - .blp extension
|
|
private const int IL_FTX = 0x044D; //!< Heavy Metal: FAKK2 Texture - .ftx extension
|
|
private const int IL_ROT = 0x044E; //!< Homeworld 2 - Relic Texture - .rot extension
|
|
private const int IL_TEXTURE = 0x044F; //!< Medieval II: Total War Texture - .texture extension
|
|
private const int IL_DPX = 0x0450; //!< Digital Picture Exchange - .dpx extension
|
|
private const int IL_UTX = 0x0451; //!< Unreal (and Unreal Tournament) Texture - .utx extension
|
|
private const int IL_MP3 = 0x0452; //!< MPEG-1 Audio Layer 3 - .mp3 extension*/
|
|
|
|
//private const int IL_JASC_PAL = 0x0475; //!< PaintShop Pro Palette
|
|
|
|
|
|
// Error Types
|
|
/*private const int IL_NO_ERROR = 0x0000;
|
|
private const int IL_INVALID_ENUM = 0x0501;
|
|
private const int IL_OUT_OF_MEMORY = 0x0502;
|
|
private const int IL_FORMAT_NOT_SUPPORTED = 0x0503;
|
|
private const int IL_INTERNAL_ERROR = 0x0504;
|
|
private const int IL_INVALID_VALUE = 0x0505;
|
|
private const int IL_ILLEGAL_OPERATION = 0x0506;
|
|
private const int IL_ILLEGAL_FILE_VALUE = 0x0507;
|
|
private const int IL_INVALID_FILE_HEADER = 0x0508;
|
|
private const int IL_INVALID_PARAM = 0x0509;
|
|
private const int IL_COULD_NOT_OPEN_FILE = 0x050A;
|
|
private const int IL_INVALID_EXTENSION = 0x050B;
|
|
private const int IL_FILE_ALREADY_EXISTS = 0x050C;
|
|
private const int IL_OUT_FORMAT_SAME = 0x050D;
|
|
private const int IL_STACK_OVERFLOW = 0x050E;
|
|
private const int IL_STACK_UNDERFLOW = 0x050F;
|
|
private const int IL_INVALID_CONVERSION = 0x0510;
|
|
private const int IL_BAD_DIMENSIONS = 0x0511;
|
|
private const int IL_FILE_READ_ERROR = 0x0512; // 05/12/2002: Addition by Sam.
|
|
private const int IL_FILE_WRITE_ERROR = 0x0512;*/
|
|
|
|
/*private const int IL_LIB_GIF_ERROR = 0x05E1;
|
|
private const int IL_LIB_JPEG_ERROR = 0x05E2;
|
|
private const int IL_LIB_PNG_ERROR = 0x05E3;
|
|
private const int IL_LIB_TIFF_ERROR = 0x05E4;
|
|
private const int IL_LIB_MNG_ERROR = 0x05E5;
|
|
private const int IL_LIB_JP2_ERROR = 0x05E6;
|
|
private const int IL_LIB_EXR_ERROR = 0x05E7;
|
|
private const int IL_UNKNOWN_ERROR = 0x05FF;*/
|
|
|
|
|
|
// Origin Definitions
|
|
/*private const int IL_ORIGIN_SET = 0x0600;
|
|
private const int IL_ORIGIN_LOWER_LEFT = 0x0601;
|
|
private const int IL_ORIGIN_UPPER_LEFT = 0x0602;
|
|
private const int IL_ORIGIN_MODE = 0x0603;*/
|
|
|
|
|
|
// Format and Type Mode Definitions
|
|
/*private const int IL_FORMAT_SET = 0x0610;
|
|
private const int IL_FORMAT_MODE = 0x0611;
|
|
private const int IL_TYPE_SET = 0x0612;
|
|
private const int IL_TYPE_MODE = 0x0613;*/
|
|
|
|
|
|
// File definitions
|
|
/*private const int IL_FILE_OVERWRITE = 0x0620;
|
|
private const int IL_FILE_MODE = 0x0621;
|
|
*/
|
|
|
|
// Palette definitions
|
|
//private const int IL_CONV_PAL = 0x0630;
|
|
|
|
|
|
// Load fail definitions
|
|
//private const int IL_DEFAULT_ON_FAIL = 0x0632;
|
|
|
|
|
|
// Key colour and alpha definitions
|
|
/*private const int IL_USE_KEY_COLOUR = 0x0635;
|
|
private const int IL_USE_KEY_COLOR = 0x0635;
|
|
private const int IL_BLIT_BLEND = 0x0636;*/
|
|
|
|
|
|
// Interlace definitions
|
|
/*private const int IL_SAVE_INTERLACED = 0x0639;
|
|
private const int IL_INTERLACE_MODE = 0x063A;*/
|
|
|
|
|
|
// Quantization definitions
|
|
/*private const int IL_QUANTIZATION_MODE = 0x0640;
|
|
private const int IL_WU_QUANT = 0x0641;
|
|
private const int IL_NEU_QUANT = 0x0642;
|
|
private const int IL_NEU_QUANT_SAMPLE = 0x0643;
|
|
private const int IL_MAX_QUANT_INDEXS = 0x0644; //XIX : ILint : Maximum number of colors to reduce to, default of 256. and has a range of 2-256
|
|
private const int IL_MAX_QUANT_INDICES = 0x0644; // Redefined, since the above private const int is misspelled*/
|
|
|
|
|
|
// Hints
|
|
/*private const int IL_FASTEST = 0x0660;
|
|
private const int IL_LESS_MEM = 0x0661;
|
|
private const int IL_DONT_CARE = 0x0662;
|
|
private const int IL_MEM_SPEED_HINT = 0x0665;
|
|
private const int IL_USE_COMPRESSION = 0x0666;
|
|
private const int IL_NO_COMPRESSION = 0x0667;
|
|
private const int IL_COMPRESSION_HINT = 0x0668;*/
|
|
|
|
|
|
// Compression
|
|
/*private const int IL_NVIDIA_COMPRESS = 0x0670;
|
|
private const int IL_SQUISH_COMPRESS = 0x0671;*/
|
|
|
|
|
|
// Subimage types
|
|
/*private const int IL_SUB_NEXT = 0x0680;
|
|
private const int IL_SUB_MIPMAP = 0x0681;
|
|
private const int IL_SUB_LAYER = 0x0682;*/
|
|
|
|
|
|
// Compression definitions
|
|
/*private const int IL_COMPRESS_MODE = 0x0700;
|
|
private const int IL_COMPRESS_NONE = 0x0701;
|
|
private const int IL_COMPRESS_RLE = 0x0702;
|
|
private const int IL_COMPRESS_LZO = 0x0703;
|
|
private const int IL_COMPRESS_ZLIB = 0x0704;*/
|
|
|
|
|
|
// File format-specific values
|
|
/*private const int IL_TGA_CREATE_STAMP = 0x0710;
|
|
private const int IL_JPG_QUALITY = 0x0711;
|
|
private const int IL_PNG_INTERLACE = 0x0712;
|
|
private const int IL_TGA_RLE = 0x0713;
|
|
private const int IL_BMP_RLE = 0x0714;
|
|
private const int IL_SGI_RLE = 0x0715;
|
|
private const int IL_TGA_ID_STRING = 0x0717;
|
|
private const int IL_TGA_AUTHNAME_STRING = 0x0718;
|
|
private const int IL_TGA_AUTHCOMMENT_STRING = 0x0719;
|
|
private const int IL_PNG_AUTHNAME_STRING = 0x071A;
|
|
private const int IL_PNG_TITLE_STRING = 0x071B;
|
|
private const int IL_PNG_DESCRIPTION_STRING = 0x071C;
|
|
private const int IL_TIF_DESCRIPTION_STRING = 0x071D;
|
|
private const int IL_TIF_HOSTCOMPUTER_STRING = 0x071E;
|
|
private const int IL_TIF_DOCUMENTNAME_STRING = 0x071F;
|
|
private const int IL_TIF_AUTHNAME_STRING = 0x0720;
|
|
private const int IL_JPG_SAVE_FORMAT = 0x0721;
|
|
private const int IL_CHEAD_HEADER_STRING = 0x0722;
|
|
private const int IL_PCD_PICNUM = 0x0723;
|
|
private const int IL_PNG_ALPHA_INDEX = 0x0724; //XIX : ILint : the color in the palette at this index value (0-255) is considered transparent, -1 for no trasparent color
|
|
private const int IL_JPG_PROGRESSIVE = 0x0725;
|
|
private const int IL_VTF_COMP = 0x0726;*/
|
|
|
|
|
|
// DXTC definitions
|
|
/*private const int IL_DXTC_FORMAT = 0x0705;
|
|
private const int IL_DXT1 = 0x0706;
|
|
private const int IL_DXT2 = 0x0707;
|
|
private const int IL_DXT3 = 0x0708;
|
|
private const int IL_DXT4 = 0x0709;
|
|
private const int IL_DXT5 = 0x070A;
|
|
private const int IL_DXT_NO_COMP = 0x070B;
|
|
private const int IL_KEEP_DXTC_DATA = 0x070C;
|
|
private const int IL_DXTC_DATA_FORMAT = 0x070D;
|
|
private const int IL_3DC = 0x070E;
|
|
private const int IL_RXGB = 0x070F;
|
|
private const int IL_ATI1N = 0x0710;
|
|
private const int IL_DXT1A = 0x0711; // Normally the same as IL_DXT1, except for nVidia Texture Tools.*/
|
|
|
|
// Environment map definitions
|
|
/*private const int IL_CUBEMAP_POSITIVEX = 0x00000400;
|
|
private const int IL_CUBEMAP_NEGATIVEX = 0x00000800;
|
|
private const int IL_CUBEMAP_POSITIVEY = 0x00001000;
|
|
private const int IL_CUBEMAP_NEGATIVEY = 0x00002000;
|
|
private const int IL_CUBEMAP_POSITIVEZ = 0x00004000;
|
|
private const int IL_CUBEMAP_NEGATIVEZ = 0x00008000;
|
|
private const int IL_SPHEREMAP = 0x00010000;*/
|
|
|
|
|
|
// Values
|
|
//private const int IL_VERSION_NUM = 0x0DE2;
|
|
private const int IL_IMAGE_WIDTH = 0x0DE4;
|
|
private const int IL_IMAGE_HEIGHT = 0x0DE5;
|
|
/*private const int IL_IMAGE_DEPTH = 0x0DE6;
|
|
private const int IL_IMAGE_SIZE_OF_DATA = 0x0DE7;
|
|
private const int IL_IMAGE_BPP = 0x0DE8;
|
|
private const int IL_IMAGE_BYTES_PER_PIXEL = 0x0DE8;
|
|
private const int IL_IMAGE_BITS_PER_PIXEL = 0x0DE9;
|
|
private const int IL_IMAGE_FORMAT = 0x0DEA;
|
|
private const int IL_IMAGE_TYPE = 0x0DEB;
|
|
private const int IL_PALETTE_TYPE = 0x0DEC;
|
|
private const int IL_PALETTE_SIZE = 0x0DED;
|
|
private const int IL_PALETTE_BPP = 0x0DEE;
|
|
private const int IL_PALETTE_NUM_COLS = 0x0DEF;
|
|
private const int IL_PALETTE_BASE_TYPE = 0x0DF0;
|
|
private const int IL_NUM_FACES = 0x0DE1;
|
|
private const int IL_NUM_IMAGES = 0x0DF1;
|
|
private const int IL_NUM_MIPMAPS = 0x0DF2;
|
|
private const int IL_NUM_LAYERS = 0x0DF3;
|
|
private const int IL_ACTIVE_IMAGE = 0x0DF4;
|
|
private const int IL_ACTIVE_MIPMAP = 0x0DF5;
|
|
private const int IL_ACTIVE_LAYER = 0x0DF6;
|
|
private const int IL_ACTIVE_FACE = 0x0E00;
|
|
private const int IL_CUR_IMAGE = 0x0DF7;
|
|
private const int IL_IMAGE_DURATION = 0x0DF8;
|
|
private const int IL_IMAGE_PLANESIZE = 0x0DF9;
|
|
private const int IL_IMAGE_BPC = 0x0DFA;
|
|
private const int IL_IMAGE_OFFX = 0x0DFB;
|
|
private const int IL_IMAGE_OFFY = 0x0DFC;
|
|
private const int IL_IMAGE_CUBEFLAGS = 0x0DFD;
|
|
private const int IL_IMAGE_ORIGIN = 0x0DFE;
|
|
private const int IL_IMAGE_CHANNELS = 0x0DFF;*/
|
|
|
|
//mxd
|
|
private readonly uint imagetype;
|
|
// [ZZ]
|
|
private byte[] imagebytes;
|
|
// [ZZ] basically, the logic here is: if the image is not loaded correctly,
|
|
// then it might be misinterpreted Doom headerless image.
|
|
// so here we just allocate a DoomFlat/Colormap/Image reader and proxy calls
|
|
private readonly int guesstype;
|
|
private readonly Playpal guesspalette;
|
|
private IImageReader proxyreader;
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
// Constructor
|
|
public FileImageReader()
|
|
{
|
|
imagetype = DevilImageType.IL_TYPE_UNKNOWN;//mxd
|
|
|
|
// We have no destructor
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
//mxd
|
|
public FileImageReader(uint devilImagetype)
|
|
{
|
|
imagetype = devilImagetype;//mxd
|
|
|
|
// We have no destructor
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
// [ZZ]
|
|
public FileImageReader(uint devilImagetype, int guesstype, Playpal guesspalette)
|
|
{
|
|
imagetype = devilImagetype;
|
|
this.guesstype = guesstype;
|
|
this.guesspalette = guesspalette;
|
|
|
|
// We have no destructor
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Methods
|
|
|
|
// This creates a Bitmap from the given data
|
|
// Returns null on failure
|
|
public Bitmap ReadAsBitmap(Stream stream, out int offsetx, out int offsety)
|
|
{
|
|
if (proxyreader != null)
|
|
return proxyreader.ReadAsBitmap(stream, out offsetx, out offsety);
|
|
|
|
offsetx = int.MinValue;
|
|
offsety = int.MinValue;
|
|
|
|
Bitmap bmp = ReadAsBitmap(stream);
|
|
|
|
//mxd. Read PNG offsets
|
|
if(imagetype == DevilImageType.IL_PNG && bmp != null)
|
|
{
|
|
stream.Position = 8;
|
|
using(BinaryReader reader = new BinaryReader(stream))
|
|
{
|
|
// Read chunks untill we encounter either "grAb" or "IDAT"
|
|
while(reader.BaseStream.Position < reader.BaseStream.Length)
|
|
{
|
|
// Big Endian!
|
|
int chunklength = ToInt32BigEndian(reader.ReadBytes(4));
|
|
string chunkname = new string(reader.ReadChars(4));
|
|
|
|
if(chunkname == "grAb")
|
|
{
|
|
offsetx = ToInt32BigEndian(reader.ReadBytes(4));
|
|
offsety = ToInt32BigEndian(reader.ReadBytes(4));
|
|
break;
|
|
}
|
|
else if(chunkname == "IDAT")
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Skip the rest of the chunk
|
|
reader.BaseStream.Position += chunklength + 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return the image
|
|
return bmp;
|
|
}
|
|
|
|
// This wraps a stream but makes Close/Dispose do nothing. That prevents.net's Image.FromStream from closing it as we want to fall back to other image loaders.
|
|
class NoCloseStream : Stream
|
|
{
|
|
Stream stream;
|
|
public NoCloseStream(Stream s) { stream = s; }
|
|
public override bool CanRead { get { return stream.CanRead; } }
|
|
public override bool CanSeek { get { return stream.CanSeek; } }
|
|
public override bool CanWrite { get { return stream.CanWrite; } }
|
|
public override bool CanTimeout { get { return stream.CanTimeout; } }
|
|
public override int ReadTimeout { get { return stream.ReadTimeout; } }
|
|
public override int WriteTimeout { get { return stream.WriteTimeout; } }
|
|
public override int EndRead(IAsyncResult asyncResult) { return stream.EndRead(asyncResult); }
|
|
public override void EndWrite(IAsyncResult asyncResult) { stream.EndWrite(asyncResult); }
|
|
public override int ReadByte() { return stream.ReadByte(); }
|
|
public override long Length { get { return stream.Length; } }
|
|
public override void WriteByte(byte value) { stream.WriteByte(value); }
|
|
public override long Position { get { return stream.Position; } set { stream.Position = value; } }
|
|
public override void Flush() { stream.Flush(); }
|
|
public override int Read(byte[] buffer, int offset, int count) { return stream.Read(buffer, offset, count); }
|
|
public override long Seek(long offset, SeekOrigin origin) { return stream.Seek(offset, origin); }
|
|
public override void SetLength(long value) { stream.SetLength(value); }
|
|
public override void Write(byte[] buffer, int offset, int count) { stream.Write(buffer, offset, count); }
|
|
}
|
|
|
|
static object syncobject = new object();
|
|
|
|
// This reads the image and returns a Bitmap
|
|
public Bitmap ReadAsBitmap(Stream stream)
|
|
{
|
|
if (proxyreader != null)
|
|
return proxyreader.ReadAsBitmap(stream);
|
|
|
|
// Let the .net framework try first
|
|
try
|
|
{
|
|
using (var image = Image.FromStream(new NoCloseStream(stream)))
|
|
{
|
|
return new Bitmap(image);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
}
|
|
|
|
string error;
|
|
lock (syncobject) // DevIL is not thread safe.
|
|
{
|
|
try
|
|
{
|
|
// Create an image in DevIL
|
|
uint imageid = 0;
|
|
ilGenImages(1, new IntPtr(&imageid));
|
|
ilBindImage(imageid);
|
|
|
|
// Read image data from stream
|
|
byte[] bytes;
|
|
if (imagebytes == null)
|
|
{
|
|
bytes = new byte[stream.Length];
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
stream.Read(bytes, 0, bytes.Length);
|
|
imagebytes = bytes;
|
|
}
|
|
else bytes = imagebytes;
|
|
|
|
ilEnable(IL_ORIGIN_SET);
|
|
ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
|
|
|
|
fixed (byte* bptr = bytes)
|
|
{
|
|
if (!ilLoadL(imagetype, new IntPtr(bptr), (uint)bytes.Length))
|
|
throw new BadImageFormatException();
|
|
}
|
|
|
|
// [ZZ] check if there was any error code
|
|
DevilError ilerror = (DevilError)ilGetError();
|
|
if (ilerror != DevilError.IL_NO_ERROR)
|
|
throw new BadImageFormatException("DevIL error: " + ilerror.ToString());
|
|
|
|
// Get the image properties
|
|
int width = ilGetInteger(IL_IMAGE_WIDTH);
|
|
int height = ilGetInteger(IL_IMAGE_HEIGHT);
|
|
if ((width < 1) || (height < 1))
|
|
throw new BadImageFormatException();
|
|
|
|
// Convert the image to ARGB if needed
|
|
ilConvertImage(IL_BGRA, IL_UNSIGNED_BYTE);
|
|
|
|
// Copy the image pixels to a Bitmap
|
|
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
|
BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
|
ilCopyPixels(0, 0, 0, (uint)width, (uint)height, 1, IL_BGRA, IL_UNSIGNED_BYTE, bmpdata.Scan0);
|
|
bmp.UnlockBits(bmpdata);
|
|
|
|
// Clean up
|
|
ilDeleteImages(1, new IntPtr(&imageid));
|
|
|
|
return bmp;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// Remove last error from the stack. Workaround for https://github.com/jewalky/GZDoom-Builder-Bugfix/issues/295
|
|
ilGetError();
|
|
|
|
error = "Unable to make file image. " + e.GetType().Name + ": " + e.Message;
|
|
}
|
|
}
|
|
|
|
// [ZZ] try to make a guessed reader
|
|
switch (guesstype)
|
|
{
|
|
case ImageDataFormat.DOOMPICTURE:
|
|
// Check if data is valid for a doom picture
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
DoomPictureReader picreader = new DoomPictureReader(guesspalette);
|
|
if (picreader.Validate(stream)) proxyreader = picreader;
|
|
break;
|
|
|
|
case ImageDataFormat.DOOMFLAT:
|
|
// Check if data is valid for a doom flat
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
DoomFlatReader flatreader = new DoomFlatReader(guesspalette);
|
|
if (flatreader.Validate(stream)) proxyreader = flatreader;
|
|
break;
|
|
|
|
case ImageDataFormat.DOOMCOLORMAP:
|
|
// Check if data is valid for a doom colormap
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
DoomColormapReader colormapreader = new DoomColormapReader(guesspalette);
|
|
if (colormapreader.Validate(stream)) proxyreader = colormapreader;
|
|
break;
|
|
}
|
|
|
|
if (proxyreader != null)
|
|
{
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
return proxyreader.ReadAsBitmap(stream);
|
|
}
|
|
|
|
// Unable to make bitmap
|
|
General.ErrorLogger.Add(ErrorType.Error, error);
|
|
return null;
|
|
}
|
|
|
|
// This draws the picture to the given pixel color data
|
|
// Throws exception on failure
|
|
public void DrawToPixelData(Stream stream, PixelColor* target, int targetwidth, int targetheight, int x, int y)
|
|
{
|
|
// Get bitmap
|
|
Bitmap bmp = ReadAsBitmap(stream);
|
|
if(bmp != null)
|
|
{
|
|
int width = bmp.Size.Width;
|
|
int height = bmp.Size.Height;
|
|
|
|
// Lock bitmap pixels
|
|
BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
|
PixelColor* pixels = (PixelColor*)bmpdata.Scan0.ToPointer();
|
|
|
|
// Go for all pixels in the original image
|
|
for(int ox = 0; ox < width; ox++)
|
|
{
|
|
for(int oy = 0; oy < height; oy++)
|
|
{
|
|
// Copy this pixel?
|
|
if(pixels[oy * width + ox].a > 0.5f)
|
|
{
|
|
// Calculate target pixel and copy when within bounds
|
|
int tx = x + ox;
|
|
int ty = y + oy;
|
|
if((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight))
|
|
target[ty * targetwidth + tx] = pixels[oy * width + ox];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Done
|
|
bmp.UnlockBits(bmpdata);
|
|
bmp.Dispose();
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidDataException();
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
private static int ToInt32BigEndian(byte[] buffer)
|
|
{
|
|
return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
|
|
}
|
|
|
|
public bool Validate(Stream stream)
|
|
{
|
|
uint _vimageid = 0;
|
|
try
|
|
{
|
|
byte[] bytes;
|
|
if (imagebytes == null)
|
|
{
|
|
bytes = new byte[stream.Length];
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
stream.Read(bytes, 0, bytes.Length);
|
|
imagebytes = bytes;
|
|
}
|
|
else bytes = imagebytes;
|
|
|
|
// Create an image in DevIL
|
|
ilGenImages(1, new IntPtr(&_vimageid));
|
|
ilBindImage(_vimageid);
|
|
|
|
// Read image data from stream
|
|
fixed (byte* bptr = bytes)
|
|
{
|
|
if (!ilLoadL(imagetype, new IntPtr(bptr), (uint)bytes.Length))
|
|
throw new BadImageFormatException();
|
|
}
|
|
|
|
// [ZZ] check if there was any error code
|
|
DevilError ilerror = (DevilError)ilGetError();
|
|
if (ilerror != DevilError.IL_NO_ERROR)
|
|
throw new BadImageFormatException("DevIL error: " + ilerror.ToString());
|
|
|
|
// Get the image properties
|
|
int width = ilGetInteger(IL_IMAGE_WIDTH);
|
|
int height = ilGetInteger(IL_IMAGE_HEIGHT);
|
|
if ((width < 1) || (height < 1))
|
|
throw new BadImageFormatException();
|
|
|
|
// Clean up
|
|
ilDeleteImages(1, new IntPtr(&_vimageid));
|
|
_vimageid = 0;
|
|
}
|
|
catch (Exception /*e*/)
|
|
{
|
|
//General.ErrorLogger.Add(ErrorType.Warning, e.ToString());
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (_vimageid != 0)
|
|
{
|
|
try
|
|
{
|
|
ilDeleteImages(1, new IntPtr(&_vimageid));
|
|
}
|
|
catch (Exception /*e_nested*/)
|
|
{
|
|
/* really really failed */
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|