SDL_Engine游戏引擎制作 5-Texture 2.x的新宠

SDL在2.x后,SDL_Texture成为了主力军,以实现各种绘制操作。简单介绍一些与之相关的函数:

1.SDL_QueryTexture。获取一个纹理(即SDL_Texture)的属性,如纹理的高和宽等。

Texture.h

#ifndef __SDL_Texture_H__
#define __SDL_Texture_H__
#include "SDL.h"
#include "Object.h"
NS_SDL_BEGIN
class Renderer;

class Texture : public Object
{
private:
	SDL_Texture* _texture;
public:
	Texture();
	virtual~Texture();

	static Texture* create(SDL_Texture* pTex);
	bool init(SDL_Texture* pTex);
	//获得贴图的属性
	void queryTexture(Uint32* format,int* access,int* w,int* h);
	//设置追加颜色 srcColor = srcColor*(color/255)	//获得追加颜色
	/*即 如果原来颜色为(255,255,255) 设置为(255,128,255)  结果为(255,128,255)*/
	int setTextureColorMod(Uint8 r,Uint8 g,Uint8 b)const;
	int getTextureColorMod(Uint8* r,Uint8* g,Uint8* b)const;
	//透明度
	int setTextureAlphaMod(Uint8 alpha)const;
	int getTextureAlphaMod(Uint8* alpha)const;
	//设置混合,主要用于SDL_RenderCopy
	/*SDL_BLENDMODE_NONE SDL_BLENDMODE_BLEND SDL_BLEND_ADD SDL_BLEND_ADD*/
	int setTextureBlendMode(SDL_BlendMode blendMode)const;
	int getTextureBlendMode(SDL_BlendMode* blendMode)const;
	//获取SDL_Texture
	SDL_Texture* getSDL_Texture()const;
	//Renderer的友元
	friend class Renderer;
};
NS_SDL_END
#endif

Texture.cpp

#include "Texture.h"
NS_SDL_BEGIN
Texture::Texture()
{
	_texture = NULL;
}

Texture::~Texture()
{
	if(_texture)
		SDL_DestroyTexture(_texture);
}

Texture* Texture::create(SDL_Texture* pTex)
{
	Texture* texture = new Texture();

	if(texture && texture->init(pTex))
		texture->autorelease();
	else
		SDL_SAFE_DELETE(texture);

	return texture;
}

bool Texture::init(SDL_Texture* pTex)
{
	if(pTex != nullptr)
	{
		_texture = pTex;
		return true;
	}
	return false;
}

void Texture::queryTexture(Uint32* format,int* access,int* w,int* h)
{
	if(_texture != nullptr)
		SDL_QueryTexture(_texture,format,access,w,h);
}

int Texture::setTextureColorMod(Uint8 r,Uint8 g,Uint8 b)const
{
	if(_texture)
		return SDL_SetTextureColorMod(_texture,r,g,b);
	else
		return -1;
}
int Texture::getTextureColorMod(Uint8* r,Uint8* g,Uint8* b)const
{
	if(_texture)
		return SDL_GetTextureColorMod(_texture,r,g,b);
	else
		return -1;
}

int Texture::setTextureAlphaMod(Uint8 alpha)const
{
	if(_texture != nullptr)
		return SDL_SetTextureAlphaMod(_texture,alpha);
	else
		return -1;
}

int Texture::getTextureAlphaMod(Uint8* alpha)const
{
	if(_texture)
		return SDL_GetTextureAlphaMod(_texture,alpha);
	else
		return -1;
}

int Texture::setTextureBlendMode(SDL_BlendMode blendMode)const
{
	if(_texture)
		return SDL_SetTextureBlendMode(_texture,blendMode);
	else
		return -1;
}

int Texture::getTextureBlendMode(SDL_BlendMode* blendMode)const
{
	if(_texture)
		return SDL_GetTextureBlendMode(_texture,blendMode);
	else
		return -1;
}

SDL_Texture* Texture::getSDL_Texture()const
{
	return _texture;
}
NS_SDL_END

在SDL中,纹理Texture是和Renderer渲染器紧密相关的(Surface则不是),所以Texture类中仅有一个为create(SDL_Texture*)的函数,其他的纹理生成函数则是在Renderer类之中。

SDL_Color为SDL提供的结构体,顾名思义,表示颜色。在SDL_Engine中,有Color3B和Color4B与之对应。3B 表示3个字节,RGB,即Red Green Blue 红绿蓝三原色。4B则是在3B的基础上,添加了一个alpha透明值。

Color.h

#ifndef __SDL_Color_H__
#define __SDL_Color_H__

