📄 targa_provider_generic.cpp
字号:
/* $Id: targa_provider_generic.cpp,v 1.10 2003/09/19 10:33:02 mbn Exp $
**
** ClanLib Game SDK
** Copyright (C) 2003 The ClanLib Team
** For a total list of contributers see the file CREDITS.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Display/display_precomp.h"
#include <cstdio>
#include "API/Display/Providers/targa_provider.h"
#include "API/Core/IOData/cl_endian.h"
#include "API/Core/System/error.h"
#include "API/Core/System/cl_assert.h"
#include "API/Core/System/clanstring.h"
#include "targa_provider_generic.h"
using namespace std;
/*
Generic info about using alphachannel/transparanty
Apparently the code works in this way (as far as I can understand):
==============================================================
The blit code "only" looks at rgb & alpha.
If alpha = 0 then a pixel is transparant
If alpha = 255 then a pixel is "fully" visible.
All values in between are used for alphablending
==============================================================
The *Loading* code works as follows:
0) you can turn nothing on (or everything off :)
1) you can turn on transparant pixels
2) you can set to ignore the alphachannel (turn it off)
ad 0) the alphachannel is just copied from the input file format
(or set to 255 if unavailable) and we don't care about
any pixels marked as transparant by color.
ad 1) If you choose to turn on transparant pixels, then all pixels
are traversed and for the pixels matching the "transparant color",
the alpha value is set to 0 (transparant).
ad 2) If you choose to ignore the alphachannel, then the alphachannel
for ALL pixels is set to 255 UNLESS you also specified to use
transparant pixels (wich means that some pixels might get aplha=0).
note: if you have transparant pixels & alphachannel on then pixels
with an alphavalue of 0 will be reset to the "transparant pixel color"
==============================================================
*/
CL_TargaProvider_Generic::CL_TargaProvider_Generic(
const std::string name,
CL_InputSourceProvider *_provider,
bool _transparent,
bool _ignore_alphachannel,
unsigned char trans_red,
unsigned char trans_green,
unsigned char trans_blue)
{
if (_provider == NULL)
{
provider = CL_InputSourceProvider::create_file_provider(".");
}
else
{
provider = _provider->clone();
}
ignore_alphachannel = _ignore_alphachannel;
transparent = _transparent;
use_alphapixels = transparent && !ignore_alphachannel;
trans_redcol = trans_red;
trans_greencol = trans_green;
trans_bluecol = trans_blue;
if (transparent)
{
trans_col = (((unsigned int) trans_redcol) << 24) +
(((unsigned int) trans_greencol)<<16) +
(((unsigned int) trans_bluecol) << 8);
}
else
{
trans_col = -1;
}
locked = false;
filename = name;
file = image = color_map = NULL;
}
CL_TargaProvider_Generic::~CL_TargaProvider_Generic()
{
perform_unlock();
delete provider;
}
/*
Read the file data - a .TGA file can exist in several
different formats - not all formats are supported by
this surfaceprovider.
*/
void CL_TargaProvider_Generic::read_data()
{
datatype = file[2];
switch (datatype)
{
case 1:
read_colormapped();
return;
break;
case 2:
read_uncompressed_rgb();
return;
break;
case 9:
// this format is not tested (but I think it works)
read_runlength_encoded_colormapped_rgb();
return;
break;
case 10:
read_runlength_encoded_rgb();
return;
break;
}
std::string err("CL_TargaProvider Fatal Error: Unsupported TGA filetype encountered");
throw CL_Error(err);
}
/*
Reads the .TGA header - this header is relatively equal
between subformats - except for whether the colormap
is interesting.
*/
void CL_TargaProvider_Generic::read_header(bool read_colormap)
{
unsigned char idlength = file[0];
unsigned char colormaptype = file[1];
pos = 18;
// Skip the id-string (if any)
if (idlength != 0)
{
pos += idlength;
}
bpp = file[16];
// read or skip the colormap (rgb-palette)
if (colormaptype == 1)
{
map_length = *((unsigned short *) &file[5]);
SWAP_IF_BIG(map_length);
unsigned char map_size = file[7]>>3;
if (!read_colormap)
{
// Skip colormap - we dont need it
pos += map_length*map_size;
}
else
{
// Read the colormap
color_map = new unsigned char[map_length * 4];
// read color depending on bytes-pr-pixel
for (unsigned int i=0;i<map_length;i++)
{
switch (bpp)
{
case 16:
read_rgb_16(&color_map[i*4+0],
&color_map[i*4+1],
&color_map[i*4+2],
&color_map[i*4+3]);
break;
case 24:
read_rgb_24(&color_map[i*4+0],
&color_map[i*4+1],
&color_map[i*4+2],
&color_map[i*4+3]);
break;
case 32:
read_rgb_32(&color_map[i*4+0],
&color_map[i*4+1],
&color_map[i*4+2],
&color_map[i*4+3]);
break;
default:
throw CL_Error(CL_String::format("Unsupported bit-depth in targafile '%1'", filename));
}
}
}
}
// read pitch, height and bits-pr-pixel
pitch = *((unsigned short *) &file[12]);
SWAP_IF_BIG(pitch);
bounding_left = pitch;
bounding_right = 0;
height = *((unsigned short *) &file[14]);
SWAP_IF_BIG(height);
bounding_top = height;
bounding_bottom = 0;
map_direction_x = (file[17] & 0x10) == 0 ? 1 : -1;
map_direction_y = (file[17] & 0x20) == 0 ? -1 : 1;
}
/*
Read and convert a rgb-color from the current position
in the file.
*/
inline bool CL_TargaProvider_Generic::read_rgb_16(
unsigned char *a,
unsigned char *b,
unsigned char *g,
unsigned char *r)
{
bool ret = true;
if (pos >= filesize)
throw CL_Error("Invalid targa file!?");
// In 16 bits pr pixel the individual color-intensities are
// described in two bytes:
// ARRRRRGG GGGBBBBB
// A = ATTRIBUTE
// R = RED
// G = GREEN
// B = BLUE
// These two bytes are in reality read backwards (last byte first)
*a = (file[pos+1]&128) ? 0 : 255;
// Transparent pixel
if (use_alphapixels && !(*a))
{
*r = trans_redcol;
*g = trans_greencol;
*b = trans_bluecol;
ret = false;
}
else
{
*r = ((file[pos+1]>>2) & 0x1f)<<3;
*g = (((file[pos+1] & 0x03)<<3) +
((file[pos]>>5) & 0x7))<<3;
*b = (file[pos] & 0x1f)<<3;
if (transparent &&
*r == trans_redcol &&
*g == trans_greencol &&
*b == trans_bluecol)
{
*a = 0;
ret = false;
}
//
else
if (ignore_alphachannel)
{
// else if we're not using any alphapixels at all, then alpha should be 255.
*a = 255;
}
//
}
pos += 2;
return ret;
}
inline bool CL_TargaProvider_Generic::read_rgb_24(
unsigned char *a,
unsigned char *b,
unsigned char *g,
unsigned char *r)
{
bool ret = true;
if (pos >= filesize)
throw CL_Error("Invalid targa file!?");
*b = file[pos];
*g = file[pos+1];
*r = file[pos+2];
*a = 255;
if (transparent &&
*r == trans_redcol &&
*g == trans_greencol &&
*b == trans_bluecol)
{
*a = 0;
ret = false;
}
pos += 3;
return ret;
}
inline bool CL_TargaProvider_Generic::read_rgb_32(
unsigned char *a,
unsigned char *b,
unsigned char *g,
unsigned char *r)
{
bool ret = true;
if (pos >= filesize)
throw CL_Error("Invalid targa file!?");
*a = file[pos+3];
if (use_alphapixels && !(*a))
{
*r = trans_redcol;
*g = trans_greencol;
*b = trans_bluecol;
ret = false;
}
else
{
*b = file[pos];
*g = file[pos+1];
*r = file[pos+2];
if (transparent &&
*r == trans_redcol &&
*g == trans_greencol &&
*b == trans_bluecol)
{
// if using transparant and we have matching transparant pixel, alpha should be 0.
*a = 0;
ret = false;
}
//
else
if (ignore_alphachannel)
{
// else if we're not using any alphapixels at all, then alpha should be 255.
*a = 255;
}
//
}
pos += 4;
return ret;
}
inline bool CL_TargaProvider_Generic::read_rgb(
unsigned char *a,
unsigned char *b,
unsigned char *g,
unsigned char *r)
{
bool ret = true;
if (pos >= filesize)
throw CL_Error("Invalid targa file!?");
switch (bpp)
{
case 16:
// In 16 bits pr pixel the individual color-intensities are
// described in two bytes:
// ARRRRRGG GGGBBBBB
// A = ATTRIBUTE
// R = RED
// G = GREEN
// B = BLUE
// These two bytes are in reality read backwards (last byte first)
*a = (int(file[pos+1]&128)>>7)*255;
// Transparent pixel
if (use_alphapixels && !(*a))
{
*r = trans_redcol;
*g = trans_greencol;
*b = trans_bluecol;
ret = false;
}
else
{
*r = ((file[pos+1]>>2) & 0x1f)<<3;
*g = (((file[pos+1] & 0x03)<<3) +
((file[pos]>>5) & 0x7))<<3;
*b = (file[pos] & 0x1f)<<3;
if (transparent &&
*r == trans_redcol &&
*g == trans_greencol &&
*b == trans_bluecol)
{
*a = 0;
ret = false;
}
//
else
if (ignore_alphachannel)
{
// else if we're not using any alphapixels at all, then alpha should be 255
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -