Initial commit.

This commit is contained in:
Jim Gray
2013-04-04 14:32:05 -07:00
parent ba5c81da32
commit d71d53e8ec
2180 changed files with 1393544 additions and 1 deletions

View File

@@ -0,0 +1,65 @@
// TgaWiz.cpp : Defines the entry point for the console application.
//
#include <windows.h>
#include <cstdio>
#include "png.h"
typedef unsigned char byte;
void R_MipMap (byte *in, int width, int height, bool simple = true);
void LoadTGA ( const char *name, byte **pic, int *width, int *height);
void SaveTGA( byte *pic, int width, int height, char *fileName );
int main(int argc, char *argv[])
{
unsigned char *img;
int w, h;
if (argc != 3)
{
printf("USAGE: %s infile outfile\n", argv[0]);
return 0;
}
// Load the PNG file, make sure that we have an alpha channel in memory
if (!LoadPNG32(argv[1], &img, &w, &h, NULL))
{
printf("ERROR: Couldn't load %s\n", argv[1]);
return 0;
}
// Save it out as TGA
SaveTGA(img, w, h, argv[2]);
return 0;
}
#if 0
int main(int argc, char* argv[])
{
unsigned char *img;
int w, h;
if (argc != 4)
{
printf("USAGE: %s infile outfile N\n");
printf(" N is largest allowed dimensions\n");
return 0;
}
int maxSize = atoi(argv[3]);
// Load it
LoadTGA(argv[1], &img, &w, &h);
while (w > maxSize || h > maxSize)
{
R_MipMap(img, w, h, true);
w /= 2;
h /= 2;
}
SaveTGA(img, w, h, argv[2]);
return 0;
}
#endif

View File

@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 7.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TgaWiz", "TgaWiz.vcproj", "{CF864863-5FC5-489B-BE7E-427F17921820}"
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
ConfigName.0 = Debug
ConfigName.1 = Release
EndGlobalSection
GlobalSection(ProjectDependencies) = postSolution
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{CF864863-5FC5-489B-BE7E-427F17921820}.Debug.ActiveCfg = Debug|Win32
{CF864863-5FC5-489B-BE7E-427F17921820}.Debug.Build.0 = Debug|Win32
{CF864863-5FC5-489B-BE7E-427F17921820}.Release.ActiveCfg = Release|Win32
{CF864863-5FC5-489B-BE7E-427F17921820}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding = "Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.00"
Name="TgaWiz"
ProjectGUID="{CF864863-5FC5-489B-BE7E-427F17921820}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/TgaWiz.exe"
LinkIncremental="2"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/TgaWiz.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
OmitFramePointers="TRUE"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/TgaWiz.exe"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
</Configuration>
</Configurations>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
<File
RelativePath="TgaWiz.cpp">
</File>
<File
RelativePath="deflate.cpp">
</File>
<File
RelativePath="deflate.h">
</File>
<File
RelativePath="inflate.cpp">
</File>
<File
RelativePath="inflate.h">
</File>
<File
RelativePath="png.cpp">
</File>
<File
RelativePath="png.h">
</File>
<File
RelativePath="tga.cpp">
</File>
<File
RelativePath="zip.h">
</File>
<File
RelativePath="zipcommon.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc">
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
</Filter>
<File
RelativePath="ReadMe.txt">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

View File

2082
tools/pngtgaTool/deflate.cpp Normal file

File diff suppressed because it is too large Load Diff

231
tools/pngtgaTool/deflate.h Normal file
View File