#include<string>
#include "SDL.h"
#include "Object.h"

NS_SDL_BEGIN
//---------------------------Color4B------------------------------------
class Color4B : public Object
{
public:
	Uint8 r;
	Uint8 g;
	Uint8 b;
	Uint8 a;
public:
	Color4B(Uint8 r = 0,Uint8 g = 0,Uint8 b = 0,Uint8 a = 255)
		:r(r),g(g),b(b),a(a)
	{
	}
	Color4B(const SDL_Color& color)
	{
		r = color.r;
		g = color.g;
		b = color.b;
		a = color.a;
	}
	/*format 255,255,255,255*/
	Color4B(const std::string& str)
	{
		int rr = 0,gg = 0,bb = 0,aa = 0;
		SDL_sscanf(str.c_str(),"%d,%d,%d,%d",&rr,&gg,&bb,&aa);

		r = rr;
		g = gg;
		b = bb;
		a = aa;
	}

	bool equals(const Color4B& other)const
	{
		if(this == &other)
			return true;

		return r == other.r &&
			g == other.g &&
			b == other.b &&
			a == other.a;
	}
	//重载运算符
	Color4B operator*(Uint8 d)
	{
		return Color4B(r * d,g * d,b * d,a * d);
	}
	Color4B operator+(const Color4B& color)
	{
		return Color4B(r + color.r,g + color.g,b + color.b,a + color.a);
	}
	Color4B operator-(const Color4B& color)
	{
		return Color4B(r - color.r,g - color.g,b - color.b);
	}
	//重载== !=
	bool operator==(const Color4B& other)
	{
		if(this == &other)
			return true;

		return r == other.r &&
			g == other.g &&
			b == other.b &&
			a == other.a;
	}
	bool operator!=(const Color4B& other)
	{
		if(this == &other)
			return false;
		return r != other.r ||
			g != other.g ||
			b != other.b ||
			a != other.a;
	}
	//获取SDL_Color
	SDL_Color getSDL_Color()const
	{
		SDL_Color color = {r,g,b,a};
		return color;
	}
};
//----------------------------------------Color3B-------------------------------
class Color3B:public Object
{
public:
	Uint8 r;
	Uint8 g;
	Uint8 b;
public:
	Color3B(Uint8 r = 0,Uint8 g = 0,Uint8 b = 0)
		:r(r),g(g),b(b)
	{
	}
	Color3B(const SDL_Color& color)
	{
		r = color.r;
		g = color.g;
		b = color.b;
	}
	/*Format 255,255,255*/
	Color3B(const std::string& str)
	{
		int rr = 0,gg = 0,bb = 0;
		SDL_sscanf(str.c_str(),"%d,%d,%d",&rr,&gg,&bb);

		r = rr;
		g = gg;
		b = bb;
	}
	bool equals(const Color3B& other)const
	{
		if(this == &other)
			return true;
		return r == other.r &&
			g == other.g &&
			b == other.b;
	}
	//重载运算符
	Color3B operator*(Uint8 d)
	{
		return Color3B(r * d,g * d,b * d);
	}
	Color3B operator+(const Color3B& color)
	{
		return Color3B(r + color.r,g + color.g,b + color.b);
	}
	Color3B operator-(const Color3B& color)
	{
		return Color3B(r - color.r,g - color.g,b - color.b);
	}
	//重载== !=
	bool operator==(const Color3B& other)
	{
		if(this == &other)
			return true;
		return r == other.r &&
			g == other.g &&
			b == other.b;
	}
	bool operator!=(const Color3B& other)
	{
		if(this == &other)
			return false;
		return r != other.r ||
			g != other.g ||
			b != other.b;
	}
	//获取SDL_Color
	SDL_Color getSDL_Color(Uint8 alpha = 255)const
	{
		SDL_Color color = {r,g,b,alpha};
		return color;
	}
};
NS_SDL_END
#endif

SDL_Renderer在SDL2.x后一个窗口允许有多于一个的渲染器。不过,在SDL_Engine中,渲染器就使用了一个。

介绍一些SDL_Renderer相关的函数:

1.SDL_CreateRenderer。创建一个基于SDL_Window窗口的渲染器。

2.SDL_RenderClear。使用相应的颜色刷新当前的渲染目标。

3.SDL_RenderPresent。呈现到屏幕。

4.SDL_SetRenderDrawColor。设置渲染器刷新颜色。

5.SDL_CreateTexture。创建一个基于渲染器的纹理。

6.SDL_CreateTextureFromSurface。创建一个基于当前渲染器和当前表面来生成一个纹理。

