From 6a75f042475ac3d601c0c85ce90f7e8cb05a11d3 Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 15 Jan 2006 20:20:51 +0000 Subject: [PATCH] added png support patch from [515] (had to rewrite most of it though) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5908 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_textures.c | 3 + image.c | 4 + image_png.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++ image_png.h | 32 +++++ makefile.inc | 1 + 5 files changed, 381 insertions(+) create mode 100644 image_png.c create mode 100644 image_png.h diff --git a/gl_textures.c b/gl_textures.c index 9fe27447..b59ff818 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -2,6 +2,7 @@ #include "quakedef.h" #include "image.h" #include "jpeg.h" +#include "image_png.h" cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048"}; cvar_t gl_max_scrapsize = {CVAR_SAVE, "gl_max_scrapsize", "256"}; @@ -506,6 +507,8 @@ static void r_textures_start(void) // Disable JPEG screenshots if the DLL isn't loaded if (! JPEG_OpenLibrary ()) Cvar_SetValueQuick (&scr_screenshot_jpeg, 0); + // TODO: support png screenshots? + PNG_OpenLibrary (); } static void r_textures_shutdown(void) diff --git a/image.c b/image.c index aeaca35c..fc73fd1b 100644 --- a/image.c +++ b/image.c @@ -2,6 +2,7 @@ #include "quakedef.h" #include "image.h" #include "jpeg.h" +#include "image_png.h" #include "r_shadow.h" int image_width; @@ -660,12 +661,15 @@ struct imageformat_s imageformats[] = { {"override/%s.tga", LoadTGA}, + {"override/%s.png", PNG_LoadImage}, {"override/%s.jpg", JPEG_LoadImage}, {"textures/%s.tga", LoadTGA}, + {"textures/%s.png", PNG_LoadImage}, {"textures/%s.jpg", JPEG_LoadImage}, {"textures/%s.pcx", LoadPCX}, {"textures/%s.wal", LoadWAL}, {"%s.tga", LoadTGA}, + {"%s.png", PNG_LoadImage}, {"%s.jpg", JPEG_LoadImage}, {"%s.pcx", LoadPCX}, {"%s.lmp", LoadLMPRGBA}, diff --git a/image_png.c b/image_png.c new file mode 100644 index 00000000..cbaddf3e --- /dev/null +++ b/image_png.c @@ -0,0 +1,341 @@ +/* + 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; +} + diff --git a/image_png.h b/image_png.h new file mode 100644 index 00000000..7862c845 --- /dev/null +++ b/image_png.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2006 Serge "(515)" Ziryukin + + 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 + +*/ + +#ifndef PNG_H +#define PNG_H + +qboolean PNG_OpenLibrary (void); +void PNG_CloseLibrary (void); +unsigned char* PNG_LoadImage (const unsigned char *f, int filesize, int matchwidth, int matchheight); + +#endif + diff --git a/makefile.inc b/makefile.inc index f5242a69..3996f070 100644 --- a/makefile.inc +++ b/makefile.inc @@ -84,6 +84,7 @@ OBJ_COMMON= \ host_cmd.o \ image.o \ jpeg.o \ + image_png.o \ keys.o \ lhnet.o \ mathlib.o \ -- 2.39.2