@@ -0,0 +1,231 @@
// Stream status
#define INIT_STATE 42
#define BUSY_STATE 113
#define FINISH_STATE 666
#define HASH_BITS 15
#define HASH_SIZE (1 << HASH_BITS)
#define HASH_MASK (HASH_SIZE - 1)
// Size of match buffer for literals/lengths. There are 4 reasons for
// limiting lit_bufsize to 64K:
// - frequencies can be kept in 16 bit counters
// - if compression is not successful for the first block, all input
// data is still in the window so we can still emit a stored block even
// when input comes from standard input. (This can also be done for
// all blocks if lit_bufsize is not greater than 32K.)
// - if compression is not successful for a file smaller than 64K, we can
// even emit a stored file instead of a stored block (saving 5 bytes).
// This is applicable only for zip (not gzip or zlib).
// - creating new Huffman trees less frequently may not provide fast
// adaptation to changes in the input data statistics. (Take for
// example a binary file with poorly compressible code followed by
// a highly compressible string table.) Smaller buffer sizes give
// fast adaptation but have of course the overhead of transmitting
// trees more frequently.
// - I can't count above 4
#define LIT_BUFSIZE (1 << 14)
#define MAX_BLOCK_SIZE 0xffff
// Number of bits by which ins_h must be shifted at each input
// step. It must be such that after MIN_MATCH steps, the oldest
// byte no longer takes part in the hash key.
#define HASH_SHIFT ((HASH_BITS + MIN_MATCH - 1) / MIN_MATCH)
// Matches of length 3 are discarded if their distance exceeds TOO_FAR
#define TOO_FAR 32767
// Number of length codes, not counting the special END_BLOCK code
#define LENGTH_CODES 29
// Number of codes used to transfer the bit lengths
#define BL_CODES 19
// Number of literal bytes 0..255
#define LITERALS 256
// Number of Literal or Length codes, including the END_BLOCK code
#define L_CODES (LITERALS + 1 + LENGTH_CODES)
// See definition of array dist_code below
#define DIST_CODE_LEN 512
// Maximum heap size
#define HEAP_SIZE (2 * L_CODES + 1)
// Index within the heap array of least frequent node in the Huffman tree
#define SMALLEST 1
// Bit length codes must not exceed MAX_BL_BITS bits
#define MAX_BL_BITS 7
// End of block literal code
#define END_BLOCK 256
// Repeat previous bit length 3-6 times (2 bits of repeat count)
#define REP_3_6 16
// Repeat a zero length 3-10 times (3 bits of repeat count)
#define REPZ_3_10 17
// Repeat a zero length 11-138 times (7 bits of repeat count)
#define REPZ_11_138 18
// Number of bits used within bi_buf. (bi_buf might be implemented on
// more than 16 bits on some systems.)
#define BUF_SIZE (8 * 2)
// Minimum amount of lookahead, except at the end of the input file.
// See deflate.c for comments about the MIN_MATCH+1.
#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
typedef enum
{
NEED_MORE, // block not completed, need more input or more output
BLOCK_DONE, // block flush performed
FINISH_STARTED, // finish started, need only more output at next deflate
FINISH_DONE // finish done, accept no more input or output
} block_state;
// Data structure describing a single value and its code string.
typedef struct ct_data_s
{
union
{
word freq; // frequency count
word code; // bit string
} fc;
union
{
word dad; // father node in Huffman tree
word len; // length of bit string
} dl;
} ct_data;
typedef struct static_tree_desc_s
{
const ct_data *static_tree; // static tree or NULL
const ulong *extra_bits; // extra bits for each code or NULL
ulong extra_base; // base index for extra_bits
ulong elems; // max number of elements in the tree
ulong max_length; // max bit length for the codes
} static_tree_desc;
typedef struct tree_desc_s
{
ct_data *dyn_tree; // the dynamic tree
ulong max_code; // largest code with non zero frequency
static_tree_desc *stat_desc; // the corresponding static tree
} tree_desc;
// Main structure which the deflate algorithm works from
typedef struct deflate_state_s
{
z_stream *z; // pointer back to this zlib stream
ulong status; // as the name implies
EFlush last_flush; // value of flush param for previous deflate call
int noheader; // suppress zlib header and adler32
byte pending_buf[MAX_BLOCK_SIZE + 5];// output still pending
byte *pending_out; // next pending byte to output to the stream
ulong pending; // nb of bytes in the pending buffer
// Sliding window. Input bytes are read into the second half of the window,
// and move to the first half later to keep a dictionary of at least wSize
// bytes. With this organization, matches are limited to a distance of
// wSize-MAX_MATCH bytes, but this ensures that IO is always
// performed with a length multiple of the block size. Also, it limits
// the window size to 64K, which is quite useful on MSDOS.
// To do: use the user input buffer as sliding window.
byte window[WINDOW_SIZE * 2];
// Link to older string with same hash index. To limit the size of this
// array to 64K, this link is maintained only for the last 32K strings.
// An index in this array is thus a window index modulo 32K.
word prev[WINDOW_SIZE];
word head[HASH_SIZE]; // Heads of the hash chains or NULL.
ulong ins_h; // hash index of string to be inserted
// Window position at the beginning of the current output block. Gets
// negative when the window is moved backwards.
int block_start;
ulong match_length; // length of best match
ulong prev_match; // previous match
ulong match_available; // set if previous match exists
ulong strstart; // start of string to insert
ulong match_start; // start of matching string
ulong lookahead; // number of valid bytes ahead in window
// Length of the best match at previous step. Matches not greater than this
// are discarded. This is used in the lazy match evaluation.
ulong prev_length;
// Attempt to find a better match only when the current match is strictly
// smaller than this value. This mechanism is used only for compression levels >= 4.
ulong max_lazy_match;
ulong good_match; // Use a faster search when the previous match is longer than this
ulong nice_match; // Stop searching when current match exceeds this
// To speed up deflation, hash chains are never searched beyond this
// length. A higher limit improves compression ratio but degrades the speed.
ulong max_chain_length;
ELevel level; // compression level (0..9)
ct_data dyn_ltree[HEAP_SIZE]; // literal and length tree
ct_data dyn_dtree[(2 * D_CODES) + 1]; // distance tree
ct_data bl_tree[(2 * BL_CODES) + 1]; // Huffman tree for bit lengths
tree_desc l_desc; // desc. for literal tree
tree_desc d_desc; // desc. for distance tree
tree_desc bl_desc; // desc. for bit length tree
word bl_count[MAX_WBITS + 1]; // number of codes at each bit length for an optimal tree
// The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
// The same heap array is used to build all trees.
ulong heap[(2 * L_CODES) + 1]; // heap used to build the Huffman trees
ulong heap_len; // number of elements in the heap
ulong heap_max; // element of largest frequency
byte depth[(2 * L_CODES) + 1]; // Depth of each subtree used as tie breaker for trees of equal frequency
byte l_buf[LIT_BUFSIZE]; // buffer for literals or lengths
ulong last_lit; // running index in l_buf
// Buffer for distances. To simplify the code, d_buf and l_buf have
// the same number of elements. To use different lengths, an extra flag
// array would be necessary.
word d_buf[LIT_BUFSIZE];
ulong opt_len; // bit length of current block with optimal trees
ulong static_len; // bit length of current block with static trees
ulong matches; // number of string matches in current block
ulong last_eob_len; // bit length of EOB code for last block
word bi_buf; // Output buffer. bits are inserted starting at the bottom (least significant bits).
ulong bi_valid; // Number of valid bits in bi_buf. All bits above the last valid bit are always zero.
ulong adler;
} deflate_state;
// Compression function. Returns the block state after the call.
typedef block_state (*compress_func) (deflate_state *s, EFlush flush);
typedef struct config_s
{
word good_length; // reduce lazy search above this match length
word max_lazy; // do not perform lazy search above this match length
word nice_length; // quit search above this match length
word max_chain;
compress_func func;
} config;
// end

1843
tools/pngtgaTool/inflate.cpp Normal file

File diff suppressed because it is too large Load Diff

145
tools/pngtgaTool/inflate.h Normal file
View File

@@ -0,0 +1,145 @@
// Maximum size of dynamic tree. The maximum found in a long but non-
// exhaustive search was 1004 huft structures (850 for length/literals
// and 154 for distances, the latter actually the result of an
// exhaustive search). The actual maximum is not known, but the
// value below is more than safe.
#define MANY 1440
// maximum bit length of any code (if BMAX needs to be larger than 16, then h and x[] should be ulong.)
#define BMAX 15
typedef ulong (*check_func) (ulong check, const byte *buf, ulong len);
typedef enum
{
TYPE, // get type bits (3, including end bit)
LENS, // get lengths for stored
STORED, // processing stored block
TABLE, // get table lengths
BTREE, // get bit lengths tree for a dynamic block
DTREE, // get length, distance trees for a dynamic block
CODES, // processing fixed or dynamic block
DRY, // output remaining window bytes
DONE, // finished last block, done
BAD // got a data error--stuck here
} inflate_block_mode;
// waiting for "i:"=input, "o:"=output, "x:"=nothing
typedef enum
{
START, // x: set up for LEN
LEN, // i: get length/literal/eob next
LENEXT, // i: getting length extra (have base)
DIST, // i: get distance next
DISTEXT, // i: getting distance extra
COPY, // o: copying bytes in window, waiting for space
LIT, // o: got literal, waiting for output space
WASH, // o: got eob, possibly still output waiting
END, // x: got eob and all data flushed
BADCODE // x: got error
} inflate_codes_mode;
typedef enum
{
imMETHOD, // waiting for method byte
imFLAG, // waiting for flag byte
imBLOCKS, // decompressing blocks
imCHECK4, // four check bytes to go
imCHECK3, // three check bytes to go
imCHECK2, // two check bytes to go
imCHECK1, // one check byte to go
imDONE, // finished check, done
imBAD // got an error--stay here
} inflate_mode;
typedef struct inflate_huft_s
{
byte Exop; // number of extra bits or operation
byte Bits; // number of bits in this code or subcode
ulong base; // literal, length base, distance base, or table offset
} inflate_huft_t;
// inflate codes private state
typedef struct inflate_codes_state_s
{
inflate_codes_mode mode; // current inflate_codes mode
// mode dependent information
ulong len;
union
{
struct
{
inflate_huft_t *tree; // pointer into tree
ulong need; // bits needed
} code; // if LEN or DIST, where in tree
ulong lit; // if LIT, literal
struct
{
ulong get; // bits to get for extra
ulong dist; // distance back to copy from
} copy; // if EXT or COPY, where and how much
}; // submode
// mode independent information
byte lbits; // ltree bits decoded per branch
byte dbits; // dtree bits decoder per branch
inflate_huft_t *ltree; // literal/length/eob tree
inflate_huft_t *dtree; // distance tree
} inflate_codes_state_t;
// inflate blocks semi-private state
typedef struct inflate_blocks_state_s
{
// mode
inflate_block_mode mode; // current inflate_block mode
// mode dependent information
union
{
ulong left; // if STORED, bytes left to copy
struct
{
ulong table; // table lengths (14 bits)
ulong index; // index into blens (or border)
ulong *blens; // bit lengths of codes
ulong bb; // bit length tree depth
inflate_huft_t *tb; // bit length decoding tree
} trees; // if DTREE, decoding info for trees
struct
{
inflate_codes_state_t *codes;
} decode; // if CODES, current state
}; // submode
bool last; // true if this block is the last block
// mode independent information
ulong bitk; // bits in bit buffer
ulong bitb; // bit buffer
inflate_huft_t *hufts; // single malloc for tree space
byte window[WINDOW_SIZE]; // sliding window
byte *end; // one byte after sliding window
byte *read; // window read pointer
byte *write; // window write pointer
ulong check; // check on output
} inflate_blocks_state_t;
// inflate private state
typedef struct inflate_state_s
{
inflate_mode mode; // current inflate mode
ulong method; // if FLAGS, method byte
// mode independent information
int nowrap; // flag for no wrapper
ulong wbits; // log2(window size) (8..15, defaults to 15)
inflate_blocks_state_t *blocks; // current inflate_blocks state
ulong adler;
ulong calcadler;
} inflate_state;
// end

