/* * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include #include "tilesheetpixelgrid.hpp" namespace nostalgia::core { void TileSheetGrid::setPixelSizeMod(float sm) noexcept { m_pixelSizeMod = sm; } ox::Error TileSheetGrid::buildShader() noexcept { const auto pixelLineVshad = ox::sfmt(VShad, glutils::GlslVersion); const auto pixelLineFshad = ox::sfmt(FShad, glutils::GlslVersion); const auto pixelLineGshad = ox::sfmt(GShad, glutils::GlslVersion); return glutils::buildShaderProgram(pixelLineVshad, pixelLineFshad, pixelLineGshad).moveTo(&m_shader); } void TileSheetGrid::draw(bool update, const geo::Vec2 &scroll) noexcept { glLineWidth(3 * m_pixelSizeMod * 0.5f); glUseProgram(m_shader); glBindVertexArray(m_bufferSet.vao); if (update) { glutils::sendVbo(m_bufferSet); } const auto uniformScroll = glGetUniformLocation(m_shader, "gScroll"); glUniform2f(uniformScroll, scroll.x, scroll.y); glDrawArrays(GL_POINTS, 0, static_cast(m_bufferSet.vertices.size() / VertexVboRowLength)); } void TileSheetGrid::initBufferSet(const geo::Vec2 &paneSize, const TileSheet &img) noexcept { // vao m_bufferSet.vao = glutils::generateVertexArrayObject(); glBindVertexArray(m_bufferSet.vao); // vbo m_bufferSet.vbo = glutils::generateBuffer(); setBufferObjects(paneSize, img, &m_bufferSet); glutils::sendVbo(m_bufferSet); // vbo layout const auto pt1Attr = static_cast(glGetAttribLocation(m_shader, "vPt1")); glEnableVertexAttribArray(pt1Attr); glVertexAttribPointer(pt1Attr, 2, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float), nullptr); const auto pt2Attr = static_cast(glGetAttribLocation(m_shader, "vPt2")); glEnableVertexAttribArray(pt2Attr); glVertexAttribPointer(pt2Attr, 2, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float), reinterpret_cast(2 * sizeof(float))); const auto colorAttr = static_cast(glGetAttribLocation(m_shader, "vColor")); glEnableVertexAttribArray(colorAttr); glVertexAttribPointer(colorAttr, 3, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float), reinterpret_cast(4 * sizeof(float))); } void TileSheetGrid::setBufferObject(geo::Point pt1, geo::Point pt2, Color32 c, float *vbo, const geo::Vec2 &pixSize) noexcept { const auto x1 = static_cast(pt1.x) * pixSize.x - 1.f; const auto y1 = 1.f - static_cast(pt1.y) * pixSize.y; const auto x2 = static_cast(pt2.x) * pixSize.x - 1.f; const auto y2 = 1.f - static_cast(pt2.y) * pixSize.y; // don't worry, this memcpy gets optimized to something much more ideal const float vertices[VertexVboLength] = {x1, y1, x2, y2, redf(c), greenf(c), bluef(c)}; memcpy(vbo, vertices, sizeof(vertices)); } void TileSheetGrid::setBufferObjects(const geo::Vec2 &paneSize, const TileSheet &img, glutils::BufferSet *bg) noexcept { const auto pixSize = pixelSize(paneSize); const auto set = [bg, pixSize](unsigned i, geo::Point pt1, geo::Point pt2, Color32 c) { const auto vbo = &bg->vertices[i * VertexVboLength]; setBufferObject(pt1, pt2, c, vbo, pixSize); }; // set buffer length const auto width = img.columns() * TileWidth; const auto height = img.rows() * TileHeight; const auto pixelCnt = static_cast(width * height); const auto tileCnt = static_cast(img.columns() * img.rows()); m_bufferSet.vertices.resize((tileCnt + pixelCnt) * VertexVboLength); // set buffer auto i = 0ull; // pixel outlines constexpr auto pixOutlineColor = color32(0.4431f, 0.4901f, 0.4941f); for (auto x = 0; x < img.columns() * TileWidth + 1; ++x) { set(i, {x, 0}, {x, img.rows() * TileHeight}, pixOutlineColor); ++i; } for (auto y = 0; y < img.rows() * TileHeight + 1; ++y) { set(i, {0, y}, {img.columns() * TileWidth, y}, pixOutlineColor); ++i; } // tile outlines constexpr auto tileOutlineColor = color32(0.f, 0.f, 0.f); for (auto x = 0; x < img.columns() * TileWidth + 1; x += TileWidth) { set(i, {x, 0}, {x, img.rows() * TileHeight}, tileOutlineColor); ++i; } for (auto y = 0; y < img.rows() * TileHeight + 1; y += TileHeight) { set(i, {0, y}, {img.columns() * TileWidth, y}, tileOutlineColor); ++i; } } geo::Vec2 TileSheetGrid::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}; } }