diff --git a/deps/glutils/include/glutils/glutils.hpp b/deps/glutils/include/glutils/glutils.hpp index 037c6b4e..bbeac254 100644 --- a/deps/glutils/include/glutils/glutils.hpp +++ b/deps/glutils/include/glutils/glutils.hpp @@ -150,8 +150,39 @@ class FrameBufferBind { void bind(const FrameBuffer &fb) noexcept; +struct ShaderVarSet { + GLsizei len{}; + ox::String name; +}; -ox::Result buildShaderProgram(ox::CStringView const&vert, ox::CStringView const&frag, ox::CStringView const&geo = "") noexcept; +struct ProgramSource { + ox::Vector const shaderParams; + GLsizei const rowLen = [this] { + GLsizei len{}; + for (auto const&v : shaderParams) { + len += v.len; + } + return len; + }(); + GLsizei const vboLen = rowLen * 4; + ox::String const vertShader{}; + ox::String const fragShader{}; + ox::String const geomShader{}; +}; + +ox::Result buildShaderProgram(ProgramSource const&src) noexcept; + +ox::Result buildShaderProgram( + ox::CStringView const&vert, + ox::CStringView const&frag, + ox::CStringView const&geo = "") noexcept; + +void setupShaderParams( + GLProgram const&shader, + ox::Vector const&vars, + GLsizei vertexRowLen) noexcept; + +void setupShaderParams(GLProgram const&shader, ox::Vector const&vars) noexcept; glutils::GLVertexArray generateVertexArrayObject() noexcept; @@ -160,6 +191,8 @@ glutils::GLBuffer generateBuffer() noexcept; [[nodiscard]] FrameBuffer generateFrameBuffer(int width, int height) noexcept; +void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept; + /** * Resizes a FrameBuffer, and creates if it does not already exist. */ diff --git a/deps/glutils/src/glutils.cpp b/deps/glutils/src/glutils.cpp index bd1ca0c8..f1eaf0cf 100644 --- a/deps/glutils/src/glutils.cpp +++ b/deps/glutils/src/glutils.cpp @@ -88,6 +88,40 @@ static ox::Result buildShader( return shader; } +ox::Result buildShaderProgram(ProgramSource const&src) noexcept { + oxRequireM(program, buildShaderProgram( + src.vertShader, + src.fragShader, + src.geomShader)); + setupShaderParams(program, src.shaderParams, src.rowLen); + return std::move(program); +} + +void setupShaderParams( + GLProgram const&shader, + ox::Vector const&vars, + GLsizei vertexRowLen) noexcept { + // setup vars + for (auto lenWritten = 0LU; auto const&v : vars) { + auto const attr = static_cast(glGetAttribLocation(shader, v.name.c_str())); + glEnableVertexAttribArray(attr); + glVertexAttribPointer( + attr, v.len, GL_FLOAT, GL_FALSE, + vertexRowLen * static_cast(sizeof(float)), + std::bit_cast(uintptr_t{lenWritten * sizeof(float)})); + lenWritten += static_cast(v.len); + } +} + +void setupShaderParams(GLProgram const&shader, ox::Vector const&vars) noexcept { + // get row len + GLsizei vertexRowLen{}; + for (auto const&v : vars) { + vertexRowLen += v.len; + } + setupShaderParams(shader, vars, vertexRowLen); +} + ox::Result buildShaderProgram( ox::CStringView const&vert, ox::CStringView const&frag, @@ -147,11 +181,7 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept { return fb; } -void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept { - if (!fb) { - fb = generateFrameBuffer(width, height); - return; - } +void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept { width = ox::max(1, width); height = ox::max(1, height); fb.width = width; @@ -171,6 +201,14 @@ void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept { glBindRenderbuffer(GL_RENDERBUFFER, 0); } +void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept { + if (!fb) { + fb = generateFrameBuffer(width, height); + return; + } + resizeFrameBuffer(fb, width, height); +} + void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept { resizeInitFrameBuffer(fb, sz.width, sz.height); } diff --git a/deps/ox/src/ox/model/modelvalue.hpp b/deps/ox/src/ox/model/modelvalue.hpp index 8f3ec13c..82892714 100644 --- a/deps/ox/src/ox/model/modelvalue.hpp +++ b/deps/ox/src/ox/model/modelvalue.hpp @@ -334,7 +334,12 @@ consteval bool isVector(const ModelValueVector*) noexcept { return true; } +constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept; +constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept; + + class ModelObject { + friend constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept; public: struct Field { String name; @@ -517,7 +522,7 @@ class ModelUnion { String name; ModelValue value; }; - oxModelFriend(ModelUnion); + friend constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept; friend ModelValue; Vector> m_fieldsOrder; HashMap m_fields; diff --git a/src/nostalgia/modules/core/include/nostalgia/core/tilesheet.hpp b/src/nostalgia/modules/core/include/nostalgia/core/tilesheet.hpp index bad7451c..06beb9c5 100644 --- a/src/nostalgia/modules/core/include/nostalgia/core/tilesheet.hpp +++ b/src/nostalgia/modules/core/include/nostalgia/core/tilesheet.hpp @@ -158,6 +158,12 @@ struct TileSheet { [[nodiscard]] std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept; +[[nodiscard]] +TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId const id) noexcept; + +[[nodiscard]] +size_t getTileIdx(TileSheet const&ts, SubSheetId id) noexcept; + [[nodiscard]] uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept; diff --git a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheetpixels.cpp b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheetpixels.cpp index db62fb73..1185f2f0 100644 --- a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheetpixels.cpp +++ b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheetpixels.cpp @@ -9,6 +9,37 @@ namespace nostalgia::core { +const glutils::ProgramSource TileSheetPixels::s_programSrc = { + .shaderParams = { + { + .len = 2, + .name = ox::String("vPosition"), + }, + { + .len = 3, + .name = ox::String("vColor"), + }, + }, + .vertShader = ox::sfmt(R"( + {} + in vec2 vPosition; + in vec3 vColor; + out vec3 fColor; + uniform vec2 vScroll; + void main() { + gl_Position = vec4(vPosition + vScroll, 0.0, 1.0); + fColor = vColor; + })", core::gl::GlslVersion), + .fragShader = ox::sfmt(R"( + {} + in vec3 fColor; + out vec4 outColor; + void main() { + //outColor = vec4(0.0, 0.7, 1.0, 1.0); + outColor = vec4(fColor, 1.0); + })", core::gl::GlslVersion), +}; + TileSheetPixels::TileSheetPixels(TileSheetEditorModel &model) noexcept: m_model(model) { } @@ -17,9 +48,7 @@ void TileSheetPixels::setPixelSizeMod(float sm) noexcept { } ox::Error TileSheetPixels::buildShader() noexcept { - auto const Vshad = ox::sfmt(VShad, gl::GlslVersion); - auto const Fshad = ox::sfmt(FShad, gl::GlslVersion); - return glutils::buildShaderProgram(Vshad, Fshad).moveTo(m_shader); + return glutils::buildShaderProgram(s_programSrc).moveTo(m_shader); } void TileSheetPixels::draw(bool update, ox::Vec2 const&scroll) noexcept { @@ -40,14 +69,7 @@ void TileSheetPixels::initBufferSet(ox::Vec2 const&paneSize) noexcept { m_bufferSet.vbo = glutils::generateBuffer(); m_bufferSet.ebo = glutils::generateBuffer(); update(paneSize); - // vbo layout - auto const posAttr = static_cast(glGetAttribLocation(m_shader, "vPosition")); - glEnableVertexAttribArray(posAttr); - glVertexAttribPointer(posAttr, 2, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float), nullptr); - auto const colorAttr = static_cast(glGetAttribLocation(m_shader, "vColor")); - glEnableVertexAttribArray(colorAttr); - glVertexAttribPointer(colorAttr, 3, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float), - std::bit_cast(uintptr_t{2 * sizeof(float)})); + glutils::setupShaderParams(m_shader, s_programSrc.shaderParams); } void TileSheetPixels::update(ox::Vec2 const&paneSize) noexcept { @@ -78,14 +100,14 @@ void TileSheetPixels::setPixelBufferObject( y += 1.0f - ymod; auto const r = redf(color), g = greenf(color), b = bluef(color); // don't worry, these memcpys gets optimized to something much more ideal - ox::Array const vertices = { + std::array const vertices = { 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.data(), sizeof(vertices)); - ox::Array const elms = { + std::array const elms = { vertexRow + 0, vertexRow + 1, vertexRow + 2, vertexRow + 2, vertexRow + 3, vertexRow + 0, }; @@ -99,7 +121,8 @@ void TileSheetPixels::setBufferObjects(ox::Vec2 const&paneSize) noexcept { auto const width = subSheet.columns * TileWidth; auto const height = subSheet.rows * TileHeight; auto const pixels = static_cast(width) * static_cast(height); - m_bufferSet.vertices.resize(pixels * VertexVboLength); + auto const vboLen = static_cast(s_programSrc.vboLen); + m_bufferSet.vertices.resize(pixels * vboLen); m_bufferSet.elements.resize(pixels * VertexEboLength); // set pixels walkPixels(subSheet, m_model.img().bpp, [&](std::size_t i, uint8_t p) { @@ -107,9 +130,9 @@ void TileSheetPixels::setBufferObjects(ox::Vec2 const&paneSize) noexcept { auto const pt = idxToPt(static_cast(i), subSheet.columns); auto const fx = static_cast(pt.x); auto const fy = static_cast(pt.y); - auto const vbo = &m_bufferSet.vertices[i * VertexVboLength]; + auto const vbo = &m_bufferSet.vertices[i * vboLen]; auto const ebo = &m_bufferSet.elements[i * VertexEboLength]; - if (i * VertexVboLength + VertexVboLength > m_bufferSet.vertices.size()) { + if (i * vboLen + vboLen > m_bufferSet.vertices.size()) { return; } if (i * VertexEboLength + VertexEboLength > m_bufferSet.elements.size()) { diff --git a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheetpixels.hpp b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheetpixels.hpp index 89c73d43..f8bc34fd 100644 --- a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheetpixels.hpp +++ b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheetpixels.hpp @@ -18,28 +18,9 @@ class TileSheetPixels { private: static constexpr auto VertexVboRows = 4; - static constexpr auto VertexVboRowLength = 5; - static constexpr auto VertexVboLength = VertexVboRows * VertexVboRowLength; static constexpr auto VertexEboLength = 6; - static constexpr auto VShad = R"( - {} - in vec2 vPosition; - in vec3 vColor; - out vec3 fColor; - uniform vec2 vScroll; - void main() { - gl_Position = vec4(vPosition + vScroll, 0.0, 1.0); - fColor = vColor; - })"; - static constexpr auto FShad = R"( - {} - in vec3 fColor; - out vec4 outColor; - void main() { - //outColor = vec4(0.0, 0.7, 1.0, 1.0); - outColor = vec4(fColor, 1.0); - })"; + static const glutils::ProgramSource s_programSrc; float m_pixelSizeMod = 1; glutils::GLProgram m_shader; glutils::BufferSet m_bufferSet; diff --git a/src/nostalgia/modules/core/src/tilesheet.cpp b/src/nostalgia/modules/core/src/tilesheet.cpp index 21edc35a..67b2c2e0 100644 --- a/src/nostalgia/modules/core/src/tilesheet.cpp +++ b/src/nostalgia/modules/core/src/tilesheet.cpp @@ -14,6 +14,44 @@ std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept { return ptToIdx(pt, ss.columns); } +static TileSheet::SubSheet const*getSubsheet(TileSheet::SubSheet const&ss, SubSheetId const id) noexcept { + if (ss.id == id) { + return &ss; + } + for (auto const&child : ss.subsheets) { + if (auto out = getSubsheet(child, id)) { + return out; + } + } + return {}; +} + +TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId const id) noexcept { + return getSubsheet(ts.subsheet, id); +} + +static ox::Optional getPixelIdx( + TileSheet::SubSheet const&ss, + SubSheetId const id, + size_t idx, + int8_t const bpp) noexcept { + for (auto const&child : ss.subsheets) { + if (child.id == id) { + return ox::Optional(ox::in_place, idx); + } + if (auto out = getPixelIdx(child, id, idx, bpp)) { + return out; + } + idx += pixelCnt(ss, bpp); + } + return {}; +} + +size_t getTileIdx(TileSheet const&ts, SubSheetId const id) noexcept { + auto const out = getPixelIdx(ts.subsheet, id, 0, ts.bpp); + return out.or_value(0) / PixelsPerTile; +} + uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept { if (idx & 1) { return ss.pixels[idx / 2] >> 4; diff --git a/src/olympic/studio/modlib/include/studio/imguiutil.hpp b/src/olympic/studio/modlib/include/studio/imguiutil.hpp index dc71cbcb..9f4aea25 100644 --- a/src/olympic/studio/modlib/include/studio/imguiutil.hpp +++ b/src/olympic/studio/modlib/include/studio/imguiutil.hpp @@ -20,6 +20,14 @@ class IDStackItem { ~IDStackItem() noexcept; }; +class IndentStackItem { + private: + float m_indent{}; + public: + explicit IndentStackItem(float id) noexcept; + ~IndentStackItem() noexcept; +}; + void centerNextWindow(turbine::Context &ctx) noexcept; bool PushButton(ox::CStringView lbl, ImVec2 const&btnSz = BtnSz) noexcept; diff --git a/src/olympic/studio/modlib/src/imguiutil.cpp b/src/olympic/studio/modlib/src/imguiutil.cpp index 3f7fc141..67eca2bf 100644 --- a/src/olympic/studio/modlib/src/imguiutil.cpp +++ b/src/olympic/studio/modlib/src/imguiutil.cpp @@ -24,6 +24,16 @@ IDStackItem::~IDStackItem() noexcept { ImGui::PopID(); } + +IndentStackItem::IndentStackItem(float indent) noexcept: m_indent(indent) { + ImGui::Indent(m_indent); +} + +IndentStackItem::~IndentStackItem() noexcept { + ImGui::Indent(-m_indent); +} + + void centerNextWindow(turbine::Context &ctx) noexcept { auto const sz = turbine::getScreenSize(ctx); auto const screenW = static_cast(sz.width);