--- /dev/null
+/*
+ Copyright (C) 2006 Serge "(515)" Ziryukin, Forest "LordHavoc" Hale
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to:
+
+ Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330
+ Boston, MA 02111-1307, USA
+
+*/
+
+//[515]: png implemented into DP ONLY FOR TESTING 2d stuff with csqc
+// so delete this bullshit :D
+//
+//LordHavoc: rewrote most of this.
+
+#include "quakedef.h"
+#include "image.h"
+#include "image_png.h"
+
+static void (*qpng_set_sig_bytes) (void*, int);
+static int (*qpng_sig_cmp) (const unsigned char*, size_t, size_t);
+static void* (*qpng_create_read_struct) (const char*, void*, void*, void*);
+static void* (*qpng_create_info_struct) (void*);
+static void (*qpng_read_info) (void*, void*);
+static void (*qpng_set_expand) (void*);
+static void (*qpng_set_gray_1_2_4_to_8) (void*);
+static void (*qpng_set_palette_to_rgb) (void*);
+static void (*qpng_set_tRNS_to_alpha) (void*);
+static void (*qpng_set_gray_to_rgb) (void*);
+static void (*qpng_set_filler) (void*, unsigned int, int);
+static void (*qpng_read_update_info) (void*, void*);
+static void (*qpng_read_image) (void*, unsigned char**);
+static void (*qpng_read_end) (void*, void*);
+static void (*qpng_destroy_read_struct) (void**, void**, void**);
+static void (*qpng_set_read_fn) (void*, void*, void*);
+static unsigned int (*qpng_get_valid) (void*, void*, unsigned int);
+static unsigned int (*qpng_get_rowbytes) (void*, void*);
+static unsigned char (*qpng_get_channels) (void*, void*);
+static unsigned char (*qpng_get_bit_depth) (void*, void*);
+static unsigned int (*qpng_get_IHDR) (void*, void*, unsigned int*, unsigned int*, int *, int *, int *, int *, int *);
+static char* (*qpng_get_libpng_ver) (void*);
+
+static dllfunction_t pngfuncs[] =
+{
+ {"png_set_sig_bytes", (void **) &qpng_set_sig_bytes},
+ {"png_sig_cmp", (void **) &qpng_sig_cmp},
+ {"png_create_read_struct", (void **) &qpng_create_read_struct},
+ {"png_create_info_struct", (void **) &qpng_create_info_struct},
+ {"png_read_info", (void **) &qpng_read_info},
+ {"png_set_expand", (void **) &qpng_set_expand},
+ {"png_set_gray_1_2_4_to_8", (void **) &qpng_set_gray_1_2_4_to_8},
+ {"png_set_palette_to_rgb", (void **) &qpng_set_palette_to_rgb},
+ {"png_set_tRNS_to_alpha", (void **) &qpng_set_tRNS_to_alpha},
+ {"png_set_gray_to_rgb", (void **) &qpng_set_gray_to_rgb},
+ {"png_set_filler", (void **) &qpng_set_filler},
+ {"png_read_update_info", (void **) &qpng_read_update_info},
+ {"png_read_image", (void **) &qpng_read_image},
+ {"png_read_end", (void **) &qpng_read_end},
+ {"png_destroy_read_struct", (void **) &qpng_destroy_read_struct},
+ {"png_set_read_fn", (void **) &qpng_set_read_fn},
+ {"png_get_valid", (void **) &qpng_get_valid},
+ {"png_get_rowbytes", (void **) &qpng_get_rowbytes},
+ {"png_get_channels", (void **) &qpng_get_channels},
+ {"png_get_bit_depth", (void **) &qpng_get_bit_depth},
+ {"png_get_IHDR", (void **) &qpng_get_IHDR},
+ {"png_get_libpng_ver", (void **) &qpng_get_libpng_ver},
+ {NULL, NULL}
+};
+
+// Handle for PNG DLL
+dllhandle_t png_dll = NULL;
+
+
+/*
+=================================================================
+
+ DLL load & unload
+
+=================================================================
+*/
+
+/*
+====================
+PNG_OpenLibrary
+
+Try to load the PNG DLL
+====================
+*/
+qboolean PNG_OpenLibrary (void)
+{
+ const char* dllnames [] =
+ {
+#ifdef WIN32
+ "libpng12.dll",
+#elif defined(MACOSX)
+ "libpng12.dylib",
+#else
+ "libpng12.so.0",
+#endif
+ NULL
+ };
+
+ // Already loaded?
+ if (png_dll)
+ return true;
+
+ // Load the DLL
+ if (! Sys_LoadLibrary (dllnames, &png_dll, pngfuncs))
+ {
+ Con_Printf ("PNG support disabled\n");
+ return false;
+ }
+
+ Con_Printf ("PNG support enabled\n");
+ return true;
+}
+
+
+/*
+====================
+PNG_CloseLibrary
+
+Unload the PNG DLL
+====================
+*/
+void PNG_CloseLibrary (void)
+{
+ Sys_UnloadLibrary (&png_dll);
+}
+
+
+/*
+=================================================================
+
+ PNG decompression
+
+=================================================================
+*/
+
+#define PNG_LIBPNG_VER_STRING "1.2.4"
+
+#define PNG_COLOR_MASK_PALETTE 1
+#define PNG_COLOR_MASK_COLOR 2
+#define PNG_COLOR_MASK_ALPHA 4
+
+#define PNG_COLOR_TYPE_GRAY 0
+#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
+#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR)
+#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
+#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
+
+#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA
+#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA
+
+#define PNG_INFO_tRNS 0x0010
+
+// this struct is only used for status information during loading
+struct
+{
+ const unsigned char *tmpBuf;
+ int tmpBuflength;
+ int tmpi;
+ //int FBgColor;
+ //int FTransparent;
+ unsigned int FRowBytes;
+ //double FGamma;
+ //double FScreenGamma;
+ unsigned char **FRowPtrs;
+ unsigned char *Data;
+ //char *Title;
+ //char *Author;
+ //char *Description;
+ int BitDepth;
+ int BytesPerPixel;
+ int ColorType;
+ unsigned int Height;
+ unsigned int Width;
+ int Interlace;
+ int Compression;
+ int Filter;
+ //double LastModified;
+ //int Transparent;
+} my_png;
+
+//LordHavoc: removed __cdecl prefix, added overrun protection, and rewrote this to be more efficient
+void PNG_fReadData(void *png, unsigned char *data, size_t length)
+{
+ size_t l;
+ l = my_png.tmpBuflength - my_png.tmpi;
+ if (l < length)
+ {
+ Con_Printf("PNG_fReadData: overrun by %i bytes\n", length - l);
+ // a read going past the end of the file, fill in the remaining bytes
+ // with 0 just to be consistent
+ memset(data + l, 0, length - l);
+ length = l;
+ }
+ memcpy(data, my_png.tmpBuf + my_png.tmpi, length);
+ my_png.tmpi += length;
+ Com_HexDumpToConsole(data, length);
+}
+
+void PNG_error_fn(void *png, const char *message)
+{
+ Con_Printf("PNG_LoadImage: error: %s\n", message);
+}
+
+void PNG_warning_fn(void *png, const char *message)
+{
+ Con_Printf("PNG_LoadImage: warning: %s\n", message);
+}
+
+extern int image_width;
+extern int image_height;
+
+unsigned char *PNG_LoadImage (const unsigned char *raw, int filesize, int matchwidth, int matchheight)
+{
+ unsigned int y;
+ void *png, *pnginfo;
+ unsigned char *imagedata;
+ unsigned char ioBuffer[8192];
+
+ // FIXME: register an error handler so that abort() won't be called on error
+
+ // No DLL = no PNGs
+ if (!png_dll)
+ return NULL;
+
+ if(qpng_sig_cmp(raw, 0, filesize))
+ return NULL;
+ png = qpng_create_read_struct(PNG_LIBPNG_VER_STRING, 0, PNG_error_fn, PNG_warning_fn);
+ if(!png)
+ return NULL;
+
+ // NOTE: this relies on jmp_buf being the first thing in the png structure
+ // created by libpng! (this is correct for libpng 1.2.x)
+ if (setjmp(png))
+ {
+ qpng_destroy_read_struct(&png, &pnginfo, 0);
+ return NULL;
+ }
+ //
+
+ pnginfo = qpng_create_info_struct(png);
+ if(!pnginfo)
+ {
+ qpng_destroy_read_struct(&png, &pnginfo, 0);
+ return NULL;
+ }
+ qpng_set_sig_bytes(png, 0);
+
+ memset(&my_png, 0, sizeof(my_png));
+ my_png.tmpBuf = raw;
+ my_png.tmpBuflength = filesize;
+ my_png.tmpi = 0;
+ //my_png.Data = NULL;
+ //my_png.FRowPtrs = NULL;
+ //my_png.Height = 0;
+ //my_png.Width = 0;
+ my_png.ColorType = PNG_COLOR_TYPE_RGB;
+ //my_png.Interlace = 0;
+ //my_png.Compression = 0;
+ //my_png.Filter = 0;
+ qpng_set_read_fn(png, ioBuffer, PNG_fReadData);
+ qpng_read_info(png, pnginfo);
+ qpng_get_IHDR(png, pnginfo, &my_png.Width, &my_png.Height,&my_png.BitDepth, &my_png.ColorType, &my_png.Interlace, &my_png.Compression, &my_png.Filter);
+ if ((matchwidth && my_png.Width != (unsigned int)matchwidth) || (matchheight && my_png.Height != (unsigned int)matchheight))
+ {
+ qpng_destroy_read_struct(&png, &pnginfo, 0);
+ return NULL;
+ }
+ if (my_png.ColorType == PNG_COLOR_TYPE_PALETTE)
+ qpng_set_palette_to_rgb(png);
+ if (my_png.ColorType == PNG_COLOR_TYPE_GRAY || my_png.ColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ qpng_set_gray_to_rgb(png);
+ if (my_png.BitDepth < 8)
+ qpng_set_gray_1_2_4_to_8(png);
+ }
+
+ if (qpng_get_valid(png, pnginfo, PNG_INFO_tRNS))
+ qpng_set_tRNS_to_alpha(png);
+ if (my_png.BitDepth == 8 && !(my_png.ColorType & PNG_COLOR_MASK_ALPHA))
+ qpng_set_filler(png, 255, 1);
+ if (( my_png.ColorType == PNG_COLOR_TYPE_GRAY) || (my_png.ColorType == PNG_COLOR_TYPE_GRAY_ALPHA ))
+ qpng_set_gray_to_rgb(png);
+ if (my_png.BitDepth < 8)
+ qpng_set_expand(png);
+
+ qpng_read_update_info(png, pnginfo);
+
+ my_png.FRowBytes = qpng_get_rowbytes(png, pnginfo);
+ my_png.BytesPerPixel = qpng_get_channels(png, pnginfo);
+
+ my_png.FRowPtrs = Mem_Alloc(tempmempool, my_png.Height * sizeof(*my_png.FRowPtrs));
+ if (my_png.FRowPtrs)
+ {
+ my_png.Data = Mem_Alloc(tempmempool, my_png.Height * my_png.FRowBytes);
+ if(my_png.Data)
+ {
+ for(y = 0;y < my_png.Height;y++)
+ my_png.FRowPtrs[y] = my_png.Data + y * my_png.FRowBytes;
+ qpng_read_image(png, my_png.FRowPtrs);
+ }
+ else
+ Con_DPrintf("PNG_LoadImage : not enough memory\n");
+ Mem_Free(my_png.FRowPtrs);
+ }
+ else
+ Con_DPrintf("PNG_LoadImage : not enough memory\n");
+
+ qpng_read_end(png, pnginfo);
+ qpng_destroy_read_struct(&png, &pnginfo, 0);
+
+ image_width = my_png.Width;
+ image_height = my_png.Height;
+ imagedata = my_png.Data;
+
+ if (my_png.BitDepth != 8)
+ {
+ Con_Printf ("PNG_LoadImage : bad color depth\n");
+ Mem_Free(imagedata);
+ imagedata = NULL;
+ }
+
+ return imagedata;
+}
+