Files
wc3re/render/Overlay.cc

98 lines
3.3 KiB
C++

#include <glbinding/gl/gl.h>
#include <SDL2/SDL.h>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "Overlay.hh"
#include "renderutil.hh"
#include "VBOManager.hh"
#include "ProgramProvider.hh"
#include "Renderer.hh"
using namespace gl;
namespace render {
namespace {
struct VertexAttribs {
int16_t vertex[2];
uint16_t texCoords[2];
} __attribute__((__packed__));
}
Overlay::Overlay(Renderer& renderer, int width, int height, int left, int top, int intWidth, int intHeight)
: Drawable(renderer), texture_(create2DTexture(intWidth, intHeight, false, 1)),
vbo_(VBOManager::getInstance().alloc(sizeof(VertexAttribs)*6)),
width_(width), height_(height), top_(top), left_(left), intWidth_(intWidth), intHeight_(intHeight)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, static_cast<int>(GL_LINEAR));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<int>(GL_CLAMP_TO_EDGE));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<int>(GL_CLAMP_TO_EDGE));
program_ = ProgramProvider::getInstance().getProgram("overlay", "overlay");
glGenVertexArrays(1, &vertexArray_.get());
short int t = top_, l = left_, b = height+top_, r = width+left_;
std::vector<VertexAttribs> vertexAttribs{
{{l, t}, {0, 0}},
{{r, b}, {65535u, 65535u}},
{{r, t}, {65535u, 0}},
{{l, t}, {0, 0}},
{{l, b}, {0, 65535u}},
{{r, b}, {65535u, 65535u}}};
glBindBuffer(GL_ARRAY_BUFFER, vbo_.getVBOId());
glBindVertexArray(vertexArray_);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, sizeof(VertexAttribs),
vbo_.getOfs(offsetof(VertexAttribs, vertex)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(VertexAttribs),
vbo_.getOfs(offsetof(VertexAttribs, texCoords)));
glBufferSubData(GL_ARRAY_BUFFER, vbo_.getBase(),
sizeof(VertexAttribs)*6,
vertexAttribs.data());
ovlProj_ = glm::ortho(0.0f, static_cast<float>(renderer_.getWidth()),
static_cast<float>(renderer_.getHeight()), 0.0f);
}
void Overlay::draw()
{
glDisable(GL_DEPTH_TEST);
useProgram(program_);
glUniformMatrix4fv(0, 1, GL_FALSE, glm::value_ptr(ovlProj_));
glUniform1i(1, 0);
glBindTexture(GL_TEXTURE_2D, texture_);
glBindVertexArray(vertexArray_);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void Overlay::setContent(SDL_Surface *content)
{
if (!content ||
(content->h != intHeight_) ||
(content->w != intWidth_))
throw Exception{"null or mismatched surface"};
glBindTexture(GL_TEXTURE_2D, texture_);
if (content->format->format != SDL_PIXELFORMAT_RGB24) {
SDLSurfaceUPtr tmpSurf(SDL_ConvertSurfaceFormat(content, SDL_PIXELFORMAT_RGB24, 0));
if (!tmpSurf)
throw SDLException{};
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tmpSurf->w, tmpSurf->h, GL_RGB, GL_UNSIGNED_BYTE, tmpSurf->pixels);
} else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, content->w, content->h, GL_RGB, GL_UNSIGNED_BYTE, content->pixels);
}
void Overlay::setContentRGB8(void *data)
{
glBindTexture(GL_TEXTURE_2D, texture_);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, intWidth_, intHeight_, GL_RGB, GL_UNSIGNED_BYTE, data);
}
}