r1132 - in trunk: . code/qcommon code/renderer

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Thu Aug 23 13:23:16 EDT 2007


Author: tma
Date: 2007-08-23 13:23:15 -0400 (Thu, 23 Aug 2007)
New Revision: 1132

Added:
   trunk/code/qcommon/puff.c
   trunk/code/qcommon/puff.h
Modified:
   trunk/Makefile
   trunk/README
   trunk/code/renderer/tr_image.c
Log:
* PNG support from Joerg Dietrich <dietrich_joerg at t-online.de>
* Cleanup of tabulation in R_LoadImage


Modified: trunk/Makefile
===================================================================
--- trunk/Makefile	2007-08-23 15:23:43 UTC (rev 1131)
+++ trunk/Makefile	2007-08-23 17:23:15 UTC (rev 1132)
@@ -945,6 +945,7 @@
   $(B)/client/q_shared.o \
   \
   $(B)/client/unzip.o \
+  $(B)/client/puff.o \
   $(B)/client/vm.o \
   $(B)/client/vm_interpreted.o \
   \

Modified: trunk/README
===================================================================
--- trunk/README	2007-08-23 15:23:43 UTC (rev 1131)
+++ trunk/README	2007-08-23 17:23:15 UTC (rev 1132)
@@ -6,7 +6,7 @@
                    |            |_|                        |
                    |                                       |
                    `---------- http://ioquake3.org --------'
-                                             
+
 The intent of this project is to provide a baseline Quake 3 which may be used
 for further development. Some of the major features currently implemented are:
 
@@ -27,6 +27,7 @@
   * HTTP/FTP download redirection (using cURL)
   * Multiuser support on Windows systems (user specific game data
     is stored in "%APPDATA%\Quake3")
+  * PNG support
   * Many, many bug fixes
 
 The map editor and associated compiling tools are not included. We suggest you
@@ -62,7 +63,7 @@
      XCode 2.2 and newer.
   2. Change to the directory containing this README file.
   3. Run './make-macosx-ub.sh'
-  4. Copy the resulting ioquake3.app in /build/release-darwin-ub to your 
+  4. Copy the resulting ioquake3.app in /build/release-darwin-ub to your
      /Applications/ioquake3 folder.
 
 Installation, for *nix
@@ -154,7 +155,7 @@
   cl_guidServerUniq                 - makes cl_guid unique for each server
   cl_cURLLib                        - filename of cURL library to load
   sv_dlURL                          - the base of the HTTP or FTP site that
-                                      holds custom pk3 files for your server 
+                                      holds custom pk3 files for your server
 
 New commands
   video [filename]        - start video capture (use with demo command)
@@ -215,7 +216,7 @@
 
   If cl_guidServerUniq is non-zero (the default), then this value is also
   pseudo-unique for each server a client connects to (based on IP:PORT of
-  the server). 
+  the server).
 
   The purpose of cl_guid is to add an identifier for each player on
   a server.  This value can be reset by the client at any time so it's not
@@ -223,7 +224,7 @@
   your mod's game code:
     1) improve logging to allow statistical tools to index players by more
        than just name
-    2) granting some weak admin rights to players without requiring passwords 
+    2) granting some weak admin rights to players without requiring passwords
 
 Using HTTP/FTP Download Support (Server)
   You can enable redirected downloads on your server even if it's not
@@ -248,7 +249,7 @@
   Server operators who are concerned about potential "leeching" from their
   HTTP servers from other ioquake3 servers can make use of the HTTP_REFERER
   that ioquake3 sets which is "ioQ3://{SERVER_IP}:{SERVER_PORT}".  For,
-  example, Apache's mod_rewrite can restrict access based on HTTP_REFERER. 
+  example, Apache's mod_rewrite can restrict access based on HTTP_REFERER.
 
 Using HTTP/FTP Download Support (Client)
   Simply setting cl_allowDownload to 1 will enable HTTP/FTP downloads
@@ -261,7 +262,7 @@
 
   When ioquake3 is built with USE_CURL_DLOPEN=1 (default on some platforms),
   it will use the value of the cvar cl_cURLLib as the filename of the cURL
-  library to dynamically load. 
+  library to dynamically load.
 
 Multiuser Support on Windows systems
   On Windows, all user specific files such as autogenerated configuration,
@@ -271,19 +272,19 @@
   On NT-based such as Windows XP, this is usually a directory named:
     "C:\Documents and Settings\%USERNAME%\Application Data\Quake3\"
 
-  Windows 95, Windows 98, and Windows ME will use a directory like: 
+  Windows 95, Windows 98, and Windows ME will use a directory like:
     "C:\Windows\Application Data\Quake3"
   in single-user mode, or:
     "C:\Windows\Profiles\%USERNAME%\Application Data\Quake3"
-  if multiple logins have been enabled. 
+  if multiple logins have been enabled.
 
   In order to access this directory more easily, the installer may create a
   Shortcut which has its target set to:
     "%APPDATA%\Quake3\"
   This Shortcut would work for all users on the system regardless of the
-  locale settings.  Unfortunately, this environment variable is only 
+  locale settings.  Unfortunately, this environment variable is only
   present on Windows NT based systems.
-  
+
   You can revert to the old single-user behaviour by setting the fs_homepath
   cvar to the directory where ioquake3 is installed.  For example:
     ioquake3.exe +set fs_homepath "c:\ioquake3"
@@ -294,7 +295,7 @@
   keyboard behaviour than the original Quake3 clients.
 
     * "Caps Lock" and "Num Lock" can not be used as normal binds since they
-      do not send a KEYUP event until the key is pressed again. 
+      do not send a KEYUP event until the key is pressed again.
 
     * SDL > 1.2.9 does not support disabling "Dead Key" recognition.
       In order to send "Dead Key" characters (e.g. ~, ', `, and ^), you
@@ -311,6 +312,12 @@
   annoying to use on many non-US keyboards.  In response, an additional
   toggleConsole bind has been added on the key combination Shift-Esc.
 
