[nostalgia/core/studio] Add pixel outline to tile sheet editor
This commit is contained in:
parent
99550b60ee
commit
f6be36741c
@ -86,6 +86,16 @@ constexpr uint8_t blue32(Color32 c) noexcept {
|
|||||||
return (c & 0x00ff0000) >> 16;
|
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]]
|
[[nodiscard]]
|
||||||
constexpr float redf(Color16 c) noexcept {
|
constexpr float redf(Color16 c) noexcept {
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <ox/model/def.hpp>
|
||||||
|
|
||||||
#include <nostalgia/common/bounds.hpp>
|
#include <nostalgia/common/bounds.hpp>
|
||||||
#include <nostalgia/core/gfx.hpp>
|
#include <nostalgia/core/gfx.hpp>
|
||||||
#include <nostalgia/glutils/glutils.hpp>
|
#include <nostalgia/glutils/glutils.hpp>
|
||||||
@ -20,7 +22,7 @@ enum class CommandId {
|
|||||||
ModPixel = 2,
|
ModPixel = 2,
|
||||||
UpdateDimension = 3,
|
UpdateDimension = 3,
|
||||||
InsertTile = 4,
|
InsertTile = 4,
|
||||||
ClipboardPaste = 4,
|
ClipboardPaste = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TileSheetTool: int {
|
enum class TileSheetTool: int {
|
||||||
@ -49,20 +51,16 @@ struct PixelChunk {
|
|||||||
int size = 0;
|
int size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
oxModelBegin(PixelChunk)
|
||||||
constexpr ox::Error model(T *io, PixelChunk *c) noexcept {
|
oxModelField(pt)
|
||||||
io->template setTypeInfo<PixelChunk>();
|
oxModelField(size)
|
||||||
oxReturnError(io->field("pt", &c->pt));
|
oxModelEnd()
|
||||||
oxReturnError(io->field("size", &c->size));
|
|
||||||
return OxError(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TileSheetClipboard {
|
struct TileSheetClipboard {
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
|
||||||
static constexpr auto TypeVersion = 1;
|
static constexpr auto TypeVersion = 1;
|
||||||
|
|
||||||
template<typename T>
|
oxModelFriend(TileSheetClipboard);
|
||||||
friend ox::Error model(T*, TileSheetClipboard*);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ox::Vector<int> m_pixels;
|
ox::Vector<int> m_pixels;
|
||||||
@ -158,4 +156,4 @@ class TileSheetEditor: public studio::Editor {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,24 +15,23 @@ ox::Error TileSheetGrid::buildShader() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetGrid::draw(bool update) noexcept {
|
void TileSheetGrid::draw(bool update) noexcept {
|
||||||
|
glLineWidth(3);
|
||||||
glUseProgram(m_shader);
|
glUseProgram(m_shader);
|
||||||
glBindVertexArray(m_bufferSet.vao);
|
glBindVertexArray(m_bufferSet.vao);
|
||||||
if (update) {
|
if (update) {
|
||||||
glutils::sendVbo(m_bufferSet);
|
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 {
|
void TileSheetGrid::initBufferSet(const NostalgiaGraphic &img) noexcept {
|
||||||
// vao
|
// vao
|
||||||
m_bufferSet.vao = glutils::generateVertexArrayObject();
|
m_bufferSet.vao = glutils::generateVertexArrayObject();
|
||||||
glBindVertexArray(m_bufferSet.vao);
|
glBindVertexArray(m_bufferSet.vao);
|
||||||
// vbo & ebo
|
// vbo
|
||||||
m_bufferSet.vbo = glutils::generateBuffer();
|
m_bufferSet.vbo = glutils::generateBuffer();
|
||||||
m_bufferSet.ebo = glutils::generateBuffer();
|
|
||||||
setBufferObjects(img, &m_bufferSet);
|
setBufferObjects(img, &m_bufferSet);
|
||||||
glutils::sendVbo(m_bufferSet);
|
glutils::sendVbo(m_bufferSet);
|
||||||
glutils::sendEbo(m_bufferSet);
|
|
||||||
// vbo layout
|
// vbo layout
|
||||||
const auto pt1Attr = static_cast<GLuint>(glGetAttribLocation(m_shader, "vPt1"));
|
const auto pt1Attr = static_cast<GLuint>(glGetAttribLocation(m_shader, "vPt1"));
|
||||||
glEnableVertexAttribArray(pt1Attr);
|
glEnableVertexAttribArray(pt1Attr);
|
||||||
@ -41,41 +40,54 @@ void TileSheetGrid::initBufferSet(const NostalgiaGraphic &img) noexcept {
|
|||||||
glEnableVertexAttribArray(pt2Attr);
|
glEnableVertexAttribArray(pt2Attr);
|
||||||
glVertexAttribPointer(pt2Attr, 2, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float),
|
glVertexAttribPointer(pt2Attr, 2, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float),
|
||||||
reinterpret_cast<void*>(2 * 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 {
|
void TileSheetGrid::setBufferObject(common::Point pt1, common::Point pt2, Color32 c, float *vbo, const ImVec2 &pixSize) noexcept {
|
||||||
const auto ps = pixelSize();
|
const auto x1 = static_cast<float>(pt1.x) * pixSize.x - 1.f;
|
||||||
const auto x1 = static_cast<float>(pt1.x) * ps.x;
|
const auto y1 = 1.f - static_cast<float>(pt1.y) * pixSize.y;
|
||||||
const auto y1 = static_cast<float>(pt1.y) * ps.y;
|
const auto x2 = static_cast<float>(pt2.x) * pixSize.x - 1.f;
|
||||||
const auto x2 = static_cast<float>(pt2.x) * ps.x;
|
const auto y2 = 1.f - static_cast<float>(pt2.y) * pixSize.y;
|
||||||
const auto y2 = static_cast<float>(pt2.y) * ps.y;
|
// don't worry, this memcpy gets optimized to something much more ideal
|
||||||
// don't worry, these memcpys gets optimized to something much more ideal
|
const float vertices[VertexVboLength] = {x1, y1, x2, y2, redf(c), greenf(c), bluef(c)};
|
||||||
const float vertices[VertexVboLength] = {x1, y1, x2, y2};
|
|
||||||
memcpy(vbo, vertices, sizeof(vertices));
|
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 {
|
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 vbo = &bg->vertices[i * VertexVboLength];
|
||||||
const auto ebo = &bg->elements[i * VertexEboLength];
|
setBufferObject(pt1, pt2, c, vbo, pixSize);
|
||||||
setBufferObject(i * VertexVboRows, pt1, pt2, vbo, ebo);
|
|
||||||
};
|
};
|
||||||
// set buffer lengths
|
// set buffer length
|
||||||
const auto width = img.columns * TileWidth;
|
const auto width = img.columns * TileWidth;
|
||||||
const auto height = img.rows * TileHeight;
|
const auto height = img.rows * TileHeight;
|
||||||
const auto tiles = static_cast<unsigned>(width * height);
|
const auto pixelCnt = static_cast<unsigned>(width * height);
|
||||||
m_bufferSet.vertices.resize(tiles * VertexVboLength);
|
const auto tileCnt = static_cast<unsigned>(img.columns * img.rows);
|
||||||
m_bufferSet.elements.resize(tiles * VertexEboLength);
|
m_bufferSet.vertices.resize((tileCnt + pixelCnt) * VertexVboLength);
|
||||||
// set buffers
|
// set buffer
|
||||||
auto i = 0ull;
|
auto i = 0ull;
|
||||||
for (auto x = 0; x < img.columns; ++x) {
|
// pixel outlines
|
||||||
set(0, {x, 0}, {x, img.rows});
|
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;
|
++i;
|
||||||
}
|
}
|
||||||
for (auto y = 0; y < img.rows; ++y) {
|
for (auto y = 0; y < img.rows * TileHeight + 1; ++y) {
|
||||||
set(0, {0, y}, {img.columns, 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;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,45 +17,45 @@ class TileSheetGrid {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr auto VertexVboRows = 1;
|
static constexpr auto VertexVboRows = 1;
|
||||||
static constexpr auto VertexVboRowLength = 4;
|
static constexpr auto VertexVboRowLength = 7;
|
||||||
static constexpr auto VertexVboLength = VertexVboRows * VertexVboRowLength;
|
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 vPt1;
|
||||||
in vec2 vPt2;
|
in vec2 vPt2;
|
||||||
out VS_OUT {
|
in vec3 vColor;
|
||||||
vec2 pt1;
|
out vec2 gPt2;
|
||||||
vec2 pt2;
|
out vec3 gColor;
|
||||||
} vs_out;
|
|
||||||
void main() {
|
void main() {
|
||||||
vs_out.pt1 = vPt1;
|
gColor = vColor;
|
||||||
vs_out.pt2 = vPt2;
|
|
||||||
gl_Position = vec4(vPt1, 0.0, 1.0);
|
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;
|
in vec3 fColor;
|
||||||
out vec4 outColor;
|
out vec4 outColor;
|
||||||
void main() {
|
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(
|
static constexpr auto GShad = R"glsl(
|
||||||
{}
|
{}
|
||||||
in VS_OUT {
|
layout(points) in;
|
||||||
vec2 pt1;
|
layout(line_strip, max_vertices = 9) out;
|
||||||
vec2 pt2;
|
in vec3 gColor[];
|
||||||
} gs_in[];
|
in vec2 gPt2[];
|
||||||
layout(line_strip, max_vertices = 2) out;
|
out vec3 fColor;
|
||||||
void main() {
|
void main() {
|
||||||
//gl_Position = vec4(gs_in[0].pt1, 0, 0);
|
fColor = gColor[0];
|
||||||
//EmitVertex();
|
gl_Position = gl_in[0].gl_Position;
|
||||||
//gl_Position = vec4(gs_in[0].pt2, 0, 0);
|
EmitVertex();
|
||||||
//EmitVertex();
|
gl_Position = vec4(gPt2[0], 0, 1);
|
||||||
//EndPrimitive();
|
EmitVertex();
|
||||||
|
EndPrimitive();
|
||||||
})glsl";
|
})glsl";
|
||||||
|
|
||||||
glutils::GLProgram m_shader;
|
glutils::GLProgram m_shader;
|
||||||
@ -69,7 +69,7 @@ class TileSheetGrid {
|
|||||||
void initBufferSet(const NostalgiaGraphic &img) noexcept;
|
void initBufferSet(const NostalgiaGraphic &img) noexcept;
|
||||||
|
|
||||||
private:
|
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;
|
void setBufferObjects(const NostalgiaGraphic &img, glutils::BufferSet *bg) noexcept;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user