822
tools/pngtgaTool/png.cpp Normal file
View File

@@ -0,0 +1,822 @@
// Generic PNG file loading code
// leave this as first line for PCH reasons...
//
//#include "../game/q_shared.h"
//#include "../qcommon/qcommon.h"
#include "zip.h"
#include "png.h"
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <stdio.h>
//#include "../qcommon/memory.h"
static int BigLong(int l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
// Error returns
#define PNG_ERROR_OK 0
#define PNG_ERROR_DECOMP 1
#define PNG_ERROR_COMP 2
#define PNG_ERROR_MEMORY 3
#define PNG_ERROR_NOSIG 4
#define PNG_ERROR_TOO_SMALL 5
#define PNG_ERROR_WNP2 6
#define PNG_ERROR_HNP2 7
#define PNG_ERROR_NOT_TC 8
#define PNG_ERROR_INV_FIL 9
#define PNG_ERROR_FAILED_CRC 10
#define PNG_ERROR_CREATE_FAIL 11
#define PNG_ERROR_WRITE 12
#define PNG_ERROR_NOT_PALETTE 13
#define PNG_ERROR_NOT8BIT 14
#define PNG_ERROR_TOO_LARGE 15
static int png_error = PNG_ERROR_OK;
static const byte png_signature[8] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
static const char png_copyright[] = "Copyright\0Raven Software Inc. 2001";
static const char *png_errors[] =
{
"OK.",
"Error decompressing image data.",
"Error compressing image data.",
"Error allocating memory.",
"PNG signature not found.",
"Image is too small to load.",
"Width is not a power of two.",
"Height is not a power of two.",
"Image is not 24 or 32 bit.",
"Invalid filter or compression type.",
"Failed CRC check.",
"Could not create file.",
"Error writing to file.",
"Image is not indexed colour.",
"Image does not have 8 bits per sample.",
"Image is too large",
};
// Gets the error string for a failed PNG operation
const char *PNG_GetError(void)
{
return(png_errors[png_error]);
}
// Create a header chunk
void PNG_CreateHeader(png_ihdr_t *header, int width, int height, int bytedepth)
{
header->width = BigLong(width);
header->height = BigLong(height);
header->bitdepth = 8;
if(bytedepth == 3)
{
header->colortype = 2;
}
if(bytedepth == 4)
{
header->colortype = 6;
}
header->compression = 0;
header->filter = 0;
header->interlace = 0;
}
// Processes the header chunk and checks to see if all the data is valid
bool PNG_HandleIHDR(const byte *data, png_image_t *image)
{
png_ihdr_t *ihdr = (png_ihdr_t *)data;
image->width = BigLong(ihdr->width);
image->height = BigLong(ihdr->height);
// Make sure image is a reasonable size
if((image->width < 2) || (image->height < 2))
{
png_error = PNG_ERROR_TOO_SMALL;
return(false);
}
if(image->width > MAX_PNG_WIDTH)
{
png_error = PNG_ERROR_TOO_LARGE;
return(false);
}
if(ihdr->bitdepth != 8)
{
png_error = PNG_ERROR_NOT8BIT;
return(false);
}
// Check for non power of two size (but not for data files)
if(image->isimage)
{
if(image->width & (image->width - 1))
{
png_error = PNG_ERROR_WNP2;
return(false);
}
if(image->height & (image->height - 1))
{
png_error = PNG_ERROR_HNP2;
return(false);
}
}
// Make sure we have a 24 or 32 bit image (for images)
if(image->isimage)
{
if((ihdr->colortype != 2) && (ihdr->colortype != 6))
{
png_error = PNG_ERROR_NOT_TC;
return(false);
}
}
// Make sure we have an 8 bit grayscale image for data files
if(!image->isimage)
{
if(ihdr->colortype && (ihdr->colortype != 3))
{
png_error = PNG_ERROR_NOT_PALETTE;
return(false);
}
}
// Make sure we aren't using any wacky compression or filter algos
if(ihdr->compression || ihdr->filter)
{
png_error = PNG_ERROR_INV_FIL;
return(false);
}
// Extract the data we need
if(!ihdr->colortype || (ihdr->colortype == 3))
{
image->bytedepth = 1;
}
if(ihdr->colortype == 2)
{
image->bytedepth = 3;
}
if(ihdr->colortype == 6)
{
image->bytedepth = 4;
}
return(true);
}
// Filter a row of data
void PNG_Filter(byte *out, byte filter, const byte *in, const byte *lastline, ulong rowbytes, ulong bpp)
{
ulong i;
switch(filter)
{
case PNG_FILTER_VALUE_NONE:
memcpy(out, in, rowbytes);
break;
case PNG_FILTER_VALUE_SUB:
for(i = 0; i < bpp; i++)
{
*out++ = *in++;
}
for(i = bpp; i < rowbytes; i++)
{
*out++ = *in - *(in - bpp);
in++;
}
break;
case PNG_FILTER_VALUE_UP:
for(i = 0; i < rowbytes; i++)
{
if(lastline)
{
*out++ = *in++ - *lastline++;
}
else
{
*out++ = *in++;
}
}
break;
case PNG_FILTER_VALUE_AVG:
for(i = 0; i < bpp; i++)
{
if(lastline)
{
*out++ = *in++ - (*lastline++ >> 1);
}
else
{
*out++ = *in++;
}
}
for(i = bpp; i < rowbytes; i++)
{
if(lastline)
{
*out++ = *in - ((*lastline++ + *(in - bpp)) >> 1);
}
else
{
*out++ = *in - (*(in - bpp) >> 1);
}
in++;
}
break;
case PNG_FILTER_VALUE_PAETH:
int a, b, c;
int pa, pb, pc, p;
for(i = 0; i < bpp; i++)
{
if(lastline)
{
*out++ = *in++ - *lastline++;
}
else
{
*out++ = *in++;
}
}
for(i = bpp; i < rowbytes; i++)
{
a = *(in - bpp);
c = 0;
b = 0;
if(lastline)
{
c = *(lastline - bpp);
b = *lastline++;
}
p = b - c;
pc = a - c;
pa = p < 0 ? -p : p;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
*out++ = *in++ - p;
}
break;
}
}
// Unfilters a row of data
void PNG_Unfilter(byte *out, byte filter, const byte *lastline, ulong rowbytes, ulong bpp)
{
ulong i;
switch(filter)
{
case PNG_FILTER_VALUE_NONE:
break;
case PNG_FILTER_VALUE_SUB:
out += bpp;
for(i = bpp; i < rowbytes; i++)
{
*out += *(out - bpp);
out++;
}
break;
case PNG_FILTER_VALUE_UP:
for(i = 0; i < rowbytes; i++)
{
if(lastline)
{
*out += *lastline++;
}
out++;
}
break;
case PNG_FILTER_VALUE_AVG:
for(i = 0; i < bpp; i++)
{
if(lastline)
{
*out += *lastline++ >> 1;
}
out++;
}
for(i = bpp; i < rowbytes; i++)
{
if(lastline)
{
*out += (*lastline++ + *(out - bpp)) >> 1;
}
else
{
*out += *(out - bpp) >> 1;
}
out++;
}
break;
case PNG_FILTER_VALUE_PAETH:
int a, b, c;
int pa, pb, pc, p;
for(i = 0; i < bpp; i++)
{
if(lastline)
{
*out += *lastline++;
}
out++;
}
for(i = bpp; i < rowbytes; i++)
{
a = *(out - bpp);
c = 0;
b = 0;
if(lastline)
{
c = *(lastline - bpp);
b = *lastline++;
}
p = b - c;
pc = a - c;
pa = p < 0 ? -p : p;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
*out++ += p;
}
break;
default:
break;
}
}
// Pack up the image data line by line
bool PNG_Pack(byte *out, ulong *size, ulong maxsize, byte *data, int width, int height, int bytedepth)
{
z_stream zdata;
ulong rowbytes;
ulong y;
const byte *lastline, *source;
// Storage for filter type and filtered row
byte workline[(MAX_PNG_WIDTH * MAX_PNG_DEPTH) + 1];
// Number of bytes per row
rowbytes = width * bytedepth;
memset(&zdata, 0, sizeof(z_stream));
if(deflateInit(&zdata, Z_FAST_COMPRESSION_HIGH) != Z_OK)
{
png_error = PNG_ERROR_COMP;
return(false);
}
zdata.next_out = out;
zdata.avail_out = maxsize;
lastline = NULL;
source = data + ((height - 1) * rowbytes);
for(y = 0; y < height; y++)
{
// Refilter using the most compressable filter algo
// Assume paeth to speed things up
workline[0] = (byte)PNG_FILTER_VALUE_PAETH;
PNG_Filter(workline + 1, (byte)PNG_FILTER_VALUE_PAETH, source, lastline, rowbytes, bytedepth);
zdata.next_in = workline;
zdata.avail_in = rowbytes + 1;
if(deflate(&zdata, Z_SYNC_FLUSH) != Z_OK)
{
deflateEnd(&zdata);
png_error = PNG_ERROR_COMP;
return(false);
}
lastline = source;
source -= rowbytes;
}
if(deflate(&zdata, Z_FINISH) != Z_STREAM_END)
{
png_error = PNG_ERROR_COMP;
return(false);
}
*size = zdata.total_out;
deflateEnd(&zdata);
return(true);
}
// Unpack the image data, line by line
bool PNG_Unpack(const byte *data, const ulong datasize, png_image_t *image)
{
ulong rowbytes, zerror, y;
byte filter;
z_stream zdata;
byte *lastline, *out;
// MD_PushTag(TAG_ZIP_TEMP);
memset(&zdata, 0, sizeof(z_stream));
if(inflateInit(&zdata, Z_SYNC_FLUSH) != Z_OK)
{
png_error = PNG_ERROR_DECOMP;
// MD_PopTag();
return(false);
}
zdata.next_in = (byte *)data;
zdata.avail_in = datasize;
rowbytes = image->width * image->bytedepth;
lastline = NULL;
out = image->data;
for(y = 0; y < image->height; y++)
{
// Inflate a row of data
zdata.next_out = &filter;
zdata.avail_out = 1;
if(inflate(&zdata) != Z_OK)
{
inflateEnd(&zdata);
png_error = PNG_ERROR_DECOMP;
// MD_PopTag();
return(false);
}
zdata.next_out = out;
zdata.avail_out = rowbytes;
zerror = inflate(&zdata);
if((zerror != Z_OK) && (zerror != Z_STREAM_END))
{
inflateEnd(&zdata);
png_error = PNG_ERROR_DECOMP;
// MD_PopTag();
return(false);
}
// Unfilter a row of data
PNG_Unfilter(out, filter, lastline, rowbytes, image->bytedepth);
lastline = out;
out += rowbytes;
}
inflateEnd(&zdata);
// MD_PopTag();
return(true);
}
// Scan through all chunks and process each one
bool PNG_Load(const byte *data, ulong datasize, png_image_t *image)
{
bool moredata;
const byte *next;
byte *workspace, *work;
ulong length, type, crc, totallength;
png_error = PNG_ERROR_OK;
if(memcmp(data, png_signature, sizeof(png_signature)))
{
png_error = PNG_ERROR_NOSIG;
return(false);
}
data += sizeof(png_signature);
// workspace = (byte *)Z_Malloc(datasize, TAG_TEMP_PNG, qfalse);
workspace = new byte[datasize];
work = workspace;
totallength = 0;
moredata = true;
while(moredata)
{
length = BigLong(*(ulong *)data);
data += sizeof(ulong);
type = BigLong(*(ulong *)data);
const byte *crcbase = data;
data += sizeof(ulong);
// CRC checksum location
next = data + length + sizeof(ulong);
// CRC checksum includes header field
crc = crc32(0, crcbase, length + sizeof(ulong));
if(crc != (ulong)BigLong(*(ulong *)(next - 4)))
{
if(image->data)
{
delete [] image->data;
//Z_Free(image->data);
image->data = NULL;
}
delete [] workspace;
//Z_Free(workspace);
png_error = PNG_ERROR_FAILED_CRC;
return(false);
}
switch(type)
{
case PNG_IHDR:
if(!PNG_HandleIHDR(data, image))
{
delete [] workspace;
//Z_Free(workspace);
return(false);
}
image->data = (byte *)Z_Malloc(image->width * image->height * image->bytedepth, TAG_TEMP_PNG, qfalse);
break;
case PNG_IDAT:
// Need to copy all the various IDAT chunks into one big one
// Everything but 3dsmax has one IDAT chunk
memcpy(work, data, length);
work += length;
totallength += length;
break;
case PNG_IEND:
if(!PNG_Unpack(workspace, totallength, image))
{
delete [] workspace;
delete [] image->data;
//Z_Free(workspace);
//Z_Free(image->data);
image->data = NULL;
return(false);
}
moredata = false;
break;
default:
break;
}
data = next;
}
delete [] workspace;
//Z_Free(workspace);
return(true);
}
// Outputs a crc'd chunk of PNG data
#if 0
bool PNG_OutputChunk(fileHandle_t fp, ulong type, byte *data, ulong size)
{
ulong crc, little, outcount;
// Output a standard PNG chunk - length, type, data, crc
little = BigLong(size);
outcount = FS_Write(&little, sizeof(little), fp);
little = BigLong(type);
crc = crc32(0, (byte *)&little, sizeof(little));
outcount += FS_Write(&little, sizeof(little), fp);
if(size)
{
crc = crc32(crc, data, size);
outcount += FS_Write(data, size, fp);
}
little = BigLong(crc);
outcount += FS_Write(&little, sizeof(little), fp);
if(outcount != (size + 12))
{
png_error = PNG_ERROR_WRITE;
return(false);
}
return(true);
}
// Saves a PNG format compressed image
bool PNG_Save(const char *name, byte *data, int width, int height, int bytedepth)
{
byte *work;
fileHandle_t fp;
int maxsize;
ulong size, outcount;
png_ihdr_t png_header;
png_error = PNG_ERROR_OK;
// Create the file
fp = FS_FOpenFileWrite(name);
if(!fp)
{
png_error = PNG_ERROR_CREATE_FAIL;
return(false);
}
// Write out the PNG signature
outcount = FS_Write(png_signature, sizeof(png_signature), fp);
if(outcount != sizeof(png_signature))
{
FS_FCloseFile(fp);
png_error = PNG_ERROR_WRITE;
return(false);
}
// Create and output a valid header
PNG_CreateHeader(&png_header, width, height, bytedepth);
if(!PNG_OutputChunk(fp, PNG_IHDR, (byte *)&png_header, sizeof(png_header)))
{
FS_FCloseFile(fp);
return(false);
}
// Create and output the copyright info
if(!PNG_OutputChunk(fp, PNG_tEXt, (byte *)png_copyright, sizeof(png_copyright)))
{
FS_FCloseFile(fp);
return(false);
}
// Max size of compressed image (source size + 0.1% + 12)
maxsize = (width * height * bytedepth) + 4096;
work = (byte *)Z_Malloc(maxsize, TAG_TEMP_PNG, qtrue); // fixme: optimise to qfalse sometime - ok?
// Pack up the image data
if(!PNG_Pack(work, &size, maxsize, data, width, height, bytedepth))
{
Z_Free(work);
FS_FCloseFile(fp);
return(false);
}
// Write out the compressed image data
if(!PNG_OutputChunk(fp, PNG_IDAT, (byte *)work, size))
{
Z_Free(work);
FS_FCloseFile(fp);
return(false);
}
Z_Free(work);
// Output terminating chunk
if(!PNG_OutputChunk(fp, PNG_IEND, NULL, 0))
{
FS_FCloseFile(fp);
return(false);
}
FS_FCloseFile(fp);
return(true);
}
#endif
/*
=============
PNG_ConvertTo32
=============
*/
void PNG_ConvertTo32(png_image_t *image)
{
byte *temp;
byte *old, *old2;
ulong i;
//temp = (byte *)Z_Malloc(image->width * image->height * 4, TAG_TEMP_PNG, qtrue);
temp = new byte[image->width * image->height * 4];
old = image->data;
old2 = old;
image->data = temp;
image->bytedepth = 4;
for(i = 0; i < image->width * image->height; i++)
{
*temp++ = *old++;
*temp++ = *old++;
*temp++ = *old++;
*temp++ = 0xff;
}
//Z_Free(old2);
delete [] old2;
}
/*
=============
LoadPNG32
=============
*/
bool LoadPNG32 (char *name, byte **pixels, int *width, int *height, int *bytedepth)
{
byte *buffer;
byte **bufferptr = &buffer;
int nLen;
png_image_t png_image;
if(!pixels)
{
bufferptr = NULL;
}
byte *pTempLoadedBuffer = 0;
HANDLE hnd = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hnd == INVALID_HANDLE_VALUE)
return false;
DWORD dwSize = GetFileSize(hnd, NULL);
if (dwSize == INVALID_FILE_SIZE)
{
CloseHandle(hnd);
return false;
}
pTempLoadedBuffer = new byte[dwSize];
DWORD dwRead;
ReadFile(hnd, pTempLoadedBuffer, dwSize, &dwRead, NULL);
CloseHandle(hnd);
if (dwRead != dwSize)
{
delete [] pTempLoadedBuffer;
return false;
}
*bufferptr = pTempLoadedBuffer;
nLen = dwSize;
*pixels = NULL;
png_image.isimage = true;
if(!PNG_Load(buffer, nLen, &png_image))
{
printf ("Error parsing %s: %s\n", name, PNG_GetError());
return(false);
}
if(png_image.bytedepth != 4)
{
PNG_ConvertTo32(&png_image);
}
*pixels = png_image.data;
if(width)
{
*width = png_image.width;
}
if(height)
{
*height = png_image.height;
}
if(bytedepth)
{
*bytedepth = png_image.bytedepth;
}
//FS_FreeFile(buffer);
return(true);
}
/*
=============
LoadPNG8
=============
*/
#if 0
bool LoadPNG8 (char *name, byte **pixels, int *width, int *height)
{
byte *buffer;
byte **bufferptr = &buffer;
int nLen;
png_image_t png_image;
if(!pixels)
{
bufferptr = NULL;
}
nLen = FS_ReadFile ( ( char * ) name, (void **)bufferptr);
if (nLen == -1)
{
if(pixels)
{
*pixels = NULL;
}
return(false);
}
if(!pixels)
{
return(true);
}
*pixels = NULL;
png_image.isimage = false;
if(!PNG_Load(buffer, nLen, &png_image))
{
Com_Printf ("Error parsing %s: %s\n", name, PNG_GetError());
return(false);
}
*pixels = png_image.data;
if(width)
{
*width = png_image.width;
}
if(height)
{
*height = png_image.height;
}
FS_FreeFile(buffer);
return(true);
}
#endif
// end