7.SDL_RenderCopy。拷贝一个纹理到当前的渲染目标上。

8.SDL_RenderCopyEx。SDL_RenderCopy的扩展,额外添加了旋转角度angle,旋转中心,以及是否翻转。

9.IMG_LoadTexture。加载文件并生成纹理。

10.SDL_RenderDrawLine。绘制一条线。

11.SDL_RenderDrawRect。绘制一个矩形。

12.SDL_RenderFillRect。填充一个矩形。

13.SDL_RenderSetScale。设置渲染缩放,图片可能会稍微变形。

14.SDL_SetRenderTarget。设置渲染目标,当为nullptr是恢复默认渲染目标。

Renderer.h

#ifndef __Renderer_H__
#define __Renderer_H__

#include "SDL.h"
#include "SDL_image.h"

#include "Object.h"
#include "Rect.h"
#include "Color.h"

NS_SDL_BEGIN
class Window;
class Surface;
class Texture;

class Renderer : public Object
{
private:
	SDL_Renderer* _renderer;
public:
	Renderer();
	~Renderer();

	static Renderer* create(Window* window,int index,Uint32 flags);
	//初始化
	bool init(Window* window,int index,Uint32 flags);
	//清空渲染器
	int renderClear();
	//呈现
	void renderPresent();
	//设置刷新颜色
	void setRenderDrawColor(Uint8 r,Uint8 g,Uint8 b,Uint8 a);
	void setRenderDrawColor(const Color4B& color);
	//获取当前刷新颜色
	Color4B getRenderDrawColor()const;
	//创建Texture
	Texture* createTexture(Uint32 format,int access,int w,int h);
	Texture* createTextureFromSurface(Surface* surface);
	//绘制
	int renderCopy(Texture* texture,const SDL_Rect* srcRect,SDL_Rect* destRect);
	int renderCopyEx(Texture* texture,const SDL_Rect* srcRect,SDL_Rect* destRect,const double angle,const SDL_Point* center,SDL_RendererFlip flip);
	int renderCopyEx(Texture* texture,const Rect& srcRect,const Rect& destRect,const double angle,const Point& center,SDL_RendererFlip flip);
	//创建Texture
	Texture* imgLoadTexture(const char* filePath);
	//创建Texture 线程安全,即不参与内存管理
	Texture* imgLoadTextureThreadSafe(const char* filepath);
	Texture* createTextureFromSurfaceThreadSafe(Surface* surface);
	//一些画图函数
	int renderDrawLine(const Point& startPos,const Point& endPos);
	int renderDrawRect(const Rect& rect);

	int renderFillRect(const Rect& rect);
	//进行与渲染无关的分辨率
	int renderSetScale(float scaleX,float scaleY);
	Size renderGetScale()const;
	//进行逻辑缩放
	int renderSetLogicalSize(int w,int h);
	void renderGetLogicalSize(int& w,int& h);
	//设置填充模式
	int setRenderDrawBlendMode(SDL_BlendMode mode);
	int getRenderDrawBlendMode(SDL_BlendMode* mode);
	//渲染区域
	int renderSetViewport(const SDL_Rect* rect);
	//这里,SDL返回的是void,所以API做了相应改变
	Rect renderGetViewport();
	/*改变渲染目标,为空时则改为默认渲染目标 
	*@ texture 必须有SDL_TEXTUREACCESS_TARGET*/
	int setRenderTarget(Texture* texture);
	/*设置遮挡*/
	int renderSetClipRect(const SDL_Rect* rect);
	Rect renderGetClipRect();
	//返回SDL_Renderer
	::SDL_Renderer* getSDL_Renderer()const;
};
NS_SDL_END
#endif

Renderer.cpp

#include "Renderer.h"
#include "Window.h"
#include "Surface.h"
#include "Texture.h"

NS_SDL_BEGIN
Renderer::Renderer()
	:_renderer(nullptr)
{
}

Renderer::~Renderer()
{
	if(_renderer)
		SDL_DestroyRenderer(_renderer);

	_renderer = nullptr;
}

Renderer*Renderer::create(Window* window,int index,Uint32 flags)
{
	Renderer* renderer = new Renderer();

	if(renderer && renderer->init(window,index,flags))
		renderer->autorelease();
	else
		SDL_SAFE_DELETE(renderer);

	return renderer;
}

bool Renderer::init(Window* window,int index,Uint32 flags)
{
	//以win作为参数创建renderer
	_renderer = SDL_CreateRenderer(window->_window,index,flags);

	return true;
}

int Renderer::renderClear()
{
	return SDL_RenderClear(_renderer);	 
}

