Files
wc3re/render/Renderer.cc

153 lines
3.7 KiB
C++

#include <glbinding/gl/gl.h>
#include <glbinding/Binding.h>
#include <glbinding/callbacks.h>
#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<int>(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<game::GameState> gs)
{
gamestates_.emplace_back(std::move(gs));
}
std::unique_ptr<game::GameState> 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_;
}
}