73
tools/pngtgaTool/png.h Normal file
View File

@@ -0,0 +1,73 @@
// Known chunk types
#define PNG_IHDR 'IHDR'
#define PNG_IDAT 'IDAT'
#define PNG_IEND 'IEND'
#define PNG_tEXt 'tEXt'
#define PNG_PLTE 'PLTE'
#define PNG_bKGD 'bKGD'
#define PNG_cHRM 'cHRM'
#define PNG_gAMA 'gAMA'
#define PNG_hIST 'hIST'
#define PNG_iCCP 'iCCP'
#define PNG_iTXt 'iTXt'
#define PNG_oFFs 'oFFs'
#define PNG_pCAL 'pCAL'
#define PNG_sCAL 'sCAL'
#define PNG_pHYs 'pHYs'
#define PNG_sBIT 'sBIT'
#define PNG_sPLT 'sPLT'
#define PNG_sRGB 'sRGB'
#define PNG_tIME 'tIME'
#define PNG_tRNS 'tRNS'
#define PNG_zTXt 'zTXt'
// Filter values
#define PNG_FILTER_VALUE_NONE 0
#define PNG_FILTER_VALUE_SUB 1
#define PNG_FILTER_VALUE_UP 2
#define PNG_FILTER_VALUE_AVG 3
#define PNG_FILTER_VALUE_PAETH 4
#define PNG_FILTER_NUM 5
// Common defines and typedefs
#define MAX_PNG_WIDTH 4096
#define MAX_PNG_DEPTH 4
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long ulong;
#pragma pack(push)
#pragma pack(1)
typedef struct png_ihdr_s
{
ulong width;
ulong height;
byte bitdepth; // Bits per sample (not per pixel)
byte colortype; // bit 0 - palette; bit 1 - RGB; bit 2 - alpha channel
byte compression; // 0 for zip - error otherwise
byte filter; // 0 for adaptive with the 5 basic types - error otherwise
byte interlace; // 0 for no interlace - 1 for Adam7 interlace
} png_ihdr_t;
#pragma pack(pop)
typedef struct png_image_s
{
byte *data;
ulong width;
ulong height;
ulong bytedepth;
bool isimage;
} png_image_t;
bool LoadPNG32 (char *name, byte **pixels, int *width, int *height, int *bytedepth);
bool LoadPNG8 (char *name, byte **pixels, int *width, int *height);
bool PNG_Save(const char *name, byte *data, int width, int height, int bytedepth);
// end

