Anm2Ed 2.0

This commit is contained in:
2025-11-13 21:53:32 -05:00
parent bb6b68311b
commit 51bf4c2012
5 changed files with 43 additions and 55 deletions

View File

@@ -89,11 +89,13 @@ namespace anm2ed
glBindVertexArray(0); glBindVertexArray(0);
// Framebuffer // Framebuffer(s)
glGenTextures(1, &texture);
glGenFramebuffers(1, &fbo); glGenFramebuffers(1, &fbo);
glGenRenderbuffers(1, &rbo); glGenRenderbuffers(1, &rbo);
// Framebuffer(s) Texture
glGenTextures(1, &texture);
framebuffer_set(); framebuffer_set();
} }
@@ -267,39 +269,15 @@ namespace anm2ed
void Canvas::viewport_set() const { glViewport(0, 0, size.x, size.y); } void Canvas::viewport_set() const { glViewport(0, 0, size.x, size.y); }
void Canvas::clear(const vec4& color) const void Canvas::clear(vec4 color) const
{ {
glDisable(GL_BLEND);
glClearColor(color.r, color.g, color.b, color.a); glClearColor(color.r, color.g, color.b, color.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
} }
void Canvas::bind() const void Canvas::bind() const { glBindFramebuffer(GL_FRAMEBUFFER, fbo); }
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLboolean blendEnabled = glIsEnabled(GL_BLEND); void Canvas::unbind() const { glBindFramebuffer(GL_FRAMEBUFFER, 0); }
if (!blendEnabled) glEnable(GL_BLEND);
glGetIntegerv(GL_BLEND_SRC_RGB, &previousSrcRGB);
glGetIntegerv(GL_BLEND_DST_RGB, &previousDstRGB);
glGetIntegerv(GL_BLEND_SRC_ALPHA, &previousSrcAlpha);
glGetIntegerv(GL_BLEND_DST_ALPHA, &previousDstAlpha);
previousBlendStored = true;
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
void Canvas::unbind() const
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (previousBlendStored)
{
glBlendFuncSeparate(previousSrcRGB, previousDstRGB, previousSrcAlpha, previousDstAlpha);
previousBlendStored = false;
}
}
std::vector<unsigned char> Canvas::pixels_get() const std::vector<unsigned char> Canvas::pixels_get() const
{ {
@@ -332,10 +310,8 @@ namespace anm2ed
{ {
uint8_t rgba[4]{}; uint8_t rgba[4]{};
glBindTexture(GL_READ_FRAMEBUFFER, fbo);
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(position.x, framebufferSize.y - 1 - position.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgba); glReadPixels(position.x, framebufferSize.y - 1 - position.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
return vec4(math::uint8_to_float(rgba[0]), math::uint8_to_float(rgba[1]), math::uint8_to_float(rgba[2]), return vec4(math::uint8_to_float(rgba[0]), math::uint8_to_float(rgba[1]), math::uint8_to_float(rgba[2]),
math::uint8_to_float(rgba[3])); math::uint8_to_float(rgba[3]));

View File

@@ -25,6 +25,8 @@ namespace anm2ed::canvas
constexpr auto GRID_SIZE_MAX = 10000; constexpr auto GRID_SIZE_MAX = 10000;
constexpr auto GRID_OFFSET_MIN = 0; constexpr auto GRID_OFFSET_MIN = 0;
constexpr auto GRID_OFFSET_MAX = 10000; constexpr auto GRID_OFFSET_MAX = 10000;
constexpr auto CHECKER_SIZE = 32.0f;
} }
namespace anm2ed namespace anm2ed
@@ -46,11 +48,6 @@ namespace anm2ed
GLuint texture{}; GLuint texture{};
glm::vec2 previousSize{}; glm::vec2 previousSize{};
glm::vec2 size{}; glm::vec2 size{};
mutable GLint previousSrcRGB{};
mutable GLint previousDstRGB{};
mutable GLint previousSrcAlpha{};
mutable GLint previousDstAlpha{};
mutable bool previousBlendStored{};
Canvas(); Canvas();
Canvas(glm::vec2); Canvas(glm::vec2);
@@ -70,7 +67,7 @@ namespace anm2ed
float dashLength = canvas::DASH_LENGTH, float dashGap = canvas::DASH_GAP, float dashLength = canvas::DASH_LENGTH, float dashGap = canvas::DASH_GAP,
float dashOffset = canvas::DASH_OFFSET) const; float dashOffset = canvas::DASH_OFFSET) const;
void viewport_set() const; void viewport_set() const;
void clear(const glm::vec4&) const; void clear(glm::vec4 = glm::vec4()) const;
void bind() const; void bind() const;
void unbind() const; void unbind() const;
void zoom_set(float&, glm::vec2&, glm::vec2, float) const; void zoom_set(float&, glm::vec2&, glm::vec2, float) const;

View File

@@ -164,10 +164,7 @@ namespace anm2ed::imgui
} }
if (ImGui::MenuItem("Save", settings.shortcutSave.c_str(), false, document)) if (ImGui::MenuItem("Save", settings.shortcutSave.c_str(), false, document))
{
if (settings.fileIsWarnOverwrite) overwritePopup.open(); if (settings.fileIsWarnOverwrite) overwritePopup.open();
manager.save();
}
if (ImGui::MenuItem("Save As", settings.shortcutSaveAs.c_str(), false, document)) if (ImGui::MenuItem("Save As", settings.shortcutSaveAs.c_str(), false, document))
dialog.file_save(dialog::ANM2_SAVE); dialog.file_save(dialog::ANM2_SAVE);

