利用SDL绘制点阵字

看sdlpal源码的时候,想了解下游戏界面上那些像素字是如何绘制显示的,于是就去了解了下点阵字。虽然有SDL_ttf这个库,你只需要找个字体文件,然后调用库提供的API就可以在屏幕上显示字体了。但是如果游戏只是显示下简单的像素字的话,加个SDL_ttf库就显得臃肿了。不管怎样,多深入了解下又不是坏事,你还是可以使用更简单方便的字体库来显示字体。
关于点阵字的一些介绍就不细讲了,网上一搜一大把。我只讲下用SDL绘制点阵字的过程。首先,我们要有在屏幕上显示的汉字字模(拿1616的点阵字来说的话,字模就是一个16行2列的一个二维数组,里边存放着十六进制数,这些十六进制数描述了这个1616矩阵中每个点是0还是1。具体是怎样的,看后面的代码),这个搜一下在线点阵字体生成器就有了。这里绘制一下“廖望塔”三个字,下面这张图就是16*16的字体点阵了:
这里写图片描述
白点代表1,蓝点代表0。所以它的十六进制数组是(上面的图和下面的数组是不对应的,因为不是同一个地方生成的,把途中的点用对应的十六进制描述会对应不上…不过都差不多,懒得统一了):

// 这里直接把三个字的字模写在一个16行6列的数组里了,也可以单独用3个16*
6的数组存放
const unsigned char wangtal[][6] = {
	// 十六进制下,2位为一个字节,二进制下8位为一个字节.所以16个点需要两个2位十六进制表示
	//  廖   |     望     |     塔
	{0x00, 0x80, 0x10, 0x04, 0x21, 0x10},
	{0x3F, 0xFC, 0x0A, 0x7E, 0x21, 0x10},
	{0x20, 0x00, 0xFF, 0x44, 0x27, 0xFC},
	{0x3F, 0x78, 0x20, 0x7C, 0x21, 0x10},
	{0x29, 0x48, 0x20, 0x44, 0x20, 0x40},
	{0x25, 0x28, 0x26, 0x7C, 0xF8, 0xA0},
	{0x29, 0xC8, 0x38, 0x44, 0x21, 0x10},
	{0x23, 0x60, 0x20, 0x8C, 0x22, 0x0E},
	{0x2C, 0x5E, 0x00, 0x00, 0x2D, 0xF4},
	{0x31, 0x84, 0x3F, 0xF8, 0x20, 0x08},
	{0x26, 0x40, 0x01, 0x00, 0x23, 0xFC},
	{0x21, 0x90, 0x1F, 0xF0, 0x3A, 0x08},
	{0x46, 0x20, 0x01, 0x00, 0xE2, 0x08},
	{0x40, 0xC0, 0x01, 0x04, 0x42, 0x08},
	{0x83, 0x00, 0xFF, 0xFE, 0x03, 0xf8},
	{0x0C, 0x00, 0x00, 0x00, 0x02, 0x08}
};

有了这个数组,先不急着用SDL在屏幕上绘制,可以简单的在终端打印出来看看效果。上代码,很简单:

#include <stdio.h>

// 记得加上上面那个数组,这里就不重复贴了

int main(int argc, char* argv[])
{
	// 第一层循环控制行数
	for (int i = 0; i < sizeof(wangtal) / sizeof(wangtal[0]); i++) {
		// 第二层循环控制列数
		for (int j = 0; j < sizeof(wangtal[0]) / sizeof(wangtal[0][0]); j++) {
			// 每个十六进制数有8位,遍历这8位哪些是0,哪些是1
			for (int k = 0; k < 8; k++) {
				// wangtal[i][j]是第i行第j列的十六进制数,将其对(0x80>>k)进行8次的与运算,就可以得知当前位是0还是1
				if (wangtal[i][j] & (0x80 >> k)) {
					// 为1打印一个 * 号和一个空格
					printf("%c ", '*');
				} else {
					// 为0打印两个空格
					printf("%c ", ' ');
				}
			}
		}
		printf("\n");
	}
	return 0;
}