void Renderer::renderPresent()
{
	SDL_RenderPresent(_renderer);
}

void Renderer::setRenderDrawColor(Uint8 r,Uint8 g,Uint8 b,Uint8 a)
{
	SDL_SetRenderDrawColor(_renderer,r,g,b,a);
}

void Renderer::setRenderDrawColor(const Color4B&color)
{
	SDL_SetRenderDrawColor(_renderer,color.r,color.g,color.b,color.a);
}

Color4B Renderer::getRenderDrawColor()const
{
	Color4B color;

	SDL_GetRenderDrawColor(_renderer,&color.r,&color.g,&color.b,&color.a);

	return color;
}

Texture* Renderer::createTexture(Uint32 format,int access,int w,int h)
{
	if(_renderer)
		return Texture::create(SDL_CreateTexture(_renderer,format,access,w,h));
	return nullptr;
}

Texture* Renderer::createTextureFromSurface(Surface* surface)
{
	Texture* texture = nullptr;

	if(_renderer != nullptr && surface != nullptr)
	{
		texture = Texture::create(SDL_CreateTextureFromSurface(_renderer,surface->_surface));
	}
	return texture;
}

int Renderer::renderCopy(Texture*texture,const SDL_Rect*srcRect,SDL_Rect*destRect)
{
	return SDL_RenderCopy(_renderer,texture->_texture,srcRect,destRect);
}

int Renderer::renderCopyEx(Texture* texture,const SDL_Rect* srcRect,SDL_Rect* destRect,const double angle,const SDL_Point* center,SDL_RendererFlip flip)
{
	return SDL_RenderCopyEx(_renderer,texture->_texture,srcRect,destRect,angle,center,flip);
}

int Renderer::renderCopyEx(Texture* texture,const Rect& srcRect,const Rect& destRect,const double angle,const Point& center,SDL_RendererFlip flip)
{
	SDL_Rect src = srcRect.getSDL_Rect();
	SDL_Rect dest = destRect.getSDL_Rect();
	SDL_Point c = center.getSDL_Point();

	return SDL_RenderCopyEx(_renderer,texture->_texture,&src,&dest,angle,&c,flip);
}

Texture*Renderer::imgLoadTexture(const char* filePath)
{
	SDL_Texture* tex = IMG_LoadTexture(_renderer,filePath);
	
	return Texture::create(tex);
}

Texture*Renderer::imgLoadTextureThreadSafe(const char* filepath)
{
	SDL_Texture*tex = IMG_LoadTexture(_renderer,filepath);
	Texture*texture = new Texture();

	texture->init(tex);
	return texture;
}

Texture*Renderer::createTextureFromSurfaceThreadSafe(Surface* surface)
{
	Texture* texture = nullptr;

	if(_renderer != nullptr && surface != nullptr)
	{
		SDL_Texture*tex = SDL_CreateTextureFromSurface(_renderer,surface->_surface);
		
		texture = new Texture();
		texture->init(tex);
	}
	return texture;
}

int Renderer::renderDrawLine(const Point& startPos,const Point& endPos)
{
	int x1 = (int)startPos.x;
	int y1 = (int)startPos.y;
	int x2 = (int)endPos.x;
	int y2 = (int)endPos.y;

	return SDL_RenderDrawLine(_renderer,x1,y1,x2,y2);
}

int Renderer::renderDrawRect(const Rect& rect)
{
	SDL_Rect r = rect.getSDL_Rect();

	return SDL_RenderDrawRect(_renderer,&r);
}

int Renderer::renderFillRect(const Rect& rect)
{
	SDL_Rect r = rect.getSDL_Rect();

	return SDL_RenderFillRect(_renderer,&r);
}

int Renderer::renderSetScale(float scaleX,float scaleY)
{
	return SDL_RenderSetScale(_renderer,scaleX,scaleY);
}

int Renderer::renderSetLogicalSize(int w,int h)
{
	return SDL_RenderSetLogicalSize(_renderer,w,h);
}

void Renderer::renderGetLogicalSize(int& w,int& h)
{
	SDL_RenderGetLogicalSize(_renderer,&w,&h);
}

int Renderer::setRenderDrawBlendMode(SDL_BlendMode mode)
{
	return SDL_SetRenderDrawBlendMode(_renderer,mode);
}

int Renderer::getRenderDrawBlendMode(SDL_BlendMode* mode)
{
	return SDL_GetRenderDrawBlendMode(_renderer,mode);
}

int Renderer::renderSetViewport(const SDL_Rect* rect)
{
	return SDL_RenderSetViewport(_renderer,rect);
}

