#include #undef main #include #include #include #include #include namespace MiniEngine { 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); } }; class RGBA { public: int r, g, b, a; RGBA(int R, int G, int B, int A) { r = R; g = G; b = B; a = A; } RGBA() { r = g = b = a = 0; } SDL_Color toSDLColor() { SDL_Color c; c.r = r; c.g = g; c.b = b; c.a = a; return c; } }; 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; }; class Surface { public: ~Surface()=default; protected: Surface() = default; private: std::shared_ptr surf; friend class Renderer; friend class Font; }; class Texture { public: ~Texture()=default; Rect getSize() { return rect; } int getw() { return rect.w; } int geth() { return rect.h; } bool isReady() { return (text.get() != nullptr); } protected: Texture()=default; /// updateInfo() must be called after Texture is changed. void updateInfo() { SDL_QueryTexture(text.get(), NULL, NULL, &rect.w, &rect.h); rect.x = rect.y = 0; } private: std::shared_ptr text; Rect rect; friend class Renderer; }; enum class RendererType { Software=SDL_RENDERER_SOFTWARE, Accelerated=SDL_RENDERER_ACCELERATED, PresentSync=SDL_RENDERER_PRESENTVSYNC, TargetTexture=SDL_RENDERER_TARGETTEXTURE }; enum class BlendMode { None=SDL_BLENDMODE_NONE, Blend=SDL_BLENDMODE_BLEND, Add=SDL_BLENDMODE_ADD, Mod=SDL_BLENDMODE_MOD }; 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; } int setBlendMode(BlendMode mode) { return SDL_SetRenderDrawBlendMode(rnd.get(),static_cast(mode)); } BlendMode getBlendMode() { SDL_BlendMode temp; SDL_GetRenderDrawBlendMode(rnd.get(),&temp); return static_cast(temp); } int setTarget(Texture& t) { return SDL_SetRenderTarget(rnd.get(),t.text.get()); } int setTarget() { return SDL_SetRenderTarget(rnd.get(),nullptr); } 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) { ErrorViewer e; e.fetch(); throw e; } 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) { ErrorViewer e; e.fetch(); throw e; } 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) { ErrorViewer e; e.fetch(); throw e; } t.text.reset(temp, SDL_DestroyTexture); t.updateInfo(); return t; } Texture createTexture(int Width,int Height) throw(ErrorViewer) { 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; } protected: /// This function is called by Window ONLY. Renderer()=default; private: std::shared_ptr rnd; friend class Window; }; class Window { public: Window(std::string Title, int Width, int Height,std::initializer_list RendererFlags= {RendererType::Accelerated,RendererType::TargetTexture}) throw(ErrorViewer) { SDL_Window* temp = SDL_CreateWindow(Title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_WINDOW_SHOWN); if (temp == NULL) { ErrorViewer e; e.fetch(); throw e; } wnd.reset(temp, SDL_DestroyWindow); setRenderer(RendererFlags); } Renderer getRenderer() const { return winrnd; } void setRenderer(std::initializer_list RendererFlags) { int flag=0; for(auto v:RendererFlags) { flag|=static_cast(v); } _setRenderer_Real(flag); } Rect getSize() { int w, h; SDL_GetWindowSize(wnd.get(), &w, &h); Rect rect(0, 0, w, h); return rect; } void setSize(Rect sizeRect) { setSize(sizeRect.w, sizeRect.h); } void setSize(int w, int h) { SDL_SetWindowSize(wnd.get(),w,h); } void setTitle(std::string Title) { SDL_SetWindowTitle(wnd.get(),Title.c_str()); } std::string getTitle() { return std::string(SDL_GetWindowTitle(wnd.get())); } private: void _setRenderer_Real(Uint32 flags) { winrnd.rnd.reset(SDL_CreateRenderer(wnd.get(), -1, flags),SDL_DestroyRenderer); } std::shared_ptr wnd; Renderer winrnd; }; class Font { public: Font()=default; Font(std::string FontFileName, int size) throw(ErrorViewer) { if (use(FontFileName, size) != 0) { ErrorViewer e; e.fetch(); throw e; } } 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 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); } }; 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 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 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: }; }/// End of namespace MiniEngine namespace App { 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; }