0ad/source/lib/res/graphics/tex_tga.cpp
Ykkrosh ab94e73385 Added 'restrict' support for non-GCC compilers (partly to benefit from the optimisation, partly to make it more likely that bugs will be found if restrict is ever used incorrectly).
Renamed to 'RESTRICT' so it doesn't conflict with __declspec(restrict)
in MSVC's standard headers.

This was SVN commit r4740.
2007-01-06 01:33:13 +00:00

174 lines
3.9 KiB
C++

/**
* =========================================================================
* File : tex_tga.cpp
* Project : 0 A.D.
* Description : TGA codec.
*
* @author Jan.Wassenberg@stud.uni-karlsruhe.de
* =========================================================================
*/
/*
* Copyright (c) 2004 Jan Wassenberg
*
* Redistribution and/or modification are also permitted under the
* terms of the GNU General Public License as published by the
* Free Software Foundation (version 2 or later, at your option).
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "precompiled.h"
#include "lib/byte_order.h"
#include "tex_codec.h"
#pragma pack(push, 1)
enum TgaImgType
{
TGA_TRUE_COLOUR = 2, // uncompressed 24 or 32 bit direct RGB
TGA_GREY = 3 // uncompressed 8 bit direct greyscale
};
enum TgaImgDesc
{
TGA_RIGHT_TO_LEFT = BIT(4),
TGA_TOP_DOWN = BIT(5),
};
typedef struct
{
u8 img_id_len; // 0 - no image identifier present
u8 colour_map_type; // 0 - no colour map present
u8 img_type; // see TgaImgType
u8 colour_map[5]; // unused
u16 x_origin; // unused
u16 y_origin; // unused
u16 w;
u16 h;
u8 bpp; // bits per pixel
u8 img_desc;
}
TgaHeader;
// TGA file: header [img id] [colour map] image data
#pragma pack(pop)
static LibError tga_transform(Tex* UNUSED(t), uint UNUSED(transforms))
{
return INFO::TEX_CODEC_CANNOT_HANDLE;
}
static bool tga_is_hdr(const u8* file)
{
TgaHeader* hdr = (TgaHeader*)file;
// the first TGA header doesn't have a magic field;
// we can only check if the first 4 bytes are valid
// .. not direct colour
if(hdr->colour_map_type != 0)
return false;
// .. wrong colour type (not uncompressed greyscale or RGB)
if(hdr->img_type != TGA_TRUE_COLOUR && hdr->img_type != TGA_GREY)
return false;
// note: we can't check img_id_len or colour_map[0] - they are
// undefined and may assume any value.
return true;
}
static bool tga_is_ext(const char* ext)
{
return !stricmp(ext, "tga");
}
static size_t tga_hdr_size(const u8* file)
{
size_t hdr_size = sizeof(TgaHeader);
if(file)
{
TgaHeader* hdr = (TgaHeader*)file;
hdr_size += hdr->img_id_len;
}
return hdr_size;
}
// requirements: uncompressed, direct colour, bottom up
static LibError tga_decode(DynArray* RESTRICT da, Tex* RESTRICT t)
{
u8* file = da->base;
TgaHeader* hdr = (TgaHeader*)file;
const u8 type = hdr->img_type;
const uint w = read_le16(&hdr->w);
const uint h = read_le16(&hdr->h);
const uint bpp = hdr->bpp;
const u8 desc = hdr->img_desc;
uint flags = 0;
flags |= (desc & TGA_TOP_DOWN)? TEX_TOP_DOWN : TEX_BOTTOM_UP;
if(desc & 0x0f) // alpha bits
flags |= TEX_ALPHA;
if(bpp == 8)
flags |= TEX_GREY;
if(type == TGA_TRUE_COLOUR)
flags |= TEX_BGR;
// sanity checks
// .. storing right-to-left is just stupid;
// we're not going to bother converting it.
if(desc & TGA_RIGHT_TO_LEFT)
WARN_RETURN(ERR::TEX_INVALID_LAYOUT);
t->w = w;
t->h = h;
t->bpp = bpp;
t->flags = flags;
return INFO::OK;
}
static LibError tga_encode(Tex* RESTRICT t, DynArray* RESTRICT da)
{
u8 img_desc = 0;
if(t->flags & TEX_TOP_DOWN)
img_desc |= TGA_TOP_DOWN;
if(t->bpp == 32)
img_desc |= 8; // size of alpha channel
TgaImgType img_type = (t->flags & TEX_GREY)? TGA_GREY : TGA_TRUE_COLOUR;
int transforms = t->flags;
transforms &= ~TEX_ORIENTATION; // no flip needed - we can set top-down bit.
transforms ^= TEX_BGR; // TGA is native BGR.
const TgaHeader hdr =
{
0, // no image identifier present
0, // no colour map present
(u8)img_type,
{0,0,0,0,0}, // unused (colour map)
0, 0, // unused (origin)
t->w,
t->h,
t->bpp,
img_desc
};
const size_t hdr_size = sizeof(hdr);
return tex_codec_write(t, transforms, &hdr, hdr_size, da);
}
TEX_CODEC_REGISTER(tga);