View File

@@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// TgaWiz.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

12
tools/pngtgaTool/stdafx.h Normal file
View File

@@ -0,0 +1,12 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <stdio.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here

512
tools/pngtgaTool/tga.cpp Normal file
View File

@@ -0,0 +1,512 @@
// Bootleg TGA support, stolen from Q3
#include <windows.h>
#include <string.h>
#include <assert.h>
#include <cstdio>
typedef unsigned char byte;
typedef unsigned short word;
// Prints an error message, and aborts the program
void Error(const char *msg)
{
fprintf(stderr, "ERROR: %s\n", msg);
exit(0);
}
/*
================
R_MipMap2
Uses temp mem, but then copies back to input, quartering the size of the texture
Proper linear filter
================
*/
void R_MipMap2( unsigned *in, int inWidth, int inHeight )
{
int i, j, k;
byte *outpix;
int inWidthMask, inHeightMask;
int total;
int outWidth, outHeight;
unsigned *temp;
outWidth = inWidth >> 1;
outHeight = inHeight >> 1;
temp = new unsigned[outWidth*outHeight*4];
inWidthMask = inWidth - 1;
inHeightMask = inHeight - 1;
for ( i = 0 ; i < outHeight ; i++ ) {
for ( j = 0 ; j < outWidth ; j++ ) {
outpix = (byte *) ( temp + i * outWidth + j );
for ( k = 0 ; k < 4 ; k++ ) {
total =
1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k];
outpix[k] = total / 36;
}
}
}
memcpy( in, temp, outWidth * outHeight * 4 );
delete [] temp;
}
/*
================
R_MipMap
Operates in place, quartering the size of the texture
================
*/
void R_MipMap (byte *in, int width, int height, bool simple)
{
int i, j;
byte *out;
int row;
if ( width == 1 && height == 1 ) {
return;
}
if ( !simple ) {
R_MipMap2( (unsigned *)in, width, height );
return;
}
row = width * 4;
out = in;
width >>= 1;
height >>= 1;
if ( width == 0 || height == 0 ) {
width += height; // get largest
for (i=0 ; i<width ; i++, out+=4, in+=8 ) {
out[0] = ( in[0] + in[4] )>>1;
out[1] = ( in[1] + in[5] )>>1;
out[2] = ( in[2] + in[6] )>>1;
out[3] = ( in[3] + in[7] )>>1;
}
return;
}
for (i=0 ; i<height ; i++, in+=row) {
for (j=0 ; j<width ; j++, out+=4, in+=8) {
out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2;
out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2;
out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2;
out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2;
}
}
}
// My TGA loader...
//
//---------------------------------------------------
#pragma pack(push,1)
typedef struct
{
byte byIDFieldLength; // must be 0
byte byColourmapType; // 0 = truecolour, 1 = paletted, else bad
byte byImageType; // 1 = colour mapped (palette), uncompressed, 2 = truecolour, uncompressed, else bad
word w1stColourMapEntry; // must be 0
word wColourMapLength; // 256 for 8-bit palettes, else 0 for true-colour
byte byColourMapEntrySize; // 24 for 8-bit palettes, else 0 for true-colour
word wImageXOrigin; // ignored
word wImageYOrigin; // ignored
word wImageWidth; // in pixels
word wImageHeight; // in pixels
byte byImagePlanes; // bits per pixel (8 for paletted, else 24 for true-colour)
byte byScanLineOrder; // Image descriptor bytes
// bits 0-3 = # attr bits (alpha chan)
// bits 4-5 = pixel order/dir
// bits 6-7 scan line interleave (00b=none,01b=2way interleave,10b=4way)
} TGAHeader_t;
#pragma pack(pop)
// *pic == pic, else NULL for failed.
//
// returns false if found but had a format error, else true for either OK or not-found (there's a reason for this)
//
void LoadTGA ( const char *name, byte **pic, int *width, int *height)
{
// these don't need to be declared or initialised until later, but the compiler whines that 'goto' skips them.
//
byte *pRGBA = NULL;
byte *pOut = NULL;
byte *pIn = NULL;
*pic = NULL;
#define TGA_FORMAT_ERROR(blah) Error(blah)
//
// load the file
//
byte *pTempLoadedBuffer = 0;
HANDLE hnd = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hnd == INVALID_HANDLE_VALUE)
return;
DWORD dwSize = GetFileSize(hnd, NULL);
if (dwSize == INVALID_FILE_SIZE)
{
CloseHandle(hnd);
return;
}
pTempLoadedBuffer = new byte[dwSize];
DWORD dwRead;
ReadFile(hnd, pTempLoadedBuffer, dwSize, &dwRead, NULL);
CloseHandle(hnd);
if (dwRead != dwSize)
{
delete [] pTempLoadedBuffer;
return;
}
TGAHeader_t *pHeader = (TGAHeader_t *) pTempLoadedBuffer;
if (pHeader->byColourmapType!=0)
{
TGA_FORMAT_ERROR("LoadTGA: colourmaps not supported\n" );
}
if (pHeader->byImageType != 2 && pHeader->byImageType != 3 && pHeader->byImageType != 10)
{
TGA_FORMAT_ERROR("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RLE-RGB) images supported\n");
}
if (pHeader->w1stColourMapEntry != 0)
{
TGA_FORMAT_ERROR("LoadTGA: colourmaps not supported\n" );
}
if (pHeader->wColourMapLength !=0 && pHeader->wColourMapLength != 256)
{
TGA_FORMAT_ERROR("LoadTGA: ColourMapLength must be either 0 or 256\n" );
}
if (pHeader->byColourMapEntrySize != 0 && pHeader->byColourMapEntrySize != 24)
{
TGA_FORMAT_ERROR("LoadTGA: ColourMapEntrySize must be either 0 or 24\n" );
}
if ( ( pHeader->byImagePlanes != 24 && pHeader->byImagePlanes != 32) && (pHeader->byImagePlanes != 8 && pHeader->byImageType != 3))
{
TGA_FORMAT_ERROR("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
}
if ((pHeader->byScanLineOrder&0x30)!=0x00 &&
(pHeader->byScanLineOrder&0x30)!=0x10 &&
(pHeader->byScanLineOrder&0x30)!=0x20 &&
(pHeader->byScanLineOrder&0x30)!=0x30
)
{
TGA_FORMAT_ERROR("LoadTGA: ScanLineOrder must be either 0x00,0x10,0x20, or 0x30\n");
}
// these last checks are so i can use ID's RLE-code. I don't dare fiddle with it or it'll probably break...
//
if ( pHeader->byImageType == 10)
{
if ((pHeader->byScanLineOrder & 0x30) != 0x00)
{
TGA_FORMAT_ERROR("LoadTGA: RLE-RGB Images (type 10) must be in bottom-to-top format\n");
}
if (pHeader->byImagePlanes != 24 && pHeader->byImagePlanes != 32) // probably won't happen, but avoids compressed greyscales?
{
TGA_FORMAT_ERROR("LoadTGA: RLE-RGB Images (type 10) must be 24 or 32 bit\n");
}
}
// now read the actual bitmap in...
//
// Image descriptor bytes
// bits 0-3 = # attr bits (alpha chan)
// bits 4-5 = pixel order/dir
// bits 6-7 scan line interleave (00b=none,01b=2way interleave,10b=4way)
//
int iYStart,iXStart,iYStep,iXStep;
switch(pHeader->byScanLineOrder & 0x30)
{
default: // default case stops the compiler complaining about using uninitialised vars
case 0x00: // left to right, bottom to top
iXStart = 0;
iXStep = 1;
iYStart = pHeader->wImageHeight-1;
iYStep = -1;
break;
case 0x10: // right to left, bottom to top
iXStart = pHeader->wImageWidth-1;
iXStep = -1;
iYStart = pHeader->wImageHeight-1;
iYStep = -1;
break;
case 0x20: // left to right, top to bottom
iXStart = 0;
iXStep = 1;
iYStart = 0;
iYStep = 1;
break;
case 0x30: // right to left, top to bottom
iXStart = pHeader->wImageWidth-1;
iXStep = -1;
iYStart = 0;
iYStep = 1;
break;
}
// feed back the results...
//
if (width)
*width = pHeader->wImageWidth;
if (height)
*height = pHeader->wImageHeight;
pRGBA = new byte[pHeader->wImageWidth * pHeader->wImageHeight * 4];
*pic = pRGBA;
pOut = pRGBA;
pIn = pTempLoadedBuffer + sizeof(*pHeader);
// I don't know if this ID-thing here is right, since comments that I've seen are at the end of the file,
// with a zero in this field. However, may as well...
//
if (pHeader->byIDFieldLength != 0)
pIn += pHeader->byIDFieldLength; // skip TARGA image comment
byte red,green,blue,alpha;
if ( pHeader->byImageType == 2 || pHeader->byImageType == 3 ) // RGB or greyscale
{
for (int y=iYStart, iYCount=0; iYCount<pHeader->wImageHeight; y+=iYStep, iYCount++)
{
pOut = pRGBA + y * pHeader->wImageWidth *4;
for (int x=iXStart, iXCount=0; iXCount<pHeader->wImageWidth; x+=iXStep, iXCount++)
{
switch (pHeader->byImagePlanes)
{
case 8:
blue = *pIn++;
green = blue;
red = blue;
*pOut++ = red;
*pOut++ = green;
*pOut++ = blue;
*pOut++ = 255;
break;
case 24:
blue = *pIn++;
green = *pIn++;
red = *pIn++;
*pOut++ = red;
*pOut++ = green;
*pOut++ = blue;
*pOut++ = 255;
break;
case 32:
blue = *pIn++;
green = *pIn++;
red = *pIn++;
alpha = *pIn++;
*pOut++ = red;
*pOut++ = green;
*pOut++ = blue;
*pOut++ = alpha;
break;
default:
assert(0); // if we ever hit this, someone deleted a header check higher up
TGA_FORMAT_ERROR("LoadTGA: Image can only have 8, 24 or 32 planes for RGB/greyscale\n");
break;
}
}
}
}
else
if (pHeader->byImageType == 10) // RLE-RGB
{
// I've no idea if this stuff works, I normally reject RLE targas, but this is from ID's code
// so maybe I should try and support it...
//
byte packetHeader, packetSize, j;
for (int y = pHeader->wImageHeight-1; y >= 0; y--)
{
pOut = pRGBA + y * pHeader->wImageWidth *4;
for (int x=0; x<pHeader->wImageWidth;)
{
packetHeader = *pIn++;
packetSize = 1 + (packetHeader & 0x7f);
if (packetHeader & 0x80) // run-length packet
{
switch (pHeader->byImagePlanes)
{
case 24:
blue = *pIn++;
green = *pIn++;
red = *pIn++;
alpha = 255;
break;
case 32:
blue = *pIn++;
green = *pIn++;
red = *pIn++;
alpha = *pIn++;
break;
default:
assert(0); // if we ever hit this, someone deleted a header check higher up
TGA_FORMAT_ERROR("LoadTGA: RLE-RGB can only have 24 or 32 planes\n");
break;
}
for (j=0; j<packetSize; j++)
{
*pOut++ = red;
*pOut++ = green;
*pOut++ = blue;
*pOut++ = alpha;
x++;
if (x == pHeader->wImageWidth) // run spans across rows
{
x = 0;
if (y > 0)
y--;
else
goto breakOut;
pOut = pRGBA + y * pHeader->wImageWidth * 4;
}
}
}
else
{ // non run-length packet
for (j=0; j<packetSize; j++)
{
switch (pHeader->byImagePlanes)
{
case 24:
blue = *pIn++;
green = *pIn++;
red = *pIn++;
*pOut++ = red;
*pOut++ = green;
*pOut++ = blue;
*pOut++ = 255;
break;
case 32:
blue = *pIn++;
green = *pIn++;
red = *pIn++;
alpha = *pIn++;
*pOut++ = red;
*pOut++ = green;
*pOut++ = blue;
*pOut++ = alpha;
break;
default:
assert(0); // if we ever hit this, someone deleted a header check higher up
TGA_FORMAT_ERROR("LoadTGA: RLE-RGB can only have 24 or 32 planes\n");
break;
}
x++;
if (x == pHeader->wImageWidth) // pixel packet run spans across rows
{
x = 0;
if (y > 0)
y--;
else
goto breakOut;
pOut = pRGBA + y * pHeader->wImageWidth * 4;
}
}
}
}
breakOut:;
}
}
delete [] pTempLoadedBuffer;
}
void SaveTGA( byte *pic, int width, int height, char *fileName )
{
TGAHeader_t header;
memset (&header, 0, sizeof(header));
header.byImageType = 2; // Uncompressed
header.wImageHeight = height;
header.wImageWidth = width;
header.byImagePlanes = 32; // BPP
header.byScanLineOrder = 0x20;
// swap rgb to bgr
byte *buffer = pic;
byte temp;
for (int i = 0; i < width * height * 4; i += 4)
{
temp = buffer[i];
buffer[i] = buffer[i+2];
buffer[i+2] = temp;
}
HANDLE hnd = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwWritten;
if (hnd == INVALID_HANDLE_VALUE)
return;
WriteFile(hnd, &header, sizeof(header), &dwWritten, NULL);
if (dwWritten != sizeof(header))
{
printf("ERROR: Couldn't write to file %s\n", fileName);
CloseHandle(hnd);
return;
}
WriteFile(hnd, pic, width * height * 4, &dwWritten, NULL);
CloseHandle(hnd);
}

