/* Copyright 2014 Michele "King_DuckZ" Santullo This file is part of CloonelJump. CloonelJump is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. CloonelJump is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with CloonelJump. If not, see . */ #include "sdlmain.hpp" #include "observersmanager.hpp" #include "sizenotifiable.hpp" #include "sizeratio.hpp" #include #include #include #include #include #include #if defined(RASPBERRY_PI) #include #endif namespace cloonel { namespace { ///---------------------------------------------------------------------- ///---------------------------------------------------------------------- std::pair GetRenderingDriver() { typedef std::pair RetPairType; const int count = SDL_GetNumRenderDrivers(); int opengles = -1; int opengles2 = -1; int opengl = -1; SDL_RendererInfo info; for (int z = 0; z < count; ++z) { const int ret = SDL_GetRenderDriverInfo(z, &info); if (0 == ret) { if (std::strcmp("opengles", info.name) == 0) opengles = z; else if (std::strcmp("opengles2", info.name) == 0) opengles2 = z; else if (std::strcmp("opengl", info.name) == 0) opengl = z; } } #if !defined(FORCE_OPENGLES) if (opengl > -1) return RetPairType(opengl, "opengl"); #endif if (opengles2 > -1) return RetPairType(opengles2, "opengles2"); if (opengles > -1) return RetPairType(opengles, "opengles"); #if defined(FORCE_OPENGLES) if (opengl > -1) return RetPairType(opengl, "opengl"); #endif return RetPairType(-1, "default"); } } //unnamed namespace struct SDLMain::LocalData { SDL_Window* window; SDL_Renderer* renderer; SizeRatio sizeratio; ObserversManager resChangeNotifList; bool initialized; #if defined(RASPBERRY_PI) bool bcmInitialized; #endif }; ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ SDLMain::SDLMain (const char* parGameName, ushort2 parRes, ushort2 parReferenceRes) : m_gameName(parGameName), m_localData(new LocalData) { m_localData->sizeratio.SetOriginal(static_cast(parReferenceRes), static_cast(parRes)); m_localData->initialized = false; #if defined(RASPBERRY_PI) m_localData->bcmInitialized = false; #endif } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ SDLMain::~SDLMain() noexcept { ClearIFN(*m_localData); #if defined(RASPBERRY_PI) assert(not m_localData->bcmInitialized); #endif } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ void SDLMain::Init() { if (not m_localData->initialized) InitSDL(*m_localData); } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ void SDLMain::InitSDL (LocalData& parInitSDL) { #if defined(RASPBERRY_PI) assert(not parInitSDL.bcmInitialized); bcm_host_init(); parInitSDL.bcmInitialized = true; #endif parInitSDL.window = nullptr; parInitSDL.renderer = nullptr; parInitSDL.initialized = false; if (SDL_Init(SDL_INIT_EVERYTHING) == -1) throw std::runtime_error(SDL_GetError()); parInitSDL.initialized = true; #if defined(FORCE_OPENGLES) SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); #endif const float2 wh(m_localData->sizeratio.Resolution()); SDL_Window* const win = SDL_CreateWindow(m_gameName.c_str(), 100, 100, static_cast(wh.x()), static_cast(wh.y()), SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); if (!win) throw std::runtime_error(SDL_GetError()); parInitSDL.window = win; const auto rendererDriver = GetRenderingDriver(); m_rendererName = rendererDriver.second; SDL_Renderer* const renderer = SDL_CreateRenderer(win, rendererDriver.first, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (!renderer) throw std::runtime_error(SDL_GetError()); parInitSDL.renderer = renderer; } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ void SDLMain::ClearIFN (LocalData& parInitSDL) noexcept { if (parInitSDL.renderer) SDL_DestroyRenderer(parInitSDL.renderer); if (parInitSDL.window) SDL_DestroyWindow(parInitSDL.window); if (parInitSDL.initialized) { parInitSDL.initialized = false; SDL_Quit(); } #if defined(RASPBERRY_PI) if (parInitSDL.bcmInitialized) { parInitSDL.bcmInitialized = false; bcm_host_deinit(); } #endif } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ SDL_Renderer* SDLMain::GetRenderer() { if (m_localData->initialized) return m_localData->renderer; else return nullptr; } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ void SDLMain::SetResolution (ushort2 parRes) { m_localData->sizeratio.UpdateResolution(static_cast(parRes)); { SDL_Renderer* const renderer = GetRenderer(); assert(renderer); const int retVal = SDL_RenderSetLogicalSize(renderer, parRes.x(), parRes.y()); if (retVal) { std::ostringstream oss; oss << "Error setting logical size to renderer to " << parRes.x() << "x" << parRes.y() << ": " << SDL_GetError(); throw std::runtime_error(oss.str()); } const SDL_Rect area = { 0, 0, parRes.x(), parRes.y() }; const int retValViewport = SDL_RenderSetViewport(renderer, &area); if (retValViewport) { std::ostringstream oss; oss << "Error setting viewport to renderer to " << parRes.x() << "x" << parRes.y() << ": " << SDL_GetError(); throw std::runtime_error(oss.str()); } } for (auto currNotifiable : m_localData->resChangeNotifList) { currNotifiable->NotifyResChanged(m_localData->sizeratio); } } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ size_t SDLMain::RegisterForResChange (SizeNotifiableBase* parNotif) { parNotif->NotifyResChanged(m_localData->sizeratio); return m_localData->resChangeNotifList.Add(parNotif); } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ void SDLMain::UnregisterForResChange (size_t parID) noexcept { m_localData->resChangeNotifList.Remove(parID); } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ void SDLMain::SwapRegisteredForResChange (size_t parID, SizeNotifiableBase* parNotif) { m_localData->resChangeNotifList.Update(parID, parNotif); } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ ushort2 SDLMain::WidthHeight() const noexcept { return static_cast(m_localData->sizeratio.Resolution()); } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ std::string SDLMain::GetVideoDriverName() const { return std::string(SDL_GetCurrentVideoDriver()); } } //namespace cloonel