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