Rect Renderer::renderGetViewport()
{
	SDL_Rect rect;
	
	SDL_RenderGetViewport(_renderer,&rect);

	return Rect(rect);
}

int Renderer::setRenderTarget(Texture* texture)
{
	if(texture != nullptr)
		return SDL_SetRenderTarget(_renderer,texture->_texture);
	else
		return SDL_SetRenderTarget(_renderer,nullptr);
}

int Renderer::renderSetClipRect(const SDL_Rect*rect)
{
	return SDL_RenderSetClipRect(_renderer,rect);
}

Rect Renderer::renderGetClipRect()
{
	SDL_Rect rect;
	SDL_RenderGetClipRect(_renderer,&rect);

	return Rect(rect);
}

SDL_Renderer* Renderer::getSDL_Renderer()const
{
	return _renderer;
}
NS_SDL_END

Renderer的主要功能包括:

1.绘制。包括绘制图片和绘制一些线段,矩形等。

2.生成纹理。创建基于本渲染器的纹理。

3.更改渲染目标。

4.设置缩放,即使用SDL_RenderSetScale函数,它能简单地实现不同分辨率主要是手机或平板的适配(图片可能稍微有点变形)。

然后i就是main.cpp要进行稍微的改变。

#include <iostream>
#include "SDL_Engine.h"
#include "SDL.h"
#include "vld.h"

USING_NS_SDL;
using namespace std;
//初始化
void initlize(Renderer* renderer);
void clear();
//绘制
void draw(Renderer* renderer);
//更新
void update(float dt);
//事件处理
void handleEvents();

bool g_bRunning = true;
Texture* g_pTexture = nullptr;

int main(int argc,char** argv)
{
	float secondsPerFrame = 1.f/60.f;
	float time = 0.f;
	Uint32 nextTick = 0u;
	Uint32 lastTick = 0u;
	int currentFrame = 0;
	//初始化全部子系统
	SDL_Init(SDL_INIT_EVERYTHING);
	IMG_Init(IMG_INIT_PNG);
	//创建窗口
	Window* window = Window::create("SDL_EngineTest",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,800,480,SDL_WINDOW_SHOWN);
	window->retain();
	//创建渲染器
	Renderer* renderer = Renderer::create(window,-1,SDL_RENDERER_PRESENTVSYNC);
	renderer->retain();

	initlize(renderer);
	//游戏循环
	while (g_bRunning)
	{
		Uint32 currentTick = SDL_GetTicks();
		if(currentTick >= nextTick)
		{
			//帧率固定为方便调试
			float dt = secondsPerFrame;
			time += (currentTick - lastTick) / 1000.f;

			lastTick = currentTick;
			nextTick = lastTick + (Uint32)(secondsPerFrame * 1000);
			//显示当前帧数
			if (time >= 1.f)
			{
				time -= 1.f;
				printf("%d\n",currentFrame);
				currentFrame = 0;
			}
			else
				currentFrame++;

			update(dt);
			
			renderer->renderClear();
			draw(renderer);
			renderer->renderPresent();
		}
		handleEvents();

		PoolManager::getInstance()->getCurReleasePool()->clear();
	}
	renderer->release();
	window->release();
	//清除
	clear();

	PoolManager::purge();

	IMG_Quit();
	SDL_Quit();
	_CrtDumpMemoryLeaks();
	return 0;
}

void initlize(Renderer* renderer)
{
	g_pTexture = renderer->imgLoadTexture("crop7_5.png");
	g_pTexture->retain();
	//设置刷新颜色
	renderer->setRenderDrawColor(Color4B(0,255,255,255));
}

void clear()
{
	g_pTexture->release();
}

void draw(Renderer* renderer)
{
	SDL_Rect destRect = {100,100,94,48};
	renderer->renderCopy(g_pTexture,nullptr,&destRect);
}

void update(float dt)
{
}

void handleEvents()
{
	SDL_Event event = {};
	//对事件进行轮询
	while(SDL_PollEvent(&event))
	{
		switch(event.type)
		{
		case SDL_QUIT: g_bRunning = false; break;
		}
	}
}
可以看到,目前的绘制使用的是Texture和Renderer。其运行结果和上一节相同。

虽然本节结果和上一节的相同,但是使用渲染器和纹理进行绘制是很有必要的,其中最主要的一个原因就是渲染器的绘制效率是远远高于Surface的。

本节代码:链接:https://pan.baidu.com/s/1C0mbP1_jG1fAmdrnRuyXqA 密码:lc66

猜你喜欢

转载自blog.csdn.net/bull521/article/details/79730331