View File

@@ -6,6 +6,7 @@
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include "imgui_internal.h"
#include "log.h" #include "log.h"
#include "math_.h" #include "math_.h"
#include "toast.h" #include "toast.h"
@@ -78,9 +79,7 @@ namespace anm2ed::imgui
auto& columns = settings.renderColumns; auto& columns = settings.renderColumns;
if (renderFrames.empty()) if (renderFrames.empty())
{
toasts.warning("No frames captured for spritesheet export."); toasts.warning("No frames captured for spritesheet export.");
}
else else
{ {
const auto& firstFrame = renderFrames.front(); const auto& firstFrame = renderFrames.front();
@@ -154,8 +153,7 @@ namespace anm2ed::imgui
if (auto animation = document.animation_get(); if (auto animation = document.animation_get();
animation && animation->triggers.isVisible && (!isOnlyShowLayers || manager.isRecording)) animation && animation->triggers.isVisible && (!isOnlyShowLayers || manager.isRecording))
{ {
if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER); if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER); trigger.isVisible)
trigger.is_visible(anm2::TRIGGER))
if (anm2.content.sounds.contains(trigger.soundID)) if (anm2.content.sounds.contains(trigger.soundID))
anm2.content.sounds[trigger.soundID].audio.play(false, mixer); anm2.content.sounds[trigger.soundID].audio.play(false, mixer);
} }
@@ -295,6 +293,8 @@ namespace anm2ed::imgui
ImGui::EndChild(); ImGui::EndChild();
auto cursorScreenPos = ImGui::GetCursorScreenPos(); auto cursorScreenPos = ImGui::GetCursorScreenPos();
auto min = cursorScreenPos;
auto max = to_imvec2(to_vec2(min) + size);
if (manager.isRecordingStart) if (manager.isRecordingStart)
{ {
@@ -307,6 +307,7 @@ namespace anm2ed::imgui
settings.previewBackgroundColor = vec4(); settings.previewBackgroundColor = vec4();
settings.previewIsGrid = false; settings.previewIsGrid = false;
settings.previewIsAxes = false; settings.previewIsAxes = false;
settings.previewIsBorder = false;
settings.timelineIsOnlyShowLayers = true; settings.timelineIsOnlyShowLayers = true;
settings.onionskinIsEnabled = false; settings.onionskinIsEnabled = false;
@@ -331,7 +332,7 @@ namespace anm2ed::imgui
if (isSizeTrySet) size_set(to_vec2(ImGui::GetContentRegionAvail())); if (isSizeTrySet) size_set(to_vec2(ImGui::GetContentRegionAvail()));
viewport_set(); viewport_set();
bind(); bind();
clear(backgroundColor); clear();
if (isAxes) axes_render(shaderAxes, zoom, pan, axesColor); if (isAxes) axes_render(shaderAxes, zoom, pan, axesColor);
if (isGrid) grid_render(shaderGrid, zoom, pan, gridSize, gridOffset, gridColor); if (isGrid) grid_render(shaderGrid, zoom, pan, gridSize, gridOffset, gridColor);
@@ -362,7 +363,7 @@ namespace anm2ed::imgui
auto& layer = anm2.content.layers.at(id); auto& layer = anm2.content.layers.at(id);
if (auto frame = layerAnimation.frame_generate(time, anm2::LAYER); frame.is_visible()) if (auto frame = layerAnimation.frame_generate(time, anm2::LAYER); frame.isVisible)
{ {
auto spritesheet = anm2.spritesheet_get(layer.spritesheetID); auto spritesheet = anm2.spritesheet_get(layer.spritesheetID);
if (!spritesheet || !spritesheet->is_valid()) continue; if (!spritesheet || !spritesheet->is_valid()) continue;
@@ -467,6 +468,9 @@ namespace anm2ed::imgui
unbind(); unbind();
ImGui::RenderColorRectWithAlphaCheckerboard(ImGui::GetWindowDrawList(), min, max, 0, CHECKER_SIZE,
to_imvec2(-size + pan));
ImGui::GetCurrentWindow()->DrawList->AddRectFilled(min, max, ImGui::GetColorU32(to_imvec4(backgroundColor)));
ImGui::Image(texture, to_imvec2(size)); ImGui::Image(texture, to_imvec2(size));
isPreviewHovered = ImGui::IsItemHovered(); isPreviewHovered = ImGui::IsItemHovered();

View File

@@ -3,6 +3,7 @@
#include <cmath> #include <cmath>
#include <utility> #include <utility>
#include "imgui_internal.h"
#include "math_.h" #include "math_.h"
#include "tool.h" #include "tool.h"
#include "types.h" #include "types.h"
@@ -15,13 +16,16 @@ using namespace glm;
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
constexpr auto BORDER_DASH_LENGTH = 1.0f;
constexpr auto BORDER_DASH_GAP = 0.5f;
constexpr auto BORDER_DASH_OFFSET = 0.0f;
constexpr auto PIVOT_COLOR = color::PINK; constexpr auto PIVOT_COLOR = color::PINK;
SpritesheetEditor::SpritesheetEditor() : Canvas(vec2()) {} SpritesheetEditor::SpritesheetEditor() : Canvas(vec2()) {}
void SpritesheetEditor::update(Manager& manager, Settings& settings, Resources& resources) void SpritesheetEditor::update(Manager& manager, Settings& settings, Resources& resources)
{ {
auto& document = *manager.get(); auto& document = *manager.get();
auto& anm2 = document.anm2; auto& anm2 = document.anm2;
auto& reference = document.reference; auto& reference = document.reference;
@@ -106,11 +110,13 @@ namespace anm2ed::imgui
ImGui::EndChild(); ImGui::EndChild();
auto cursorScreenPos = ImGui::GetCursorScreenPos(); auto cursorScreenPos = ImGui::GetCursorScreenPos();
auto min = ImGui::GetCursorScreenPos();
auto max = to_imvec2(to_vec2(min) + size);
size_set(to_vec2(ImGui::GetContentRegionAvail())); size_set(to_vec2(ImGui::GetContentRegionAvail()));
bind(); bind();
viewport_set(); viewport_set();
clear(backgroundColor); clear();
auto frame = document.frame_get(); auto frame = document.frame_get();
@@ -122,7 +128,9 @@ namespace anm2ed::imgui
auto spritesheetModel = math::quad_model_get(texture.size); auto spritesheetModel = math::quad_model_get(texture.size);
auto spritesheetTransform = transform * spritesheetModel; auto spritesheetTransform = transform * spritesheetModel;
texture_render(shaderTexture, texture.id, spritesheetTransform); texture_render(shaderTexture, texture.id, spritesheetTransform);
if (isBorder) rect_render(dashedShader, spritesheetTransform, spritesheetModel); if (isBorder)
rect_render(dashedShader, spritesheetTransform, spritesheetModel, color::WHITE, BORDER_DASH_LENGTH,
BORDER_DASH_GAP, BORDER_DASH_OFFSET);
if (frame && reference.itemID > -1 && if (frame && reference.itemID > -1 &&
anm2.content.layers.at(reference.itemID).spritesheetID == referenceSpritesheet) anm2.content.layers.at(reference.itemID).spritesheetID == referenceSpritesheet)
@@ -141,6 +149,9 @@ namespace anm2ed::imgui
unbind(); unbind();
ImGui::RenderColorRectWithAlphaCheckerboard(ImGui::GetWindowDrawList(), min, max, 0, CHECKER_SIZE,
to_imvec2(-size * 0.5f + pan));
ImGui::GetCurrentWindow()->DrawList->AddRectFilled(min, max, ImGui::GetColorU32(to_imvec4(backgroundColor)));
ImGui::Image(texture, to_imvec2(size)); ImGui::Image(texture, to_imvec2(size));
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
@@ -233,11 +244,12 @@ namespace anm2ed::imgui
case tool::MOVE: case tool::MOVE:
if (!frame) break; if (!frame) break;
if (isBegin) document.snapshot("Frame Pivot"); if (isBegin) document.snapshot("Frame Pivot");
if (isMouseDown) frame->pivot = ivec2(mousePos - frame->crop); if (isMouseDown) frame->pivot = vec2(ivec2(mousePos - frame->crop));
if (isLeftPressed) frame->pivot.x -= step; if (isLeftPressed) frame->pivot.x -= step;
if (isRightPressed) frame->pivot.x += step; if (isRightPressed) frame->pivot.x += step;
if (isUpPressed) frame->pivot.y -= step; if (isUpPressed) frame->pivot.y -= step;
if (isDownPressed) frame->pivot.y += step; if (isDownPressed) frame->pivot.y += step;
frame->pivot = vec2(ivec2(frame->pivot));
if (isDuring) if (isDuring)
{ {
if (ImGui::BeginTooltip()) if (ImGui::BeginTooltip())
@@ -258,27 +270,29 @@ namespace anm2ed::imgui
if (isMouseClicked) if (isMouseClicked)
{ {
cropAnchor = mousePos; cropAnchor = mousePos;
frame->crop = cropAnchor; frame->crop = vec2(ivec2(cropAnchor));
frame->size = vec2(); frame->size = vec2();
} }
if (isMouseDown) if (isMouseDown)
{ {
auto [minPoint, maxPoint] = snap_rect(glm::min(cropAnchor, mousePos), glm::max(cropAnchor, mousePos)); auto [minPoint, maxPoint] = snap_rect(glm::min(cropAnchor, mousePos), glm::max(cropAnchor, mousePos));
frame->crop = minPoint; frame->crop = vec2(ivec2(minPoint));
frame->size = maxPoint - minPoint; frame->size = vec2(ivec2(maxPoint - minPoint));
} }
if (isLeftPressed) frame->crop.x -= stepX; if (isLeftPressed) frame->crop.x -= stepX;
if (isRightPressed) frame->crop.x += stepX; if (isRightPressed) frame->crop.x += stepX;
if (isUpPressed) frame->crop.y -= stepY; if (isUpPressed) frame->crop.y -= stepY;
if (isDownPressed) frame->crop.y += stepY; if (isDownPressed) frame->crop.y += stepY;
frame->crop = vec2(ivec2(frame->crop));
frame->size = vec2(ivec2(frame->size));
if (isDuring) if (isDuring)
{ {
if (!isMouseDown) if (!isMouseDown)
{ {
auto minPoint = glm::min(frame->crop, frame->crop + frame->size); auto minPoint = glm::min(frame->crop, frame->crop + frame->size);
auto maxPoint = glm::max(frame->crop, frame->crop + frame->size); auto maxPoint = glm::max(frame->crop, frame->crop + frame->size);
frame->crop = minPoint; frame->crop = vec2(ivec2(minPoint));
frame->size = maxPoint - minPoint; frame->size = vec2(ivec2(maxPoint - minPoint));
if (isGridSnap) if (isGridSnap)
{ {
auto [snapMin, snapMax] = snap_rect(frame->crop, frame->crop + frame->size); auto [snapMin, snapMax] = snap_rect(frame->crop, frame->crop + frame->size);