[nostalgia/core/studio] Add pixel outline to tile sheet editor

This commit is contained in:
Gary Talent 2022-01-29 21:53:48 -06:00
parent 99550b60ee
commit f6be36741c
4 changed files with 81 additions and 61 deletions

View File

@ -86,6 +86,16 @@ constexpr uint8_t blue32(Color32 c) noexcept {
return (c & 0x00ff0000) >> 16;
}
[[nodiscard]]
constexpr Color32 color32(uint8_t r, uint8_t g, uint8_t b) noexcept {
return static_cast<Color32>(r | (g << 8) | (b << 16));
}
[[nodiscard]]
constexpr Color32 color32(float r, float g, float b) noexcept {
return static_cast<Color32>(static_cast<uint8_t>(r * 255) | (static_cast<uint8_t>(g * 255) << 8) | (static_cast<uint8_t>(b * 255) << 16));
}
[[nodiscard]]
constexpr float redf(Color16 c) noexcept {

View File

@ -4,6 +4,8 @@
#pragma once
#include <ox/model/def.hpp>
#include <nostalgia/common/bounds.hpp>
#include <nostalgia/core/gfx.hpp>
#include <nostalgia/glutils/glutils.hpp>
@ -20,7 +22,7 @@ enum class CommandId {
ModPixel = 2,
UpdateDimension = 3,
InsertTile = 4,
ClipboardPaste = 4,
ClipboardPaste = 5,
};
enum class TileSheetTool: int {
@ -49,20 +51,16 @@ struct PixelChunk {
int size = 0;
};
template<typename T>
constexpr ox::Error model(T *io, PixelChunk *c) noexcept {
io->template setTypeInfo<PixelChunk>();
oxReturnError(io->field("pt", &c->pt));
oxReturnError(io->field("size", &c->size));
return OxError(0);
}
oxModelBegin(PixelChunk)
oxModelField(pt)
oxModelField(size)
oxModelEnd()
struct TileSheetClipboard {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
static constexpr auto TypeVersion = 1;
template<typename T>
friend ox::Error model(T*, TileSheetClipboard*);
oxModelFriend(TileSheetClipboard);
protected:
ox::Vector<int> m_pixels;

View File

@ -15,24 +15,23 @@ ox::Error TileSheetGrid::buildShader() noexcept {
}
void TileSheetGrid::draw(bool update) noexcept {
glLineWidth(3);
glUseProgram(m_shader);
glBindVertexArray(m_bufferSet.vao);
if (update) {
glutils::sendVbo(m_bufferSet);
}
glDrawElements(GL_POINTS, static_cast<GLsizei>(m_bufferSet.elements.size()), GL_UNSIGNED_INT, nullptr);
glDrawArrays(GL_POINTS, 0, m_bufferSet.vertices.size() / VertexVboRowLength);
}
void TileSheetGrid::initBufferSet(const NostalgiaGraphic &img) noexcept {
// vao
m_bufferSet.vao = glutils::generateVertexArrayObject();
glBindVertexArray(m_bufferSet.vao);
// vbo & ebo
// vbo
m_bufferSet.vbo = glutils::generateBuffer();
m_bufferSet.ebo = glutils::generateBuffer();
setBufferObjects(img, &m_bufferSet);
glutils::sendVbo(m_bufferSet);
glutils::sendEbo(m_bufferSet);
// vbo layout
const auto pt1Attr = static_cast<GLuint>(glGetAttribLocation(m_shader, "vPt1"));
glEnableVertexAttribArray(pt1Attr);
@ -41,41 +40,54 @@ void TileSheetGrid::initBufferSet(const NostalgiaGraphic &img) noexcept {
glEnableVertexAttribArray(pt2Attr);
glVertexAttribPointer(pt2Attr, 2, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(float)));
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*>(4 * sizeof(float)));
}
void TileSheetGrid::setBufferObject(unsigned vertexRow, common::Point pt1, common::Point pt2, float *vbo, GLuint *ebo) noexcept {
const auto ps = pixelSize();
const auto x1 = static_cast<float>(pt1.x) * ps.x;
const auto y1 = static_cast<float>(pt1.y) * ps.y;
const auto x2 = static_cast<float>(pt2.x) * ps.x;
const auto y2 = static_cast<float>(pt2.y) * ps.y;
// don't worry, these memcpys gets optimized to something much more ideal
const float vertices[VertexVboLength] = {x1, y1, x2, y2};
void TileSheetGrid::setBufferObject(common::Point pt1, common::Point pt2, Color32 c, float *vbo, const ImVec2 &pixSize) noexcept {
const auto x1 = static_cast<float>(pt1.x) * pixSize.x - 1.f;
const auto y1 = 1.f - static_cast<float>(pt1.y) * pixSize.y;
const auto x2 = static_cast<float>(pt2.x) * pixSize.x - 1.f;
const auto y2 = 1.f - static_cast<float>(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));
const GLuint elms[VertexEboLength] = {vertexRow};
memcpy(ebo, elms, sizeof(elms));
}
void TileSheetGrid::setBufferObjects(const NostalgiaGraphic &img, glutils::BufferSet *bg) noexcept {
const auto set = [bg](unsigned i, common::Point pt1, common::Point pt2) {
const auto pixSize = pixelSize();
const auto set = [bg, pixSize](unsigned i, common::Point pt1, common::Point pt2, Color32 c) {
const auto vbo = &bg->vertices[i * VertexVboLength];
const auto ebo = &bg->elements[i * VertexEboLength];
setBufferObject(i * VertexVboRows, pt1, pt2, vbo, ebo);
setBufferObject(pt1, pt2, c, vbo, pixSize);
};
// set buffer lengths
// set buffer length
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 buffers
const auto pixelCnt = static_cast<unsigned>(width * height);
const auto tileCnt = static_cast<unsigned>(img.columns * img.rows);
m_bufferSet.vertices.resize((tileCnt + pixelCnt) * VertexVboLength);
// set buffer
auto i = 0ull;
for (auto x = 0; x < img.columns; ++x) {
set(0, {x, 0}, {x, img.rows});
// 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; ++y) {
set(0, {0, y}, {img.columns, y});
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;
}
}

View File

@ -17,45 +17,45 @@ class TileSheetGrid {
private:
static constexpr auto VertexVboRows = 1;
static constexpr auto VertexVboRowLength = 4;
static constexpr auto VertexVboRowLength = 7;
static constexpr auto VertexVboLength = VertexVboRows * VertexVboRowLength;
static constexpr auto VertexEboLength = 1;
static constexpr auto VShad = R"(
static constexpr auto VShad = R"glsl(
{}
in vec2 vPt1;
in vec2 vPt2;
out VS_OUT {
vec2 pt1;
vec2 pt2;
} vs_out;
in vec3 vColor;
out vec2 gPt2;
out vec3 gColor;
void main() {
vs_out.pt1 = vPt1;
vs_out.pt2 = vPt2;
gColor = vColor;
gl_Position = vec4(vPt1, 0.0, 1.0);
})";
gPt2 = vPt2;
})glsl";
static constexpr auto FShad = R"(
static constexpr auto FShad = R"glsl(
{}
in vec3 fColor;
out vec4 outColor;
void main() {
outColor = vec4(0.4431, 0.4901, 0.4941, 1.0);
})";
outColor = vec4(fColor, 1);
//outColor = vec4(0.4431, 0.4901, 0.4941, 1.0);
})glsl";
static constexpr auto GShad = R"glsl(
{}
in VS_OUT {
vec2 pt1;
vec2 pt2;
} gs_in[];
layout(line_strip, max_vertices = 2) out;
layout(points) in;
layout(line_strip, max_vertices = 9) out;
in vec3 gColor[];
in vec2 gPt2[];
out vec3 fColor;
void main() {
//gl_Position = vec4(gs_in[0].pt1, 0, 0);
//EmitVertex();
//gl_Position = vec4(gs_in[0].pt2, 0, 0);
//EmitVertex();
//EndPrimitive();
fColor = gColor[0];
gl_Position = gl_in[0].gl_Position;
EmitVertex();
gl_Position = vec4(gPt2[0], 0, 1);
EmitVertex();
EndPrimitive();
})glsl";
glutils::GLProgram m_shader;
@ -69,7 +69,7 @@ class TileSheetGrid {
void initBufferSet(const NostalgiaGraphic &img) noexcept;
private:
static void setBufferObject(unsigned vertexRow, common::Point pt1, common::Point pt2, float *vbo, GLuint *ebo) noexcept;
static void setBufferObject(common::Point pt1, common::Point pt2, Color32 c, float *vbo, const ImVec2 &pixSize) noexcept;
void setBufferObjects(const NostalgiaGraphic &img, glutils::BufferSet *bg) noexcept;