114 lines
4.2 KiB
C++
114 lines
4.2 KiB
C++
/*
|
|
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
|
*/
|
|
|
|
#include <nostalgia/core/consts.hpp>
|
|
#include <nostalgia/core/ptidxconv.hpp>
|
|
#include "tilesheetpixels.hpp"
|
|
|
|
namespace nostalgia::core {
|
|
|
|
void TileSheetPixels::setPixelSizeMod(float sm) noexcept {
|
|
m_pixelSizeMod = sm;
|
|
}
|
|
|
|
ox::Error TileSheetPixels::buildShader() noexcept {
|
|
const auto Vshad = ox::sfmt(VShad, glutils::GlslVersion);
|
|
const auto Fshad = ox::sfmt(FShad, glutils::GlslVersion);
|
|
return glutils::buildShaderProgram(Vshad, Fshad).moveTo(&m_shader);
|
|
}
|
|
|
|
void TileSheetPixels::draw(bool update, const geo::Vec2 &scroll) noexcept {
|
|
glUseProgram(m_shader);
|
|
glBindVertexArray(m_bufferSet.vao);
|
|
if (update) {
|
|
glutils::sendVbo(m_bufferSet);
|
|
}
|
|
const auto uniformScroll = glGetUniformLocation(m_shader, "vScroll");
|
|
glUniform2f(uniformScroll, scroll.x, scroll.y);
|
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_bufferSet.elements.size()), GL_UNSIGNED_INT, nullptr);
|
|
}
|
|
|
|
void TileSheetPixels::initBufferSet(const geo::Vec2 &paneSize, const TileSheet &img, const Palette &pal) noexcept {
|
|
// vao
|
|
m_bufferSet.vao = glutils::generateVertexArrayObject();
|
|
glBindVertexArray(m_bufferSet.vao);
|
|
// vbo & ebo
|
|
m_bufferSet.vbo = glutils::generateBuffer();
|
|
m_bufferSet.ebo = glutils::generateBuffer();
|
|
setBufferObjects(paneSize, img, pal, &m_bufferSet);
|
|
glutils::sendVbo(m_bufferSet);
|
|
glutils::sendEbo(m_bufferSet);
|
|
// vbo layout
|
|
const auto posAttr = static_cast<GLuint>(glGetAttribLocation(m_shader, "vPosition"));
|
|
glEnableVertexAttribArray(posAttr);
|
|
glVertexAttribPointer(posAttr, 2, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float), nullptr);
|
|
const auto colorAttr = static_cast<GLuint>(glGetAttribLocation(m_shader, "vColor"));
|
|
glEnableVertexAttribArray(colorAttr);
|
|
glVertexAttribPointer(colorAttr, 3, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float),
|
|
reinterpret_cast<void*>(2 * sizeof(float)));
|
|
}
|
|
|
|
geo::Vec2 TileSheetPixels::pixelSize(const geo::Vec2 &paneSize) const noexcept {
|
|
const auto [sw, sh] = paneSize;
|
|
constexpr float ymod = 0.35f / 10.0f;
|
|
const auto xmod = ymod * sh / sw;
|
|
return {xmod * m_pixelSizeMod, ymod * m_pixelSizeMod};
|
|
}
|
|
|
|
void TileSheetPixels::setPixelBufferObject(const geo::Vec2 &paneSize, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) const noexcept {
|
|
const auto [xmod, ymod] = pixelSize(paneSize);
|
|
x *= xmod;
|
|
y *= -ymod;
|
|
x -= 1.0f;
|
|
y += 1.0f - ymod;
|
|
const auto r = redf(color), g = greenf(color), b = bluef(color);
|
|
// don't worry, these memcpys gets optimized to something much more ideal
|
|
const float vertices[VertexVboLength] = {
|
|
x, y, r, g, b, // bottom left
|
|
x + xmod, y, r, g, b, // bottom right
|
|
x + xmod, y + ymod, r, g, b, // top right
|
|
x, y + ymod, r, g, b, // top left
|
|
};
|
|
memcpy(vbo, vertices, sizeof(vertices));
|
|
const GLuint elms[VertexEboLength] = {
|
|
vertexRow + 0, vertexRow + 1, vertexRow + 2,
|
|
vertexRow + 2, vertexRow + 3, vertexRow + 0,
|
|
};
|
|
memcpy(ebo, elms, sizeof(elms));
|
|
}
|
|
|
|
void TileSheetPixels::setBufferObjects(const geo::Vec2 &paneSize, const TileSheet &img, const Palette &pal, glutils::BufferSet *bg) noexcept {
|
|
const auto setPixel = [this, paneSize, bg, img, pal](std::size_t i, uint8_t p) {
|
|
const auto color = pal.colors[p];
|
|
const auto pt = idxToPt(static_cast<int>(i), img.columns);
|
|
const auto fx = static_cast<float>(pt.x);
|
|
const auto fy = static_cast<float>(pt.y);
|
|
const auto vbo = &bg->vertices[i * VertexVboLength];
|
|
const auto ebo = &bg->elements[i * VertexEboLength];
|
|
setPixelBufferObject(paneSize, i * VertexVboRows, fx, fy, color, vbo, ebo);
|
|
};
|
|
// set buffer lengths
|
|
const auto width = img.columns * TileWidth;
|
|
const auto height = img.rows * TileHeight;
|
|
const auto tiles = static_cast<unsigned>(width * height);
|
|
m_bufferSet.vertices.resize(tiles * VertexVboLength);
|
|
m_bufferSet.elements.resize(tiles * VertexEboLength);
|
|
// set pixels
|
|
if (img.bpp == 4) {
|
|
for (std::size_t i = 0; i < img.pixels.size(); ++i) {
|
|
const auto colorIdx1 = img.pixels[i] & 0xF;
|
|
const auto colorIdx2 = img.pixels[i] >> 4;
|
|
setPixel(i * 2 + 0, colorIdx1);
|
|
setPixel(i * 2 + 1, colorIdx2);
|
|
}
|
|
} else {
|
|
for (std::size_t i = 0; i < img.pixels.size(); ++i) {
|
|
const auto p = img.pixels[i];
|
|
setPixel(i, p);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|