+PNG support
+  ioquake3 supports the use of PNG (Portable Network Graphic) images as
+  textures. It should be noted that the use of such images in a maps will
+  result in missing placeholder textures where the map is used with the id
+  Quake 3 client or earlier versions of ioquake3.
+
 ------------------------------------------------------------- Contributing -----
 
 Please send all patches to bugzilla (https://bugzilla.icculus.org), or join the

Added: trunk/code/qcommon/puff.c
===================================================================
--- trunk/code/qcommon/puff.c	                        (rev 0)
+++ trunk/code/qcommon/puff.c	2007-08-23 17:23:15 UTC (rev 1132)
@@ -0,0 +1,758 @@
+/*
+ *  This is a modified version of Mark Adlers work,
+ *  see below for the original copyright.
+ *  2006 - Joerg Dietrich <dietrich_joerg at gmx.de>
+ */
+
+/*
+ * puff.c
+ * Copyright (C) 2002-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in puff.h
+ * version 1.8, 9 Jan 2004
+ *
+ * puff.c is a simple inflate written to be an unambiguous way to specify the
+ * deflate format.  It is not written for speed but rather simplicity.  As a
+ * side benefit, this code might actually be useful when small code is more
+ * important than speed, such as bootstrap applications.  For typical deflate
+ * data, zlib's inflate() is about four times as fast as puff().  zlib's
+ * inflate compiles to around 20K on my machine, whereas puff.c compiles to
+ * around 4K on my machine (a PowerPC using GNU cc).  If the faster decode()
+ * function here is used, then puff() is only twice as slow as zlib's
+ * inflate().
+ *
+ * All dynamically allocated memory comes from the stack.  The stack required
+ * is less than 2K bytes.  This code is compatible with 16-bit int's and
+ * assumes that long's are at least 32 bits.  puff.c uses the short data type,
+ * assumed to be 16 bits, for arrays in order to to conserve memory.  The code
+ * works whether integers are stored big endian or little endian.
+ *
+ * In the comments below are "Format notes" that describe the inflate process
+ * and document some of the less obvious aspects of the format.  This source
+ * code is meant to supplement RFC 1951, which formally describes the deflate
+ * format:
+ *
+ *    http://www.zlib.org/rfc-deflate.html
+ */
+
+/*
+ * Change history:
+ *
+ * 1.0  10 Feb 2002     - First version
+ * 1.1  17 Feb 2002     - Clarifications of some comments and notes
+ *                      - Update puff() dest and source pointers on negative
+ *                        errors to facilitate debugging deflators
+ *                      - Remove longest from struct huffman -- not needed
+ *                      - Simplify offs[] index in construct()
+ *                      - Add input size and checking, using longjmp() to
+ *                        maintain easy readability
+ *                      - Use short data type for large arrays
+ *                      - Use pointers instead of long to specify source and
+ *                        destination sizes to avoid arbitrary 4 GB limits
+ * 1.2  17 Mar 2002     - Add faster version of decode(), doubles speed (!),
+ *                        but leave simple version for readabilty
+ *                      - Make sure invalid distances detected if pointers
+ *                        are 16 bits
+ *                      - Fix fixed codes table error
+ *                      - Provide a scanning mode for determining size of
+ *                        uncompressed data
+ * 1.3  20 Mar 2002     - Go back to lengths for puff() parameters [Jean-loup]
+ *                      - Add a puff.h file for the interface
+ *                      - Add braces in puff() for else do [Jean-loup]
+ *                      - Use indexes instead of pointers for readability
+ * 1.4  31 Mar 2002     - Simplify construct() code set check
+ *                      - Fix some comments
+ *                      - Add FIXLCODES #define
+ * 1.5   6 Apr 2002     - Minor comment fixes
+ * 1.6   7 Aug 2002     - Minor format changes
+ * 1.7   3 Mar 2003     - Added test code for distribution
+ *                      - Added zlib-like license
+ * 1.8   9 Jan 2004     - Added some comments on no distance codes case
+ */
+
+#include <setjmp.h>             /* for setjmp(), longjmp(), and jmp_buf */
+#include "puff.h"		/* prototype for puff() */
+
+#define local static            /* for local function definitions */
+
+/*
+ * Maximums for allocations and loops.  It is not useful to change these --
+ * they are fixed by the deflate format.
+ */
+#define MAXBITS 15              /* maximum bits in a code */
+#define MAXLCODES 286           /* maximum number of literal/length codes */
+#define MAXDCODES 30            /* maximum number of distance codes */
+#define MAXCODES (MAXLCODES+MAXDCODES)  /* maximum codes lengths to read */
+#define FIXLCODES 288           /* number of fixed literal/length codes */
+
+/* input and output state */
+struct state {
+    /* output state */
+    uint8_t *out;         /* output buffer */
+    uint32_t outlen;       /* available space at out */
+    uint32_t outcnt;       /* bytes written to out so far */
+
+    /* input state */
+    uint8_t *in;          /* input buffer */
+    uint32_t inlen;        /* available input at in */
+    uint32_t incnt;        /* bytes read so far */
+    int32_t bitbuf;                 /* bit buffer */
+    int32_t bitcnt;                 /* number of bits in bit buffer */
+
+    /* input limit error return state for bits() and decode() */
+    jmp_buf env;
+};
+
+/*
+ * Return need bits from the input stream.  This always leaves less than
+ * eight bits in the buffer.  bits() works properly for need == 0.
+ *
+ * Format notes:
+ *
+ * - Bits are stored in bytes from the least significant bit to the most
+ *   significant bit.  Therefore bits are dropped from the bottom of the bit
+ *   buffer, using shift right, and new bytes are appended to the top of the
+ *   bit buffer, using shift left.
+ */
+local int32_t bits(struct state *s, int32_t need)
+{
+    int32_t val;           /* bit accumulator (can use up to 20 bits) */
+
+    /* load at least need bits into val */
+    val = s->bitbuf;
+    while (s->bitcnt < need) {
+        if (s->incnt == s->inlen) longjmp(s->env, 1);   /* out of input */
+        val |= (int32_t)(s->in[s->incnt++]) << s->bitcnt;  /* load eight bits */
+        s->bitcnt += 8;
+    }
+
+    /* drop need bits and update buffer, always zero to seven bits left */
+    s->bitbuf = (int32_t)(val >> need);
+    s->bitcnt -= need;
+
+    /* return need bits, zeroing the bits above that */
+    return (int32_t)(val & ((1L << need) - 1));
+}
+
+/*
+ * Process a stored block.
+ *
+ * Format notes:
+ *
+ * - After the two-bit stored block type (00), the stored block length and
+ *   stored bytes are byte-aligned for fast copying.  Therefore any leftover
+ *   bits in the byte that has the last bit of the type, as many as seven, are
+ *   discarded.  The value of the discarded bits are not defined and should not
+ *   be checked against any expectation.
+ *
+ * - The second inverted copy of the stored block length does not have to be
+ *   checked, but it's probably a good idea to do so anyway.
+ *
+ * - A stored block can have zero length.  This is sometimes used to byte-align
+ *   subsets of the compressed data for random access or partial recovery.
+ */
+local int32_t stored(struct state *s)
+{
+    uint32_t len;       /* length of stored block */
+
+    /* discard leftover bits from current byte (assumes s->bitcnt < 8) */
+    s->bitbuf = 0;
+    s->bitcnt = 0;
+
+    /* get length and check against its one's complement */
+    if (s->incnt + 4 > s->inlen) return 2;      /* not enough input */
+    len = s->in[s->incnt++];
+    len |= s->in[s->incnt++] << 8;
+    if (s->in[s->incnt++] != (~len & 0xff) ||
+        s->in[s->incnt++] != ((~len >> 8) & 0xff))
+        return -2;                              /* didn't match complement! */
+
+    /* copy len bytes from in to out */
+    if (s->incnt + len > s->inlen) return 2;    /* not enough input */
+    if (s->out != NULL) {
+        if (s->outcnt + len > s->outlen)
+            return 1;                           /* not enough output space */
+        while (len--)
+            s->out[s->outcnt++] = s->in[s->incnt++];
+    }
+    else {                                      /* just scanning */
+        s->outcnt += len;
+        s->incnt += len;
+    }
+
+    /* done with a valid stored block */
+    return 0;
+}
+
+/*
+ * Huffman code decoding tables.  count[1..MAXBITS] is the number of symbols of
+ * each length, which for a canonical code are stepped through in order.
+ * symbol[] are the symbol values in canonical order, where the number of
+ * entries is the sum of the counts in count[].  The decoding process can be
+ * seen in the function decode() below.
+ */
+struct huffman {
+    int16_t *count;       /* number of symbols of each length */
+    int16_t *symbol;      /* canonically ordered symbols */
+};
+
+/*
+ * Decode a code from the stream s using huffman table h.  Return the symbol or
+ * a negative value if there is an error.  If all of the lengths are zero, i.e.
+ * an empty code, or if the code is incomplete and an invalid code is received,
+ * then -9 is returned after reading MAXBITS bits.
+ *
+ * Format notes:
+ *
+ * - The codes as stored in the compressed data are bit-reversed relative to
+ *   a simple integer ordering of codes of the same lengths.  Hence below the
+ *   bits are pulled from the compressed data one at a time and used to
+ *   build the code value reversed from what is in the stream in order to
+ *   permit simple integer comparisons for decoding.  A table-based decoding
+ *   scheme (as used in zlib) does not need to do this reversal.
+ *
+ * - The first code for the shortest length is all zeros.  Subsequent codes of
+ *   the same length are simply integer increments of the previous code.  When
+ *   moving up a length, a zero bit is appended to the code.  For a complete
+ *   code, the last code of the longest length will be all ones.
+ *
+ * - Incomplete codes are handled by this decoder, since they are permitted
+ *   in the deflate format.  See the format notes for fixed() and dynamic().
+ */
+local int32_t decode(struct state *s, struct huffman *h)
+{
+    int32_t len;            /* current number of bits in code */
+    int32_t code;           /* len bits being decoded */
+    int32_t first;          /* first code of length len */
+    int32_t count;          /* number of codes of length len */
+    int32_t index;          /* index of first code of length len in symbol table */
+    int32_t bitbuf;         /* bits from stream */
+    int32_t left;           /* bits left in next or left to process */
+    int16_t *next;        /* next number of codes */
+
+    bitbuf = s->bitbuf;
+    left = s->bitcnt;
+    code = first = index = 0;
+    len = 1;
+    next = h->count + 1;
+    while (1) {
+        while (left--) {
+            code |= bitbuf & 1;
+            bitbuf >>= 1;
+            count = *next++;
+            if (code < first + count) { /* if length len, return symbol */
+                s->bitbuf = bitbuf;
+                s->bitcnt = (s->bitcnt - len) & 7;
+                return h->symbol[index + (code - first)];
+            }
+            index += count;             /* else update for next length */
+            first += count;
+            first <<= 1;
+            code <<= 1;
+            len++;
+        }
+        left = (MAXBITS+1) - len;
+        if (left == 0) break;
+        if (s->incnt == s->inlen) longjmp(s->env, 1);   /* out of input */
+        bitbuf = s->in[s->incnt++];
+        if (left > 8) left = 8;
+    }
+    return -9;                          /* ran out of codes */
+}
+
+/*
+ * Given the list of code lengths length[0..n-1] representing a canonical
+ * Huffman code for n symbols, construct the tables required to decode those
+ * codes.  Those tables are the number of codes of each length, and the symbols
+ * sorted by length, retaining their original order within each length.  The
+ * return value is zero for a complete code set, negative for an over-
+ * subscribed code set, and positive for an incomplete code set.  The tables
+ * can be used if the return value is zero or positive, but they cannot be used
+ * if the return value is negative.  If the return value is zero, it is not
+ * possible for decode() using that table to return an error--any stream of
+ * enough bits will resolve to a symbol.  If the return value is positive, then
+ * it is possible for decode() using that table to return an error for received
+ * codes past the end of the incomplete lengths.
+ *
+ * Not used by decode(), but used for error checking, h->count[0] is the number
+ * of the n symbols not in the code.  So n - h->count[0] is the number of
+ * codes.  This is useful for checking for incomplete codes that have more than
+ * one symbol, which is an error in a dynamic block.
+ *
+ * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS
+ * This is assured by the construction of the length arrays in dynamic() and
+ * fixed() and is not verified by construct().
+ *
+ * Format notes:
+ *
+ * - Permitted and expected examples of incomplete codes are one of the fixed
+ *   codes and any code with a single symbol which in deflate is coded as one
+ *   bit instead of zero bits.  See the format notes for fixed() and dynamic().
+ *
+ * - Within a given code length, the symbols are kept in ascending order for
+ *   the code bits definition.
+ */
+local int32_t construct(struct huffman *h, int16_t *length, int32_t n)
+{
+    int32_t symbol;         /* current symbol when stepping through length[] */
+    int32_t len;            /* current length when stepping through h->count[] */
+    int32_t left;           /* number of possible codes left of current length */
+    int16_t offs[MAXBITS+1];      /* offsets in symbol table for each length */
+
+    /* count number of codes of each length */
+    for (len = 0; len <= MAXBITS; len++)
+        h->count[len] = 0;
+    for (symbol = 0; symbol < n; symbol++)
+        (h->count[length[symbol]])++;   /* assumes lengths are within bounds */
+    if (h->count[0] == n)               /* no codes! */
+        return 0;                       /* complete, but decode() will fail */
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;                           /* one possible code of zero length */
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;                     /* one more bit, double codes left */
+        left -= h->count[len];          /* deduct count from possible codes */
+        if (left < 0) return left;      /* over-subscribed--return negative */
+    }                                   /* left > 0 means incomplete */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + h->count[len];
+
+    /*
+     * put symbols in table sorted by length, by symbol order within each
+     * length
+     */
+    for (symbol = 0; symbol < n; symbol++)
+        if (length[symbol] != 0)
+            h->symbol[offs[length[symbol]]++] = symbol;
+
+    /* return zero for complete set, positive for incomplete set */
+    return left;
+}
+
+/*
+ * Decode literal/length and distance codes until an end-of-block code.
+ *
+ * Format notes:
+ *
+ * - Compressed data that is after the block type if fixed or after the code
+ *   description if dynamic is a combination of literals and length/distance
+ *   pairs terminated by and end-of-block code.  Literals are simply Huffman
+ *   coded bytes.  A length/distance pair is a coded length followed by a
+ *   coded distance to represent a string that occurs earlier in the
+ *   uncompressed data that occurs again at the current location.
+ *
+ * - Literals, lengths, and the end-of-block code are combined into a single
+ *   code of up to 286 symbols.  They are 256 literals (0..255), 29 length
+ *   symbols (257..285), and the end-of-block symbol (256).
+ *
+ * - There are 256 possible lengths (3..258), and so 29 symbols are not enough
+ *   to represent all of those.  Lengths 3..10 and 258 are in fact represented
+ *   by just a length symbol.  Lengths 11..257 are represented as a symbol and
+ *   some number of extra bits that are added as an integer to the base length
+ *   of the length symbol.  The number of extra bits is determined by the base
+ *   length symbol.  These are in the static arrays below, lens[] for the base
+ *   lengths and lext[] for the corresponding number of extra bits.
+ *
+ * - The reason that 258 gets its own symbol is that the longest length is used
+ *   often in highly redundant files.  Note that 258 can also be coded as the
+ *   base value 227 plus the maximum extra value of 31.  While a good deflate
+ *   should never do this, it is not an error, and should be decoded properly.
+ *
+ * - If a length is decoded, including its extra bits if any, then it is
+ *   followed a distance code.  There are up to 30 distance symbols.  Again
+ *   there are many more possible distances (1..32768), so extra bits are added
+ *   to a base value represented by the symbol.  The distances 1..4 get their
+ *   own symbol, but the rest require extra bits.  The base distances and
+ *   corresponding number of extra bits are below in the static arrays dist[]
+ *   and dext[].
+ *
+ * - Literal bytes are simply written to the output.  A length/distance pair is
+ *   an instruction to copy previously uncompressed bytes to the output.  The
+ *   copy is from distance bytes back in the output stream, copying for length
+ *   bytes.
+ *
+ * - Distances pointing before the beginning of the output data are not
+ *   permitted.
+ *
+ * - Overlapped copies, where the length is greater than the distance, are
+ *   allowed and common.  For example, a distance of one and a length of 258
+ *   simply copies the last byte 258 times.  A distance of four and a length of
+ *   twelve copies the last four bytes three times.  A simple forward copy
+ *   ignoring whether the length is greater than the distance or not implements
+ *   this correctly.  You should not use memcpy() since its behavior is not
+ *   defined for overlapped arrays.  You should not use memmove() or bcopy()
+ *   since though their behavior -is- defined for overlapping arrays, it is
+ *   defined to do the wrong thing in this case.
+ */
+local int32_t codes(struct state *s,
+                struct huffman *lencode,
+                struct huffman *distcode)
+{
+    int32_t symbol;         /* decoded symbol */
+    int32_t len;            /* length for copy */
+    uint32_t dist;          /* distance for copy */
+    static const int16_t lens[29] = { /* Size base for length codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
+    static const int16_t lext[29] = { /* Extra bits for length codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
+    static const int16_t dists[30] = { /* Offset base for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+    static const int16_t dext[30] = { /* Extra bits for distance codes 0..29 */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+    /* decode literals and length/distance pairs */
+    do {
+        symbol = decode(s, lencode);
+        if (symbol < 0) return symbol;  /* invalid symbol */
+        if (symbol < 256) {             /* literal: symbol is the byte */
+            /* write out the literal */
+            if (s->out != NULL) {
+                if (s->outcnt == s->outlen) return 1;
+                s->out[s->outcnt] = symbol;
+            }
+            s->outcnt++;
+        }
+        else if (symbol > 256) {        /* length */
+            /* get and compute length */
+            symbol -= 257;
+            if (symbol >= 29) return -9;        /* invalid fixed code */
+            len = lens[symbol] + bits(s, lext[symbol]);
+
+            /* get and check distance */
+            symbol = decode(s, distcode);
+            if (symbol < 0) return symbol;      /* invalid symbol */
+            dist = dists[symbol] + bits(s, dext[symbol]);
+            if (dist > s->outcnt)
+                return -10;     /* distance too far back */
+
+            /* copy length bytes from distance bytes back */
+            if (s->out != NULL) {
+                if (s->outcnt + len > s->outlen) return 1;
+                while (len--) {
+                    s->out[s->outcnt] = s->out[s->outcnt - dist];
+                    s->outcnt++;
+                }
+            }
+            else
+                s->outcnt += len;
+        }
+    } while (symbol != 256);            /* end of block symbol */
+
+    /* done with a valid fixed or dynamic block */
+    return 0;
+}
+
+/*
+ * Process a fixed codes block.
+ *
+ * Format notes:
+ *
+ * - This block type can be useful for compressing small amounts of data for
+ *   which the size of the code descriptions in a dynamic block exceeds the
+ *   benefit of custom codes for that block.  For fixed codes, no bits are
+ *   spent on code descriptions.  Instead the code lengths for literal/length
+ *   codes and distance codes are fixed.  The specific lengths for each symbol
+ *   can be seen in the "for" loops below.
+ *
+ * - The literal/length code is complete, but has two symbols that are invalid
+ *   and should result in an error if received.  This cannot be implemented
+ *   simply as an incomplete code since those two symbols are in the "middle"
+ *   of the code.  They are eight bits long and the longest literal/length\
+ *   code is nine bits.  Therefore the code must be constructed with those
+ *   symbols, and the invalid symbols must be detected after decoding.
+ *
+ * - The fixed distance codes also have two invalid symbols that should result
+ *   in an error if received.  Since all of the distance codes are the same
+ *   length, this can be implemented as an incomplete code.  Then the invalid
+ *   codes are detected while decoding.
+ */
+local int32_t fixed(struct state *s)
+{
+    static int32_t virgin = 1;
+    static int16_t lencnt[MAXBITS+1], lensym[FIXLCODES];
+    static int16_t distcnt[MAXBITS+1], distsym[MAXDCODES];
+    static struct huffman lencode = {lencnt, lensym};
+    static struct huffman distcode = {distcnt, distsym};
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        int32_t symbol;
+        int16_t lengths[FIXLCODES];
+
+        /* literal/length table */
+        for (symbol = 0; symbol < 144; symbol++)
+            lengths[symbol] = 8;
+        for (; symbol < 256; symbol++)
+            lengths[symbol] = 9;
+        for (; symbol < 280; symbol++)
+            lengths[symbol] = 7;
+        for (; symbol < FIXLCODES; symbol++)
+            lengths[symbol] = 8;
+        construct(&lencode, lengths, FIXLCODES);
+
+        /* distance table */
+        for (symbol = 0; symbol < MAXDCODES; symbol++)
+            lengths[symbol] = 5;
+        construct(&distcode, lengths, MAXDCODES);
+
+        /* do this just once */
+        virgin = 0;
+    }
+
+    /* decode data until end-of-block code */
+    return codes(s, &lencode, &distcode);
+}
+
+/*
+ * Process a dynamic codes block.
+ *
+ * Format notes:
+ *
+ * - A dynamic block starts with a description of the literal/length and
+ *   distance codes for that block.  New dynamic blocks allow the compressor to
+ *   rapidly adapt to changing data with new codes optimized for that data.
+ *
+ * - The codes used by the deflate format are "canonical", which means that
+ *   the actual bits of the codes are generated in an unambiguous way simply
+ *   from the number of bits in each code.  Therefore the code descriptions
+ *   are simply a list of code lengths for each symbol.
+ *
+ * - The code lengths are stored in order for the symbols, so lengths are
+ *   provided for each of the literal/length symbols, and for each of the
+ *   distance symbols.
+ *
+ * - If a symbol is not used in the block, this is represented by a zero as
+ *   as the code length.  This does not mean a zero-length code, but rather
+ *   that no code should be created for this symbol.  There is no way in the
+ *   deflate format to represent a zero-length code.
+ *
+ * - The maximum number of bits in a code is 15, so the possible lengths for
+ *   any code are 1..15.
+ *
+ * - The fact that a length of zero is not permitted for a code has an
+ *   interesting consequence.  Normally if only one symbol is used for a given
+ *   code, then in fact that code could be represented with zero bits.  However
+ *   in deflate, that code has to be at least one bit.  So for example, if
+ *   only a single distance base symbol appears in a block, then it will be
+ *   represented by a single code of length one, in particular one 0 bit.  This
+ *   is an incomplete code, since if a 1 bit is received, it has no meaning,
+ *   and should result in an error.  So incomplete distance codes of one symbol
+ *   should be permitted, and the receipt of invalid codes should be handled.
+ *
+ * - It is also possible to have a single literal/length code, but that code
+ *   must be the end-of-block code, since every dynamic block has one.  This
+ *   is not the most efficient way to create an empty block (an empty fixed
+ *   block is fewer bits), but it is allowed by the format.  So incomplete
+ *   literal/length codes of one symbol should also be permitted.
+ *
+ * - If there are only literal codes and no lengths, then there are no distance
+ *   codes.  This is represented by one distance code with zero bits.
+ *
+ * - The list of up to 286 length/literal lengths and up to 30 distance lengths
+ *   are themselves compressed using Huffman codes and run-length encoding.  In
+ *   the list of code lengths, a 0 symbol means no code, a 1..15 symbol means
+ *   that length, and the symbols 16, 17, and 18 are run-length instructions.
+ *   Each of 16, 17, and 18 are follwed by extra bits to define the length of
+ *   the run.  16 copies the last length 3 to 6 times.  17 represents 3 to 10
+ *   zero lengths, and 18 represents 11 to 138 zero lengths.  Unused symbols
+ *   are common, hence the special coding for zero lengths.
+ *
+ * - The symbols for 0..18 are Huffman coded, and so that code must be
+ *   described first.  This is simply a sequence of up to 19 three-bit values
+ *   representing no code (0) or the code length for that symbol (1..7).
+ *
+ * - A dynamic block starts with three fixed-size counts from which is computed
+ *   the number of literal/length code lengths, the number of distance code
+ *   lengths, and the number of code length code lengths (ok, you come up with
+ *   a better name!) in the code descriptions.  For the literal/length and
+ *   distance codes, lengths after those provided are considered zero, i.e. no
+ *   code.  The code length code lengths are received in a permuted order (see
+ *   the order[] array below) to make a short code length code length list more
+ *   likely.  As it turns out, very short and very long codes are less likely
+ *   to be seen in a dynamic code description, hence what may appear initially
+ *   to be a peculiar ordering.
+ *
+ * - Given the number of literal/length code lengths (nlen) and distance code
+ *   lengths (ndist), then they are treated as one long list of nlen + ndist
+ *   code lengths.  Therefore run-length coding can and often does cross the
+ *   boundary between the two sets of lengths.
+ *
+ * - So to summarize, the code description at the start of a dynamic block is
+ *   three counts for the number of code lengths for the literal/length codes,
+ *   the distance codes, and the code length codes.  This is followed by the
+ *   code length code lengths, three bits each.  This is used to construct the
+ *   code length code which is used to read the remainder of the lengths.  Then
+ *   the literal/length code lengths and distance lengths are read as a single
+ *   set of lengths using the code length codes.  Codes are constructed from
+ *   the resulting two sets of lengths, and then finally you can start
+ *   decoding actual compressed data in the block.
+ *
+ * - For reference, a "typical" size for the code description in a dynamic
+ *   block is around 80 bytes.
+ */
+local int32_t dynamic(struct state *s)
+{
+    int32_t nlen, ndist, ncode;             /* number of lengths in descriptor */
+    int32_t index;                          /* index of lengths[] */
+    int32_t err;                            /* construct() return value */
+    int16_t lengths[MAXCODES];            /* descriptor code lengths */
+    int16_t lencnt[MAXBITS+1], lensym[MAXLCODES];         /* lencode memory */
+    int16_t distcnt[MAXBITS+1], distsym[MAXDCODES];       /* distcode memory */
+    struct huffman lencode = {lencnt, lensym};          /* length code */
+    struct huffman distcode = {distcnt, distsym};       /* distance code */
+    static const int16_t order[19] =      /* permutation of code length codes */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    /* get number of lengths in each table, check lengths */
+    nlen = bits(s, 5) + 257;
+    ndist = bits(s, 5) + 1;
+    ncode = bits(s, 4) + 4;
+    if (nlen > MAXLCODES || ndist > MAXDCODES)
+        return -3;                      /* bad counts */
+
+    /* read code length code lengths (really), missing lengths are zero */
+    for (index = 0; index < ncode; index++)
+        lengths[order[index]] = bits(s, 3);
+    for (; index < 19; index++)
+        lengths[order[index]] = 0;
+
+    /* build huffman table for code lengths codes (use lencode temporarily) */
+    err = construct(&lencode, lengths, 19);
+    if (err != 0) return -4;            /* require complete code set here */
+
+    /* read length/literal and distance code length tables */
+    index = 0;
+    while (index < nlen + ndist) {
+        int32_t symbol;             /* decoded value */
+        int32_t len;                /* last length to repeat */
+
+        symbol = decode(s, &lencode);
+        if (symbol < 16)                /* length in 0..15 */
+            lengths[index++] = symbol;
+        else {                          /* repeat instruction */
+            len = 0;                    /* assume repeating zeros */
+            if (symbol == 16) {         /* repeat last length 3..6 times */
+                if (index == 0) return -5;      /* no last length! */
+                len = lengths[index - 1];       /* last length */
+                symbol = 3 + bits(s, 2);
+            }
+            else if (symbol == 17)      /* repeat zero 3..10 times */
+                symbol = 3 + bits(s, 3);
+            else                        /* == 18, repeat zero 11..138 times */
+                symbol = 11 + bits(s, 7);
+            if (index + symbol > nlen + ndist)
+                return -6;              /* too many lengths! */
+            while (symbol--)            /* repeat last or zero symbol times */
+                lengths[index++] = len;
+        }
+    }
+
+    /* build huffman table for literal/length codes */
+    err = construct(&lencode, lengths, nlen);
+    if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
+        return -7;      /* only allow incomplete codes if just one code */
+
+    /* build huffman table for distance codes */
+    err = construct(&distcode, lengths + nlen, ndist);
+    if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
+        return -8;      /* only allow incomplete codes if just one code */
+
+    /* decode data until end-of-block code */
+    return codes(s, &lencode, &distcode);
+}
+
+/*
+ * Inflate source to dest.  On return, destlen and sourcelen are updated to the
+ * size of the uncompressed data and the size of the deflate data respectively.
+ * On success, the return value of puff() is zero.  If there is an error in the
+ * source data, i.e. it is not in the deflate format, then a negative value is
+ * returned.  If there is not enough input available or there is not enough
+ * output space, then a positive error is returned.  In that case, destlen and
+ * sourcelen are not updated to facilitate retrying from the beginning with the
+ * provision of more input data or more output space.  In the case of invalid
+ * inflate data (a negative error), the dest and source pointers are updated to
+ * facilitate the debugging of deflators.
+ *
+ * puff() also has a mode to determine the size of the uncompressed output with
+ * no output written.  For this dest must be (uint8_t *)0.  In this case,
+ * the input value of *destlen is ignored, and on return *destlen is set to the
+ * size of the uncompressed output.
+ *
+ * The return codes are:
+ *
+ *   2:  available inflate data did not terminate
+ *   1:  output space exhausted before completing inflate
+ *   0:  successful inflate
+ *  -1:  invalid block type (type == 3)
+ *  -2:  stored block length did not match one's complement
+ *  -3:  dynamic block code description: too many length or distance codes
+ *  -4:  dynamic block code description: code lengths codes incomplete
+ *  -5:  dynamic block code description: repeat lengths with no first length
+ *  -6:  dynamic block code description: repeat more than specified lengths
+ *  -7:  dynamic block code description: invalid literal/length code lengths
+ *  -8:  dynamic block code description: invalid distance code lengths
+ *  -9:  invalid literal/length or distance code in fixed or dynamic block
+ * -10:  distance is too far back in fixed or dynamic block
+ *
+ * Format notes:
+ *
+ * - Three bits are read for each block to determine the kind of block and
+ *   whether or not it is the last block.  Then the block is decoded and the
+ *   process repeated if it was not the last block.
+ *
+ * - The leftover bits in the last byte of the deflate data after the last
+ *   block (if it was a fixed or dynamic block) are undefined and have no
+ *   expected values to check.
+ */
+int32_t puff(uint8_t  *dest,           /* pointer to destination pointer */
+             uint32_t *destlen,        /* amount of output space */
+             uint8_t  *source,         /* pointer to source data pointer */
+             uint32_t *sourcelen)      /* amount of input available */
+{
+    struct state s;             /* input/output state */
+    int32_t last, type;             /* block information */
+    int32_t err;                    /* return value */
+
+    /* initialize output state */
+    s.out = dest;
+    s.outlen = *destlen;                /* ignored if dest is NULL */
+    s.outcnt = 0;
+
+    /* initialize input state */
+    s.in = source;
+    s.inlen = *sourcelen;
+    s.incnt = 0;
+    s.bitbuf = 0;
+    s.bitcnt = 0;
+
+    /* return if bits() or decode() tries to read past available input */
+    if (setjmp(s.env) != 0)             /* if came back here via longjmp() */
+        err = 2;                        /* then skip do-loop, return error */
+    else {
+        /* process blocks until last block or error */
+        do {
+            last = bits(&s, 1);         /* one if last block */
+            type = bits(&s, 2);         /* block type 0..3 */
+            err = type == 0 ? stored(&s) :
+                  (type == 1 ? fixed(&s) :
+                   (type == 2 ? dynamic(&s) :
+                    -1));               /* type == 3, invalid */
+            if (err != 0) break;        /* return with error */
+        } while (!last);
+    }
+
+    /* update the lengths and return */
+    if (err <= 0) {
+        *destlen = s.outcnt;
+        *sourcelen = s.incnt;
+    }
+    return err;
+}

