added png support patch from [515] (had to rewrite most of it though)
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 15 Jan 2006 20:20:51 +0000 (20:20 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 15 Jan 2006 20:20:51 +0000 (20:20 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5908 d7cf8633-e32d-0410-b094-e92efae38249

gl_textures.c
image.c
image_png.c [new file with mode: 0644]
image_png.h [new file with mode: 0644]
makefile.inc

index 9fe2744..b59ff81 100644 (file)
@@ -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 aeaca35..fc73fd1 100644 (file)
--- 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 (file)
index 0000000..cbaddf3
--- /dev/null
@@ -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 (file)
index 0000000..7862c84
--- /dev/null
@@ -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
+
index f5242a6..3996f07 100644 (file)
@@ -84,6 +84,7 @@ OBJ_COMMON= \
        host_cmd.o \
        image.o \
        jpeg.o \
+       image_png.o \
        keys.o \
        lhnet.o \
        mathlib.o \