#include #include #include #include "Renderer.hh" #include "GlResource.hh" #include "game/GameState.hh" #include "exceptions.hh" using namespace gl; namespace render { class GLException : public Exception { public: GLException(GLenum err) : Exception(), err_(err) { } GLenum getErr() const {return err_;} std::string errToString() const { std::string ret; if (err_ == GL_INVALID_ENUM) ret += "GL_INVALID_ENUM "; if (err_ == GL_INVALID_VALUE) ret += "GL_INVALID_VALUE "; if (err_ == GL_INVALID_OPERATION) ret += "GL_INVALID_OPERATION "; if (err_ == GL_INVALID_FRAMEBUFFER_OPERATION) ret += "GL_INVALID_FRAMEBUFFER_OPERATION "; if (err_ == GL_OUT_OF_MEMORY) ret += "GL_OUT_OF_MEMORY "; if (err_ == GL_STACK_UNDERFLOW) ret += "GL_STACK_UNDERFLOW "; if (err_ == GL_STACK_OVERFLOW) ret += "GL_STACK_OVERFLOW "; return ret; } std::string toString() const override { return "GLException: " + errToString() + "(" + std::to_string(static_cast(err_)) + ")"; } private: GLenum err_; }; void glAfterCallback(glbinding::FunctionCall const& fc) { glbinding::setCallbackMask(glbinding::CallbackMask::None); GLenum error = glGetError(); glbinding::setCallbackMask(glbinding::CallbackMask::After); if (error != GL_NO_ERROR) throw GLException(error); } Renderer::Renderer() : sdlInit_(), window_(), context_() { glbinding::Binding::initialize(); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); window_.reset(SDL_CreateWindow("WC3 RE", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_OPENGL)); if (!window_) throw SDLException{}; context_ = SDLGLContext(window_.get()); SDL_GetWindowSize(window_.get(), &width_, &height_); glbinding::setCallbackMask(glbinding::CallbackMask::After); glbinding::setAfterCallback(glAfterCallback); #ifndef NDEBUG { int depth, stencil, aa, major, minor; SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depth); SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil); SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &aa); SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); printf("Depth: %d, Stencil: %d, AA: %d, GL %d.%d\n", depth, stencil, aa, major, minor); } #endif glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glViewport(0, 0, width_, height_); } void Renderer::run() { bool close = false; auto last = SDL_GetTicks(); while (!close && gamestates_.size()) { SDL_Event event; while (SDL_PollEvent(&event)) { switch(event.type) { case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_q) close = true; break; case SDL_WINDOWEVENT: if (event.window.event == SDL_WINDOWEVENT_CLOSE) close = true; break; } } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); auto now = SDL_GetTicks(); gamestates_.back()->draw(now-last); SDL_GL_SwapWindow(window_.get()); last = now; } } void Renderer::pushGS(std::unique_ptr gs) { gamestates_.emplace_back(std::move(gs)); } std::unique_ptr Renderer::popGS() { auto ret = std::move(gamestates_.back()); gamestates_.pop_back(); return ret; } int Renderer::getWidth() const { return width_; } int Renderer::getHeight() const { return height_; } }