Added: trunk/code/qcommon/puff.h
===================================================================
--- trunk/code/qcommon/puff.h	                        (rev 0)
+++ trunk/code/qcommon/puff.h	2007-08-23 17:23:15 UTC (rev 1132)
@@ -0,0 +1,43 @@
+/*
+ *  This is a modified version of Mark Adlers work,
+ *  see below for the original copyright.
+ *  2006 - Joerg Dietrich <dietrich_joerg at gmx.de>
+ */
+
+/* puff.h
+  Copyright (C) 2002, 2003 Mark Adler, all rights reserved
+  version 1.7, 3 Mar 2002
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the author be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Mark Adler    madler at alumni.caltech.edu
+ */
+
+#ifndef __PUFF_H
+#define __PUFF_H
+
+#include "q_shared.h"			/* for definitions of the <stdint.h> types */
+
+/*
+ * See puff.c for purpose and usage.
+ */
+int32_t puff(uint8_t  *dest,		/* pointer to destination pointer */
+             uint32_t *destlen,		/* amount of output space */
+             uint8_t  *source,		/* pointer to source data pointer */
+             uint32_t *sourcelen);	/* amount of input available */
+
+#endif // __PUFF_H

Modified: trunk/code/renderer/tr_image.c
===================================================================
--- trunk/code/renderer/tr_image.c	2007-08-23 15:23:43 UTC (rev 1131)
+++ trunk/code/renderer/tr_image.c	2007-08-23 17:23:15 UTC (rev 1132)
@@ -33,10 +33,13 @@
 #define JPEG_INTERNALS
 #include "../jpeg-6/jpeglib.h"
 
