2017-02-17 14:25:12 +08:00
|
|
|
#include <SDL2/SDL.h>
|
|
|
|
#undef main
|
|
|
|
#include <SDL2/SDL_image.h>
|
|
|
|
#include <SDL2/SDL_ttf.h>
|
|
|
|
#include <SDL2/SDL_mixer.h>
|
|
|
|
|
2017-02-23 16:51:13 +08:00
|
|
|
#include <string>
|
2017-02-17 14:25:12 +08:00
|
|
|
#include <memory>
|
2017-02-24 12:10:06 +08:00
|
|
|
#include <map>
|
|
|
|
#include <mutex>
|
2017-02-17 14:25:12 +08:00
|
|
|
|
2017-02-23 22:42:49 +08:00
|
|
|
#define _DECL_DEPRECATED __declspec(deprecated)
|
|
|
|
#define _DECL_DEPRECATED_MSG(InfoString) __declspec(deprecated(InfoString))
|
|
|
|
|
2017-02-17 14:25:12 +08:00
|
|
|
namespace MiniEngine
|
|
|
|
{
|
2017-02-23 16:51:13 +08:00
|
|
|
|
|
|
|
class Rect
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int x, y, w, h;
|
|
|
|
Rect(int X, int Y, int W, int H)
|
|
|
|
{
|
|
|
|
x = X;
|
|
|
|
y = Y;
|
|
|
|
w = W;
|
|
|
|
h = H;
|
|
|
|
}
|
|
|
|
Rect()
|
|
|
|
{
|
|
|
|
x = y = w = h = 0;
|
|
|
|
}
|
|
|
|
SDL_Rect toSDLRect()
|
|
|
|
{
|
|
|
|
SDL_Rect r;
|
|
|
|
r.x = x;
|
|
|
|
r.y = y;
|
|
|
|
r.w = w;
|
|
|
|
r.h = h;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class Point
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int x,y;
|
|
|
|
Point(int X,int Y)
|
|
|
|
{
|
|
|
|
x=X;
|
|
|
|
y=Y;
|
|
|
|
}
|
|
|
|
Point()
|
|
|
|
{
|
|
|
|
x=y=0;
|
|
|
|
}
|
|
|
|
SDL_Point toSDLPoint()
|
|
|
|
{
|
|
|
|
SDL_Point p;
|
|
|
|
p.x=x;
|
|
|
|
p.y=y;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
bool inRect(Rect rect)
|
|
|
|
{
|
|
|
|
auto p=toSDLPoint();
|
|
|
|
auto r=rect.toSDLRect();
|
|
|
|
return SDL_PointInRect(&p,&r);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-02-23 22:42:49 +08:00
|
|
|
class ColorMode
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int r,g,b;
|
|
|
|
ColorMode(int R,int G,int B)
|
|
|
|
{
|
|
|
|
r=R;
|
|
|
|
g=G;
|
|
|
|
b=B;
|
|
|
|
}
|
|
|
|
ColorMode()
|
|
|
|
{
|
|
|
|
r=g=b=0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-02-23 16:51:13 +08:00
|
|
|
class RGBA
|
|
|
|
{
|
|
|
|
public:
|
2017-02-23 22:42:49 +08:00
|
|
|
int r,g,b,a;
|
2017-02-23 16:51:13 +08:00
|
|
|
RGBA(int R, int G, int B, int A)
|
|
|
|
{
|
2017-02-23 22:42:49 +08:00
|
|
|
r=R;
|
|
|
|
g=G;
|
|
|
|
b=B;
|
2017-02-23 16:51:13 +08:00
|
|
|
a = A;
|
|
|
|
}
|
2017-02-23 22:42:49 +08:00
|
|
|
RGBA(ColorMode mode,int A)
|
|
|
|
{
|
|
|
|
r=mode.r;
|
|
|
|
g=mode.g;
|
|
|
|
b=mode.b;
|
|
|
|
a=A;
|
|
|
|
}
|
2017-02-23 16:51:13 +08:00
|
|
|
RGBA()
|
|
|
|
{
|
2017-02-23 22:42:49 +08:00
|
|
|
r=g=b=a=0;
|
2017-02-23 16:51:13 +08:00
|
|
|
}
|
|
|
|
SDL_Color toSDLColor()
|
|
|
|
{
|
|
|
|
SDL_Color c;
|
|
|
|
c.r = r;
|
|
|
|
c.g = g;
|
|
|
|
c.b = b;
|
|
|
|
c.a = a;
|
|
|
|
return c;
|
|
|
|
}
|
2017-02-23 22:42:49 +08:00
|
|
|
ColorMode toColorMode()
|
|
|
|
{
|
|
|
|
return ColorMode(r,g,b);
|
|
|
|
}
|
2017-02-23 16:51:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class NonCopyable
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
NonCopyable() = default;
|
|
|
|
~NonCopyable() = default;
|
|
|
|
NonCopyable(const NonCopyable&) = delete;
|
|
|
|
NonCopyable& operator = (const NonCopyable&) = delete;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ErrorViewer : public std::exception
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void fetch()
|
|
|
|
{
|
|
|
|
str = SDL_GetError();
|
|
|
|
}
|
|
|
|
std::string getError()
|
|
|
|
{
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
const char* what() const throw() override
|
|
|
|
{
|
|
|
|
return str.c_str();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::string str;
|
|
|
|
};
|
|
|
|
|
2017-02-23 22:42:49 +08:00
|
|
|
enum class BlendMode
|
|
|
|
{
|
|
|
|
None=SDL_BLENDMODE_NONE,
|
|
|
|
Blend=SDL_BLENDMODE_BLEND,
|
|
|
|
Add=SDL_BLENDMODE_ADD,
|
|
|
|
Mod=SDL_BLENDMODE_MOD
|
|
|
|
};
|
|
|
|
|
2017-02-23 16:51:13 +08:00
|
|
|
class Surface
|
|
|
|
{
|
|
|
|
public:
|
2017-02-23 21:27:29 +08:00
|
|
|
~Surface()=default;
|
2017-02-23 16:51:13 +08:00
|
|
|
protected:
|
|
|
|
Surface() = default;
|
|
|
|
private:
|
|
|
|
std::shared_ptr<SDL_Surface> surf;
|
2017-02-23 22:42:49 +08:00
|
|
|
friend class Window;
|
2017-02-23 16:51:13 +08:00
|
|
|
friend class Renderer;
|
|
|
|
friend class Font;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Texture
|
|
|
|
{
|
|
|
|
public:
|
2017-02-23 21:27:29 +08:00
|
|
|
~Texture()=default;
|
2017-02-23 16:51:13 +08:00
|
|
|
Rect getSize()
|
|
|
|
{
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
int getw()
|
|
|
|
{
|
|
|
|
return rect.w;
|
|
|
|
}
|
|
|
|
int geth()
|
|
|
|
{
|
|
|
|
return rect.h;
|
|
|
|
}
|
2017-02-23 21:27:29 +08:00
|
|
|
bool isReady()
|
2017-02-23 16:51:13 +08:00
|
|
|
{
|
2017-02-23 21:27:29 +08:00
|
|
|
return (text.get() != nullptr);
|
2017-02-23 16:51:13 +08:00
|
|
|
}
|
2017-02-23 22:42:49 +08:00
|
|
|
int setBlendMode(BlendMode mode)
|
|
|
|
{
|
|
|
|
return SDL_SetTextureBlendMode(text.get(),static_cast<SDL_BlendMode>(mode));
|
|
|
|
}
|
|
|
|
BlendMode getBlendMode()
|
|
|
|
{
|
|
|
|
SDL_BlendMode temp;
|
|
|
|
SDL_GetTextureBlendMode(text.get(),&temp);
|
|
|
|
return static_cast<BlendMode>(temp);
|
|
|
|
}
|
|
|
|
/// Alpha: 0: Transparent 255: opaque
|
|
|
|
int setAlphaMode(int alpha)
|
|
|
|
{
|
|
|
|
Uint8 temp=std::max(std::min(alpha,255),0);
|
|
|
|
return SDL_SetTextureAlphaMod(text.get(),temp);
|
|
|
|
}
|
|
|
|
int getAlphaMode()
|
|
|
|
{
|
|
|
|
Uint8 temp;
|
|
|
|
SDL_GetTextureAlphaMod(text.get(),&temp);
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
ColorMode getColorMode()
|
|
|
|
{
|
|
|
|
ColorMode pack;
|
|
|
|
Uint8 r,g,b;
|
|
|
|
SDL_GetTextureColorMod(text.get(),&r,&g,&b);
|
|
|
|
pack.r=r;
|
|
|
|
pack.g=g;
|
|
|
|
pack.b=b;
|
|
|
|
return pack;
|
|
|
|
}
|
|
|
|
int setColorMode(ColorMode mode)
|
|
|
|
{
|
|
|
|
return SDL_SetTextureColorMod(text.get(),mode.r,mode.g,mode.b);
|
|
|
|
}
|
|
|
|
RGBA getRGBA()
|
|
|
|
{
|
|
|
|
return RGBA(getColorMode(),getAlphaMode());
|
|
|
|
}
|
|
|
|
void setRGBA(RGBA pack)
|
|
|
|
{
|
|
|
|
setColorMode(pack.toColorMode());
|
|
|
|
setAlphaMode(pack.a);
|
|
|
|
}
|
2017-02-23 21:27:29 +08:00
|
|
|
protected:
|
|
|
|
Texture()=default;
|
|
|
|
/// updateInfo() must be called after Texture is changed.
|
2017-02-23 16:51:13 +08:00
|
|
|
void updateInfo()
|
|
|
|
{
|
|
|
|
SDL_QueryTexture(text.get(), NULL, NULL, &rect.w, &rect.h);
|
|
|
|
rect.x = rect.y = 0;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::shared_ptr<SDL_Texture> text;
|
|
|
|
Rect rect;
|
|
|
|
friend class Renderer;
|
|
|
|
};
|
|
|
|
|
2017-02-23 21:27:29 +08:00
|
|
|
enum class RendererType
|
|
|
|
{
|
|
|
|
Software=SDL_RENDERER_SOFTWARE,
|
|
|
|
Accelerated=SDL_RENDERER_ACCELERATED,
|
|
|
|
PresentSync=SDL_RENDERER_PRESENTVSYNC,
|
|
|
|
TargetTexture=SDL_RENDERER_TARGETTEXTURE
|
|
|
|
};
|
|
|
|
|
2017-02-23 22:42:49 +08:00
|
|
|
|
2017-02-23 16:51:13 +08:00
|
|
|
|
|
|
|
class Renderer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int setColor(RGBA pack)
|
|
|
|
{
|
|
|
|
return SDL_SetRenderDrawColor(rnd.get(), pack.r, pack.g, pack.b, pack.a);
|
|
|
|
}
|
|
|
|
RGBA getColor()
|
|
|
|
{
|
|
|
|
Uint8 r, g, b, a;
|
|
|
|
SDL_GetRenderDrawColor(rnd.get(), &r, &g, &b, &a);
|
|
|
|
RGBA pack(r, g, b, a);
|
|
|
|
return pack;
|
|
|
|
}
|
2017-02-23 21:27:29 +08:00
|
|
|
int setBlendMode(BlendMode mode)
|
|
|
|
{
|
|
|
|
return SDL_SetRenderDrawBlendMode(rnd.get(),static_cast<SDL_BlendMode>(mode));
|
|
|
|
}
|
|
|
|
BlendMode getBlendMode()
|
|
|
|
{
|
|
|
|
SDL_BlendMode temp;
|
|
|
|
SDL_GetRenderDrawBlendMode(rnd.get(),&temp);
|
|
|
|
return static_cast<BlendMode>(temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
int setTarget(Texture& t)
|
|
|
|
{
|
|
|
|
return SDL_SetRenderTarget(rnd.get(),t.text.get());
|
|
|
|
}
|
|
|
|
int setTarget()
|
|
|
|
{
|
|
|
|
return SDL_SetRenderTarget(rnd.get(),nullptr);
|
|
|
|
}
|
|
|
|
|
2017-02-23 16:51:13 +08:00
|
|
|
int fillRect(Rect rect)
|
|
|
|
{
|
|
|
|
auto inr = rect.toSDLRect();
|
|
|
|
return SDL_RenderFillRect(rnd.get(), &inr);
|
|
|
|
}
|
|
|
|
int drawRect(Rect rect)
|
|
|
|
{
|
|
|
|
auto inr = rect.toSDLRect();
|
|
|
|
return SDL_RenderDrawRect(rnd.get(), &inr);
|
|
|
|
}
|
|
|
|
int clear()
|
|
|
|
{
|
|
|
|
return SDL_RenderClear(rnd.get());
|
|
|
|
}
|
|
|
|
void update()
|
|
|
|
{
|
|
|
|
SDL_RenderPresent(rnd.get());
|
|
|
|
}
|
|
|
|
int copy(Texture t, Rect src, Rect dst)
|
|
|
|
{
|
|
|
|
SDL_Rect s = src.toSDLRect();
|
|
|
|
SDL_Rect d = dst.toSDLRect();
|
|
|
|
return SDL_RenderCopy(rnd.get(), t.text.get(), &s, &d);
|
|
|
|
}
|
|
|
|
int copyTo(Texture t, Rect dst)
|
|
|
|
{
|
|
|
|
SDL_Rect d = dst.toSDLRect();
|
|
|
|
return SDL_RenderCopy(rnd.get(), t.text.get(), NULL, &d);
|
|
|
|
}
|
|
|
|
int copyFill(Texture t, Rect src)
|
|
|
|
{
|
|
|
|
SDL_Rect s = src.toSDLRect();
|
|
|
|
return SDL_RenderCopy(rnd.get(), t.text.get(), &s, NULL);
|
|
|
|
}
|
|
|
|
int copyFullFill(Texture t)
|
|
|
|
{
|
|
|
|
return SDL_RenderCopy(rnd.get(), t.text.get(), NULL, NULL);
|
|
|
|
}
|
|
|
|
Surface loadSurface(std::string FileName) throw(ErrorViewer)
|
|
|
|
{
|
|
|
|
Surface surf;
|
|
|
|
SDL_Surface* temp = IMG_Load(FileName.c_str());
|
|
|
|
if (temp == nullptr)
|
2017-02-18 01:46:18 +08:00
|
|
|
{
|
2017-02-23 16:51:13 +08:00
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
2017-02-18 01:46:18 +08:00
|
|
|
}
|
2017-02-23 16:51:13 +08:00
|
|
|
surf.surf.reset(temp, SDL_FreeSurface);
|
|
|
|
return surf;
|
|
|
|
}
|
|
|
|
Texture render(Surface surf) throw (ErrorViewer)
|
|
|
|
{
|
|
|
|
Texture t;
|
|
|
|
SDL_Texture* temp = SDL_CreateTextureFromSurface(rnd.get(), surf.surf.get());
|
|
|
|
if (temp == nullptr)
|
2017-02-18 01:46:18 +08:00
|
|
|
{
|
2017-02-23 16:51:13 +08:00
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
2017-02-18 01:46:18 +08:00
|
|
|
}
|
2017-02-23 16:51:13 +08:00
|
|
|
t.text.reset(temp, SDL_DestroyTexture);
|
|
|
|
t.updateInfo();
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
Texture loadTexture(std::string FileName) throw(ErrorViewer)
|
|
|
|
{
|
|
|
|
Texture t;
|
|
|
|
SDL_Texture* temp = IMG_LoadTexture(rnd.get(), FileName.c_str());
|
|
|
|
if (temp == nullptr)
|
2017-02-18 01:46:18 +08:00
|
|
|
{
|
2017-02-23 16:51:13 +08:00
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
2017-02-18 01:46:18 +08:00
|
|
|
}
|
2017-02-23 16:51:13 +08:00
|
|
|
t.text.reset(temp, SDL_DestroyTexture);
|
|
|
|
t.updateInfo();
|
|
|
|
return t;
|
|
|
|
}
|
2017-02-23 21:27:29 +08:00
|
|
|
Texture createTexture(int Width,int Height) throw(ErrorViewer)
|
2017-02-23 16:51:13 +08:00
|
|
|
{
|
2017-02-23 21:27:29 +08:00
|
|
|
SDL_Texture* temp=SDL_CreateTexture(rnd.get(),SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, Width, Height);
|
|
|
|
if(temp==NULL)
|
|
|
|
{
|
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
Texture t;
|
|
|
|
t.text.reset(temp,SDL_DestroyTexture);
|
|
|
|
t.updateInfo();
|
|
|
|
return t;
|
2017-02-23 16:51:13 +08:00
|
|
|
}
|
2017-02-23 21:27:29 +08:00
|
|
|
|
|
|
|
protected:
|
2017-02-23 22:42:49 +08:00
|
|
|
/// This function is called by class Window ONLY.
|
2017-02-23 21:27:29 +08:00
|
|
|
Renderer()=default;
|
2017-02-23 16:51:13 +08:00
|
|
|
private:
|
|
|
|
std::shared_ptr<SDL_Renderer> rnd;
|
|
|
|
friend class Window;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Window
|
|
|
|
{
|
|
|
|
public:
|
2017-02-23 21:27:29 +08:00
|
|
|
Window(std::string Title, int Width, int Height,std::initializer_list<RendererType> RendererFlags= {RendererType::Accelerated,RendererType::TargetTexture}) throw(ErrorViewer)
|
2017-02-23 16:51:13 +08:00
|
|
|
{
|
|
|
|
SDL_Window* temp = SDL_CreateWindow(Title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_WINDOW_SHOWN);
|
|
|
|
if (temp == NULL)
|
2017-02-18 01:46:18 +08:00
|
|
|
{
|
2017-02-23 16:51:13 +08:00
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
2017-02-18 01:46:18 +08:00
|
|
|
}
|
2017-02-23 16:51:13 +08:00
|
|
|
wnd.reset(temp, SDL_DestroyWindow);
|
2017-02-23 21:27:29 +08:00
|
|
|
setRenderer(RendererFlags);
|
2017-02-23 16:51:13 +08:00
|
|
|
}
|
|
|
|
Renderer getRenderer() const
|
|
|
|
{
|
|
|
|
return winrnd;
|
|
|
|
}
|
|
|
|
|
2017-02-23 21:27:29 +08:00
|
|
|
void setRenderer(std::initializer_list<RendererType> RendererFlags)
|
2017-02-23 16:51:13 +08:00
|
|
|
{
|
2017-02-23 21:27:29 +08:00
|
|
|
int flag=0;
|
|
|
|
for(auto v:RendererFlags)
|
|
|
|
{
|
|
|
|
flag|=static_cast<int>(v);
|
|
|
|
}
|
|
|
|
_setRenderer_Real(flag);
|
2017-02-23 16:51:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Rect getSize()
|
|
|
|
{
|
|
|
|
int w, h;
|
|
|
|
SDL_GetWindowSize(wnd.get(), &w, &h);
|
2017-02-23 22:42:49 +08:00
|
|
|
return Rect(0, 0, w, h);
|
2017-02-23 16:51:13 +08:00
|
|
|
}
|
|
|
|
void setSize(Rect sizeRect)
|
|
|
|
{
|
|
|
|
setSize(sizeRect.w, sizeRect.h);
|
|
|
|
}
|
|
|
|
void setSize(int w, int h)
|
|
|
|
{
|
|
|
|
SDL_SetWindowSize(wnd.get(),w,h);
|
|
|
|
}
|
|
|
|
|
2017-02-23 22:42:49 +08:00
|
|
|
Rect getPosition()
|
|
|
|
{
|
|
|
|
int x,y;
|
|
|
|
SDL_GetWindowPosition(wnd.get(),&x,&y);
|
|
|
|
return Rect(x,y,0,0);
|
|
|
|
}
|
|
|
|
void setPosition(int x,int y)
|
|
|
|
{
|
|
|
|
SDL_SetWindowPosition(wnd.get(),x,y);
|
|
|
|
}
|
|
|
|
/// FIXME: Use class Point or class Rect ?
|
|
|
|
void setPosition(Point point)
|
|
|
|
{
|
|
|
|
SDL_SetWindowPosition(wnd.get(),point.x,point.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-23 16:51:13 +08:00
|
|
|
void setTitle(std::string Title)
|
|
|
|
{
|
2017-02-23 21:27:29 +08:00
|
|
|
SDL_SetWindowTitle(wnd.get(),Title.c_str());
|
|
|
|
}
|
|
|
|
std::string getTitle()
|
|
|
|
{
|
|
|
|
return std::string(SDL_GetWindowTitle(wnd.get()));
|
2017-02-23 16:51:13 +08:00
|
|
|
}
|
2017-02-23 22:42:49 +08:00
|
|
|
|
|
|
|
void setResizable(bool resizable)
|
|
|
|
{
|
|
|
|
SDL_SetWindowResizable(wnd.get(),static_cast<SDL_bool>(resizable));
|
|
|
|
}
|
|
|
|
|
|
|
|
void show()
|
|
|
|
{
|
|
|
|
SDL_ShowWindow(wnd.get());
|
|
|
|
}
|
|
|
|
void hide()
|
|
|
|
{
|
|
|
|
SDL_HideWindow(wnd.get());
|
|
|
|
}
|
|
|
|
void raise()
|
|
|
|
{
|
|
|
|
SDL_RaiseWindow(wnd.get());
|
|
|
|
}
|
|
|
|
void minimize()
|
|
|
|
{
|
|
|
|
SDL_MinimizeWindow(wnd.get());
|
|
|
|
}
|
|
|
|
void maximize()
|
|
|
|
{
|
|
|
|
SDL_MaximizeWindow(wnd.get());
|
|
|
|
}
|
|
|
|
void restore()
|
|
|
|
{
|
|
|
|
SDL_RestoreWindow(wnd.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_DECL_DEPRECATED Surface getSurface()
|
|
|
|
{
|
|
|
|
SDL_Surface* temp=SDL_GetWindowSurface(wnd.get());
|
|
|
|
Surface s;
|
|
|
|
/// Don't Free This Surface
|
2017-02-24 12:10:06 +08:00
|
|
|
s.surf.reset(temp,[](SDL_Surface*) {});
|
2017-02-23 22:42:49 +08:00
|
|
|
return s;
|
|
|
|
}
|
2017-02-23 16:51:13 +08:00
|
|
|
private:
|
|
|
|
void _setRenderer_Real(Uint32 flags)
|
|
|
|
{
|
|
|
|
winrnd.rnd.reset(SDL_CreateRenderer(wnd.get(), -1, flags),SDL_DestroyRenderer);
|
|
|
|
}
|
|
|
|
std::shared_ptr<SDL_Window> wnd;
|
|
|
|
Renderer winrnd;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Font
|
|
|
|
{
|
|
|
|
public:
|
2017-02-23 21:27:29 +08:00
|
|
|
Font()=default;
|
2017-02-23 16:51:13 +08:00
|
|
|
Font(std::string FontFileName, int size) throw(ErrorViewer)
|
|
|
|
{
|
|
|
|
if (use(FontFileName, size) != 0)
|
2017-02-18 02:07:16 +08:00
|
|
|
{
|
2017-02-23 16:51:13 +08:00
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
2017-02-18 02:07:16 +08:00
|
|
|
}
|
2017-02-23 16:51:13 +08:00
|
|
|
}
|
|
|
|
int use(std::string FontFileName, int size)
|
|
|
|
{
|
|
|
|
TTF_Font* temp = TTF_OpenFont(FontFileName.c_str(), size);
|
|
|
|
if (temp == NULL) return -1;
|
|
|
|
font.reset(temp, TTF_CloseFont);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
Texture renderText(Renderer rnd, std::string Text, RGBA fg)
|
|
|
|
{
|
|
|
|
Surface surf;
|
|
|
|
surf.surf.reset(TTF_RenderText_Blended(font.get(), Text.c_str(), fg.toSDLColor()));
|
|
|
|
Texture t = rnd.render(surf);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
Texture renderUTF8(Renderer rnd, std::string Text, RGBA fg)
|
|
|
|
{
|
|
|
|
Surface surf;
|
|
|
|
surf.surf.reset(TTF_RenderUTF8_Blended(font.get(), Text.c_str(), fg.toSDLColor()));
|
|
|
|
Texture t = rnd.render(surf);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::shared_ptr<TTF_Font> font;
|
|
|
|
};
|
|
|
|
|
|
|
|
class SDLSystem
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static int SDLInit()
|
|
|
|
{
|
|
|
|
return SDL_Init(SDL_INIT_EVERYTHING);
|
|
|
|
}
|
|
|
|
static void SDLQuit()
|
|
|
|
{
|
|
|
|
SDL_Quit();
|
|
|
|
}
|
|
|
|
static int IMGInit()
|
|
|
|
{
|
|
|
|
return IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
|
|
|
|
}
|
|
|
|
static void IMGQuit()
|
|
|
|
{
|
|
|
|
IMG_Quit();
|
|
|
|
}
|
|
|
|
static int TTFInit()
|
|
|
|
{
|
|
|
|
return TTF_Init();
|
|
|
|
}
|
|
|
|
static void TTFQuit()
|
|
|
|
{
|
|
|
|
TTF_Quit();
|
|
|
|
}
|
|
|
|
static int MixInit()
|
|
|
|
{
|
|
|
|
return Mix_Init(MIX_INIT_MP3);
|
|
|
|
}
|
|
|
|
static void MixQuit()
|
|
|
|
{
|
|
|
|
Mix_Quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Init()
|
|
|
|
{
|
|
|
|
SDLInit();
|
|
|
|
IMGInit();
|
|
|
|
TTFInit();
|
|
|
|
MixInit();
|
|
|
|
}
|
|
|
|
static void Quit()
|
|
|
|
{
|
|
|
|
MixQuit();
|
|
|
|
TTFQuit();
|
|
|
|
IMGQuit();
|
|
|
|
SDLQuit();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Delay(int ms)
|
|
|
|
{
|
|
|
|
SDL_Delay(ms);
|
|
|
|
}
|
|
|
|
};
|
2017-02-18 02:07:16 +08:00
|
|
|
|
2017-02-17 14:25:12 +08:00
|
|
|
|
2017-02-23 21:27:29 +08:00
|
|
|
class AudioPlayer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AudioPlayer()
|
|
|
|
{
|
|
|
|
if(!_sysAudioCounter)
|
|
|
|
{
|
|
|
|
_sysAudio=new _Audio;
|
|
|
|
}
|
|
|
|
++_sysAudioCounter;
|
|
|
|
}
|
|
|
|
~AudioPlayer()
|
|
|
|
{
|
|
|
|
--_sysAudioCounter;
|
|
|
|
if(!_sysAudioCounter)
|
|
|
|
{
|
|
|
|
delete _sysAudio;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
class _Audio
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
_Audio()
|
|
|
|
{
|
|
|
|
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024);
|
|
|
|
}
|
|
|
|
~_Audio()
|
|
|
|
{
|
|
|
|
Mix_CloseAudio();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static _Audio* _sysAudio;
|
|
|
|
static int _sysAudioCounter;
|
|
|
|
};
|
|
|
|
AudioPlayer::_Audio* AudioPlayer::_sysAudio=NULL;
|
|
|
|
int AudioPlayer::_sysAudioCounter=0;
|
|
|
|
|
|
|
|
|
|
|
|
/// Forward Declaration
|
|
|
|
class Music
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
protected:
|
|
|
|
Music()=default;
|
|
|
|
private:
|
|
|
|
std::shared_ptr<Mix_Music> music;
|
|
|
|
friend class MusicPlayer;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MusicPlayer : public AudioPlayer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Music loadMusic(std::string Filename) throw (ErrorViewer)
|
|
|
|
{
|
|
|
|
Mix_Music* temp=Mix_LoadMUS(Filename.c_str());
|
|
|
|
if(temp==nullptr)
|
|
|
|
{
|
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
Music m;
|
|
|
|
m.music.reset(temp,Mix_FreeMusic);
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
void load(Music music)
|
|
|
|
{
|
|
|
|
m=music;
|
|
|
|
}
|
|
|
|
int play(int loops)
|
|
|
|
{
|
|
|
|
return Mix_PlayMusic(m.music.get(),loops);
|
|
|
|
}
|
|
|
|
void pause()
|
|
|
|
{
|
|
|
|
Mix_PauseMusic();
|
|
|
|
}
|
|
|
|
void resume()
|
|
|
|
{
|
|
|
|
Mix_ResumeMusic();
|
|
|
|
}
|
|
|
|
void rewind()
|
|
|
|
{
|
|
|
|
Mix_RewindMusic();
|
|
|
|
}
|
|
|
|
int stop()
|
|
|
|
{
|
|
|
|
return Mix_HaltMusic();
|
|
|
|
}
|
|
|
|
int fadeIn(int loops,int ms)
|
|
|
|
{
|
|
|
|
return Mix_FadeInMusic(m.music.get(),loops,ms);
|
|
|
|
}
|
|
|
|
int fadeOut(int ms)
|
|
|
|
{
|
|
|
|
return Mix_FadeOutMusic(ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isPlaying()
|
|
|
|
{
|
|
|
|
return Mix_PlayingMusic();
|
|
|
|
}
|
|
|
|
bool isPaused()
|
|
|
|
{
|
|
|
|
return Mix_PausedMusic();
|
|
|
|
}
|
|
|
|
int isFading()
|
|
|
|
{
|
|
|
|
switch(Mix_FadingMusic())
|
|
|
|
{
|
|
|
|
case MIX_NO_FADING:
|
|
|
|
return 0;
|
|
|
|
case MIX_FADING_IN:
|
|
|
|
return 1;
|
|
|
|
case MIX_FADING_OUT:
|
|
|
|
return 2;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Music m;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Sound
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
protected:
|
|
|
|
Sound()=default;
|
|
|
|
private:
|
|
|
|
std::shared_ptr<Mix_Chunk> sound;
|
|
|
|
friend class SoundPlayer;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef int ChannelID;
|
|
|
|
|
|
|
|
class SoundPlayer : public AudioPlayer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SoundPlayer(int Channels=16)
|
|
|
|
{
|
|
|
|
Mix_AllocateChannels(Channels);
|
|
|
|
}
|
|
|
|
Sound loadSound(std::string Filename) throw (ErrorViewer)
|
|
|
|
{
|
|
|
|
Mix_Chunk* temp=Mix_LoadWAV(Filename.c_str());
|
|
|
|
if(temp==NULL)
|
|
|
|
{
|
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
Sound s;
|
|
|
|
s.sound.reset(temp,Mix_FreeChunk);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
ChannelID playSound(Sound sound,int loops) throw (ErrorViewer)
|
|
|
|
{
|
|
|
|
ChannelID id;
|
|
|
|
if(-1==(id=Mix_PlayChannel(-1,sound.sound.get(),loops)))
|
|
|
|
{
|
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
ChannelID fadein(Sound sound,int loops,int ms) throw (ErrorViewer)
|
|
|
|
{
|
|
|
|
ChannelID id;
|
|
|
|
if(-1==(id=Mix_FadeInChannel(-1,sound.sound.get(),loops,ms)))
|
|
|
|
{
|
|
|
|
ErrorViewer e;
|
|
|
|
e.fetch();
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
int fadeout(ChannelID id,int ms)
|
|
|
|
{
|
|
|
|
return Mix_FadeOutChannel(id,ms);
|
|
|
|
}
|
|
|
|
void pause(ChannelID id)
|
|
|
|
{
|
|
|
|
Mix_Pause(id);
|
|
|
|
}
|
|
|
|
void resume(ChannelID id)
|
|
|
|
{
|
|
|
|
Mix_Resume(id);
|
|
|
|
}
|
|
|
|
int stop(ChannelID id)
|
|
|
|
{
|
|
|
|
return Mix_HaltChannel(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2017-02-24 11:12:48 +08:00
|
|
|
class Event
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int gettype()
|
|
|
|
{
|
|
|
|
return e.type;
|
|
|
|
}
|
|
|
|
protected:
|
|
|
|
Event()=default;
|
|
|
|
SDL_Event e;
|
|
|
|
private:
|
|
|
|
friend class EventEngine;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MouseButtonEvent : public Event
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int getx()
|
|
|
|
{
|
|
|
|
return e.button.x;
|
|
|
|
}
|
|
|
|
int gety()
|
|
|
|
{
|
|
|
|
return e.button.y;
|
|
|
|
}
|
|
|
|
int getbutton()
|
|
|
|
{
|
|
|
|
return e.button.button;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class EventEngine
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Event poll(bool mustNew=false) /// mustNew: false=SDL_PollEvent(&e) returns 0 ; true=SDL_PollEvent(&e) returns 1
|
|
|
|
{
|
|
|
|
Event e;
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
int ret=SDL_PollEvent(&e.e);
|
|
|
|
if((mustNew&&ret)||!mustNew) break;
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
Event wait()
|
|
|
|
{
|
|
|
|
Event e;
|
|
|
|
SDL_WaitEvent(&e.e);
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
Event waitfor(int ms)
|
|
|
|
{
|
|
|
|
Event e;
|
|
|
|
SDL_WaitEventTimeout(&e.e,ms);
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
};
|
2017-02-23 21:27:29 +08:00
|
|
|
|
2017-02-24 12:10:06 +08:00
|
|
|
|
|
|
|
|
|
|
|
namespace EventHandle
|
|
|
|
{
|
|
|
|
|
|
|
|
using DispatcherType = std::function<void(SDL_Event e,int& running,int& update)> ;
|
|
|
|
std::map<int,DispatcherType> disvec;
|
|
|
|
|
|
|
|
std::mutex mdisvec_counter;
|
|
|
|
int disvec_counter=0;
|
|
|
|
|
|
|
|
int RegistDispatcher(DispatcherType func)
|
|
|
|
{
|
|
|
|
mdisvec_counter.lock();
|
|
|
|
int id=disvec_counter++;
|
|
|
|
mdisvec_counter.unlock();
|
|
|
|
|
|
|
|
disvec.insert(make_pair(id,func));
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
int UnregistDispatcher(int callbackid)
|
|
|
|
{
|
|
|
|
for(auto it=disvec.begin(); it!=disvec.end(); it++)
|
|
|
|
{
|
|
|
|
if(callbackid==it->first)
|
|
|
|
{
|
|
|
|
disvec.erase(it);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
using UpdaterType = std::function<void(Renderer& rnd)> ;
|
|
|
|
std::map<int,UpdaterType> upvec;
|
|
|
|
|
|
|
|
std::mutex mupvec_counter;
|
|
|
|
int upvec_counter=0;
|
|
|
|
|
|
|
|
int RegistUpdater(UpdaterType func)
|
|
|
|
{
|
|
|
|
mupvec_counter.lock();
|
|
|
|
int id=upvec_counter++;
|
|
|
|
mupvec_counter.unlock();
|
|
|
|
|
|
|
|
upvec.insert(make_pair(id,func));
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
int UnregistUpdater(int callbackid)
|
|
|
|
{
|
|
|
|
for(auto it=upvec.begin(); it!=upvec.end(); it++)
|
|
|
|
{
|
|
|
|
if(callbackid==it->first)
|
|
|
|
{
|
|
|
|
upvec.erase(it);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dispatcher(SDL_Event e,int& running,int& update)
|
|
|
|
{
|
|
|
|
for(auto& func:disvec)
|
|
|
|
{
|
|
|
|
int r=1;
|
|
|
|
int u=0;
|
|
|
|
func.second(e,r,u);
|
|
|
|
running&=r;
|
|
|
|
update|=u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Updater(Renderer& rnd)
|
|
|
|
{
|
|
|
|
for(auto& func:upvec)
|
|
|
|
{
|
|
|
|
func.second(rnd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Loop(Renderer& rnd)
|
|
|
|
{
|
|
|
|
SDL_Event e;
|
|
|
|
int running=1;
|
|
|
|
int update=1;
|
|
|
|
while(running)
|
|
|
|
{
|
|
|
|
while(!update&&SDL_WaitEvent(&e))
|
|
|
|
{
|
|
|
|
Dispatcher(e,running,update);
|
|
|
|
}
|
|
|
|
|
|
|
|
rnd.clear();
|
|
|
|
Updater(rnd);
|
|
|
|
rnd.update();
|
|
|
|
update=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}/// End of namespace MiniEngine::EventHandle
|
|
|
|
|
2017-02-23 16:51:13 +08:00
|
|
|
}/// End of namespace MiniEngine
|
2017-02-18 01:46:18 +08:00
|
|
|
|
2017-02-23 16:51:13 +08:00
|
|
|
namespace App
|
|
|
|
{
|
2017-02-18 01:46:18 +08:00
|
|
|
|
2017-02-23 16:51:13 +08:00
|
|
|
int main(int argc,char* argv[]);
|
|
|
|
|
|
|
|
}/// End of namespace App
|
|
|
|
|
|
|
|
|
|
|
|
/// Default Setup Code
|
|
|
|
int main(int argc,char* argv[])
|
|
|
|
{
|
|
|
|
MiniEngine::SDLSystem::Init();
|
|
|
|
int ret=App::main(argc,argv);
|
|
|
|
MiniEngine::SDLSystem::Quit();
|
|
|
|
return ret;
|
|
|
|
}
|