编译运行后的效果:
这里写图片描述


接下来就用SDL在屏幕上绘制,这就需要初始化SDL,创建一个window和一个renderer,然后根据数组,在一个surface中填充颜色,再把该surface转成textrue,最后copy到renderer中就可以显示了。比上面的复杂一点,不过也难不到哪去。上代码:

#include <stdio.h>
#include "wtlDisplay.h" // 该头文件是我写的用来初始化SDL的,这里就不给出了,不清楚的可以看下SDL的官方教程

// 记得贴上开头给的数组

static SDL_Surface* gpSurface = NULL;
static SDL_Texture* gpTexture = NULL;

void Startup(void);
void Shutdown(void);
void wtlText_DrawChar(unsigned char color, int x, int y, int size);

int main(int argc, char* argv[])
{
	SDL_bool quit = SDL_FALSE;
	SDL_Event event;

	wtlDisplay_Init();
	Startup();

	wtlText_DrawChar(0xFF, 60, 80, 9);

	SDL_Renderer* renderer = wtlDisplay_GetRenderer();
	gpTexture = SDL_CreateTextureFromSurface(renderer, gpSurface);

	while (!quit) {
		while (SDL_PollEvent(&event)) {
			if (event.type == SDL_QUIT) {
				quit = SDL_TRUE;
			}
		}

		//SDL_RenderClear(renderer);
		//SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
		SDL_RenderCopy(renderer, gpTexture, NULL, NULL);

		SDL_RenderPresent(renderer);
	}
	
	wtlDisplay_Quit();
	Shutdown();

	return 0;
}

void Startup(void){
	if (NULL == gpSurface) {
		gpSurface = SDL_CreateRGBSurface(0, 640, 320, 32, 0, 0, 0, 0);
	}
	//printf("gpSurface pitch:%d\n", gpSurface->pitch);

	/*if (NULL == gpTexture) {
		gpTexture = SDL_CreateTexture(
				wtlDisplay_GetRenderer(),
				SDL_PIXELFORMAT_ARGB8888,
				SDL_TEXTUREACCESS_STREAMING,
				640, 320
		);
	}*/
}

void Shutdown(void){
	if (gpSurface) {
		SDL_FreeSurface(gpSurface);
		gpSurface = NULL;
	}
	if (gpTexture) {
		SDL_DestroyTexture(gpTexture);
		gpTexture = NULL;
	}
}

// 要点就是这个函数了,写的不是通用的,只是用来演示绘制“廖望塔”的...
// color就是字体颜色了,不过有点问题,可能是SDL_FillRect或SDL_CreateTextureFromSurface改变了颜色信息,导致颜色不是我们填的那样
// x,y就是在屏幕中的位置了,size为每个点填充多少个像素。如果每个点填充一个像素,这样是看不到绘制出来字体的,太小了
void wtlText_DrawChar(unsigned char color, int x, int y, int size){
	SDL_Rect _stRect = {x, y, size, size};

	// 第一层循环控制行数
	for (int i = 0; i < sizeof(wangtal) / sizeof(wangtal[0]); i++) {
		// 第二层循环控制列数
		for (int j = 0; j < sizeof(wangtal[0]) / sizeof(wangtal[0][0]); j++) {
			// 每个十六进制数有8位,遍历这8位哪些是0,哪些是1
			for (int k = 0; k < 8; k++) {
				if (wangtal[i][j] & (0x80 >> k)) {
					// 为1,则在gpSurface的_stRect区域填充color颜色
					SDL_FillRect(gpSurface, &_stRect, (Uint32)color);
				}
				// x轴位置偏移,以便进行下一个点的绘制
				_stRect.x += size;
			}
		}
		// 绘制完一行后,y轴坐标向下偏移
		_stRect.y += size;
		// x轴坐标回到初始值
		_stRect.x = x;
	}
}

效果图:
这里写图片描述


一般不会手动去写字模信息,而是从点阵字库中读取字模信息,这样会方便点。内容就是这样,不要介意代码写的难看…清楚内容就行了。 : )

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值