+#include "../qcommon/puff.h"
 
+
 static void LoadBMP( const char *name, byte **pic, int *width, int *height );
 static void LoadTGA( const char *name, byte **pic, int *width, int *height );
 static void LoadJPG( const char *name, byte **pic, int *width, int *height );
+static void LoadPNG( const char *name, byte **pic, int *width, int *height );
 
 static byte			 s_intensitytable[256];
 static unsigned char s_gammatable[256];
@@ -1931,6 +1934,2450 @@
 
 /*
 =================
+PNG LOADING
+=================
+*/
+
+/*
+ *  Quake 3 image format : RGBA
+ */
+
+#define Q3IMAGE_BYTESPERPIXEL (4)
+
+/*
+ *  PNG specifications
+ */
+
+/*
+ *  The first 8 Bytes of every PNG-File are a fixed signature
+ *  to identify the file as a PNG.
+ */
+
+#define PNG_Signature "\x89\x50\x4E\x47\xD\xA\x1A\xA"
+#define PNG_Signature_Size (8)
+
+/*
+ *  After the signature diverse chunks follow.
+ *  A chunk consists of a header and if Length
+ *  is bigger than 0 a body and a CRC of the body follow.
+ */
+
+struct PNG_ChunkHeader
+{
+    uint32_t Length;
+    uint32_t Type;
+};
+
+#define PNG_ChunkHeader_Size (8)
+
+typedef uint32_t PNG_ChunkCRC;
+
+#define PNG_ChunkCRC_Size (4)
+
+/*
+ *  We use the following ChunkTypes.
+ *  All others are ignored.
+ */
+
+#define MAKE_CHUNKTYPE(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | ((d)))
+
+#define PNG_ChunkType_IHDR MAKE_CHUNKTYPE('I', 'H', 'D', 'R')
+#define PNG_ChunkType_PLTE MAKE_CHUNKTYPE('P', 'L', 'T', 'E')
+#define PNG_ChunkType_IDAT MAKE_CHUNKTYPE('I', 'D', 'A', 'T')
+#define PNG_ChunkType_IEND MAKE_CHUNKTYPE('I', 'E', 'N', 'D')
+#define PNG_ChunkType_tRNS MAKE_CHUNKTYPE('t', 'R', 'N', 'S')
+
+/*
+ *  Per specification the first chunk after the signature SHALL be IHDR.
+ */
+
+struct PNG_Chunk_IHDR
+{
+    uint32_t Width;
+    uint32_t Height;
+    uint8_t  BitDepth;
+    uint8_t  ColourType;
+    uint8_t  CompressionMethod;
+    uint8_t  FilterMethod;
+    uint8_t  InterlaceMethod;
+};
+
+#define PNG_Chunk_IHDR_Size (13)
+
+/*
+ *  ColourTypes
+ */
+
+#define PNG_ColourType_Grey      (0)
+#define PNG_ColourType_True      (2)
+#define PNG_ColourType_Indexed   (3)
+#define PNG_ColourType_GreyAlpha (4)
+#define PNG_ColourType_TrueAlpha (6)
+
+/*
+ *  number of colour components
+ *
+ *  Grey      : 1 grey
+ *  True      : 1 R, 1 G, 1 B
+ *  Indexed   : 1 index
+ *  GreyAlpha : 1 grey, 1 alpha
+ *  TrueAlpha : 1 R, 1 G, 1 B, 1 alpha
+ */
+
+#define PNG_NumColourComponents_Grey      (1)
+#define PNG_NumColourComponents_True      (3)
+#define PNG_NumColourComponents_Indexed   (1)
+#define PNG_NumColourComponents_GreyAlpha (2)
+#define PNG_NumColourComponents_TrueAlpha (4)
+
+/*
+ *  For the different ColourTypes
+ *  different BitDepths are specified.
+ */
+
+#define PNG_BitDepth_1  ( 1)
+#define PNG_BitDepth_2  ( 2)
+#define PNG_BitDepth_4  ( 4)
+#define PNG_BitDepth_8  ( 8)
+#define PNG_BitDepth_16 (16)
+
+/*
+ *  Only one valid CompressionMethod is standardized.
+ */
+
+#define PNG_CompressionMethod_0 (0)
+
+/*
+ *  Only one valid FilterMethod is currently standardized.
+ */
+
+#define PNG_FilterMethod_0 (0)
+
+/*
+ *  This FilterMethod defines 5 FilterTypes
+ */
+
+#define PNG_FilterType_None    (0)
+#define PNG_FilterType_Sub     (1)
+#define PNG_FilterType_Up      (2)
+#define PNG_FilterType_Average (3)
+#define PNG_FilterType_Paeth   (4)
+
+/*
+ *  Two InterlaceMethods are standardized :
+ *  0 - NonInterlaced
+ *  1 - Interlaced
+ */
+
+#define PNG_InterlaceMethod_NonInterlaced (0)
+#define PNG_InterlaceMethod_Interlaced    (1)
+
+/*
+ *  The Adam7 interlace method uses 7 passes.
+ */
+
+#define PNG_Adam7_NumPasses (7)
+
+/*
+ *  The compressed data starts with a header ...
+ */
+
+struct PNG_ZlibHeader
+{
+    uint8_t CompressionMethod;
+    uint8_t Flags;
+};
+
+#define PNG_ZlibHeader_Size (2)
+
+/*
+ *  ... and is followed by a check value
+ */
+
+#define PNG_ZlibCheckValue_Size (4)
+
+/*
+ *  Some support functions for buffered files follow.
+ */
+
+/*
+ *  buffered file representation
+ */
+
+struct BufferedFile
+{
+    byte *Buffer;
+    int   Length;
+    byte *Ptr;
+    int   BytesLeft;
+};
+
+/*
+ *  Read a file into a buffer.
+ */
+
+static struct BufferedFile *ReadBufferedFile(const char *name)
+{
+    struct BufferedFile *BF;
+
+    /*
+     *  input verification
+     */
+
+    if(!name)
+    {
+        return(NULL);
+    }
+
+    /*
+     *  Allocate control struct.
+     */
+
+    BF = ri.Malloc(sizeof(struct BufferedFile));
+    if(!BF)
+    {
+        return(NULL);
+    }
+
+    /*
+     *  Initialize the structs components.
+     */
+
+    BF->Length    = 0;
+    BF->Buffer    = NULL;
+    BF->Ptr       = NULL;
+    BF->BytesLeft = 0;
+
+    /*
+     *  Read the file.
+     */
+
+    BF->Length = ri.FS_ReadFile((char *) name, (void **) &BF->Buffer);
+
+    /*
+     *  Did we get it? Is it big enough?
+     */
+
+    if(!(BF->Buffer && (BF->Length > 0)))
+    {
+        ri.Free(BF);
+
+        return(NULL);
+    }
+
+    /*
+     *  Set the pointers and counters.
+     */
+
+    BF->Ptr       = BF->Buffer;
+    BF->BytesLeft = BF->Length;
+
+    return(BF);
+}
+
+/*
+ *  Close a buffered file.
+ */
+
+static void CloseBufferedFile(struct BufferedFile *BF)
+{
+    if(BF)
+    {
+        if(BF->Buffer)
+        {
+            ri.FS_FreeFile(BF->Buffer);
+        }
+ 
+        ri.Free(BF);
+    }
+}
+
+/*
+ *  Get a pointer to the requested bytes.
+ */
+
+static void *BufferedFileRead(struct BufferedFile *BF, int Length)
+{
+    void *RetVal;
+
+    /*
+     *  input verification
+     */
+
+    if(!(BF && Length))
+    {
+        return(NULL);
+    }
+ 
+    /*
+     *  not enough bytes left
+     */
+
+    if(Length > BF->BytesLeft)
+    {
+        return(NULL);
+    }
+
+    /*
+     *  the pointer to the requested data
+     */
+
+    RetVal = BF->Ptr;
+ 
+    /*
+     *  Raise the pointer and counter.
+     */
+
+    BF->Ptr       += Length;
+    BF->BytesLeft -= Length;
+
+    return(RetVal);
+}
+
+/*
+ *  Rewind the buffer.
+ */
+
+static qboolean BufferedFileRewind(struct BufferedFile *BF, int Offset)
+{
+    int BytesRead; 
+
+    /*
+     *  input verification
+     */
+
+    if(!BF)
+    {
+        return(qfalse);
+    }
+
+    /*
+     *  special trick to rewind to the beginning of the buffer
+     */
+
+    if(Offset == -1)
+    {
+        BF->Ptr       = BF->Buffer;
+        BF->BytesLeft = BF->Length;
+  
+        return(qtrue);
+    }
+
+    /*
+     *  How many bytes do we have already read?
+     */
+
+    BytesRead = BF->Ptr - BF->Buffer;
+
+    /*
+     *  We can only rewind to the beginning of the BufferedFile.
+     */
+
+    if(Offset > BytesRead)
+    {
+        return(qfalse);
+    }
+
+    /*
+     *  lower the pointer and counter.
+     */
+
+    BF->Ptr       -= Offset;
+    BF->BytesLeft += Offset;
+
+    return(qtrue);
+}
+
+/*
+ *  Skip some bytes.
+ */
+
+static qboolean BufferedFileSkip(struct BufferedFile *BF, int Offset)
+{
+    /*
+     *  input verification
+     */
+
+    if(!BF)
+    {
+        return(qfalse);
+    }
+ 
+    /*
+     *  We can only skip to the end of the BufferedFile.
+     */
+
+    if(Offset > BF->BytesLeft)
+    {
+        return(qfalse);
+    }
+
+    /*
+     *  lower the pointer and counter.
+     */
+
+    BF->Ptr       += Offset;
+    BF->BytesLeft -= Offset;
+
+    return(qtrue);
+}
+
+/*
+ *  Find a chunk
+ */
+
+static qboolean FindChunk(struct BufferedFile *BF, uint32_t ChunkType)
+{
+    struct PNG_ChunkHeader *CH;
+
+    uint32_t Length;
+    uint32_t Type;
+
+    /*
+     *  input verification
+     */
+
+    if(!BF)
+    {
+        return(qfalse);
+    }
+
+    /*
+     *  cycle trough the chunks
+     */
+
+    while(qtrue)
+    {
+        /*
+         *  Read the chunk-header.
+         */
+
+        CH = BufferedFileRead(BF, PNG_ChunkHeader_Size);
+        if(!CH)
+        {
+            return(qfalse);
+        }
+
+        /*
+         *  Do not swap the original types
+         *  they might be needed later.
+         */
+
+        Length = BigLong(CH->Length);
+        Type   = BigLong(CH->Type);
+  
+        /*
+         *  We found it!
+         */
+
+        if(Type == ChunkType)
+        {
+            /*
+             *  Rewind to the start of the chunk.
+             */
+	     
+            BufferedFileRewind(BF, PNG_ChunkHeader_Size);
+  
+            break;
+        }
+        else
+        {
+            /*
+             *  Skip the rest of the chunk.
+             */
+
+            if(Length)
+            {
+                if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size))
+                {
+                    return(qfalse);
+                }  
+            }
+        }
+    }
+
+    return(qtrue);
+}
+
+/*
+ *  Decompress all IDATs
+ */
+
+static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer)
+{
+    uint8_t  *DecompressedData;
+    uint32_t  DecompressedDataLength;
+
+    uint8_t  *CompressedData;
+    uint8_t  *CompressedDataPtr;
+    uint32_t  CompressedDataLength;
+
+    struct PNG_ChunkHeader *CH;
+
+    uint32_t Length;
+    uint32_t Type;
+
+    int BytesToRewind;
+
+    int32_t   puffResult;
+    uint8_t  *puffDest;
+    uint32_t  puffDestLen;
+    uint8_t  *puffSrc;
+    uint32_t  puffSrcLen;
+
+    /*
+     *  input verification
+     */
+
+    if(!(BF && Buffer))
+    {
+        return(-1);
+    }
+
+    /*
+     *  some zeroing
+     */
+
+    DecompressedData = NULL;
+    DecompressedDataLength = 0;
+    *Buffer = DecompressedData;
+
+    CompressedData = NULL;
+    CompressedDataLength = 0;
+
+    BytesToRewind = 0;
+
+    /*
+     *  Find the first IDAT chunk.
+     */
+
+    if(!FindChunk(BF, PNG_ChunkType_IDAT))
+    {
+        return(-1);
+    }
+
+    /*
+     *  Count the size of the uncompressed data
+     */
+
+    while(qtrue)
+    {
+        /*
+         *  Read chunk header
+         */
+
+        CH = BufferedFileRead(BF, PNG_ChunkHeader_Size);
+        if(!CH)
+        {
+            /*
+             *  Rewind to the start of this adventure
+             *  and return unsuccessfull
+             */
+
+            BufferedFileRewind(BF, BytesToRewind);
+
+            return(-1);
+        }
+
+        /*
+         *  Length and Type of chunk
+         */
+
+        Length = BigLong(CH->Length);
+        Type   = BigLong(CH->Type);
+
+        /*
+         *  We have reached the end of the IDAT chunks
+         */
+
+        if(!(Type == PNG_ChunkType_IDAT))
+        {
+            BufferedFileRewind(BF, PNG_ChunkHeader_Size); 
+  
+            break;
+        }
+
+        /*
+         *  Add chunk header to count.
+         */
+
+        BytesToRewind += PNG_ChunkHeader_Size;
+
+        /*
+         *  Skip to next chunk
+         */
+
+        if(Length)
+        {
+            if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size))
+            {
+                BufferedFileRewind(BF, BytesToRewind);
+
+                return(-1);
+            }
+
+            BytesToRewind += Length + PNG_ChunkCRC_Size;
+            CompressedDataLength += Length;
+        } 
+    }
+
+    BufferedFileRewind(BF, BytesToRewind);
+
+    CompressedData = ri.Malloc(CompressedDataLength);
+    if(!CompressedData)
+    {
+        return(-1);
+    }
+ 
+    CompressedDataPtr = CompressedData;
+
+    /*
+     *  Collect the compressed Data
+     */
+
+    while(qtrue)
+    {
+        /*
+         *  Read chunk header
+         */
+
+        CH = BufferedFileRead(BF, PNG_ChunkHeader_Size);
+        if(!CH)
+        {
+            ri.Free(CompressedData); 
+  
+            return(-1);
+        }
+
+        /*
+         *  Length and Type of chunk
+         */
+
+        Length = BigLong(CH->Length);
+        Type   = BigLong(CH->Type);
+
+        /*
+         *  We have reached the end of the IDAT chunks
+         */
+
+        if(!(Type == PNG_ChunkType_IDAT))
+        {
+            BufferedFileRewind(BF, PNG_ChunkHeader_Size); 
+  
+            break;
+        }
+
+        /*
+         *  Copy the Data
+         */
+
+        if(Length)
+        {
+            uint8_t *OrigCompressedData;
+   
+            OrigCompressedData = BufferedFileRead(BF, Length);
+            if(!OrigCompressedData)
+            {
+                ri.Free(CompressedData); 
+  
+                return(-1);
+            }
+
+            if(!BufferedFileSkip(BF, PNG_ChunkCRC_Size))
+            {
+                ri.Free(CompressedData); 
+
+                return(-1);
+            }
+  
+            memcpy(CompressedDataPtr, OrigCompressedData, Length);
+            CompressedDataPtr += Length;
+        } 
+    }
+
+    /*
+     *  Let puff() calculate the decompressed data length.
+     */
+
+    puffDest    = NULL;
+    puffDestLen = 0;
+ 
+    /*
+     *  The zlib header and checkvalue don't belong to the compressed data.
+     */
+
+    puffSrc    = CompressedData + PNG_ZlibHeader_Size;
+    puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size;
+
+    /*
+     *  first puff() to calculate the size of the uncompressed data
+     */
+
+    puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen);
+    if(!((puffResult == 0) && (puffDestLen > 0)))
+    {
+        ri.Free(CompressedData);
+ 
+        return(-1);
+    }
+
+    /*
+     *  Allocate the buffer for the uncompressed data.
+     */
+
+    DecompressedData = ri.Malloc(puffDestLen);
+    if(!DecompressedData)
+    {
+        ri.Free(CompressedData);
+ 
+        return(-1);
+    }
+
+    /*
+     *  Set the input again in case something was changed by the last puff() .
+     */
+
+    puffDest   = DecompressedData;
+    puffSrc    = CompressedData + PNG_ZlibHeader_Size;
+    puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size;
+ 
+    /*
+     *  decompression puff()
+     */
+
+    puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen);
+
+    /*
+     *  The compressed data is not needed anymore.
+     */
+
+    ri.Free(CompressedData);
+
+    /*
+     *  Check if the last puff() was successfull.
+     */
+
+    if(!((puffResult == 0) && (puffDestLen > 0)))
+    {
+        ri.Free(DecompressedData);
+ 
+        return(-1);
+    }
+
+    /*
+     *  Set the output of this function.
+     */
+
+    DecompressedDataLength = puffDestLen;
+    *Buffer = DecompressedData;
+
+    return(DecompressedDataLength);
+}
+
+/*
+ *  the Paeth predictor
+ */
+
+static uint8_t PredictPaeth(uint8_t a, uint8_t b, uint8_t c)
+{
+    /*
+     *  a == Left
+     *  b == Up
+     *  c == UpLeft
+     */
+
+    uint8_t Pr;
+    int p;
+    int pa, pb, pc;
+
+    Pr = 0;
+
+    p  = ((int) a) + ((int) b) - ((int) c);
+    pa = abs(p - ((int) a));
+    pb = abs(p - ((int) b));
+    pc = abs(p - ((int) c));
+
+    if((pa <= pb) && (pa <= pc))
+    {
+        Pr = a;
+    }
+    else if(pb <= pc)
+    {
+        Pr = b;
+    }
+    else
+    {
+        Pr = c;
+    }
+
+    return(Pr);
+
+}
+
+/*
+ *  Reverse the filters.
+ */
+
+static qboolean UnfilterImage(uint8_t  *DecompressedData, 
+                              uint32_t  ImageHeight,
+		              uint32_t  BytesPerScanline, 
+		              uint32_t  BytesPerPixel)
+{
+    uint8_t   *DecompPtr;
+    uint8_t   FilterType;
+    uint8_t  *PixelLeft, *PixelUp, *PixelUpLeft;
+    uint32_t  w, h, p;
+
+    /*
+     *  some zeros for the filters
+     */
+
+    uint8_t Zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+    /*
+     *  input verification
+     *
+     *  ImageHeight and BytesPerScanline are not checked,
+     *  because these can be zero in some interlace passes.
+     */
+
+    if(!(DecompressedData && BytesPerPixel))
+    {
+	return(qfalse);
+    }
+
+
+    /*
+     *  Set the pointer to the start of the decompressed Data.
+     */
+
+    DecompPtr = DecompressedData;
+
+    /*
+     *  Un-filtering is done in place.
+     */
+
+    /*
+     *  Go trough all scanlines.
+     */
+
+    for(h = 0; h < ImageHeight; h++)
+    {
+        /*
+         *  Every scanline starts with a FilterType byte.
+         */
+
+        FilterType = *DecompPtr;
+        DecompPtr++;
+
+        /*
+         *  Left pixel of the first byte in a scanline is zero.
+         */
+
+        PixelLeft = Zeros;
+
+        /*
+         *  Set PixelUp to previous line only if we are on the second line or above.
+         *
+         *  Plus one byte for the FilterType
+         */
+
+        if(h > 0)
+        {
+            PixelUp = DecompPtr - (BytesPerScanline + 1);
+        }
+        else
+        {
+            PixelUp = Zeros;
+        }
+
+        /*
+         * The pixel left to the first pixel of the previous scanline is zero too.
+         */
+
+        PixelUpLeft = Zeros;
+
+        /*
+         *  Cycle trough all pixels of the scanline.
+         */
+
+        for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++)
+        {
+            /*
+             *  Cycle trough the bytes of the pixel.
+             */
+
+            for(p = 0; p < BytesPerPixel; p++)
+            {
+                switch(FilterType)
+                { 
+                    case PNG_FilterType_None :
+                    {
+                        /*
+                         *  The byte is unfiltered.
+                         */
+
+                        break;
+                    }
+
+                    case PNG_FilterType_Sub :
+                    {
+                        DecompPtr[p] += PixelLeft[p];
+
+                        break;
+                    }
+
+		    case PNG_FilterType_Up :
+                    {
+                        DecompPtr[p] += PixelUp[p];
+
+                        break;
+                    }
+
+                    case PNG_FilterType_Average :
+                    {
+                        DecompPtr[p] += ((uint8_t) ((((uint16_t) PixelLeft[p]) + ((uint16_t) PixelUp[p])) / 2));
+
+                        break;
+                    }
+
+                    case PNG_FilterType_Paeth :
+                    {
+                        DecompPtr[p] += PredictPaeth(PixelLeft[p], PixelUp[p], PixelUpLeft[p]);
+
+                        break;
+                    }
+
+                    default :
+                    {
+                        return(qfalse);
+                    }
+                }
+            }
+   
+            PixelLeft = DecompPtr;
+
+            /*
+             *  We only have a upleft pixel if we are on the second line or above.
+             */
+
+            if(h > 0)
+            {
+                PixelUpLeft = DecompPtr - (BytesPerScanline + 1);
+            }
+
+	    /*
+             *  Skip to the next pixel.
+             */
+
+            DecompPtr += BytesPerPixel;
+	 
+            /*
+             *  We only have a previous line if we are on the second line and above.
+             */
+
+            if(h > 0)
+            {
+                PixelUp = DecompPtr - (BytesPerScanline + 1);
+            }
+        }
+    }
+
+ return(qtrue);
+}
+
+/*
+ *  Convert a raw input pixel to Quake 3 RGA format.
+ */
+
+static qboolean ConvertPixel(struct PNG_Chunk_IHDR *IHDR,
+			     byte                  *OutPtr,
+			     uint8_t               *DecompPtr,
+                             qboolean               HasTransparentColour,
+                             uint8_t               *TransparentColour,
+                             uint8_t               *OutPal)
+{
+    /*
+     *  input verification
+     */
+    
+    if(!(IHDR && OutPtr && DecompPtr && TransparentColour && OutPal))
+    {
+     return(qfalse);
+    }
+
+    switch(IHDR->ColourType)
+    {
+        case PNG_ColourType_Grey :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_1 :
+                case PNG_BitDepth_2 :
+                case PNG_BitDepth_4 :
+                {
+    		    uint8_t Step;
+                    uint8_t GreyValue;
+
+                    Step = 0xFF / ((1 << IHDR->BitDepth) - 1);
+
+                    GreyValue = DecompPtr[0] * Step;
+  
+                    OutPtr[0] = GreyValue;
+                    OutPtr[1] = GreyValue;
+                    OutPtr[2] = GreyValue;
+                    OutPtr[3] = 0xFF;
+
+                    /*
+                     *  Grey supports full transparency for one specified colour
+                     */
+
+                    if(HasTransparentColour)
+                    {
+                        if(TransparentColour[1] == DecompPtr[0])
+                        {
+                            OutPtr[3] = 0x00;
+                        }
+                    }
+	
+
+                    break;
+                }
+      
+                case PNG_BitDepth_8 :
+                case PNG_BitDepth_16 :
+                {
+                    OutPtr[0] = DecompPtr[0];
+                    OutPtr[1] = DecompPtr[0];
+                    OutPtr[2] = DecompPtr[0];
+                    OutPtr[3] = 0xFF;
+      
+                    /*
+                     *  Grey supports full transparency for one specified colour
+                     */
+
+                    if(HasTransparentColour)
+                    {
+                        if(IHDR->BitDepth == PNG_BitDepth_8)
+                        {
+                            if(TransparentColour[1] == DecompPtr[0])
+                            {
+                                OutPtr[3] = 0x00;
+                            }
+                        }
+                        else
+                        {
+                            if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1]))
+                            {
+                                OutPtr[3] = 0x00;
+                            }
+                        }
+                    }
+
+                    break;
+                }
+      
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+    
+            break;
+        }
+
+        case PNG_ColourType_True :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_8 :
+                {
+                    OutPtr[0] = DecompPtr[0];
+                    OutPtr[1] = DecompPtr[1];
+                    OutPtr[2] = DecompPtr[2];
+                    OutPtr[3] = 0xFF;
+      
+                    /*
+                     *  True supports full transparency for one specified colour
+                     */
+
+                    if(HasTransparentColour)
+                    {
+                        if((TransparentColour[1] == DecompPtr[0]) &&
+                           (TransparentColour[3] == DecompPtr[1]) &&
+                           (TransparentColour[5] == DecompPtr[3]))
+                        {
+                            OutPtr[3] = 0x00;
+                        }
+                    }
+
+                    break;
+                }
+      
+                case PNG_BitDepth_16 :
+                {
+                    /*
+                     *  We use only the upper byte.
+                     */
+
+                    OutPtr[0] = DecompPtr[0];
+                    OutPtr[1] = DecompPtr[2];
+                    OutPtr[2] = DecompPtr[4];
+                    OutPtr[3] = 0xFF;
+      
+                    /*
+                     *  True supports full transparency for one specified colour
+                     */
+
+                    if(HasTransparentColour)
+                    {
+                        if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1]) &&
+                           (TransparentColour[2] == DecompPtr[2]) && (TransparentColour[3] == DecompPtr[3]) &&
+                           (TransparentColour[4] == DecompPtr[4]) && (TransparentColour[5] == DecompPtr[5]))
+                        {
+                            OutPtr[3] = 0x00;
+                        }
+                    }
+
+                    break;
+                }
+
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+
+            break;
+        }
+
+        case PNG_ColourType_Indexed :
+        {
+            OutPtr[0] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 0];
+            OutPtr[1] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 1];
+            OutPtr[2] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 2];
+            OutPtr[3] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 3];
+	
+            break;
+        }
+
+        case PNG_ColourType_GreyAlpha :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_8 :
+                {
+                    OutPtr[0] = DecompPtr[0];
+                    OutPtr[1] = DecompPtr[0];
+                    OutPtr[2] = DecompPtr[0];
+                    OutPtr[3] = DecompPtr[1];
+      
+                    break;
+                }
+  
+                case PNG_BitDepth_16 :
+                {
+                    /*
+                     *  We use only the upper byte.
+                     */
+
+                    OutPtr[0] = DecompPtr[0];
+                    OutPtr[1] = DecompPtr[0];
+                    OutPtr[2] = DecompPtr[0];
+                    OutPtr[3] = DecompPtr[2];
+      
+                    break;
+                }
+
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+
+            break;
+        }
+
+        case PNG_ColourType_TrueAlpha :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_8 :
+                {
+                    OutPtr[0] = DecompPtr[0];
+                    OutPtr[1] = DecompPtr[1];
+                    OutPtr[2] = DecompPtr[2];
+                    OutPtr[3] = DecompPtr[3];
+      
+                    break;
+                }
+      
+                case PNG_BitDepth_16 :
+                {
+                    /*
+                     *  We use only the upper byte.
+                     */
+
+                    OutPtr[0] = DecompPtr[0];
+                    OutPtr[1] = DecompPtr[2];
+                    OutPtr[2] = DecompPtr[4];
+                    OutPtr[3] = DecompPtr[6];
+      
+                    break;
+                }
+
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+
+            break;
+        }
+
+        default :
+        {
+            return(qfalse);
+        }
+    }
+
+    return(qtrue);
+}
+
+
+/*
+ *  Decode a non-interlaced image.
+ */
+
+static qboolean DecodeImageNonInterlaced(struct PNG_Chunk_IHDR *IHDR,
+                                         byte                  *OutBuffer, 
+                                         uint8_t               *DecompressedData,
+                                         uint32_t               DecompressedDataLength,
+                                         qboolean               HasTransparentColour,
+                                         uint8_t               *TransparentColour,
+                                         uint8_t               *OutPal)
+{
+    uint32_t IHDR_Width;
+    uint32_t IHDR_Height;
+    uint32_t BytesPerScanline, BytesPerPixel, PixelsPerByte;
+    uint32_t  w, h, p;
+    byte *OutPtr;
+    uint8_t *DecompPtr;
+
+    /*
+     *  input verification
+     */
+
+    if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal))
+    {
+	return(qfalse);
+    }
+
+    /*
+     *  byte swapping
+     */
+     
+    IHDR_Width  = BigLong(IHDR->Width);
+    IHDR_Height = BigLong(IHDR->Height);
+
+    /*
+     *  information for un-filtering
+     */
+
+    switch(IHDR->ColourType)
+    {
+        case PNG_ColourType_Grey :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_1 :
+                case PNG_BitDepth_2 :
+                case PNG_BitDepth_4 :
+                {
+                    BytesPerPixel    = 1;
+                    PixelsPerByte    = 8 / IHDR->BitDepth;
+
+                    break;
+                }
+
+                case PNG_BitDepth_8  :
+                case PNG_BitDepth_16 :
+                {
+                    BytesPerPixel    = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+  
+            break;
+        }
+  
+        case PNG_ColourType_True :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_8  :
+                case PNG_BitDepth_16 :
+                {
+                    BytesPerPixel    = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+     
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+  
+            break;
+        }
+
+        case PNG_ColourType_Indexed :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_1 :
+                case PNG_BitDepth_2 :
+                case PNG_BitDepth_4 :
+                {
+                    BytesPerPixel    = 1;
+                    PixelsPerByte    = 8 / IHDR->BitDepth;
+
+                    break;
+                }
+
+                case PNG_BitDepth_8 :
+                {
+                    BytesPerPixel    = PNG_NumColourComponents_Indexed;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+         
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+  
+            break;
+        }
+
+        case PNG_ColourType_GreyAlpha :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_8 :
+                case PNG_BitDepth_16 :
+                {
+                    BytesPerPixel    = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+     
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+  
+            break;
+        }
+
+        case PNG_ColourType_TrueAlpha :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_8 :
+                case PNG_BitDepth_16 :
+                {
+                    BytesPerPixel    = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+    
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+
+            break;
+        }
+
+        default :
+        {
+            return(qfalse);
+        }
+    }
+
+    /*
+     *  Calculate the size of one scanline
+     */
+
+    BytesPerScanline = (IHDR_Width * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte;
+
+    /*
+     *  Check if we have enough data for the whole image.
+     */
+
+    if(!(DecompressedDataLength == ((BytesPerScanline + 1) * IHDR_Height)))
+    {
+        return(qfalse);
+    }
+
+    /*
+     *  Unfilter the image.
+     */
+
+    if(!UnfilterImage(DecompressedData, IHDR_Height, BytesPerScanline, BytesPerPixel))
+    {
+        return(qfalse);
+    }
+
+    /*
+     *  Set the working pointers to the beginning of the buffers.
+     */
+
+    OutPtr = OutBuffer;
+    DecompPtr = DecompressedData;
+
+    /*
+     *  Create the output image.
+     */
+
+    for(h = 0; h < IHDR_Height; h++)
+    {
+        /*
+         *  Count the pixels on the scanline for those multipixel bytes
+         */
+
+        uint32_t CurrPixel;
+  
+        /*
+         *  skip FilterType
+         */
+
+        DecompPtr++;
+
+        /*
+         *  Reset the pixel count.
+         */
+
+        CurrPixel = 0;
+
+        for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++)
+        {
+	    if(PixelsPerByte > 1)
+	    {
+                uint8_t  Mask;
+                uint32_t Shift;
+		uint8_t  SinglePixel;
+
+                for(p = 0; p < PixelsPerByte; p++)
+                {
+                    if(CurrPixel < IHDR_Width)
+                    {
+                        Mask  = (1 << IHDR->BitDepth) - 1;
+                        Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth;
+
+                        SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift);
+
+			if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal))
+			{
+			    return(qfalse);
+			}
+
+                        OutPtr += Q3IMAGE_BYTESPERPIXEL;
+                        CurrPixel++;
+                    }
+                }
+	    
+	    }
+	    else
+	    {
+		if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal))
+		{
+		    return(qfalse);
+		}
+  
+
+                OutPtr += Q3IMAGE_BYTESPERPIXEL;
+	    }
+
+            DecompPtr += BytesPerPixel;
+        }
+    }
+
+    return(qtrue);
+}
+
+/*
+ *  Decode an interlaced image.
+ */
+
+static qboolean DecodeImageInterlaced(struct PNG_Chunk_IHDR *IHDR,
+                                      byte                  *OutBuffer, 
+                                      uint8_t               *DecompressedData,
+                                      uint32_t               DecompressedDataLength,
+                                      qboolean               HasTransparentColour,
+                                      uint8_t               *TransparentColour,
+                                      uint8_t               *OutPal)
+{
+    uint32_t IHDR_Width;
+    uint32_t IHDR_Height;
+    uint32_t BytesPerScanline[PNG_Adam7_NumPasses], BytesPerPixel, PixelsPerByte;
+    uint32_t PassWidth[PNG_Adam7_NumPasses], PassHeight[PNG_Adam7_NumPasses];
+    uint32_t WSkip[PNG_Adam7_NumPasses], WOffset[PNG_Adam7_NumPasses], HSkip[PNG_Adam7_NumPasses], HOffset[PNG_Adam7_NumPasses];
+    uint32_t w, h, p, a;
+    byte *OutPtr;
+    uint8_t *DecompPtr;
+    uint32_t TargetLength;
+
+    /*
+     *  input verification
+     */
+
+    if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal))
+    {
+	return(qfalse);
+    }
+
+    /*
+     *  byte swapping
+     */
+
+    IHDR_Width  = BigLong(IHDR->Width);
+    IHDR_Height = BigLong(IHDR->Height);
+
+    /*
+     *  Skip and Offset for the passes.
+     */
+
+    WSkip[0]   = 8;
+    WOffset[0] = 0;
+    HSkip[0]   = 8;
+    HOffset[0] = 0;
+
+    WSkip[1]   = 8;
+    WOffset[1] = 4;
+    HSkip[1]   = 8;
+    HOffset[1] = 0;
+
+    WSkip[2]   = 4;
+    WOffset[2] = 0;
+    HSkip[2]   = 8;
+    HOffset[2] = 4;
+
+    WSkip[3]   = 4;
+    WOffset[3] = 2;
+    HSkip[3]   = 4;
+    HOffset[3] = 0;
+
+    WSkip[4]   = 2;
+    WOffset[4] = 0;
+    HSkip[4]   = 4;
+    HOffset[4] = 2;
+
+    WSkip[5]   = 2;
+    WOffset[5] = 1;
+    HSkip[5]   = 2;
+    HOffset[5] = 0;
+
+    WSkip[6]   = 1;
+    WOffset[6] = 0;
+    HSkip[6]   = 2;
+    HOffset[6] = 1;
+
+    /*
+     *  Calculate the sizes of the passes.
+     */
+
+    PassWidth[0]  = (IHDR_Width  + 7) / 8;
+    PassHeight[0] = (IHDR_Height + 7) / 8;
+
+    PassWidth[1]  = (IHDR_Width  + 3) / 8;
+    PassHeight[1] = (IHDR_Height + 7) / 8;
+
+    PassWidth[2]  = (IHDR_Width  + 3) / 4;
+    PassHeight[2] = (IHDR_Height + 3) / 8;
+
+    PassWidth[3]  = (IHDR_Width  + 1) / 4;
+    PassHeight[3] = (IHDR_Height + 3) / 4;
+
+    PassWidth[4]  = (IHDR_Width  + 1) / 2;
+    PassHeight[4] = (IHDR_Height + 1) / 4;
+
+    PassWidth[5]  = (IHDR_Width  + 0) / 2;
+    PassHeight[5] = (IHDR_Height + 1) / 2;
+
+    PassWidth[6]  = (IHDR_Width  + 0) / 1;
+    PassHeight[6] = (IHDR_Height + 0) / 2;
+
+    /*
+     *  information for un-filtering
+     */
+
+    switch(IHDR->ColourType)
+    {
+        case PNG_ColourType_Grey :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_1 :
+                case PNG_BitDepth_2 :
+                case PNG_BitDepth_4 :
+                {
+                    BytesPerPixel    = 1;
+                    PixelsPerByte    = 8 / IHDR->BitDepth;
+
+                    break;
+                }
+
+                case PNG_BitDepth_8  :
+                case PNG_BitDepth_16 :
+                {
+                    BytesPerPixel    = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+  
+            break;
+        }
+  
+        case PNG_ColourType_True :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_8  :
+                case PNG_BitDepth_16 :
+                {
+                    BytesPerPixel    = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+     
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+  
+            break;
+        }
+
+        case PNG_ColourType_Indexed :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_1 :
+                case PNG_BitDepth_2 :
+                case PNG_BitDepth_4 :
+                {
+                    BytesPerPixel    = 1;
+                    PixelsPerByte    = 8 / IHDR->BitDepth;
+
+                    break;
+                }
+
+                case PNG_BitDepth_8 :
+                {
+                    BytesPerPixel    = PNG_NumColourComponents_Indexed;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+         
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+  
+            break;
+        }
+
+        case PNG_ColourType_GreyAlpha :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_8 :
+                case PNG_BitDepth_16 :
+                {
+                    BytesPerPixel    = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+     
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+  
+            break;
+        }
+
+        case PNG_ColourType_TrueAlpha :
+        {
+            switch(IHDR->BitDepth)
+            {
+                case PNG_BitDepth_8 :
+                case PNG_BitDepth_16 :
+                {
+                    BytesPerPixel    = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha;
+                    PixelsPerByte    = 1;
+
+                    break;
+                }
+    
+                default :
+                {
+                    return(qfalse);
+                }
+            }
+
+            break;
+        }
+
+        default :
+        {
+            return(qfalse);
+        }
+    }
+
+    /*
+     *  Calculate the size of the scanlines per pass
+     */
+
+    for(a = 0; a < PNG_Adam7_NumPasses; a++)
+    {
+	BytesPerScanline[a] = (PassWidth[a] * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte;
+    }
+
+    /*
+     *  Calculate the size of all passes
+     */
+
+    TargetLength = 0;
+
+    for(a = 0; a < PNG_Adam7_NumPasses; a++)
+    {
+	TargetLength += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]);
+    }
+
+    /*
+     *  Check if we have enough data for the whole image.
+     */
+
+    if(!(DecompressedDataLength == TargetLength))
+    {
+        return(qfalse);
+    }
+
+    /*
+     *  Unfilter the image.
+     */
+
+    DecompPtr = DecompressedData;
+
+    for(a = 0; a < PNG_Adam7_NumPasses; a++)
+    {
+        if(!UnfilterImage(DecompPtr, PassHeight[a], BytesPerScanline[a], BytesPerPixel))
+        {
+            return(qfalse);
+        }
+	
+	DecompPtr += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]);
+    }
+
+    /*
+     *  Set the working pointers to the beginning of the buffers.
+     */
+
+    DecompPtr = DecompressedData;
+
+    /*
+     *  Create the output image.
+     */
+
+    for(a = 0; a < PNG_Adam7_NumPasses; a++)
+    {
+        for(h = 0; h < PassHeight[a]; h++)
+        {
+            /*
+             *  Count the pixels on the scanline for those multipixel bytes
+             */
+
+            uint32_t CurrPixel;
+
+            /*
+             *  skip FilterType
+             */
+
+            DecompPtr++;
+
+            /*
+             *  Reset the pixel count.
+             */
+
+            CurrPixel = 0;
+
+            for(w = 0; w < (BytesPerScanline[a] / BytesPerPixel); w++)
+            {
+        	if(PixelsPerByte > 1)
+	        {
+                    uint8_t  Mask;
+                    uint32_t Shift;
+		    uint8_t  SinglePixel;
+
+                    for(p = 0; p < PixelsPerByte; p++)
+                    {
+                        if(CurrPixel < PassWidth[a])
+                        {
+                            Mask  = (1 << IHDR->BitDepth) - 1;
+                            Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth;
+
+                            SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift);
+
+    			    OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((CurrPixel * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL);
+
+    			    if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal))
+			    {
+			        return(qfalse);
+			    }
+
+                            CurrPixel++;
+                        }
+                    }
+	    
+	        }
+    	        else
+	        {
+	    	    OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((w * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL);
+
+		    if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal))
+		    {
+		        return(qfalse);
+		    }
+	        }
+
+                DecompPtr += BytesPerPixel;
+            }
+        }
+    }
+
+    return(qtrue);
+}
+
+/*
+ *  The PNG loader
+ */
+
+static void LoadPNG(const char *name, byte **pic, int *width, int *height)
+{
+    struct BufferedFile *ThePNG;
+    byte *OutBuffer;
+    uint8_t *Signature;
+    struct PNG_ChunkHeader *CH;
+    uint32_t ChunkHeaderLength;
+    uint32_t ChunkHeaderType;
+    struct PNG_Chunk_IHDR *IHDR;
+    uint32_t IHDR_Width;
+    uint32_t IHDR_Height;
+    PNG_ChunkCRC *CRC;
+    uint8_t *InPal;
+    uint8_t *DecompressedData;
+    uint32_t DecompressedDataLength;
+    uint32_t i;
+
+    /*
+     *  palette with 256 RGBA entries
+     */
+
+    uint8_t OutPal[1024];
+
+    /*
+     *  transparent colour from the tRNS chunk
+     */
+
+    qboolean HasTransparentColour = qfalse;
+    uint8_t TransparentColour[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+    /*
+     *  input verification
+     */
+
+    if(!(name && pic))
+    {
+        return;
+    }
+
+    /*
+     *  Zero out return values.
+     */
+
+    *pic = NULL;
+
+    if(width)
+    {
+        *width = 0;
+    }
+
+    if(height)
+    {
+        *height = 0;
+    }
+
+    /*
+     *  Read the file.
+     */
+
+    ThePNG = ReadBufferedFile(name);
+    if(!ThePNG)
+    {
+        return;
+    }           
+
+    /*
+     *  Read the siganture of the file.
+     */
+
+    Signature = BufferedFileRead(ThePNG, PNG_Signature_Size);
+    if(!Signature)
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return;
+    }
+ 
+    /*
+     *  Is it a PNG?
+     */
+
+    if(memcmp(Signature, PNG_Signature, PNG_Signature_Size))
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return; 
+    }
+
+    /*
+     *  Read the first chunk-header.
+     */
+
+    CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
+    if(!CH)
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return; 
+    }
+
+    /*
+     *  PNG multi-byte types are in Big Endian
+     */
+
+    ChunkHeaderLength = BigLong(CH->Length);
+    ChunkHeaderType   = BigLong(CH->Type);
+
+    /*
+     *  Check if the first chunk is an IHDR.
+     */
+
+    if(!((ChunkHeaderType == PNG_ChunkType_IHDR) && (ChunkHeaderLength == PNG_Chunk_IHDR_Size)))
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return; 
+    }
+
+    /*
+     *  Read the IHDR.
+     */ 
+
+    IHDR = BufferedFileRead(ThePNG, PNG_Chunk_IHDR_Size);
+    if(!IHDR)
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return; 
+    }
+
+    /*
+     *  Read the CRC for IHDR
+     */
+
+    CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
+    if(!CRC)
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return; 
+    }
+ 
+    /*
+     *  Here we could check the CRC if we wanted to.
+     */
+ 
+    /*
+     *  multi-byte type swapping
+     */
+
+    IHDR_Width  = BigLong(IHDR->Width);
+    IHDR_Height = BigLong(IHDR->Height);
+ 
+    /*
+     *  Check if Width and Height are valid.
+     */
+
+    if(!((IHDR_Width > 0) && (IHDR_Height > 0)))
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return; 
+    }
+
+    /*
+     *  Do we need to check if the dimensions of the image are valid for Quake3?
+     */
+
+    /*
+     *  Check if CompressionMethod and FilterMethod are valid.
+     */
+
+    if(!((IHDR->CompressionMethod == PNG_CompressionMethod_0) && (IHDR->FilterMethod == PNG_FilterMethod_0)))
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return; 
+    }
+
+    /*
+     *  Check if InterlaceMethod is valid.
+     */
+
+    if(!((IHDR->InterlaceMethod == PNG_InterlaceMethod_NonInterlaced)  || (IHDR->InterlaceMethod == PNG_InterlaceMethod_Interlaced)))
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return;
+    }
+
+    /*
+     *  Read palette for an indexed image.
+     */
+
+    if(IHDR->ColourType == PNG_ColourType_Indexed)
+    {
+        /*
+         *  We need the palette first.
+         */
+
+        if(!FindChunk(ThePNG, PNG_ChunkType_PLTE))
+        {
+            CloseBufferedFile(ThePNG);
+  
+            return;
+        }
+
+        /*
+         *  Read the chunk-header.
+         */
+
+        CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
+        if(!CH)
+        {
+            CloseBufferedFile(ThePNG);
+   
+            return; 
+        }
+
+        /*
+         *  PNG multi-byte types are in Big Endian
+         */
+
+        ChunkHeaderLength = BigLong(CH->Length);
+        ChunkHeaderType   = BigLong(CH->Type);
+  
+        /*
+         *  Check if the chunk is an PLTE.
+         */
+
+        if(!(ChunkHeaderType == PNG_ChunkType_PLTE))
+        {
+            CloseBufferedFile(ThePNG);
+   
+            return; 
+        }
+
+        /*
+         *  Check if Length is divisible by 3
+         */
+
+        if(ChunkHeaderLength % 3)
+        {
+            CloseBufferedFile(ThePNG);
+   
+            return;   
+        }
+
+        /*
+         *  Read the raw palette data
+         */
+
+        InPal = BufferedFileRead(ThePNG, ChunkHeaderLength);
+        if(!InPal)
+        {
+            CloseBufferedFile(ThePNG);
+   
+            return; 
+        }
+   
+        /*
+         *  Read the CRC for the palette
+         */
+
+        CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
+        if(!CRC)
+        {
+            CloseBufferedFile(ThePNG);
+ 
+            return; 
+        }
+
+        /*
+         *  Set some default values.
+         */
+
+        for(i = 0; i < 256; i++)
+        {
+            OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = 0x00;
+            OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = 0x00;
+            OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = 0x00;
+            OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF;  
+        }
+
+        /*
+         *  Convert to the Quake3 RGBA-format.
+         */
+
+        for(i = 0; i < (ChunkHeaderLength / 3); i++)
+        {
+            OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = InPal[i*3+0];
+            OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = InPal[i*3+1];
+            OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = InPal[i*3+2];
+            OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF;
+        }
+    }
+
+    /*
+     *  transparency information is sometimes stored in an tRNS chunk
+     */
+
+    /*
+     *  Let's see if there is a tRNS chunk
+     */
+
+    if(FindChunk(ThePNG, PNG_ChunkType_tRNS))
+    {
+        uint8_t *Trans;
+
+        /*
+         *  Read the chunk-header.
+         */
+
+        CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
+        if(!CH)
+        {
+            CloseBufferedFile(ThePNG);
+ 
+            return; 
+        }
+
+        /*
+         *  PNG multi-byte types are in Big Endian
+         */
+
+        ChunkHeaderLength = BigLong(CH->Length);
+        ChunkHeaderType   = BigLong(CH->Type);
+
+        /*
+         *  Check if the chunk is an tRNS.
+         */
+
+        if(!(ChunkHeaderType == PNG_ChunkType_tRNS))
+        {
+            CloseBufferedFile(ThePNG);
+ 
+            return; 
+        }
+
+        /*
+         *  Read the transparency information.
+         */
+
+        Trans = BufferedFileRead(ThePNG, ChunkHeaderLength);
+        if(!Trans)
+        {
+            CloseBufferedFile(ThePNG);
+ 
+            return;  
+        }
+
+        /*
+         *  Read the CRC.
+         */
+
+        CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
+        if(!CRC)
+        {
+            CloseBufferedFile(ThePNG);
+  
+            return; 
+        }
+ 
+        /*
+         *  Only for Grey, True and Indexed ColourType should tRNS exist.
+         */
+
+        switch(IHDR->ColourType)
+        {
+            case PNG_ColourType_Grey :
+            {
+                if(!ChunkHeaderLength == 2)
+                {
+                    CloseBufferedFile(ThePNG);
+  
+                    return;    
+                }
+   
+                HasTransparentColour = qtrue;
+   
+		/*
+		 *  Grey can have one colour which is completely transparent.
+		 *  This colour is always stored in 16 bits.
+		 */
+
+                TransparentColour[0] = Trans[0];
+                TransparentColour[1] = Trans[1];
+   
+                break;
+            }
+   
+            case PNG_ColourType_True :
+            {
+                if(!ChunkHeaderLength == 6)
+                {
+                    CloseBufferedFile(ThePNG);
+  
+                    return;    
+                }
+   
+                HasTransparentColour = qtrue;
+
+		/*
+		 *  True can have one colour which is completely transparent.
+		 *  This colour is always stored in 16 bits.
+		 */
+
+                TransparentColour[0] = Trans[0];
+                TransparentColour[1] = Trans[1];
+                TransparentColour[2] = Trans[2];
+                TransparentColour[3] = Trans[3];
+                TransparentColour[4] = Trans[4];
+                TransparentColour[5] = Trans[5];
+   
+                break;
+            }
+   
+            case PNG_ColourType_Indexed :
+            {
+                /*
+		 *  Maximum of 256 one byte transparency entries.
+		 */
+		
+		if(ChunkHeaderLength > 256)
+                {
+                    CloseBufferedFile(ThePNG);
+  
+                    return;    
+                }
+
+                HasTransparentColour = qtrue;
+
+                /*
+                 *  alpha values for palette entries
+                 */
+
+                for(i = 0; i < ChunkHeaderLength; i++)
+                {
+                    OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = Trans[i];
+                }
+
+                break;
+            }
+  
+            /*
+             *  All other ColourTypes should not have tRNS chunks
+             */
+
+            default :
+            {
+                CloseBufferedFile(ThePNG);
+  
+                return;
+            }
+        } 
+    }
+
+    /*
+     *  Rewind to the start of the file.
+     */
+
+    if(!BufferedFileRewind(ThePNG, -1))
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return; 
+    }
+ 
+    /*
+     *  Skip the signature
+     */
+
+    if(!BufferedFileSkip(ThePNG, PNG_Signature_Size))
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return; 
+    }
+
+    /*
+     *  Decompress all IDAT chunks
+     */
+
+    DecompressedDataLength = DecompressIDATs(ThePNG, &DecompressedData);
+    if(!(DecompressedDataLength && DecompressedData))
+    {
+        CloseBufferedFile(ThePNG);
+ 
+        return;
+    }
+
+    /*
+     *  Allocate output buffer.
+     */
+
+    OutBuffer = ri.Malloc(IHDR_Width * IHDR_Height * Q3IMAGE_BYTESPERPIXEL); 
+    if(!OutBuffer)
+    {
+        ri.Free(DecompressedData); 
+        CloseBufferedFile(ThePNG);
+ 
+        return;  
+    }
+
+    /*
+     *  Interlaced and Non-interlaced images need to be handled differently.
+     */
+
+    switch(IHDR->InterlaceMethod)
+    {
+	case PNG_InterlaceMethod_NonInterlaced :
+	{
+	    if(!DecodeImageNonInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal))
+	    {
+		ri.Free(OutBuffer); 
+    		ri.Free(DecompressedData); 
+    		CloseBufferedFile(ThePNG);
+
+		return;
+	    }
+	
+	    break;
+	}
+	
+	case PNG_InterlaceMethod_Interlaced :
+	{
+	    if(!DecodeImageInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal))
+	    {
+		ri.Free(OutBuffer); 
+    		ri.Free(DecompressedData); 
+    		CloseBufferedFile(ThePNG);
+
+		return;
+	    }
+	
+	    break;
+	}
+    
+	default :
+	{
+	    ri.Free(OutBuffer); 
+    	    ri.Free(DecompressedData); 
+    	    CloseBufferedFile(ThePNG);
+
+	    return;
+	}
+    }
+
+    /*
+     *  update the pointer to the image data
+     */
+
+    *pic = OutBuffer;
+ 
+    /*
+     *  Fill width and height.
+     */
+
+    if(width)
+    {
+        *width = IHDR_Width;
+    }
+
+    if(height)
+    {
+        *height = IHDR_Height;
+    }
+
+    /*
+     *  DecompressedData is not needed anymore.
+     */
+
+    ri.Free(DecompressedData); 
+
+    /*
+     *  We have all data, so close the file.
+     */
+
+    CloseBufferedFile(ThePNG);
+}
+
+//===================================================================
+
+/*
+=================
 R_LoadImage
 
 Loads any of the supported image types into a cannonical
@@ -1950,23 +4397,38 @@
 	}
 
 	if ( !Q_stricmp( name+len-4, ".tga" ) ) {
-	  LoadTGA( name, pic, width, height );            // try tga first
-    if (!*pic) {                                    //
-		  char altname[MAX_QPATH];                      // try jpg in place of tga 
-      strcpy( altname, name );                      
-      len = strlen( altname );                  
-      altname[len-3] = 'j';
-      altname[len-2] = 'p';
-      altname[len-1] = 'g';
+		LoadTGA( name, pic, width, height );
+
+		// This is a hack to get around the fact that some
+		// baseq3 shaders refer to tga files where the images
+		// are actually jpgs
+		if (!*pic) {
+			// try jpg in place of tga 
+			char altname[MAX_QPATH];
+			strcpy( altname, name );
+			len = strlen( altname );
+			altname[len-3] = 'j';
+			altname[len-2] = 'p';
+			altname[len-1] = 'g';
 			LoadJPG( altname, pic, width, height );
 		}
-  } else if ( !Q_stricmp(name+len-4, ".pcx") ) {
-    LoadPCX32( name, pic, width, height );
-	} else if ( !Q_stricmp( name+len-4, ".bmp" ) ) {
+	}
+	else if ( !Q_stricmp(name+len-4, ".pcx") )
+	{
+		LoadPCX32( name, pic, width, height );
+	}
+	else if ( !Q_stricmp( name+len-4, ".bmp" ) )
+	{
 		LoadBMP( name, pic, width, height );
-	} else if ( !Q_stricmp( name+len-4, ".jpg" ) ) {
+	}
+	else if ( !Q_stricmp( name+len-4, ".jpg" ) )
+	{
 		LoadJPG( name, pic, width, height );
 	}
+	else if ( !Q_stricmp( name+len-4, ".png" ) )
+	{
+		LoadPNG( name, pic, width, height );
+	}
 }
 
 
@@ -2023,7 +4485,7 @@
     altname[len-3] = toupper(altname[len-3]);             // and try upper case extension for unix systems
     altname[len-2] = toupper(altname[len-2]);             //
     altname[len-1] = toupper(altname[len-1]);             //
-		ri.Printf( PRINT_ALL, "trying %s...\n", altname );    // 
+		ri.Printf( PRINT_DEVELOPER, "trying %s...\n", altname );    // 
 	  R_LoadImage( altname, &pic, &width, &height );        //
     if (pic == NULL) {                                    // if that fails
       return NULL;                                        // bail




More information about the quake3-commits mailing list