206 lines
4.8 KiB
C++
206 lines
4.8 KiB
C++
#include <glbinding/gl/gl.h>
|
|
#include <glbinding/Binding.h>
|
|
#include <glbinding/callbacks.h>
|
|
#include <glbinding/Meta.h>
|
|
|
|
#include "Renderer.hh"
|
|
#include "GlResource.hh"
|
|
#include "game/GameState.hh"
|
|
#include "exceptions.hh"
|
|
#include "Overlay.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_(), ttfInit_(), window_(), context_()
|
|
{
|
|
glbinding::Binding::initialize();
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
|
|
|
|
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 major, minor;
|
|
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
|
|
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
|
|
|
|
printf("GL %d.%d\n",
|
|
major, minor);
|
|
}
|
|
#endif
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
glViewport(0, 0, width_, height_);
|
|
|
|
fpsFont_.reset(TTF_OpenFont("DejaVuSans.ttf", 10));
|
|
if (!fpsFont_)
|
|
throw TTFException{};
|
|
|
|
SDL_Color white;
|
|
white.r = 255;
|
|
white.g = 255;
|
|
white.b = 255;
|
|
white.a = 255;
|
|
SDLSurfaceUPtr fpsSurf(TTF_RenderUTF8_Blended(fpsFont_.get(), "0 FPS", white));
|
|
if (!fpsSurf)
|
|
throw TTFException{};
|
|
|
|
fpsOverlay_ = std::make_unique<Overlay>(*this, fpsSurf->w*2, fpsSurf->h, 0, 0, fpsSurf->w*2, fpsSurf->h);
|
|
fpsOverlay_->clear();
|
|
fpsOverlay_->setContent(fpsSurf.get());
|
|
}
|
|
|
|
Renderer::~Renderer()
|
|
{
|
|
}
|
|
|
|
void Renderer::run()
|
|
{
|
|
bool close = false;
|
|
|
|
auto last = SDL_GetTicks();
|
|
unsigned fpsTime = 0, fpsCount = 0, lastFps = 0;
|
|
|
|
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;
|
|
continue;
|
|
}
|
|
break;
|
|
case SDL_WINDOWEVENT:
|
|
if (event.window.event == SDL_WINDOWEVENT_CLOSE) {
|
|
close = true;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (gamestates_.back()->handleEvent(event))
|
|
continue;
|
|
break;
|
|
}
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
auto now = SDL_GetTicks();
|
|
auto delta = now-last;
|
|
|
|
gamestates_.back()->draw(delta);
|
|
|
|
if (fpsTime+delta > 1000) {
|
|
if (fpsCount+1 != lastFps) {
|
|
std::string fpsText{std::to_string(fpsCount+1) + " FPS"};
|
|
SDLSurfaceUPtr fpsSurf(TTF_RenderUTF8_Blended(fpsFont_.get(), fpsText.c_str(),
|
|
SDL_Color({255, 255, 255, 255})));
|
|
if (!fpsSurf)
|
|
throw TTFException{};
|
|
fpsOverlay_->clear();
|
|
fpsOverlay_->setContent(fpsSurf.get());
|
|
lastFps = fpsCount+1;
|
|
}
|
|
fpsCount = 0;
|
|
fpsTime = 0;
|
|
} else {
|
|
++fpsCount;
|
|
fpsTime += delta;
|
|
}
|
|
|
|
fpsOverlay_->draw();
|
|
|
|
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_;
|
|
}
|
|
}
|