⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 targa_provider_generic.cpp

📁 这是一款2d游戏引擎
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*  $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 + -