Add third party files for reading/writing TGA files.

This commit is contained in:
Pavel Krajcevski 2013-11-19 12:04:06 -05:00
parent 6794a0fffb
commit 56259e2861
3 changed files with 875 additions and 0 deletions

View file

@ -78,6 +78,11 @@ IF( PVRTEXLIB_FOUND )
SET( HEADERS ${HEADERS} "src/ImageLoaderPVR.h" )
ENDIF( PVRTEXLIB_FOUND )
# Add third-party TGA library...
SET( SOURCES ${SOURCES} "third_party/tga/targa.c" )
SET( HEADERS ${HEADERS} "third_party/tga/targa.h" )
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/IO/third_party/tga )
CONFIGURE_FILE(
"config/ImageLoader.h.in"
"include/ImageLoader.h"

643
IO/third_party/tga/targa.c vendored Executable file
View file

@ -0,0 +1,643 @@
/*
* targa.c
*
* Copyright (C) 2006 - 2009 by Joshua S. English.
*
* This software is the intellectual property of Joshua S. English. 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 version must be plainly marked as such, and must not be
* misrepresented as being original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
*
* Notes:
*
* A plugin to read targa (TGA) image files into an OpenGL-compatible RGBA
* format.
*
* Written by Joshua S. English.
*/
// preprocessor directives
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "targa.h"
// define targa private constants
#define TGA_COLOR_MAP_NONE 0
#define TGA_IMAGE_TYPE_NONE 0
#define TGA_IMAGE_TYPE_CM 1
#define TGA_IMAGE_TYPE_BGR 2
#define TGA_IMAGE_TYPE_BW 3
#define TGA_IMAGE_TYPE_RLE_CM 9
#define TGA_IMAGE_TYPE_RLE_BGR 10
#define TGA_IMAGE_TYPE_RLE_BW 11
#define TGA_R 0
#define TGA_G 1
#define TGA_B 2
#define TGA_A 3
// declare targa private functions
static int handleTargaError(FILE *fh, int errorCode, const char *function,
size_t line);
static int ctoi(char value);
static char *localStrndup(char *string, int length);
// define targa private macros
#define targaErrorf() \
handleTargaError(fh, rc, __FUNCTION__, __LINE__)
// define targa private functions
static int handleTargaError(FILE *fh, int errorCode, const char *function,
size_t line)
{
char *errorMessage = NULL;
if((errorMessage = strerror(errno)) == NULL) {
errorMessage = "uknown error";
}
fprintf(stderr, "[%s():%i] error(%i) - #%i, '%s'.\n",
(char *)function, (int)line, errorCode, (int)errno, errorMessage);
if(fh != NULL) {
fclose(fh);
}
return -1;
}
static int ctoi(char value)
{
return (int)((unsigned char)value);
}
static char *localStrndup(char *string, int length)
{
char *result = NULL;
if((string == NULL) || (length < 1)) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return NULL;
}
#if defined(_GNU_SOURCE)
result = strndup(string, length);
#else // !_GNU_SOURCE
result = (char *)malloc(sizeof(char) * (length + 1));
memset(result, 0, (sizeof(char) * (length + 1)));
memcpy(result, string, length);
#endif // _GNU_SOURCE
return result;
}
// define targa public functions
int targa_init(Targa *targa)
{
if(targa == NULL) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return -1;
}
memset((void *)targa, 0, sizeof(Targa));
targa->width = 0;
targa->height = 0;
targa->imageLength = 0;
targa->image = NULL;
return 0;
}
int targa_free(Targa *targa)
{
if(targa == NULL) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return -1;
}
if(targa->image != NULL) {
free(targa->image);
}
memset((void *)targa, 0, sizeof(Targa));
return 0;
}
int targa_getDimensions(Targa *targa, int *width, int *height)
{
if((targa == NULL) || (width == NULL) || (height == NULL)) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return -1;
}
*width = targa->width;
*height = targa->height;
return 0;
}
int targa_getImageLength(Targa *targa, int *imageLength)
{
if((targa == NULL) || (imageLength == NULL)) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return -1;
}
*imageLength = targa->imageLength;
return 0;
}
int targa_getRgbaTexture(Targa *targa, char **texture, int *textureLength)
{
if((targa == NULL) || (texture == NULL) || (textureLength == NULL)) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return -1;
}
*texture = (char *)targa->image;
*textureLength = targa->imageLength;
return 0;
}
int targa_loadFromFile(Targa *targa, char *filename)
{
int rc = 0;
int fileLength = 0;
unsigned char *buffer = NULL;
FILE *fh = NULL;
if((targa == NULL) || (filename == NULL)) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return -1;
}
if((fh = fopen(filename, "r+b")) == NULL) {
return targaErrorf();
}
if((rc = fseek(fh, 0, SEEK_END)) != 0) {
return targaErrorf();
}
if((fileLength = ftell(fh)) < 0) {
return targaErrorf();
}
if((rc = fseek(fh, 0, SEEK_SET)) != 0) {
return targaErrorf();
}
if(fileLength < 18) {
fprintf(stderr, "error - TGA file '%s' length %i invalid.\n",
filename, fileLength);
fclose(fh);
return -1;
}
buffer = (unsigned char *)malloc(sizeof(unsigned char) * fileLength);
memset(buffer, 0, (sizeof(unsigned char) * fileLength));
rc = (int)fread((char *)buffer, sizeof(char), fileLength, fh);
if(rc != fileLength) {
return targaErrorf();
}
fclose(fh);
rc = targa_loadFromData(targa, buffer, fileLength);
free(buffer);
return rc;
}
int targa_loadFromData(Targa *targa, unsigned char *data, int dataLength)
{
short sNumber = 0;
int ii = 0;
int nn = 0;
int imageIdLength = 0;
int colorMap = 0;
int imageType = 0;
int bitLength = 0;
int colorMode = 0;
int length = 0;
int rleId = 0;
int pixel[4];
unsigned char *imageId = NULL;
unsigned char *ptr = NULL;
if((targa == NULL) || (data == NULL) || (dataLength < 18)) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return -1;
}
ptr = data;
// determine image ID length
imageIdLength = (int)ptr[0];
ptr++;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs "
"%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data),
dataLength);
return -1;
}
// check for color map
colorMap = (int)ptr[0];
ptr++;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs "
"%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data),
dataLength);
return -1;
}
if(colorMap != TGA_COLOR_MAP_NONE) {
fprintf(stderr, "[%s():%i] error - unable to read TARGA color map "
"%i.\n", __FUNCTION__, __LINE__, colorMap);
return -1;
}
// obtain image type
imageType = (int)ptr[0];
ptr++;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs "
"%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data),
dataLength);
return -1;
}
if((imageType == TGA_IMAGE_TYPE_NONE) ||
(imageType == TGA_IMAGE_TYPE_CM) ||
(imageType == TGA_IMAGE_TYPE_RLE_CM)) {
fprintf(stderr, "[%s():%i] error - unsupported image type %i.\n",
__FUNCTION__, __LINE__, imageType);
return -1;
}
// skip 9 bytes (color-map information and x & y origins)
ptr += 9;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs "
"%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data),
dataLength);
return -1;
}
// obtain image width
memcpy((char *)&sNumber, ptr, sizeof(short));
ptr += sizeof(short);
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs "
"%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data),
dataLength);
return -1;
}
if(sNumber < 1) {
fprintf(stderr, "[%s():%i] error - invalid image width %i.\n",
__FUNCTION__, __LINE__, (int)sNumber);
return -1;
}
targa->width = (int)sNumber;
// obtain image height
memcpy((char *)&sNumber, ptr, sizeof(short));
ptr += sizeof(short);
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs "
"%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data),
dataLength);
return -1;
}
if(sNumber < 1) {
fprintf(stderr, "[%s():%i] error - invalid image height %i.\n",
__FUNCTION__, __LINE__, (int)sNumber);
return -1;
}
targa->height = (int)sNumber;
// determine pixel depth
bitLength = (int)ptr[0];
ptr++;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs "
"%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data),
dataLength);
return -1;
}
if((bitLength != 16) && (bitLength != 24) && (bitLength != 32)) {
fprintf(stderr, "[%s():%i] error - unknown pixel depth of %i-bits.\n",
__FUNCTION__, __LINE__, bitLength);
return -1;
}
if((bitLength == 16) &&
((imageType != TGA_IMAGE_TYPE_BGR) &&
(imageType != TGA_IMAGE_TYPE_BW))) {
fprintf(stderr, "[%s():%i] error - unable to RLE-decode pixel depth "
"of %i-bits.\n", __FUNCTION__, __LINE__, bitLength);
return -1;
}
// skip 1 byte (image descriptor)
ptr++;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs "
"%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data),
dataLength);
return -1;
}
// obtain the image ID
if(imageIdLength > 0) {
if(((int)(ptr - data) + imageIdLength) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun at %i "
"(image ID) by %i bytes.\n", __FUNCTION__, __LINE__,
(int)(ptr - data),
(((int)(ptr - data) + imageIdLength) - dataLength));
return -1;
}
imageId = (unsigned char *)localStrndup((char *)ptr, imageIdLength);
ptr += imageIdLength;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with %i "
"vs %i.\n", __FUNCTION__, __LINE__, (int)(ptr - data),
dataLength);
return -1;
}
}
// process the image
targa->imageLength = (long int)(targa->width * targa->height * 4);
targa->image = (unsigned char *)malloc(sizeof(unsigned char) *
targa->imageLength);
if((imageType == TGA_IMAGE_TYPE_BGR) || (imageType == TGA_IMAGE_TYPE_BW)) {
if(bitLength == 16) {
colorMode = 2;
}
else {
colorMode = (bitLength / 8);
}
length = (targa->width * targa->height * colorMode);
if(((int)(ptr - data) + length) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun at %i "
"(image pixels) by %i bytes.\n", __FUNCTION__, __LINE__,
(int)(ptr - data),
(((int)(ptr - data) + length) - dataLength));
return -1;
}
for(ii = 0, nn = 0; ((ii < length) && (nn < targa->imageLength));
ii += colorMode, nn += 4) {
if(colorMode == 2) {
memcpy((char *)&sNumber, ptr, sizeof(short));
pixel[TGA_R] = ctoi((sNumber & 0x1f) << 3);
pixel[TGA_G] = ctoi(((sNumber >> 5) & 0x1f) << 3);
pixel[TGA_B] = ctoi(((sNumber >> 10) & 0x1f) << 3);
pixel[TGA_A] = 255;
}
else {
pixel[TGA_R] = ctoi(ptr[2]);
pixel[TGA_G] = ctoi(ptr[1]);
pixel[TGA_B] = ctoi(ptr[0]);
if(colorMode == 3) {
pixel[TGA_A] = 255;
}
else {
pixel[TGA_A] = ctoi(ptr[3]);
}
}
targa->image[(nn + 0)] = (unsigned char)pixel[TGA_R];
targa->image[(nn + 1)] = (unsigned char)pixel[TGA_G];
targa->image[(nn + 2)] = (unsigned char)pixel[TGA_B];
targa->image[(nn + 3)] = (unsigned char)pixel[TGA_A];
ptr += colorMode;
}
}
else { // RLE image
ii = 0;
nn = 0;
rleId = 0;
colorMode = (bitLength / 8);
length = (targa->width * targa->height);
while(ii < length) {
rleId = (int)ptr[0];
ptr++;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun with "
"%i vs %i.\n", __FUNCTION__, __LINE__,
(int)(ptr - data), dataLength);
return -1;
}
if(rleId < 128) {
rleId++;
while(rleId > 0) {
pixel[TGA_R] = ctoi(ptr[2]);
pixel[TGA_G] = ctoi(ptr[1]);
pixel[TGA_B] = ctoi(ptr[0]);
if(colorMode == 3) {
pixel[TGA_A] = 255;
}
else {
pixel[TGA_A] = ctoi(ptr[3]);
}
targa->image[(nn + 0)] = (unsigned char)pixel[TGA_R];
targa->image[(nn + 1)] = (unsigned char)pixel[TGA_G];
targa->image[(nn + 2)] = (unsigned char)pixel[TGA_B];
targa->image[(nn + 3)] = (unsigned char)pixel[TGA_A];
rleId--;
ii++;
nn += 4;
if(nn >= targa->imageLength) {
break;
}
ptr += colorMode;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data "
"overrun with %i vs %i.\n", __FUNCTION__,
__LINE__, (int)(ptr - data), dataLength);
return -1;
}
}
}
else {
pixel[TGA_R] = ctoi(ptr[2]);
pixel[TGA_G] = ctoi(ptr[1]);
pixel[TGA_B] = ctoi(ptr[0]);
if(colorMode == 3) {
pixel[TGA_A] = 255;
}
else {
pixel[TGA_A] = ctoi(ptr[3]);
}
ptr += colorMode;
if((int)(ptr - data) > dataLength) {
fprintf(stderr, "[%s():%i] error - detected data overrun "
"with %i vs %i.\n", __FUNCTION__, __LINE__,
(int)(ptr - data), dataLength);
return -1;
}
rleId -= 127;
while(rleId > 0) {
targa->image[(nn + 0)] = (unsigned char)pixel[TGA_R];
targa->image[(nn + 1)] = (unsigned char)pixel[TGA_G];
targa->image[(nn + 2)] = (unsigned char)pixel[TGA_B];
targa->image[(nn + 3)] = (unsigned char)pixel[TGA_A];
rleId--;
ii++;
nn += 4;
if(nn >= targa->imageLength) {
break;
}
}
}
if(nn >= targa->imageLength) {
break;
}
}
}
if(imageId != NULL) {
free(imageId);
}
return 0;
}
int targa_applyRgbaMask(Targa *targa, int colorType, unsigned char value)
{
int ii = 0;
int startPosition = 0;
if((targa == NULL) ||
((colorType != TARGA_COLOR_RED) &&
(colorType != TARGA_COLOR_GREEN) &&
(colorType != TARGA_COLOR_BLUE) &&
(colorType != TARGA_COLOR_ALPHA))) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return -1;
}
switch(colorType) {
case TARGA_COLOR_RED:
startPosition = 0;
break;
case TARGA_COLOR_GREEN:
startPosition = 1;
break;
case TARGA_COLOR_BLUE:
startPosition = 2;
break;
case TARGA_COLOR_ALPHA:
startPosition = 3;
break;
}
for(ii = startPosition; ii < targa->imageLength; ii += 4) {
targa->image[ii] += value;
}
return 0;
}
int targa_setRgbaChannel(Targa *targa, int colorType, unsigned char value)
{
int ii = 0;
int startPosition = 0;
if((targa == NULL) ||
((colorType != TARGA_COLOR_RED) &&
(colorType != TARGA_COLOR_GREEN) &&
(colorType != TARGA_COLOR_BLUE) &&
(colorType != TARGA_COLOR_ALPHA))) {
fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n",
__FUNCTION__, __LINE__);
return -1;
}
switch(colorType) {
case TARGA_COLOR_RED:
startPosition = 0;
break;
case TARGA_COLOR_GREEN:
startPosition = 1;
break;
case TARGA_COLOR_BLUE:
startPosition = 2;
break;
case TARGA_COLOR_ALPHA:
startPosition = 3;
break;
}
for(ii = startPosition; ii < targa->imageLength; ii += 4) {
targa->image[ii] = value;
}
return 0;
}

