diff --git a/implementations/Crafter.Graphics-Image.cpp b/implementations/Crafter.Graphics-Image.cpp new file mode 100644 index 0000000..c9e7c88 --- /dev/null +++ b/implementations/Crafter.Graphics-Image.cpp @@ -0,0 +1,63 @@ +/* +Crafter®.Graphics +Copyright (C) 2025 Catcrafts® +Catcrafts.net + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +module; +#include "../lib/stb_image.h" +module Crafter.Graphics:Image_impl; +import :Image; +import std; + +using namespace Crafter; + +Image::Image(const std::string_view path) { + std::filesystem::path abs = std::filesystem::absolute(path); + int xSize; + int ySize; + unsigned char* bgData = stbi_load(abs.string().c_str(), &xSize, &ySize, nullptr, 4); + + buffer.resize(xSize*ySize); + width = xSize; + height = ySize; + + opaque = OpaqueType::FullyOpaque; + + for(std::uint_fast32_t x = 0; x < xSize; x++) { + for(std::uint_fast32_t y = 0; y < ySize; y++) { + std::uint_fast32_t idx = (x*ySize+y)*4; + buffer[x*ySize+y].r = bgData[idx]; + buffer[x*ySize+y].g = bgData[idx+1]; + buffer[x*ySize+y].b = bgData[idx+2]; + buffer[x*ySize+y].a = bgData[idx+3]; + } + } + + for(std::uint_fast32_t i = 0; i < xSize*ySize; i++) { + if(buffer[i].a != 255) { + opaque = OpaqueType::SemiOpaque; + for(std::uint_fast32_t i2 = 0; i2 < xSize*ySize; i2++) { + if(buffer[i2].a != 0 && buffer[i2].a != 255) { + opaque = OpaqueType::Transparent; + return; + } + } + return; + } + } +} \ No newline at end of file diff --git a/implementations/Crafter.Graphics-MouseElement.cpp b/implementations/Crafter.Graphics-MouseElement.cpp index 529371c..0419f1b 100644 --- a/implementations/Crafter.Graphics-MouseElement.cpp +++ b/implementations/Crafter.Graphics-MouseElement.cpp @@ -35,6 +35,10 @@ MouseElement::MouseElement(Anchor anchor) : Transform(anchor) { } +MouseElement::MouseElement(WindowMouse& window) : Transform({FractionalToMapped(0), FractionalToMapped(0), FractionalToMapped(1), FractionalToMapped(1), FractionalToMapped(0), FractionalToMapped(0), 0}) { + window.mouseElements.push_back(this); +} + void MouseElement::UpdatePosition(Window& window) { window.ScaleMouse(*this); diff --git a/interfaces/Crafter.Graphics-Image.cppm b/interfaces/Crafter.Graphics-Image.cppm new file mode 100644 index 0000000..c8afc7d --- /dev/null +++ b/interfaces/Crafter.Graphics-Image.cppm @@ -0,0 +1,34 @@ +/* +Crafter®.Graphics +Copyright (C) 2025 Catcrafts® +Catcrafts.net + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +export module Crafter.Graphics:Image; +import std; + +import :Types; + +namespace Crafter { + export struct Image { + std::vector buffer; + std::uint_fast32_t width; + std::uint_fast32_t height; + OpaqueType opaque; + Image(const std::string_view path); + }; +} \ No newline at end of file diff --git a/interfaces/Crafter.Graphics-MouseElement.cppm b/interfaces/Crafter.Graphics-MouseElement.cppm index d8c89d6..d1b9269 100644 --- a/interfaces/Crafter.Graphics-MouseElement.cppm +++ b/interfaces/Crafter.Graphics-MouseElement.cppm @@ -38,6 +38,7 @@ export namespace Crafter { Event onMouseRightRelease; Event onMouseLeftRelease; + MouseElement(WindowMouse& window); MouseElement(Anchor anchor); MouseElement(Anchor anchor, WindowMouse& window); void UpdatePosition(Window& window) override; diff --git a/interfaces/Crafter.Graphics-RenderingElement.cppm b/interfaces/Crafter.Graphics-RenderingElement.cppm index 591895b..697fa0e 100644 --- a/interfaces/Crafter.Graphics-RenderingElement.cppm +++ b/interfaces/Crafter.Graphics-RenderingElement.cppm @@ -24,16 +24,10 @@ export module Crafter.Graphics:RenderingElement; import std; import :Transform; import :Types; +import :Image; import :Window; export namespace Crafter { - enum class OpaqueType { - FullyOpaque, // All pixels have A of 255 - SemiOpaque, // All pixels have A of 0 or 255 (no blending needed) - Transparent // Color blending is used - }; - - struct RenderElementScalingOwning { std::vector scalingBuffer; std::uint_fast32_t bufferWidth; @@ -91,6 +85,9 @@ export namespace Crafter { public: std::vector buffer; OpaqueType opaque; + RenderingElementBase(Anchor anchor) : Transform(anchor) { + scaled.width = 0; + } RenderingElementBase(Anchor anchor, OpaqueType opaque) : Transform(anchor), opaque(opaque) { scaled.width = 0; } @@ -107,10 +104,10 @@ export namespace Crafter { } - RenderingElement(Anchor anchor, const std::string_view imagePath) : Transform(anchor) { + RenderingElement(Anchor anchor, const std::string_view imagePath) : RenderingElementBase(anchor) { LoadImage(imagePath); } - RenderingElement(Anchor anchor, const std::string_view imagePath, std::uint_fast32_t rotation) requires(Rotating) : Transform(anchor), RotatingBase(rotation) { + RenderingElement(Anchor anchor, const std::string_view imagePath, std::uint_fast32_t rotation) requires(Rotating) : RenderingElementBase(anchor), RotatingBase(rotation) { LoadImage(imagePath); } @@ -128,6 +125,20 @@ export namespace Crafter { } + RenderingElement(Anchor anchor, OpaqueType opaque, Image& image) requires(Scaling && !Owning) : RenderingElementBase(anchor, opaque), ScalingBase(image.buffer.data(), image.width, image.height) { + + } + RenderingElement(Anchor anchor, OpaqueType opaque, Image& image, std::uint_fast32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElementBase(anchor, opaque), ScalingBase(image.buffer.data(), image.width, image.height), RotatingBase(rotation) { + + } + + RenderingElement(Anchor anchor, Image& image) requires(Scaling && !Owning) : RenderingElementBase(anchor, image.opaque), ScalingBase(image.buffer.data(), image.width, image.height) { + + } + RenderingElement(Anchor anchor, Image& image, std::uint_fast32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElementBase(anchor, image.opaque), ScalingBase(image.buffer.data(), image.width, image.height), RotatingBase(rotation) { + + } + RenderingElement(Anchor anchor, OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight) requires(Owning) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight) { } @@ -169,8 +180,8 @@ export namespace Crafter { scaled.x -= diffX; scaled.y -= diffY; - ScalingBase::scalingBuffer.clear(); - ScalingBase::scalingBuffer.resize(scaled.width * scaled.height); + buffer.clear(); + buffer.resize(scaled.width * scaled.height); // Destination center const double dstCx = (static_cast(scaled.width) - 1.0) * 0.5; @@ -289,6 +300,7 @@ export namespace Crafter { ScalingBase::bufferWidth = xSize; ScalingBase::bufferHeight = ySize; ScalingBase::bufferUpdated = true; + ScalingBase::scalingBuffer.resize(xSize*ySize); } else { buffer.resize(xSize*ySize); } @@ -302,7 +314,7 @@ export namespace Crafter { ScalingBase::scalingBuffer[x*ySize+y].r = bgData[idx]; ScalingBase::scalingBuffer[x*ySize+y].g = bgData[idx+1]; ScalingBase::scalingBuffer[x*ySize+y].b = bgData[idx+2]; - ScalingBase::calingBuffer[x*ySize+y].a = bgData[idx+3]; + ScalingBase::scalingBuffer[x*ySize+y].a = bgData[idx+3]; } } @@ -356,6 +368,7 @@ export namespace Crafter { ScalingBase::bufferWidth = xSize; ScalingBase::bufferHeight = ySize; ScalingBase::bufferUpdated = true; + ScalingBase::scalingBuffer.resize(xSize*ySize); } else { buffer.resize(xSize*ySize); } diff --git a/interfaces/Crafter.Graphics-Types.cppm b/interfaces/Crafter.Graphics-Types.cppm index 189c9ef..4fe607d 100644 --- a/interfaces/Crafter.Graphics-Types.cppm +++ b/interfaces/Crafter.Graphics-Types.cppm @@ -107,6 +107,11 @@ namespace Crafter { std::chrono::duration delta; }; + export enum class OpaqueType { + FullyOpaque, // All pixels have A of 255 + SemiOpaque, // All pixels have A of 0 or 255 (no blending needed) + Transparent // Color blending is used + }; export constexpr std::int_fast32_t BOUND = 9; export constexpr std::int_fast32_t SCALE = std::numeric_limits::max() / BOUND; diff --git a/interfaces/Crafter.Graphics.cppm b/interfaces/Crafter.Graphics.cppm index 6655f56..542d787 100644 --- a/interfaces/Crafter.Graphics.cppm +++ b/interfaces/Crafter.Graphics.cppm @@ -28,6 +28,7 @@ export import :TextElement; export import :GridElement; export import :Types; export import :Font; +export import :Image; export import :Shm; export import :Animation; diff --git a/project.json b/project.json index 70f90ff..31087bd 100644 --- a/project.json +++ b/project.json @@ -3,8 +3,8 @@ "configurations": [ { "name": "base", - "implementations": ["implementations/Crafter.Graphics-Font", "implementations/Crafter.Graphics-Shm", "implementations/Crafter.Graphics-Window", "implementations/Crafter.Graphics-TextElement", "implementations/Crafter.Graphics-MouseElement", "implementations/Crafter.Graphics-Transform", "implementations/Crafter.Graphics-GridElement"], - "interfaces": ["interfaces/Crafter.Graphics-Window", "interfaces/Crafter.Graphics", "interfaces/Crafter.Graphics-Types", "interfaces/Crafter.Graphics-Font", "interfaces/Crafter.Graphics-Shm", "interfaces/Crafter.Graphics-Animation", "interfaces/Crafter.Graphics-RenderingElement", "interfaces/Crafter.Graphics-TextElement", "interfaces/Crafter.Graphics-MouseElement", "interfaces/Crafter.Graphics-Transform", "interfaces/Crafter.Graphics-GridElement"], + "implementations": ["implementations/Crafter.Graphics-Font", "implementations/Crafter.Graphics-Shm", "implementations/Crafter.Graphics-Window", "implementations/Crafter.Graphics-TextElement", "implementations/Crafter.Graphics-MouseElement", "implementations/Crafter.Graphics-Transform", "implementations/Crafter.Graphics-GridElement", "implementations/Crafter.Graphics-Image"], + "interfaces": ["interfaces/Crafter.Graphics-Window", "interfaces/Crafter.Graphics", "interfaces/Crafter.Graphics-Types", "interfaces/Crafter.Graphics-Font", "interfaces/Crafter.Graphics-Image", "interfaces/Crafter.Graphics-Shm", "interfaces/Crafter.Graphics-Animation", "interfaces/Crafter.Graphics-RenderingElement", "interfaces/Crafter.Graphics-TextElement", "interfaces/Crafter.Graphics-MouseElement", "interfaces/Crafter.Graphics-Transform", "interfaces/Crafter.Graphics-GridElement"], "type": "library" }, {