201
tools/pngtgaTool/zip.h Normal file
View File

@@ -0,0 +1,201 @@
//
// zlib.h -- interface of the 'zlib' general purpose compression library
// version 1.1.3, July 9th, 1998
//
// Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors 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.
//
// Jean-loup Gailly Mark Adler
// jloup@gzip.org madler@alumni.caltech.edu
//
// The data format used by the zlib library is described by RFCs (Request for
// Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
// (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
//
// The 'zlib' compression library provides in-memory compression and
// decompression functions, including integrity checks of the uncompressed
// data. This version of the library supports only one compression method
// (deflation) but other algorithms will be added later and will have the same
// stream interface.
//
// Compression can be done in a single step if the buffers are large
// enough (for example if an input file is mmap'ed), or can be done by
// repeated calls of the compression function. In the latter case, the
// application must provide more input and/or consume the output
// (providing more output space) before each call.
//
// The library does not install any signal handler. The decoder checks
// the consistency of the compressed data, so the library should never
// crash even in case of corrupted input.
// This particular implementation has been heavily modified by jscott@ravensoft.com
// to increase inflate/deflate speeds on 32 bit machines.
// for more info about .ZIP format, see
// ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
// PkWare has also a specification at :
// ftp://ftp.pkware.com/probdesc.zip
// ========================================================================================
// External calls and defines required for the zlib
// ========================================================================================
// The deflate compression method
#define ZF_STORED 0
#define ZF_DEFLATED 8
// Compression levels
typedef enum
{
Z_STORE_COMPRESSION,
Z_FAST_COMPRESSION_LOW,
Z_FAST_COMPRESSION,
Z_FAST_COMPRESSION_HIGH,
Z_SLOW_COMPRESSION_LOWEST,
Z_SLOW_COMPRESSION_LOW,
Z_DEFAULT_COMPRESSION,
Z_SLOW_COMPRESSION_HIGH,
Z_SLOW_COMPRESSION_HIGHEST,
Z_MAX_COMPRESSION,
} ELevel;
// Allowed flush values
typedef enum
{
Z_NEED_MORE = -1, // Special case when finishing up the stream
Z_NO_FLUSH,
Z_SYNC_FLUSH, // Sync up the stream ready for another call
Z_FINISH // Finish up the stream
} EFlush;
// Return codes for the compression/decompression functions. Negative
// values are errors, positive values are used for special but normal events.
typedef enum
{
Z_STREAM_ERROR = -3, // Basic error from failed sanity checks
Z_BUF_ERROR, // Not enough input or output
Z_DATA_ERROR, // Invalid data in the stream
Z_OK,
Z_STREAM_END // End of stream
} EStatus;
// Maximum value for windowBits in deflateInit and inflateInit.
// The memory requirements for inflate are (in bytes) 1 << windowBits
// that is, 32K for windowBits=15 (default value) plus a few kilobytes
// for small objects.
#define MAX_WBITS 15 // 32K LZ77 window
#define WINDOW_SIZE (1 << MAX_WBITS)
#define BIG_WINDOW_SIZE (WINDOW_SIZE << 1)
#define WINDOW_MASK (WINDOW_SIZE - 1)
// The three kinds of block type
#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES 2
#define MODE_ILLEGAL 3
// The minimum and maximum match lengths
#define MIN_MATCH 3
#define MAX_MATCH 258
// number of distance codes
#define D_CODES 30
typedef unsigned long ulong;
typedef unsigned char byte;
typedef unsigned short word;
extern const ulong extra_dbits[D_CODES];
// Structure to be used by external applications
#define Z_Malloc(s, x1, x2) malloc((s))
#define Z_Free(p) free((p))
// The application must update next_in and avail_in when avail_in has
// dropped to zero. It must update next_out and avail_out when avail_out
// has dropped to zero. All other fields are set by the
// compression library and must not be updated by the application.
typedef struct z_stream_s
{
byte *next_in; // next input unsigned char
ulong avail_in; // number of unsigned chars available at next_in
ulong total_in; // total number of bytes processed so far
byte *next_out; // next output unsigned char should be put there
ulong avail_out; // remaining free space at next_out
ulong total_out; // total number of bytes output
EStatus status;
EStatus error; // error code
struct inflate_state_s *istate; // not visible by applications
struct deflate_state_s *dstate; // not visible by applications
ulong quality;
} z_stream;
// Update a running crc with the bytes buf[0..len-1] and return the updated
// crc. If buf is NULL, this function returns the required initial value
// for the crc. Pre- and post-conditioning (one's complement) is performed
// within this function so it shouldn't be done by the application.
// Usage example:
//
// ulong crc = crc32(0L, NULL, 0);
//
// while (read_buffer(buffer, length) != EOF) {
// crc = crc32(crc, buffer, length);
// }
// if (crc != original_crc) error();
ulong crc32(ulong crc, const byte *buf, ulong len);
// Update a running Adler-32 checksum with the bytes buf[0..len-1] and
// return the updated checksum. If buf is NULL, this function returns
// the required initial value for the checksum.
// An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
// much faster. Usage example:
//
// ulong adler = adler32(0L, NULL, 0);
//
// while (read_buffer(buffer, length) != EOF) {
// adler = adler32(adler, buffer, length);
// }
// if (adler != original_adler) error();
ulong adler32(ulong adler, const byte *buf, ulong len);
// External calls to the deflate code
EStatus deflateInit(z_stream *strm, ELevel level, int noWrap = 0);
EStatus deflateCopy(z_stream *dest, z_stream *source);
EStatus deflate(z_stream *strm, EFlush flush);
EStatus deflateEnd(z_stream *strm);
const char *deflateError(void);
// External calls to the deflate code
EStatus inflateInit(z_stream *strm, EFlush flush, int noWrap = 0);
EStatus inflate(z_stream *z);
EStatus inflateEnd(z_stream *strm);
const char *inflateError(void);
// External calls to the zipfile code
bool InflateFile(byte *src, ulong compressedSize, byte *dst, ulong uncompressedSize, int noWrap = 0);
bool DeflateFile(byte *src, ulong uncompressedSize, byte *dst, ulong maxCompressedSize, ulong *compressedSize, ELevel level, int noWrap = 0);
// end