227
IO/third_party/tga/targa.h vendored Executable file
View file

@ -0,0 +1,227 @@
/*
* targa.h
*
* Copyright (C) 2006 - 2009 by Joshua S. English.
*
* This software is the intellectual property of Joshua S. English. 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 version must be plainly marked as such, and must not be
* misrepresented as being original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
*
* Notes:
*
* A plugin to read targa (TGA) image files into an OpenGL-compatible RGBA
* format, header file.
*
* Written by Joshua S. English.
*
*
* The TARGA Specification:
*
* Position: Length: Description:
* -------- ------ -----------
* 0 1 length of the image ID
* 1 1 type of color map included (if any)
* 0 => no color map
* 1 => has color map
* 2 1 image type
* 0 => no image data
* 1 => color-mapped image
* 2 => true-color image
* 3 => black & white image
* 9 => RLE color-mapped image
* 10 => RLE true-color image
* 11 => RLE black & white image
* 3 2 index of the first color-map entry as an offest
* into the color-map table
* 5 2 color-map length (number of entries)
* 7 1 color-map entry length - (number of bits per entry)
* 8 2 x-origin of image
* 10 2 y-origin of image
* 12 2 image width in pixels
* 14 2 image height in pixels
* 16 1 pixel depth - the number of bits per pixel
* 17 1 image descriptor
* n var image id - only exists if non-zero
* n var color-map data - only exists if non-zero
* n var image data
*/
#if !defined(_TARGA_H)
#define _TARGA_H
// define targa public constants
#define TARGA_COLOR_RED 1
#define TARGA_COLOR_GREEN 2
#define TARGA_COLOR_BLUE 3
#define TARGA_COLOR_ALPHA 4
// define targa public data types
typedef struct _Targa {
int width;
int height;
int imageLength;
unsigned char *image;
} Targa;
// declare targa public functions
/**
* targa_init()
*
* Initilize the Targa structure for utilization.
*
* @param targa(in) The Targa struct to initialize.
*
* @return An integer where zero is pass, less than zero is failure.
*/
int targa_init(Targa *targa);
/**
* targa_free()
*
* Free the Targa structure.
*
* @param targa(in) The Targa struct to free.
*
* @return An integer where zero is pass, less than zero is failure.
*/
int targa_free(Targa *targa);
/**
* targa_getDimensions()
*
* Obtain the width and height in pixels of a loaded Targa image.
*
* @param targa(in) The Targa struct of a loaded image.
*
* @param width(out) The width in pixels of a loaded Targa image.
*
* @param height(out) The height in pixels of a loaded Targa image.
*
* @return An integer where zero is pass, less than zero is failure.
*/
int targa_getDimensions(Targa *targa, int *width, int *height);
/**
* targa_getImageLength()
*
* Obtain the length in bytes of the serialized RGBA image.
*
* @param targa(in) The Targa struct of a loaded image.
*
* @param imageLength(out) The length in bytes of the RGBA image.
*
* @return An integer where zero is pass, less than zero is failure.
*/
int targa_getImageLength(Targa *targa, int *imageLength);
/**
* targa_getRgbaTexture()
*
* Obtain the serialized RGBA texture and its' length from a Targa image.
*
* @param targa(in) The Targa struct of a loaded image.
*
* @param texture(out) The serialized RGBA image pointer.
*
* @param textureLength(out) The serialized RGBA image length in bytes.
*
* @return An integer where zero is pass, less than zero is failure.
*/
int targa_getRgbaTexture(Targa *targa, char **texture, int *textureLength);
/**
* targa_loadFromFile()
*
* Load a targa file and decode it into a 32-bit RGBA serialized image.
*
* @param targa(in) The Targa struct of an image to load.
*
* @param filename(in) The filename of the image to load.
*
* @return An integer where zero is pass, less than zero is failure.
*/
int targa_loadFromFile(Targa *targa, char *filename);
/**
* targa_loadFromData()
*
* Load the targa from an in-memory location and decode it into a 32-bit RGBA
* serialize image.
*
* @param targa(in) The Targa struct an image to load.
*
* @param data(in) A pointer to an in-memory location containing a
* Targa image.
*
* @param dataLength(in) The length of the Targa in-memory image.
*
* @return An integer where zero is pass, less than zero is failure.
*/
int targa_loadFromData(Targa *targa, unsigned char *data, int dataLength);
/**
* targa_applyRgbaMask()
*
* Apply a red, green, blue or alpha-channel additive color-mask to a loaded
* Targa image.
*
* @param targa(in) The Targa struct of a loaded image.
*
* @param colorType(in) The color channel to mask.
*
* @param value(in) The color code (0 - 255) to mask.
*
* @return An integer where zero is pass, less than zero is failure.
*/
int targa_applyRgbaMask(Targa *targa, int colorType, unsigned char value);
/**
* targa_setRgbaChannel()
*
* Apply a red, green, blue or alpha-channel additive color-channel
* replacement to a loaded Targa image.
*
* @param targa(in) The Targa struct of a loaded image.
*
* @param colorType(in) The color channel to replace.
*
* @param value(in) The color code (0 - 255) to replace.
*
* @return An integer where zero is pass, less than zero is failure.
*/
int targa_setRgbaChannel(Targa *targa, int colorType, unsigned char value);
#endif // _TARGA_H