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

📄 rlebitmap.cpp

📁 游戏c++开发简例
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
行压缩位图,带有图像轮廓信息
目前仅支持高彩色模式

  ..........	'.'代表透明像素
  ..AA......
  .A...A....
  ..........
  压缩为:
	去掉顶行,末行和最左边一列
  0201 0302 0000				代表轮廓
  0301 0102 AAAA AAAA 0201 0301 0000
  0101 AAAA 0203 0101 AAAA 0000
  0301 0203 0301 0000			代表轮廓

  源图80字节,压缩后40字节
*/

#include "gl.h"
//#include "gengine.h"

#define RLE_LINEEND		0x0000
#define RLE_PIXELS		0x0100
#define RLE_TRANS		0x0200
#define RLE_OUTLINE		0x0300
#define RLE_SIGNATURE	0x42454c52	//"RLEB"

#define RLE_OUTLINECOLOR	0xffe0ffe0	//轮廓的颜色
#define RLE_SHADOWCOLOR		0x0			//影子的颜色
/*
class RleBitmap{
public:
	int colorDepth;
	int x, y;		//位置矫正
	int width, height;		//压缩后的大小
	DWORD size;			//像素数据量
	char **line;

	RleBitmap();
	~RleBitmap();
};
*/
RleBitmap::RleBitmap()
{
	width = height = 0;
	line = NULL;
}

RleBitmap::~RleBitmap()
{
	delete line;
}

void RleBitmap::ConvertFormat( int format )
{
	if( format == colorDepth )
		return;

	short* data = (short*)line[0];
	int lines = 0, i;
	if( colorDepth == 15 && format == 16 ){
//		OutDebugString( "rlebmp coverformat" );
		while( lines < height ){
			switch( *data & 0xff00 ){
			case RLE_LINEEND:
				lines ++;
				data ++;
				break;
			case RLE_PIXELS:
				i = *data & 0xff;
				data ++;
				for( ; i>0; i--, data++ )
					*data = ((*data & 0x7fe0) << 1) | (*data & 0x1f);
				break;
			case RLE_TRANS:
			case RLE_OUTLINE:
				data ++;
				break;
			}
		}
	}
	else if( colorDepth == 16 && format == 15 ){
	}
	else 
		return;
}

//存盘
int SaveRleBitmap( char *filename, RleBitmap *src )
{
	FILE *fp = fopen( filename, "wb" );
	if( fp == NULL )
		return -1;

	errno = 0;
	DWORD signature = RLE_SIGNATURE;
	DWORD temp;
	fwrite( &signature, 1, 4, fp );

	//写数据头
	fwrite( &(src->size), sizeof(src->size), 1, fp );
	fwrite( &(src->colorDepth), sizeof(src->colorDepth), 1, fp );
	fwrite( &(src->x), sizeof(src->x), 1, fp );
	fwrite( &(src->y), sizeof(src->y), 1, fp );
	fwrite( &(src->width), sizeof(src->width), 1, fp );
	fwrite( &(src->height), sizeof(src->height), 1, fp );
	//写入每行像素的首地址相对于line[0]的偏移
	for( int i=0; i<src->height; i++ ){
		temp = src->line[i] - src->line[0];
		fwrite( &temp, sizeof( DWORD ), 1, fp );
	}
	//写入像素数据
	fwrite( src->line[0], 1, src->size, fp ); 

	fclose( fp );
	if( errno )
		return -1;
	return 0;
}

//从文件中读入
RleBitmap* LoadRleBitmap( char *fname )
{
	File *fp;
	fp = cfile.Open( fname );
	if( fp == NULL )
		return NULL;

	DWORD signature;
	RleBitmap* rle;
	int i;

	signature = fp->Getdw();
	if( signature != RLE_SIGNATURE ){
		fp->Close();
		return NULL;
	}
	rle = new RleBitmap;
	if( rle == NULL )
		goto error;

	//数据头
	fp->Read( &(rle->size), sizeof(rle->size));
	fp->Read( &(rle->colorDepth), sizeof(rle->colorDepth) );
	fp->Read( &(rle->x), sizeof(rle->x));
	fp->Read( &(rle->y), sizeof(rle->y));
	fp->Read( &(rle->width), sizeof(rle->width));
	fp->Read( &(rle->height), sizeof(rle->height));
	//分配空间
	rle->line = (char**) new char[ rle->height * sizeof(char*) + rle->size ];
	if( rle->line == NULL )
		goto error;

	rle->line[0] = (char*)rle->line + rle->height * sizeof(char*);
	//设置行指针
	for( i=0; i<rle->height; i++ )
		rle->line[i] = rle->line[0] + fp->Getdw();

	//读入像素数据
	fp->Read( rle->line[0], rle->size );

	fp->Close();
	return rle;

error:
	delete rle;
	fp->Close();
	return NULL;
}

