/* =========================================================================== * Sago Multi Scrambler Puzzle Copyright (C) 2022-2024 Poul Sander This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/ Source information and contacts persons can be found at https://github.com/sago007/saland =========================================================================== */ #include "SagoTextureSelector.hpp" #include #include "imgui.h" #include "backends/imgui_impl_sdl2.h" #include "backends/imgui_impl_sdlrenderer2.h" #include #include "../../sago/SagoMisc.hpp" #include "../global.hpp" #include "../common.h" const char* const editor_texture_grid_size = "editor_texture_grid_size"; class ChangeSDLColor { public: ChangeSDLColor(SDL_Renderer* renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a) : renderer(renderer) { SDL_GetRenderDrawColor(renderer, &oldr, &oldg, &oldb, &olda); SDL_SetRenderDrawColor(renderer, r, g, b, a); } ChangeSDLColor(SDL_Renderer* renderer) : renderer(renderer) { SDL_GetRenderDrawColor(renderer, &oldr, &oldg, &oldb, &olda); } void setRed() { SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE); } void setYellow() { SDL_SetRenderDrawColor(renderer, 255, 255, 0, SDL_ALPHA_OPAQUE); } void reset() { SDL_SetRenderDrawColor(renderer, oldr, oldg, oldb, olda); } ~ChangeSDLColor() { SDL_SetRenderDrawColor(renderer, oldr, oldg, oldb, olda); } private: SDL_Renderer* renderer; Uint8 oldr, oldg, oldb, olda; }; static void addLinesToCanvas(SDL_Renderer* renderer, SDL_Texture* texture, int xstep = 32, int ystep = 32, int xoffset = 0, int yoffset = 0) { int width, height; SDL_QueryTexture(texture, nullptr, nullptr, &width, &height); Uint8 r, g, b, a; SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a); if (xstep > 0) { for (int i = 0; i < width+1; i += xstep) { ImGui::GetWindowDrawList()->AddLine(ImVec2(i+xoffset, yoffset), ImVec2(i+xoffset, height+yoffset), IM_COL32(r, g, b, a)); } } if (ystep > 0) { for (int i = 0; i < height+1; i += ystep) { ImGui::GetWindowDrawList()->AddLine(ImVec2(xoffset, i+yoffset), ImVec2(width+xoffset, i+yoffset), IM_COL32(r, g, b, a)); } } } static void addRectableToCanvas(SDL_Renderer* renderer, int topx = 0, int topy = 0, int height = 100, int width = 100, int xoffset = 0, int yoffset = 0) { Uint8 r, g, b, a; SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a); topx += xoffset; topy += yoffset; ImGui::GetWindowDrawList()->AddLine(ImVec2(topx, topy), ImVec2(topx+width, topy), IM_COL32(r, g, b, a)); ImGui::GetWindowDrawList()->AddLine(ImVec2(topx+width, topy), ImVec2(topx+width, topy+height), IM_COL32(r, g, b, a)); ImGui::GetWindowDrawList()->AddLine(ImVec2(topx+width, topy+height), ImVec2(topx, topy+height), IM_COL32(r, g, b, a)); ImGui::GetWindowDrawList()->AddLine(ImVec2(topx, topy+height), ImVec2(topx, topy), IM_COL32(r, g, b, a)); } static void addFolderToList(const std::string& folder, std::vector& list, const std::string& filter = "") { std::vector textures = sago::GetFileList(folder.c_str()); for (const auto& texture : textures) { std::cout << "Texture: " << texture << "\n"; if (texture.find(".png") == std::string::npos) { continue; } if (filter.empty() || texture.find(filter) != std::string::npos) { list.push_back(texture); } } } static std::vector populateTree(const std::string& filter = "") { std::vector textures; addFolderToList("textures", textures, filter); return textures; } std::string remove_file_extension(const std::string& filename) { size_t lastindex = filename.find_last_of("."); return filename.substr(0, lastindex); } static void ImGuiWritePartOfImage(SDL_Texture* texture, int topx, int topy, int w, int h) { int tex_w, tex_h; SDL_QueryTexture(texture, nullptr, nullptr, &tex_w, &tex_h); float sprite_w = w; float sprite_h = h; float topxf = topx; float topyf = topy; ImVec2 uv0 = ImVec2(topxf / tex_w, topyf / tex_h); ImVec2 uv1 = ImVec2((topxf + sprite_w) / tex_w, (topyf + sprite_h) / tex_h); ImGui::Image((ImTextureID)(intptr_t)texture, ImVec2((float)w, (float)h), uv0, uv1); } void SagoTextureSelector::runSpriteSelectorFrame(SDL_Renderer* target) { ImGui::Begin("SpriteList", nullptr, ImGuiWindowFlags_NoCollapse); static char filter[256] = ""; ImGui::InputText("Filter", filter, IM_ARRAYSIZE(filter)); ImGui::Separator(); for (const auto& sprite : sprites) { std::string sprite_name = sprite.first; if (filter[0] == '\0' || sprite_name.find(filter) != std::string::npos) { if (ImGui::Selectable(sprite_name.c_str(), selected_sprite == sprite_name)) { selected_sprite = sprite_name; } } } ImGui::End(); ImGui::Begin("SpriteViewer"); if (selected_sprite.length()) { const SagoSprite& current_sprite = sprites[selected_sprite]; SDL_Texture* current_texture = globalData.dataHolder->getTexturePtr(current_sprite.texture); ImGui::Text("Size: %d x %d", current_sprite.width, current_sprite.height); ImGui::BeginChild("Test"); int offset = current_sprite.width * (SDL_GetTicks()/current_sprite.frame_time % current_sprite.number_of_frames); ImGuiWritePartOfImage(current_texture, current_sprite.topx+offset, current_sprite.topy, current_sprite.width, current_sprite.height); ImGui::EndChild(); } ImGui::End(); ImGui::Begin("SpriteTexture"); if (selected_sprite.length() && sprites[selected_sprite].texture.length()) { int tex_w, tex_h; const SagoSprite& current_sprite = sprites[selected_sprite]; SDL_Texture* current_texture = globalData.dataHolder->getTexturePtr(current_sprite.texture); SDL_QueryTexture(current_texture, nullptr, nullptr, &tex_w, &tex_h); ImGui::Text("Size: %d x %d", tex_w, tex_h); ImGui::BeginChild("Test"); ImVec2 p = ImGui::GetCursorScreenPos(); ImGui::Image((ImTextureID)(intptr_t)current_texture, ImVec2((float)tex_w, (float)tex_h)); ChangeSDLColor color(target); color.setYellow(); for (int i = 1; i < current_sprite.number_of_frames; i++) { addRectableToCanvas(target, current_sprite.topx+i*current_sprite.width, current_sprite.topy, current_sprite.height, current_sprite.width, p.x, p.y); } color.setRed(); addRectableToCanvas(target, current_sprite.topx, current_sprite.topy, current_sprite.height, current_sprite.width, p.x, p.y); ImGui::EndChild(); } ImGui::End(); } void SagoTextureSelector::runTextureSelectorFrame(SDL_Renderer* target) { ImGui::Begin("TextureList", nullptr, ImGuiWindowFlags_NoCollapse); if (ImGui::SliderInt("grid size", &grid_size, 0, 100)) { Config::getInstance()->setInt(editor_texture_grid_size, grid_size); } static char filter[256] = ""; ImGui::InputText("Filter", filter, IM_ARRAYSIZE(filter)); ImGui::Separator(); for (const auto& texture : textures) { if (filter[0] == '\0' || texture.find(filter) != std::string::npos) { if (ImGui::Selectable(texture.c_str(), selected_texture == texture)) { selected_texture = texture; } } } ImGui::End(); ImGui::Begin("TextureViewer"); if (selected_texture.length()) { int tex_w, tex_h; SDL_Texture* current_texture = globalData.dataHolder->getTexturePtr(remove_file_extension(selected_texture)); SDL_QueryTexture(current_texture, nullptr, nullptr, &tex_w, &tex_h); ImGui::Text("Size: %d x %d", tex_w, tex_h); ImGui::BeginChild("Test"); ImVec2 p = ImGui::GetCursorScreenPos(); ImGui::Image((ImTextureID)(intptr_t)current_texture, ImVec2((float)tex_w, (float)tex_h)); ChangeSDLColor color(target); color.setRed(); if (grid_size) { addLinesToCanvas(target, current_texture, grid_size, grid_size, p.x, p.y); } ImGui::EndChild(); } ImGui::End(); } SagoTextureSelector::SagoTextureSelector() { grid_size = Config::getInstance()->getInt(editor_texture_grid_size, 32); } SagoTextureSelector::~SagoTextureSelector() { } bool SagoTextureSelector::IsActive() { return isActive; } void SagoTextureSelector::ProcessInput(const SDL_Event& event, bool &processed) { } void SagoTextureSelector::Draw(SDL_Renderer* target) { runTextureSelectorFrame(target); runSpriteSelectorFrame(target); } void SagoTextureSelector::Update() { } void SagoTextureSelector::Init() { textures = populateTree(); sprites = LoadSprites(); }