View File

@@ -0,0 +1,117 @@
// -----------------------------------------------------------------------------------------------
// Table of CRC-32's of all single-byte values (made by make_crc_table)
// -----------------------------------------------------------------------------------------------
static const unsigned long crc_table[256] =
{
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
// -----------------------------------------------------------------------------------------------
// Calculate 32 bit CRC checksum for len bytes
// -----------------------------------------------------------------------------------------------
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned long len)
{
if(!buf)
{
return(0);
}
crc = crc ^ 0xffffffff;
while(len--)
{
crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
}
return(crc ^ 0xffffffff);
}
// -----------------------------------------------------------------------------------------------
// Calculate 32 bit Adler checksum (quicker than CRC)
// -----------------------------------------------------------------------------------------------
// largest prime smaller than 65536
#define BASE 65521
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
#define NMAX 5552
unsigned long adler32(unsigned long adler, const unsigned char *buf, unsigned long len)
{
unsigned long s1;
unsigned long s2;
int k;
if(!buf)
{
return(1);
}
s1 = adler & 0xffff;
s2 = (adler >> 16) & 0xffff;
while (len > 0)
{
k = len < NMAX ? len : NMAX;
len -= k;
while (k--)
{
s1 += *buf++;
s2 += s1;
}
s1 %= BASE;
s2 %= BASE;
}
return (s2 << 16) | s1;
}
// end