//进行压缩的辅助函数
//点(x,y)是否为轮廓上的点
static int IsOutlineEx( Bitmap *src, int x, int y )
{	
#define CHECK( a, b ) ( ((WORD*)(src->line[a]))[b] == src->colorKey &&																	\
	(( a > 0 && ((WORD*)(src->line[a-1]))[b] != src->colorKey && ((WORD*)(src->line[a-1]))[b] != RLE_SHADOWCOLOR )						\
	|| ( a < src->height-1 && ((WORD*)(src->line[a+1]))[b] != src->colorKey && ((WORD*)(src->line[a+1]))[b] != RLE_SHADOWCOLOR )))

	if( CHECK( x, y ) && (( y > 0 && CHECK( x, y-1 )) || (y < src->width-1 && CHECK( x, y+1 ))))
		return 1;
	return 0;

}

static int IsOutline( Bitmap *src, int x, int y )
{
	if( CHECK( x, y ) )
		return 1;
	return 0;
}
#undef CHECK

RleBitmap* CreateRleBitmap( Bitmap* src, int genOl = 1 ) // genOl是否产生轮廓
{
	if( src == NULL || BYTES_PER_PIXEL(src->colorDepth) != 2 )
		return NULL;

	int i, j, counter;
	int top, bottom, height, left, right, width;
	WORD *data;
	RleBitmap* rle = new RleBitmap;
	if( rle == NULL )
		return NULL;
	right = 0;
	left = src->width;

	//搜索不全透明的最顶行
	for( i=0; i<src->height; i++ )
		for( j=0; j<src->width; j++ )
			if( ((WORD*)(src->line[i]))[j] != src->colorKey )
				goto top_found;
top_found:
	if( i == src->height ){
		return new RleBitmap;
	}
	top = i;
	//搜索不全透明的最末行
	for( i=src->height-1; i>=0; i-- )
		for( j=0; j<src->width; j++ )
			if( ((WORD*)(src->line[i]))[j] != src->colorKey )
				goto bottom_found;
bottom_found:
	bottom = i;
	height = i - top + 3;
	//搜索最左不透明像素
	for( i=top; i<=bottom; i++ ){
		for( j=0; ((WORD*)(src->line[i]))[j] == src->colorKey && j<left; j++ );
		if( j < left ) left = j;
	}
	//创建rleBitmap
	rle = new RleBitmap;
	if( rle == NULL )
		return NULL;
	rle->line = (char**)new char[ sizeof( char* ) * height ];
	if( rle->line == NULL ){
		delete rle;
		return NULL;
	}
	rle->line[0] = new char[ (src->width - left) * height * 4 ];
	if( rle->line[0] == NULL ){
		delete rle;
		return NULL;
	}
//压缩
	data = (WORD*)(rle->line[0]);
	//处理第一行
	//搜索行末
	if( genOl ){
		for( i=src->width-1; (((WORD*)(src->line[top]))[i] == src->colorKey 
			|| ((WORD*)(src->line[top]))[i] == RLE_SHADOWCOLOR) && !IsOutlineEx( src, top, i ) && i > 0; i-- );
		for( j=left; j<=i; ){
			if( ((WORD*)(src->line[top]))[j] == src->colorKey || ((WORD*)(src->line[top]))[i] == RLE_SHADOWCOLOR ){
				*data = RLE_TRANS;
				while( (((WORD*)(src->line[top]))[j] == src->colorKey || ((WORD*)(src->line[top]))[i] == RLE_SHADOWCOLOR) && j<=i && *(char*)data < 255 ){
					j ++; (*data) ++;
				}
				data ++;
			}
			else{
				*data = RLE_OUTLINE;
				while( ((WORD*)(src->line[top]))[j] != src->colorKey && j<=i && *(char*)data < 255 ){
					j ++; (*data) ++;
				}
				data ++;
			}
		}
	}
	*(data++) = RLE_LINEEND;
	i=IsOutline( src, 47, 54 );
	//处理从第一行到最后一行的像素,包括第一行和最后一行
	for( i=top; i<=bottom; i++ ){
		rle->line[i-top+1] = (char*)data;
		//搜索行末
		for( j=src->width-1; ((WORD*)(src->line[i]))[j] == src->colorKey && (!genOl | !IsOutlineEx( src, i, j )) && j > 0; j-- );
		if( j > right ) right = j;
		width = j;
		for( j=left; j<=width; ){
			counter = 0;
			if( ((WORD*)(src->line[i]))[j] == src->colorKey ){
				if( genOl && IsOutlineEx(src, i, j) ){
					*data =	RLE_OUTLINE;		//标志为轮廓
					while( IsOutline( src, i, j ) && j <= width && counter < 255 ){
						counter ++;
						j++;
					}
				}
				else{
					*data = RLE_TRANS;		//标志为透明
					while( ((WORD*)(src->line[i]))[j] == src->colorKey && (!genOl | !IsOutlineEx( src, i, j )) && j <= width && counter < 255 ){
						counter ++;
						j ++;
					}
				}
				(*data) += counter; 
				data ++;
			}
			else{
				*data = RLE_PIXELS;
				while( ((WORD*)(src->line[i]))[j] != src->colorKey && j <= width && counter < 255 ){
					counter ++;
					*(data+counter) = ((WORD*)(src->line[i]))[j];
					j ++;
				}
				*data += counter;
				data += counter + 1;
			}
		} // end of one line
		*(data++) = RLE_LINEEND;
	}
	//处理最后一行
	rle->line[ height-1 ] = (char*)data;
	//搜索行末
	if( genOl ){
		for( i=src->width-1; (((WORD*)(src->line[bottom]))[i] == src->colorKey 
			|| ((WORD*)(src->line[bottom]))[i] == RLE_SHADOWCOLOR) && !IsOutlineEx( src, bottom, i ) && i > 0; i-- );
		for( j=left; j<=i; ){
			if( ((WORD*)(src->line[bottom]))[j] == src->colorKey || ((WORD*)(src->line[bottom]))[i] == RLE_SHADOWCOLOR ){
				*data = RLE_TRANS;
				while( (((WORD*)(src->line[bottom]))[j] == src->colorKey || ((WORD*)(src->line[bottom]))[i] == RLE_SHADOWCOLOR) && j<=i && *(char*)data < 255 ){
					j ++; (*data) ++;
				}
				data ++;
			}
			else{
				*data = RLE_OUTLINE;
				while( ((WORD*)(src->line[bottom]))[j] != src->colorKey && j<=i && *(char*)data < 255 ){
					j ++; (*data) ++;
				}
				data ++;
			}
		}
	}
	*(data++) = RLE_LINEEND;

	rle->colorDepth = src->colorDepth;
	rle->x = left;
	rle->y = top - 1;
	rle->width = right - left + 2;	//比实际的大1
	rle->height = height;
	rle->size = (DWORD)data - (DWORD)(rle->line[0]);
	rle->line[0] = (char*)realloc( rle->line[0], rle->size );

	return rle;
}

#define RLE_CLIP									\
	int w = src->width;								\
	int h = src->height;							\
	int sx, sy;										\
	x += src->x;									\
	y += src->y;									\
	if( x >= dest->cr || y >= dest->cb )			\
		return;										\
													\
	if( x < dest->cl ){								\
		sx = dest->cl - x; x = dest->cl; w -= sx;	\
		if( w <= 0 ) return;						\
	}												\
	else sx = 0;									\
	if( y < dest->ct ){								\
		sy = dest->ct - y; y = dest->ct; h -= sy;	\
		if( h <= 0 ) return;						\
	}												\
	else sy = 0;									\
	if( x + w > dest->cr )							\
		w = dest->cr - x;							\
	if( y + h > dest->cb )							\
		h = dest->cb - y;

//no outline
void RleBitmapBlit( Bitmap* dest, int x, int y, RleBitmap* src )
{
	RLE_CLIP;

	int pitch, dptr;
	char** sline = &(src->line[sy]);
	pitch = dest->pitch;

	__asm{
		mov ebx, y;
		cld;
		mov ecx, sline;
		mov eax, dest;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -