SDL自更新至2.x后,原先在1.x大放异彩的SDL_Surface大部分功能被SDL_Texture所取代,如渲染。不过SDL_Surface还是有用武之地的,比如在使用SDL_ttf.h的部分函数时还是需要用到SDL_Surface,之后再转换成SDL_Texture。
列举一些常用的API(Application Programming Interface),详细可参见SDL wiki。
1.IMG_Load。加载图片(.png .jpg 等)并返回SDL_Surface
2.SDL_LoadBMP。 加载BMP图片并返回SDL_Surface
3.SDL_CreateRGBSurface 。根据RGB 宽高等 创建一个新的Surface
4.SDL_BlitSurface 。渲染SDL_Surface 到对应SDL_Surface
5.SDL_FillRect 。在SDL_Surface中填充一个矩形
6.SDL_UpdateWindowSurface。使用这个函数复制这个窗口的Surface到屏幕上。
首先,需要在Window类下增加getWindowSurface函数。
Surface* Window::getWindowSurface()
{
if(_window != nullptr)
return Surface::create(SDL_GetWindowSurface(_window));
return NULL;
}
SDL_GetWindowSurface函数是用来返回该SDL_Window所对应的SDL_Surface(该函数返回的SDL_Surface相同),以便于其他的SDL_Surface可以绘制到该窗口上等。
Surface.h
#ifndef __SDL_Surface_H__
#define __SDL_Surface_H__
#include "SDL.h"
#include "SDL_image.h"
#include "Object.h"
NS_SDL_BEGIN
class Renderer;
class Surface : public Object
{
private:
SDL_Surface*_surface;
public:
Surface();
virtual~Surface();
//调用这个函数后,就把内存交给了引擎处理,就不需要主动释放,若主动释放,会出错
static Surface*create(SDL_Surface*surface);
static Surface*create(const std::string&filepath);
static Surface*createWithBMP(const std::string&filepath);
static Surface*create(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask);
bool init(SDL_Surface*sur);
bool init(const std::string&filepath);
bool initWithBMP(const std::string&filepath);
bool init(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask);
//绘制 可切割,但不能缩放
int blitSurface(const SDL_Rect*srcRect,Surface*dest,SDL_Rect*destRect);
//SDL_ConvertSurface(SDL_Surface*src,const SDL_PixelFormat* fmt,Uint32flags)
Surface*convertSurface(const SDL_PixelFormat*fmt,Uint32 flags);
//矩形填充函数
int fillRect(const SDL_Rect*rect,Uint32 color);
//设置关键色并返回关键色
Uint32 mapRGB(Uint8 r,Uint8 g,Uint8 b)const;
Uint32 mapRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)const;
//设置关键色,对png图片格式尤其有效
int setColorKey(Uint32 colorkey)const;
//获得对应位置像素的ARGB值
Uint32 getARGB(int x,int y)const;
//混合模式
int setSurfaceBlendMode(SDL_BlendMode blendMode);
int getSurfaceBlendMode(SDL_BlendMode*blendMode);
SDL_Surface*getSDL_Surface()const;
friend class Renderer;
};
NS_SDL_END
#endif
Surface.cpp
#include "Surface.h"
NS_SDL_BEGIN
Surface::Surface()
:_surface(nullptr)
{
}
Surface::~Surface()
{
SDL_FreeSurface(_surface);
_surface = nullptr;
}
Surface*Surface::create(SDL_Surface*surface)
{
Surface*sur = new Surface();
if(sur && sur->init(surface))
sur->autorelease();
else
SDL_SAFE_DELETE(sur);
return sur;
}
Surface*Surface::create(const std::string& filepath)
{
auto sur = new Surface();
if(sur && sur->init(filepath))
sur->autorelease();
else
SDL_SAFE_DELETE(sur);
return sur;
}
Surface*Surface::createWithBMP(const std::string& filepath)
{
auto sur = new Surface();
if(sur && sur->initWithBMP(filepath))
sur->autorelease();
else
SDL_SAFE_DELETE(sur);
return sur;
}
Surface*Surface::create(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)
{
Surface* sur = new Surface();
if(sur && sur->init(flags,width,height,depth,Rmask,Gmask,Bmask,Amask))
sur->autorelease();
else
SDL_SAFE_DELETE(sur);
return sur;
}
bool Surface::init(SDL_Surface* sur)
{
_surface = sur;
return true;
}
bool Surface::init(const std::string&filepath)
{
_surface = IMG_Load(filepath.c_str());
if(_surface == nullptr)
{
printf("error:%s",IMG_GetError());
return false;
}
return true;
}
bool Surface::initWithBMP(const std::string&filepath)
{
_surface = SDL_LoadBMP(filepath.c_str());
if(_surface == nullptr)
{
printf("error:%s",SDL_GetError());
return false;
}
return true;
}
bool Surface::init(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)
{
_surface = SDL_CreateRGBSurface(flags,width,height,depth,Rmask,Gmask,Bmask,Amask);
if(_surface == nullptr)
{
printf("error:%s",SDL_GetError());
return false;
}
return true;
}
int Surface::blitSurface(const SDL_Rect*srcRect,Surface*dest,SDL_Rect*destRect)
{
return SDL_BlitSurface(_surface,srcRect,dest->_surface,destRect);
}
Surface*Surface::convertSurface(const SDL_PixelFormat*fmt,Uint32 flags)
{
SDL_Surface* sur = SDL_ConvertSurface(_surface,fmt,flags);
return Surface::create(sur);
}
int Surface::fillRect(const SDL_Rect*rect,Uint32 color)
{
return SDL_FillRect(_surface,rect,color);
}
Uint32 Surface::mapRGB(Uint8 r,Uint8 g,Uint8 b)const
{
return SDL_MapRGB(_surface->format,r,g,b);
}
Uint32 Surface::mapRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)const
{
return SDL_MapRGBA(_surface->format,r,g,b,a);
}
int Surface::setColorKey(Uint32 colorkey)const
{
return SDL_SetColorKey(_surface,SDL_TRUE,colorkey);
}
Uint32 Surface::getARGB(int x,int y)const
{
int index = y*_surface->w+x;
Uint32*pixels = (Uint32*)_surface->pixels;
return pixels[index];
}
int Surface::setSurfaceBlendMode(SDL_BlendMode mode)
{
return SDL_SetSurfaceBlendMode(_surface,mode);
}
int Surface::getSurfaceBlendMode(SDL_BlendMode*mode)
{
return SDL_GetSurfaceBlendMode(_surface,mode);
}
SDL_Surface*Surface::getSDL_Surface()const
{
return _surface;
}
NS_SDL_END
Surface类包括了创建和销毁,绘制(如blitSurface),以及一些功能函数。另外,setColorKey函数是设置关键色,用于纯背景色图片的背景隐藏。比如一个角色,带有0x00ff00的背景色,如果设置为该关键色的话,在渲染的时候则不会显示该颜色。
接着就是修改main.cpp函数
#include <iostream>
#include "SDL_Engine.h"
#include "SDL.h"
#include "vld.h"
USING_NS_SDL;
using namespace std;
//初始化
void initlize();
void clear();
//绘制
void draw(Surface* screen);
//更新
void update(float dt);
//事件处理
void handleEvents();
bool g_bRunning = true;
Surface* g_pSurface = 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();
//获取窗口对应的surface
Surface* screen = window->getWindowSurface();
screen->retain();
initlize();
//游戏循环
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);
draw(screen);
window->updateWindowSurface();
}
handleEvents();
PoolManager::getInstance()->getCurReleasePool()->clear();
}
screen->release();
window->release();
//清除
clear();
PoolManager::purge();
IMG_Quit();
SDL_Quit();
_CrtDumpMemoryLeaks();
return 0;
}
void initlize()
{
g_pSurface = Surface::create("crop7_5.png");
g_pSurface->retain();
}
void clear()
{
g_pSurface->release();
}
void draw(Surface* screen)
{
SDL_Rect rect = {};
screen->fillRect(nullptr,0x00ffff);
SDL_Rect srcRect = {0,0,94,48};
SDL_Rect destRect = {100,100,94,48};
g_pSurface->blitSurface(&srcRect,screen,&destRect);
}
void update(float dt)
{
}
void handleEvents()
{
SDL_Event event = {};
//对事件进行轮询
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT: g_bRunning = false; break;
}
}
}
除了增加一些语句外,还增加了一些函数,用于在合适的地方进行初始化,内存回收,绘制,以及逻辑更新。在draw函数中,先在屏幕上用0x00ffff进行渲染整个窗口,然后绘制了一个图片到窗口对应的Surface上,之后调用的window->updateWindowSurface()显示到窗口上。结果如图所示:
本节代码:链接:https://pan.baidu.com/s/100kTbyxnchP0K6y86LTZOw 密码:ye0g