diff --git a/examples/HelloUI/main.cpp b/examples/HelloUI/main.cpp index 300b71d..1b3f315 100644 --- a/examples/HelloUI/main.cpp +++ b/examples/HelloUI/main.cpp @@ -8,12 +8,12 @@ int main() { RenderingElement element( { - FractionalToMapped(0.5), //anchorX: relative position where this elements x anchor (top-left) is placed to its parent x anchor - FractionalToMapped(0.5), //anchorY: relative position where this elements y anchor (top-left) is placed to its parent y anchor - FractionalToMapped(0.5), //relativeSizeX: the relative x size this element should be scaled to compared to its parent - FractionalToMapped(0.5), //relativeSizeY: the relative y size this element should be scaled to compared to its parent - FractionalToMapped(0.5), //anchorOffsetX: the amount this element's anchor should be offset from the top left corner (0.5 to in the middle) - FractionalToMapped(0.5), //anchorOffsetY: the amount this element's anchor should be offset from the top left corner (0.5 to place it in the middle) + FractionalToMapped(0.5), //anchorX: relative position where this elements x anchor (top-left) is placed to its parent x anchor + FractionalToMapped(0.5), //anchorY: relative position where this elements y anchor (top-left) is placed to its parent y anchor + FractionalToMapped(0.5), //relativeSizeX: the relative x size this element should be scaled to compared to its parent + FractionalToMapped(0.5), //relativeSizeY: the relative y size this element should be scaled to compared to its parent + FractionalToMapped(0.5), //anchorOffsetX: the amount this element's anchor should be offset from the top left corner (0.5 to in the middle) + FractionalToMapped(0.5), //anchorOffsetY: the amount this element's anchor should be offset from the top left corner (0.5 to place it in the middle) 0 //z: this elements Z position }, OpaqueType::FullyOpaque, @@ -21,32 +21,23 @@ int main() { 1 ); - MouseElement mouse({ - FractionalToMapped(0), //anchorX: relative position where this elements x anchor (top-left) is placed to its parent x anchor - FractionalToMapped(0), //anchorY: relative position where this elements y anchor (top-left) is placed to its parent y anchor - FractionalToMapped(1), //relativeSizeX: the relative x size this element should be scaled to compared to its parent - FractionalToMapped(1), //relativeSizeY: the relative y size this element should be scaled to compared to its parent - FractionalToMapped(0), //anchorOffsetX: the amount this element's anchor should be offset from the top left corner (0.5 to in the middle) - FractionalToMapped(0), //anchorOffsetY: the amount this element's anchor should be offset from the top left corner (0.5 to place it in the middle) - 0 //z: this elements Z position - }, window); + MouseElement mouse(window); element.children.push_back(&mouse); window.elements.push_back(&element); element.scalingBuffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}}; element.UpdatePosition(window); - EventListener clickListener(&mouse.onMouseLeftClick, [&mouse, &window](MousePoint point){ + EventListener clickListener(&mouse.onMouseLeftClick, [&mouse, &window](MousePoint point) { // Print the coordinates where the user clicked relative to the element's top left corner. - - //Mapped space - std::cout << std::format("Clicked on Mapped X:{} Y:{}!", point.x, point.y) << std::endl; - - // Fraction space - std::cout << std::format("Clicked on Fraction X:{} Y:{}!", MappedToFractionalBoundless(point.x), MappedToFractionalBoundless(point.y)) << std::endl; - - // Screen space - std::cout << std::format("Clicked on Screen X:{} Y:{}!\n", MappedToPixelBoundless(point.x, MappedToPixelBoundless(mouse.scaled.width, window.width)), MappedToPixelBoundless(point.y, MappedToPixelBoundless(mouse.scaled.width, window.height))) << std::endl; + std::println("Clicked on Mapped X:{} Y:{}!\nClicked on Fraction X:{} Y:{}!\nClicked on Screen X:{} Y:{}!\n", + //Mapped space + point.x, point.y, + // Fraction space + MappedToFractionalBoundless(point.x), MappedToFractionalBoundless(point.y), + // Screen space + MappedToAbsoluteBoundless(point.x, MappedToAbsoluteBoundless(mouse.mouseScaled.width, window.width)), MappedToAbsoluteBoundless(point.y, MappedToAbsoluteBoundless(mouse.mouseScaled.width, window.height)) + ); }); window.Render(); diff --git a/implementations/Crafter.Graphics-GridElement.cpp b/implementations/Crafter.Graphics-GridElement.cpp index 3bbf139..2b68734 100644 --- a/implementations/Crafter.Graphics-GridElement.cpp +++ b/implementations/Crafter.Graphics-GridElement.cpp @@ -26,23 +26,23 @@ import std; using namespace Crafter; -GridElement::GridElement(std::uint_fast32_t columns, std::uint_fast32_t rows, std::int_fast32_t spacingX, std::int_fast32_t spacingY, std::int_fast32_t paddingX, std::int_fast32_t paddingY, Anchor anchor) : Transform(anchor), columns(columns), rows(rows), spacingX(spacingX), spacingY(spacingY), paddingX(paddingX), paddingY(paddingY) { +GridElement::GridElement(std::uint32_t columns, std::uint32_t rows, std::int32_t spacingX, std::int32_t spacingY, std::int32_t paddingX, std::int32_t paddingY, Anchor anchor) : Transform(anchor), columns(columns), rows(rows), spacingX(spacingX), spacingY(spacingY), paddingX(paddingX), paddingY(paddingY) { } void GridElement::UpdatePositionScaled(Window& window) { - std::int_fast32_t cellWidth = (SCALE - (paddingX * 2) - (spacingX * (columns - 1))) / columns; - std::int_fast32_t cellHeight = (SCALE - (paddingY * 2) - (spacingY * (rows - 1))) / rows; + std::int32_t cellWidth = (SCALE32 - (paddingX * 2) - (spacingX * (columns - 1))) / columns; + std::int32_t cellHeight = (SCALE32 - (paddingY * 2) - (spacingY * (rows - 1))) / rows; std::size_t childIndex = 0; - for (std::uint_fast32_t row = 0; row < rows && childIndex < children.size(); ++row) { - for (std::uint_fast32_t col = 0; col < columns && childIndex < children.size(); ++col) { + for (std::uint32_t row = 0; row < rows && childIndex < children.size(); ++row) { + for (std::uint32_t col = 0; col < columns && childIndex < children.size(); ++col) { Transform* child = children[childIndex]; // Calculate position for this child - std::int_fast32_t childX = (cellWidth * col) + (spacingX * col) + paddingX; + std::int32_t childX = (cellWidth * col) + (spacingX * col) + paddingX; - std::int_fast32_t childY = (cellHeight * row) + (spacingY * row) + paddingY; + std::int32_t childY = (cellHeight * row) + (spacingY * row) + paddingY; // Apply relative positioning child->anchor.x = childX; diff --git a/implementations/Crafter.Graphics-MouseElement.cpp b/implementations/Crafter.Graphics-MouseElement.cpp index 48756bc..a75ef0a 100644 --- a/implementations/Crafter.Graphics-MouseElement.cpp +++ b/implementations/Crafter.Graphics-MouseElement.cpp @@ -35,17 +35,18 @@ MouseElement::MouseElement(Anchor anchor) : Transform(anchor) { } -MouseElement::MouseElement(WindowMouse& window) : Transform({FractionalToMapped(0), FractionalToMapped(0), FractionalToMapped(1), FractionalToMapped(1), FractionalToMapped(0), FractionalToMapped(0), 0}) { +MouseElement::MouseElement(WindowMouse& window) : Transform({FractionalToMapped(0), FractionalToMapped(0), FractionalToMapped(1), FractionalToMapped(1), FractionalToMapped(0), FractionalToMapped(0), 0}) { window.mouseElements.push_back(this); } -MouseElement::MouseElement() : Transform({FractionalToMapped(0), FractionalToMapped(0), FractionalToMapped(1), FractionalToMapped(1), FractionalToMapped(0), FractionalToMapped(0), 0}) { +MouseElement::MouseElement() : Transform({FractionalToMapped(0), FractionalToMapped(0), FractionalToMapped(1), FractionalToMapped(1), FractionalToMapped(0), FractionalToMapped(0), 0}) { } void MouseElement::UpdatePosition(Window& window) { window.ScaleMouse(*this); + window.ScaleElement(*this); for(Transform* child : children) { child->UpdatePosition(window, *this); } @@ -53,6 +54,7 @@ void MouseElement::UpdatePosition(Window& window) { void MouseElement::UpdatePosition(Window& window, Transform& parent) { window.ScaleMouse(*this, parent); + window.ScaleElement(*this, parent); for(Transform* child : children) { child->UpdatePosition(window, *this); } diff --git a/implementations/Crafter.Graphics-Transform.cpp b/implementations/Crafter.Graphics-Transform.cpp index de55e9e..2bcfe24 100644 --- a/implementations/Crafter.Graphics-Transform.cpp +++ b/implementations/Crafter.Graphics-Transform.cpp @@ -28,7 +28,7 @@ import std; using namespace Crafter; -Anchor::Anchor(std::int_fast32_t x, std::int_fast32_t y, std::uint_fast32_t width, std::uint_fast32_t height, std::int_fast32_t offsetX, std::int_fast32_t offsetY, std::int_fast32_t z, bool maintainAspectRatio): x(x), y(y), width(width), height(height), offsetX(offsetX), offsetY(offsetY), z(z), maintainAspectRatio(maintainAspectRatio) { +Anchor::Anchor(std::int32_t x, std::int32_t y, std::uint32_t width, std::uint32_t height, std::int32_t offsetX, std::int32_t offsetY, std::int32_t z, bool maintainAspectRatio): x(x), y(y), width(width), height(height), offsetX(offsetX), offsetY(offsetY), z(z), maintainAspectRatio(maintainAspectRatio) { } diff --git a/implementations/Crafter.Graphics-Window.cpp b/implementations/Crafter.Graphics-Window.cpp index 46106cf..1cc850c 100644 --- a/implementations/Crafter.Graphics-Window.cpp +++ b/implementations/Crafter.Graphics-Window.cpp @@ -20,51 +20,59 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA module Crafter.Graphics:Window_impl; import :Window; import :Transform; +import :MouseElement; import std; using namespace Crafter; -Window::Window(std::int_fast32_t width, std::int_fast32_t height) : width(width), height(height) { +Window::Window(std::int32_t width, std::int32_t height) : width(width), height(height) { } void Window::ScaleElement(Transform& element) { if(element.anchor.maintainAspectRatio) { if(width > height) { - element.scaled.width = MappedToPixel(element.anchor.width, height); - element.scaled.height = MappedToPixel(element.anchor.height, height); + element.scaled.width = MappedToAbsolute(element.anchor.width, height); + element.scaled.height = MappedToAbsolute(element.anchor.height, height); } else { - element.scaled.width = MappedToPixel(element.anchor.width, width); - element.scaled.height = MappedToPixel(element.anchor.height, width); + element.scaled.width = MappedToAbsolute(element.anchor.width, width); + element.scaled.height = MappedToAbsolute(element.anchor.height, width); } } else { - element.scaled.width = MappedToPixel(element.anchor.width, width); - element.scaled.height = MappedToPixel(element.anchor.height, height); + element.scaled.width = MappedToAbsolute(element.anchor.width, width); + element.scaled.height = MappedToAbsolute(element.anchor.height, height); } - element.scaled.x = MappedToPixel(element.anchor.x, width) - MappedToPixel(element.anchor.offsetX, element.scaled.width); - element.scaled.y = MappedToPixel(element.anchor.y, height) - MappedToPixel(element.anchor.offsetY, element.scaled.height); + element.scaled.x = MappedToAbsolute(element.anchor.x, width) - MappedToAbsolute(element.anchor.offsetX, element.scaled.width); + element.scaled.y = MappedToAbsolute(element.anchor.y, height) - MappedToAbsolute(element.anchor.offsetY, element.scaled.height); } void Window::ScaleElement(Transform& element, Transform& parent) { - element.scaled.width = MappedToPixel(element.anchor.width, parent.scaled.width); - element.scaled.height = MappedToPixel(element.anchor.height, parent.scaled.height); - element.scaled.x = MappedToPixel(element.anchor.x, parent.scaled.width) - MappedToPixel(element.anchor.offsetX, element.scaled.width) + parent.scaled.x; - element.scaled.y = MappedToPixel(element.anchor.y, parent.scaled.height) - MappedToPixel(element.anchor.offsetY, element.scaled.height) + parent.scaled.y; + element.scaled.width = MappedToAbsolute(element.anchor.width, parent.scaled.width); + element.scaled.height = MappedToAbsolute(element.anchor.height, parent.scaled.height); + element.scaled.x = MappedToAbsolute(element.anchor.x, parent.scaled.width) - MappedToAbsolute(element.anchor.offsetX, element.scaled.width) + parent.scaled.x; + element.scaled.y = MappedToAbsolute(element.anchor.y, parent.scaled.height) - MappedToAbsolute(element.anchor.offsetY, element.scaled.height) + parent.scaled.y; } -void Window::ScaleMouse(Transform& element, Transform& parent) { - std::int_fast32_t boundlessWidth = PixelToMappedBoundless(parent.scaled.width, width); - std::int_fast32_t boundlessHeight = PixelToMappedBoundless(parent.scaled.height, height); - element.scaled.width = BoundToBoundless(MappedToPixel(element.anchor.width, PixelToMapped(parent.scaled.width, width))); - element.scaled.height = BoundToBoundless(MappedToPixel(element.anchor.height, PixelToMapped(parent.scaled.height, height))); - element.scaled.x = MappedToPixelBoundless(element.anchor.x, boundlessWidth) - MappedToPixelBoundless(element.anchor.offsetX, element.scaled.width) + PixelToMappedBoundless(parent.scaled.x, width); - element.scaled.y = MappedToPixelBoundless(element.anchor.y, boundlessHeight) - MappedToPixelBoundless(element.anchor.offsetY, element.scaled.height) + PixelToMappedBoundless(parent.scaled.y, height); +void Window::ScaleMouse(MouseElement& element, Transform& parent) { + // element.scaled.width = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.width), parent.scaled.width); + // element.scaled.height = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.height), parent.scaled.height); + // element.scaled.x = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.x), parent.scaled.width) - MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.offsetX), element.scaled.width) + BoundToBoundless(parent.scaled.x); + // element.scaled.y = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.y), parent.scaled.height) - MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.offsetY), element.scaled.height) + BoundToBoundless(parent.scaled.y); + + std::uint32_t mappedParentWidth = AbsoluteToMappedBoundless(parent.scaled.width, width); + std::uint32_t mappedParentHeight = AbsoluteToMappedBoundless(parent.scaled.height, height); + std::uint32_t mappedParentX = AbsoluteToMappedBoundless(parent.scaled.x, width); + std::uint32_t mappedParentY = AbsoluteToMappedBoundless(parent.scaled.y, height); + element.mouseScaled.width = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.width), mappedParentWidth); + element.mouseScaled.height = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.height), mappedParentHeight); + element.mouseScaled.x = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.x), mappedParentWidth) - MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.offsetX), element.mouseScaled.width) + mappedParentX; + element.mouseScaled.y = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.y), mappedParentHeight) - MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.offsetY), element.mouseScaled.height) + mappedParentY; } -void Window::ScaleMouse(Transform& element) { -// std::int_fast32_t boundlessWidth = PixelToMappedBoundless(parent.scaled.width, width); -// std::int_fast32_t boundlessHeight = PixelToMappedBoundless(parent.scaled.height, height); +void Window::ScaleMouse(MouseElement& element) { +// std::int32_t boundlessWidth = PixelToMappedBoundless(parent.scaled.width, width); +// std::int32_t boundlessHeight = PixelToMappedBoundless(parent.scaled.height, height); // element.scaled.width = BoundToBoundless(MappedToPixel(element.anchor.width, width)); // element.scaled.height = BoundToBoundless(MappedToPixel(element.anchor.height, height)); // element.scaled.x = MappedToPixelBoundless(element.anchor.x, boundlessWidth) - MappedToPixelBoundless(element.anchor.offsetX, element.scaled.width) + PixelToMappedBoundless(parent.scaled.x, width); @@ -78,7 +86,7 @@ void Window::LogTiming() { std::cout << std::format("\t{} {}", reinterpret_cast(entry.first), duration_cast(entry.second)) << std::endl; } std::cout << std::format("Render: {}", duration_cast(totalRender)) << std::endl; - for (const std::tuple& entry : renderTimings) { + for (const std::tuple& entry : renderTimings) { std::cout << std::format("\t{} {}x{} {}", reinterpret_cast(std::get<0>(entry)), std::get<1>(entry), std::get<2>(entry), duration_cast(std::get<3>(entry))) << std::endl; } std::cout << std::format("Total: {}", duration_cast(totalUpdate+totalRender)) << std::endl; @@ -112,9 +120,9 @@ void Window::LogTiming() { void Window::AddDirtyRect(ScaleData scale) { ClipRect rect { - .left = std::max(scale.x, std::int_fast32_t(0)), + .left = std::max(scale.x, std::int32_t(0)), .right = std::min(scale.x + scale.width, width), - .top = std::max(scale.y, std::int_fast32_t(0)), + .top = std::max(scale.y, std::int32_t(0)), .bottom = std::min(scale.y + scale.height, height), }; diff --git a/implementations/Crafter.Graphics-Window_wayland.cpp b/implementations/Crafter.Graphics-Window_wayland.cpp index c65c23b..63fc117 100644 --- a/implementations/Crafter.Graphics-Window_wayland.cpp +++ b/implementations/Crafter.Graphics-Window_wayland.cpp @@ -49,11 +49,11 @@ import Crafter.Event; using namespace Crafter; -WindowFramebuffer::WindowFramebuffer(std::uint_fast32_t width, std::uint_fast32_t height) : Window(width, height) { +WindowFramebuffer::WindowFramebuffer(std::uint32_t width, std::uint32_t height) : Window(width, height) { } -WindowWayland::WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height) : WindowFramebuffer(width, height) { +WindowWayland::WindowWayland(std::uint32_t width, std::uint32_t height) : WindowFramebuffer(width, height) { display = wl_display_connect(NULL); if (display == NULL) { std::cerr << "failed to create display" << std::endl; @@ -127,7 +127,7 @@ WindowWayland::WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height wl_surface_commit(surface); } -WindowWayland::WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height, const std::string_view title) : WindowWayland(width, height) { +WindowWayland::WindowWayland(std::uint32_t width, std::uint32_t height, const std::string_view title) : WindowWayland(width, height) { xdg_toplevel_set_title(xdgToplevel, title.data()); } @@ -182,17 +182,17 @@ void WindowWayland::RenderElement(Transform* transform) { dirty.bottom = std::min(element->scaled.y+element->scaled.height, dirty.bottom); const Pixel_BU8_GU8_RU8_AU8* src_buffer = element->buffer.data(); - std::int_fast32_t src_width = element->scaled.width; - std::int_fast32_t src_height = element->scaled.height; + std::int32_t src_width = element->scaled.width; + std::int32_t src_height = element->scaled.height; switch (element->opaque) { case OpaqueType::FullyOpaque: // For fully opaque, just copy pixels directly - for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) { - std::int_fast32_t src_y = y - element->scaled.y; + for (std::int32_t y = dirty.top; y < dirty.bottom; y++) { + std::int32_t src_y = y - element->scaled.y; - for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) { - std::int_fast32_t src_x = x - element->scaled.x; + for (std::int32_t x = dirty.left; x < dirty.right; x++) { + std::int32_t src_x = x - element->scaled.x; framebuffer[y * width + x] = src_buffer[src_y * src_width + src_x]; } @@ -201,11 +201,11 @@ void WindowWayland::RenderElement(Transform* transform) { case OpaqueType::SemiOpaque: // For semi-opaque, we can avoid blending when alpha is 0 or 255 - for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) { - std::int_fast32_t src_y = y - element->scaled.y; + for (std::int32_t y = dirty.top; y < dirty.bottom; y++) { + std::int32_t src_y = y - element->scaled.y; - for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) { - std::int_fast32_t src_x = x - element->scaled.x; + for (std::int32_t x = dirty.left; x < dirty.right; x++) { + std::int32_t src_x = x - element->scaled.x; Pixel_BU8_GU8_RU8_AU8 src_pixel = src_buffer[src_y * src_width + src_x]; if (src_pixel.a == 0) { @@ -218,11 +218,11 @@ void WindowWayland::RenderElement(Transform* transform) { case OpaqueType::Transparent: // For transparent, always perform blending - for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) { - std::int_fast32_t src_y = y - element->scaled.y; + for (std::int32_t y = dirty.top; y < dirty.bottom; y++) { + std::int32_t src_y = y - element->scaled.y; - for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) { - std::int_fast32_t src_x = x - element->scaled.x; + for (std::int32_t x = dirty.left; x < dirty.right; x++) { + std::int32_t src_x = x - element->scaled.x; blend_pixel_optimized(framebuffer[y * width + x], src_buffer[src_y * src_width + src_x]); } } @@ -248,9 +248,9 @@ void WindowWayland::Render() { //std::vector newClip; - // for (std::uint_fast32_t i = 0; i < dirtyRects.size(); i++) { + // for (std::uint32_t i = 0; i < dirtyRects.size(); i++) { // ClipRect rect = dirtyRects[i]; - // for (std::uint_fast32_t i2 = i + 1; i2 < dirtyRects.size(); i2++) { + // for (std::uint32_t i2 = i + 1; i2 < dirtyRects.size(); i2++) { // ClipRect existing = dirtyRects[i2]; // if(rect.bottom >= existing.top && rect.top <= existing.top) { // newClip.push_back({ @@ -337,8 +337,8 @@ void WindowWayland::Render() { // color.r, color.g, color.b, color.a // ) << std::endl; - // for (std::int_fast32_t y = rect.top; y < rect.bottom; ++y) { - // for (std::int_fast32_t x = rect.left; x < rect.right; ++x) { + // for (std::int32_t y = rect.top; y < rect.bottom; ++y) { + // for (std::int32_t x = rect.left; x < rect.right; ++x) { // framebuffer[y * width + x] = color; // } // } @@ -348,8 +348,8 @@ void WindowWayland::Render() { if (!dirtyRects.empty()) { for (ClipRect rect : dirtyRects) { - for (std::int_fast32_t y = rect.top; y < rect.bottom; y++) { - for (std::int_fast32_t x = rect.left; x < rect.right; x++) { + for (std::int32_t y = rect.top; y < rect.bottom; y++) { + for (std::int32_t x = rect.left; x < rect.right; x++) { framebuffer[y * width + x] = {0, 0, 0, 0}; } } @@ -392,7 +392,7 @@ void WindowWayland::SetTitle(const std::string_view title) { xdg_toplevel_set_title(xdgToplevel, title.data()); } -void WindowWayland::Resize(std::uint_fast32_t width, std::uint_fast32_t height) { +void WindowWayland::Resize(std::uint32_t width, std::uint32_t height) { } @@ -400,11 +400,11 @@ void WindowWayland::Write(Pixel_BU8_GU8_RU8_AU8* pixels) { std::memcpy(framebuffer, pixels, width*height*sizeof(Pixel_BU8_GU8_RU8_AU8)); } -void WindowWayland::Write(std::uint_fast32_t x, std::uint_fast32_t y, Pixel_BU8_GU8_RU8_AU8 pixel) { +void WindowWayland::Write(std::uint32_t x, std::uint32_t y, Pixel_BU8_GU8_RU8_AU8 pixel) { framebuffer[y * width + x] = pixel; } -Pixel_BU8_GU8_RU8_AU8 WindowWayland::Read(std::uint_fast32_t x, std::uint_fast32_t y) const{ +Pixel_BU8_GU8_RU8_AU8 WindowWayland::Read(std::uint32_t x, std::uint32_t y) const{ return framebuffer[y * width + x]; } @@ -477,14 +477,15 @@ void WindowWayland::wl_surface_frame_done(void* data, struct wl_callback *cb, ui void WindowWayland::pointer_handle_button(void* data, wl_pointer* pointer, std::uint32_t serial, std::uint32_t time, std::uint32_t button, std::uint32_t state) { WindowWayland* window = reinterpret_cast(data); + if (button == BTN_LEFT) { if(state == WL_POINTER_BUTTON_STATE_PRESSED) { window->mouseLeftHeld = true; window->onMouseLeftClick.Invoke(window->currentMousePos); for(MouseElement* element : window->mouseElements) { if(element) { - if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) { - element->onMouseLeftClick.Invoke({FractionalToMappedBoundless(static_cast(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast(window->currentMousePos.y - element->scaled.y) / element->scaled.height)}); + if(window->currentMousePos.x >= element->mouseScaled.x && window->currentMousePos.x <= element->mouseScaled.x+element->mouseScaled.width && window->currentMousePos.y > element->mouseScaled.y && window->currentMousePos.y < element->mouseScaled.y+element->mouseScaled.height) { + element->onMouseLeftClick.Invoke({AbsoluteToMappedBoundless(window->currentMousePos.x - element->mouseScaled.x, element->mouseScaled.width), AbsoluteToMappedBoundless(window->currentMousePos.y - element->mouseScaled.y, element->mouseScaled.height)}); } } } @@ -493,8 +494,8 @@ void WindowWayland::pointer_handle_button(void* data, wl_pointer* pointer, std:: window->onMouseLeftRelease.Invoke(window->currentMousePos); for(MouseElement* element : window->mouseElements) { if(element) { - if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) { - element->onMouseLeftRelease.Invoke({FractionalToMappedBoundless(static_cast(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast(window->currentMousePos.y - element->scaled.y) / element->scaled.height)}); + if(window->currentMousePos.x >= element->mouseScaled.x && window->currentMousePos.x <= element->mouseScaled.x+element->mouseScaled.width && window->currentMousePos.y > element->mouseScaled.y && window->currentMousePos.y < element->mouseScaled.y+element->mouseScaled.height) { + element->onMouseLeftRelease.Invoke({AbsoluteToMappedBoundless(window->currentMousePos.x - element->mouseScaled.x, element->mouseScaled.width), AbsoluteToMappedBoundless(window->currentMousePos.y - element->mouseScaled.y, element->mouseScaled.height)}); } } } @@ -505,8 +506,8 @@ void WindowWayland::pointer_handle_button(void* data, wl_pointer* pointer, std:: window->onMouseRightClick.Invoke(window->currentMousePos); for(MouseElement* element : window->mouseElements) { if(element) { - if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) { - element->onMouseRightClick.Invoke({FractionalToMappedBoundless(static_cast(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast(window->currentMousePos.y - element->scaled.y) / element->scaled.height)}); + if(window->currentMousePos.x >= element->mouseScaled.x && window->currentMousePos.x <= element->mouseScaled.x+element->mouseScaled.width && window->currentMousePos.y > element->mouseScaled.y && window->currentMousePos.y < element->mouseScaled.y+element->mouseScaled.height) { + element->onMouseRightClick.Invoke({AbsoluteToMappedBoundless(window->currentMousePos.x - element->mouseScaled.x, element->mouseScaled.width), AbsoluteToMappedBoundless(window->currentMousePos.y - element->mouseScaled.y, element->mouseScaled.height)}); } } } @@ -515,8 +516,8 @@ void WindowWayland::pointer_handle_button(void* data, wl_pointer* pointer, std:: window->onMouseRightRelease.Invoke(window->currentMousePos); for(MouseElement* element : window->mouseElements) { if(element) { - if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) { - element->onMouseRightRelease.Invoke({FractionalToMappedBoundless(static_cast(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast(window->currentMousePos.y - element->scaled.y) / element->scaled.height)}); + if(window->currentMousePos.x >= element->mouseScaled.x && window->currentMousePos.x <= element->mouseScaled.x+element->mouseScaled.width && window->currentMousePos.y > element->mouseScaled.y && window->currentMousePos.y < element->mouseScaled.y+element->mouseScaled.height) { + element->onMouseRightRelease.Invoke({AbsoluteToMappedBoundless(window->currentMousePos.x - element->mouseScaled.x, element->mouseScaled.width), AbsoluteToMappedBoundless(window->currentMousePos.y - element->mouseScaled.y, element->mouseScaled.height)}); } } } @@ -529,20 +530,20 @@ void WindowWayland::pointer_handle_button(void* data, wl_pointer* pointer, std:: void WindowWayland::PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, uint time, wl_fixed_t surface_x, wl_fixed_t surface_y) { WindowWayland* window = reinterpret_cast(data); - MousePoint pos = {FractionalToMappedBoundless((wl_fixed_to_double(surface_x) * window->scale) / window->width), FractionalToMappedBoundless((wl_fixed_to_double(surface_y) * window->scale) / window->height)}; + MousePoint pos = {FractionalToMappedBoundless((wl_fixed_to_double(surface_x) * window->scale) / window->width), FractionalToMappedBoundless((wl_fixed_to_double(surface_y) * window->scale) / window->height)}; window->lastMousePos = window->currentMousePos; window->currentMousePos = pos; window->mouseDelta = {window->currentMousePos.x-window->lastMousePos.x, window->currentMousePos.y-window->lastMousePos.y}; window->onMouseMove.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); for(MouseElement* element : window->mouseElements) { if(element) { - if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) { - element->onMouseMove.Invoke({FractionalToMappedBoundless(static_cast(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast(window->currentMousePos.y - element->scaled.y) / element->scaled.height)}); - if(!(window->lastMousePos.x >= element->scaled.x && window->lastMousePos.x <= element->scaled.x+element->scaled.width && window->lastMousePos.y > element->scaled.y && window->lastMousePos.y < element->scaled.y+element->scaled.height)) { - element->onMouseEnter.Invoke({FractionalToMappedBoundless(static_cast(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast(window->currentMousePos.y - element->scaled.y) / element->scaled.height)}); + if(window->currentMousePos.x >= element->mouseScaled.x && window->currentMousePos.x <= element->mouseScaled.x+element->mouseScaled.width && window->currentMousePos.y > element->mouseScaled.y && window->currentMousePos.y < element->mouseScaled.y+element->mouseScaled.height) { + element->onMouseMove.Invoke({AbsoluteToMappedBoundless(window->currentMousePos.x - element->mouseScaled.x, element->mouseScaled.width), AbsoluteToMappedBoundless(window->currentMousePos.y - element->mouseScaled.y, element->mouseScaled.height)}); + if(!(window->lastMousePos.x >= element->mouseScaled.x && window->lastMousePos.x <= element->mouseScaled.x+element->mouseScaled.width && window->lastMousePos.y > element->mouseScaled.y && window->lastMousePos.y < element->mouseScaled.y+element->mouseScaled.height)) { + element->onMouseEnter.Invoke({AbsoluteToMappedBoundless(window->currentMousePos.x - element->mouseScaled.x, element->mouseScaled.width), AbsoluteToMappedBoundless(window->currentMousePos.y - element->mouseScaled.y, element->mouseScaled.height)}); } - } else if(window->lastMousePos.x >= element->scaled.x && window->lastMousePos.x <= element->scaled.x+element->scaled.width && window->lastMousePos.y > element->scaled.y && window->lastMousePos.y < element->scaled.y+element->scaled.height) { - element->onMouseLeave.Invoke({FractionalToMappedBoundless(static_cast(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast(window->currentMousePos.y - element->scaled.y) / element->scaled.height)}); + } else if(window->lastMousePos.x >= element->mouseScaled.x && window->lastMousePos.x <= element->mouseScaled.x+element->mouseScaled.width && window->lastMousePos.y > element->mouseScaled.y && window->lastMousePos.y < element->mouseScaled.y+element->mouseScaled.height) { + element->onMouseLeave.Invoke({AbsoluteToMappedBoundless(window->currentMousePos.x - element->mouseScaled.x, element->mouseScaled.width), AbsoluteToMappedBoundless(window->currentMousePos.y - element->mouseScaled.y, element->mouseScaled.height)}); } } } @@ -556,7 +557,7 @@ void WindowWayland::PointerListenerHandleEnter(void* data, wl_pointer* wl_pointe void WindowWayland::PointerListenerHandleLeave(void* data, wl_pointer*, std::uint32_t, wl_surface*) { WindowWayland* window = reinterpret_cast(data); - window->onMouseEnter.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); + window->onMouseLeave.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); } void WindowWayland::PointerListenerHandleAxis(void*, wl_pointer*, std::uint32_t, std::uint32_t, wl_fixed_t value) { diff --git a/interfaces/Crafter.Graphics-GridElement.cppm b/interfaces/Crafter.Graphics-GridElement.cppm index 1168dd4..6433c9a 100644 --- a/interfaces/Crafter.Graphics-GridElement.cppm +++ b/interfaces/Crafter.Graphics-GridElement.cppm @@ -25,13 +25,13 @@ import :Types; export namespace Crafter { class GridElement : public Transform { public: - std::uint_fast32_t columns; - std::uint_fast32_t rows; - std::int_fast32_t spacingX; - std::int_fast32_t spacingY; - std::int_fast32_t paddingX; - std::int_fast32_t paddingY; - GridElement(std::uint_fast32_t columns, std::uint_fast32_t rows, std::int_fast32_t spacingX, std::int_fast32_t spacingY, std::int_fast32_t paddingX, std::int_fast32_t paddingY, Anchor anchor); + std::uint32_t columns; + std::uint32_t rows; + std::int32_t spacingX; + std::int32_t spacingY; + std::int32_t paddingX; + std::int32_t paddingY; + GridElement(std::uint32_t columns, std::uint32_t rows, std::int32_t spacingX, std::int32_t spacingY, std::int32_t paddingX, std::int32_t paddingY, Anchor anchor); void UpdatePositionScaled(Window& window); void UpdatePosition(Window& window) override; void UpdatePosition(Window& window, Transform& parent) override; diff --git a/interfaces/Crafter.Graphics-MouseElement.cppm b/interfaces/Crafter.Graphics-MouseElement.cppm index cafa295..97f3220 100644 --- a/interfaces/Crafter.Graphics-MouseElement.cppm +++ b/interfaces/Crafter.Graphics-MouseElement.cppm @@ -37,6 +37,7 @@ export namespace Crafter { Event onMouseLeftHold; Event onMouseRightRelease; Event onMouseLeftRelease; + ScaleDataBoundless mouseScaled; MouseElement(); MouseElement(WindowMouse& window); diff --git a/interfaces/Crafter.Graphics-RenderingElement.cppm b/interfaces/Crafter.Graphics-RenderingElement.cppm index 9a4e57e..5a8640d 100644 --- a/interfaces/Crafter.Graphics-RenderingElement.cppm +++ b/interfaces/Crafter.Graphics-RenderingElement.cppm @@ -20,41 +20,61 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA module; #define STB_IMAGE_IMPLEMENTATION #include "../lib/stb_image.h" +#include "../lib/stb_truetype.h" export module Crafter.Graphics:RenderingElement; import std; import :Transform; +import :Font; import :Types; import :Image; import :Window; export namespace Crafter { + enum class TextAlignment { + Left, + Center, + Right + }; + + enum class TextOverflowMode { + Clip, + Wrap + }; + + enum class TextScaleMode { + None, + Font, + Element, + Buffer + }; + struct RenderElementScalingOwning { std::vector scalingBuffer; - std::uint_fast32_t bufferWidth; - std::uint_fast32_t bufferHeight; + std::uint32_t bufferWidth; + std::uint32_t bufferHeight; bool bufferUpdated = true; RenderElementScalingOwning() = default; - RenderElementScalingOwning(std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight) : scalingBuffer(bufferWidth*bufferHeight), bufferWidth(bufferWidth), bufferHeight(bufferHeight) { + RenderElementScalingOwning(std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(bufferWidth*bufferHeight), bufferWidth(bufferWidth), bufferHeight(bufferHeight) { } }; struct RenderElementScalingNonOwning { Pixel_BU8_GU8_RU8_AU8* scalingBuffer; - std::uint_fast32_t bufferWidth; - std::uint_fast32_t bufferHeight; + std::uint32_t bufferWidth; + std::uint32_t bufferHeight; bool bufferUpdated = true; RenderElementScalingNonOwning() = default; - RenderElementScalingNonOwning(Pixel_BU8_GU8_RU8_AU8* scalingBuffer, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight) : scalingBuffer(scalingBuffer), bufferWidth(bufferWidth), bufferHeight(bufferHeight) { + RenderElementScalingNonOwning(Pixel_BU8_GU8_RU8_AU8* scalingBuffer, std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(scalingBuffer), bufferWidth(bufferWidth), bufferHeight(bufferHeight) { } }; struct RenderElementRotating { - std::uint_fast32_t rotation; + std::uint32_t rotation; bool rotationUpdated = true; RenderElementRotating() = default; - RenderElementRotating(std::uint_fast32_t rotation) : rotation(rotation) { + RenderElementRotating(std::uint32_t rotation) : rotation(rotation) { } }; @@ -100,49 +120,49 @@ export namespace Crafter { RenderingElement(Anchor anchor, OpaqueType opaque) : RenderingElementBase(anchor, opaque) { } - RenderingElement(Anchor anchor, OpaqueType opaque, std::uint_fast32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase(rotation) { + RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase(rotation) { } 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) : RenderingElementBase(anchor), RotatingBase(rotation) { + RenderingElement(Anchor anchor, const std::string_view imagePath, std::uint32_t rotation) requires(Rotating) : RenderingElementBase(anchor), RotatingBase(rotation) { LoadImage(imagePath); } RenderingElement(Anchor anchor, const std::string_view imagePath, OpaqueType opaque) : RenderingElementBase(anchor, opaque) { LoadImageNoOpaqueCheck(imagePath); } - RenderingElement(Anchor anchor, const std::string_view imagePath, OpaqueType opaque, std::uint_fast32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase(rotation) { + RenderingElement(Anchor anchor, const std::string_view imagePath, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase(rotation) { LoadImageNoOpaqueCheck(imagePath); } - RenderingElement(Anchor anchor, OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, Pixel_BU8_GU8_RU8_AU8* scalingBuffer) requires(Scaling && !Owning) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer) { + RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Pixel_BU8_GU8_RU8_AU8* scalingBuffer) requires(Scaling && !Owning) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer) { } - RenderingElement(Anchor anchor, OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, Pixel_BU8_GU8_RU8_AU8* scalingBuffer, std::uint_fast32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer), RotatingBase(rotation) { + RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Pixel_BU8_GU8_RU8_AU8* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer), RotatingBase(rotation) { } 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, OpaqueType opaque, Image& image, std::uint32_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, Image& image, std::uint32_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) { + RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight) { } - RenderingElement(Anchor anchor, OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::uint_fast32_t rotation) requires(Owning && Rotating) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight) , RotatingBase(rotation) { + RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, std::uint32_t rotation) requires(Owning && Rotating) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight) , RotatingBase(rotation) { } @@ -150,20 +170,20 @@ export namespace Crafter { RenderingElement& operator=(RenderingElement&) = delete; void ScaleNearestNeighbor() requires(Scaling) { - for (std::uint_fast32_t y = 0; y < scaled.height; y++) { - std::uint_fast32_t srcY = y * ScalingBase::bufferHeight / scaled.height; - for (std::uint_fast32_t x = 0; x < scaled.width; x++) { - std::uint_fast32_t srcX = x * ScalingBase::bufferWidth / scaled.width; + for (std::uint32_t y = 0; y < scaled.height; y++) { + std::uint32_t srcY = y * ScalingBase::bufferHeight / scaled.height; + for (std::uint32_t x = 0; x < scaled.width; x++) { + std::uint32_t srcX = x * ScalingBase::bufferWidth / scaled.width; buffer[y * scaled.width + x] = ScalingBase::scalingBuffer[srcY * ScalingBase::bufferWidth + srcX]; } } } void ScaleRotating() requires(Scaling) { - const double rad = (static_cast(RotatingBase::rotation) / static_cast(std::numeric_limits::max())) * 2.0 * std::numbers::pi; + const double rad = (static_cast(RotatingBase::rotation) / static_cast(std::numeric_limits::max())) * 2.0 * std::numbers::pi; - const std::uint_fast32_t dstWidth = scaled.width; - const std::uint_fast32_t dstHeight = scaled.height; + const std::uint32_t dstWidth = scaled.width; + const std::uint32_t dstHeight = scaled.height; const double c2 = std::abs(std::cos(rad)); const double s2 = std::abs(std::sin(rad)); @@ -171,8 +191,8 @@ export namespace Crafter { const double rotatedWidth = dstWidth * c2 + dstHeight * s2; const double rotatedHeight = dstWidth * s2 + dstHeight * c2; - const std::uint_fast32_t diffX = static_cast(std::ceil((rotatedWidth - dstWidth) * 0.5)); - const std::uint_fast32_t diffY = static_cast(std::ceil((rotatedHeight - dstHeight) * 0.5)); + const std::uint32_t diffX = static_cast(std::ceil((rotatedWidth - dstWidth) * 0.5)); + const std::uint32_t diffY = static_cast(std::ceil((rotatedHeight - dstHeight) * 0.5)); scaled.width += diffX + diffX; scaled.height += diffY + diffY; @@ -198,8 +218,8 @@ export namespace Crafter { const double scaleX = static_cast(ScalingBase::bufferWidth) / dstWidth; const double scaleY = static_cast(ScalingBase::bufferHeight) / dstHeight; - for (std::uint_fast32_t yB = 0; yB < scaled.height; ++yB) { - for (std::uint_fast32_t xB = 0; xB < scaled.width; ++xB) { + for (std::uint32_t yB = 0; yB < scaled.height; ++yB) { + for (std::uint32_t xB = 0; xB < scaled.width; ++xB) { // ---- Destination pixel relative to center ---- const double dx = (static_cast(xB) - dstCx) * scaleX; @@ -210,8 +230,8 @@ export namespace Crafter { const double sy = (s * dx + c * dy) + srcCy; // ---- Nearest neighbour sampling ---- - const std::int_fast32_t srcX = static_cast(std::round(sx)); - const std::int_fast32_t srcY = static_cast(std::round(sy)); + const std::int32_t srcX = static_cast(std::round(sx)); + const std::int32_t srcY = static_cast(std::round(sy)); if (srcX >= 0 && srcX < ScalingBase::bufferWidth && srcY >= 0 && srcY < ScalingBase::bufferHeight) { buffer[yB * scaled.width + xB] = ScalingBase::scalingBuffer[srcY * ScalingBase::bufferWidth + srcX]; @@ -308,9 +328,9 @@ export namespace Crafter { opaque = OpaqueType::FullyOpaque; if constexpr(Scaling) { - 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; + for(std::uint32_t x = 0; x < xSize; x++) { + for(std::uint32_t y = 0; y < ySize; y++) { + std::uint32_t idx = (x*ySize+y)*4; 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]; @@ -318,10 +338,10 @@ export namespace Crafter { } } - for(std::uint_fast32_t i = 0; i < xSize*ySize; i++) { + for(std::uint32_t i = 0; i < xSize*ySize; i++) { if(ScalingBase::scalingBuffer[i].a != 255) { opaque = OpaqueType::SemiOpaque; - for(std::uint_fast32_t i2 = 0; i2 < xSize*ySize; i2++) { + for(std::uint32_t i2 = 0; i2 < xSize*ySize; i2++) { if(ScalingBase::scalingBuffer[i2].a != 0 && ScalingBase::scalingBuffer[i2].a != 255) { opaque = OpaqueType::Transparent; return; @@ -331,9 +351,9 @@ export namespace Crafter { } } } else { - 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; + for(std::uint32_t x = 0; x < xSize; x++) { + for(std::uint32_t y = 0; y < ySize; y++) { + std::uint32_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]; @@ -341,10 +361,10 @@ export namespace Crafter { } } - for(std::uint_fast32_t i = 0; i < xSize*ySize; i++) { + for(std::uint32_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++) { + for(std::uint32_t i2 = 0; i2 < xSize*ySize; i2++) { if(buffer[i2].a != 0 && buffer[i2].a != 255) { opaque = OpaqueType::Transparent; return; @@ -375,9 +395,9 @@ export namespace Crafter { if constexpr(Scaling) { - 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; + for(std::uint32_t x = 0; x < xSize; x++) { + for(std::uint32_t y = 0; y < ySize; y++) { + std::uint32_t idx = (x*ySize+y)*4; 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]; @@ -385,9 +405,9 @@ export namespace Crafter { } } } else { - 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; + for(std::uint32_t x = 0; x < xSize; x++) { + for(std::uint32_t y = 0; y < ySize; y++) { + std::uint32_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]; @@ -396,5 +416,238 @@ export namespace Crafter { } } } + std::vector ResizeText(Window& window, const std::string_view text, float size, Font& font, TextOverflowMode overflowMode = TextOverflowMode::Clip, TextScaleMode scaleMode = TextScaleMode::None, Transform* parent = nullptr) { + float scale = stbtt_ScaleForPixelHeight(&font.font, size); + int baseline = (int)(font.ascent * scale); + + std::vector lines; + std::string_view remaining = text; + + std::uint32_t lineHeight = (font.ascent - font.descent) * scale; + + if(overflowMode == TextOverflowMode::Clip) { + while (!remaining.empty()) { + // Find next newline or end of string + auto newlinePos = remaining.find('\n'); + if (newlinePos != std::string_view::npos) { + lines.emplace_back(remaining.substr(0, newlinePos)); + remaining = remaining.substr(newlinePos + 1); + } else { + lines.emplace_back(remaining); + break; + } + } + std::uint32_t maxWidth = 0; + + for(const std::string_view line: lines) { + std::uint32_t lineWidth = 0; + for (const char c : line) { + int advance, lsb; + stbtt_GetCodepointHMetrics(&font.font, c, &advance, &lsb); + lineWidth += (int)(advance * scale); + } + if(lineWidth > maxWidth) { + maxWidth = lineWidth; + } + } + + + if(scaleMode == TextScaleMode::Element) { + std::int32_t logicalPerPixelY = anchor.height / scaled.height; + std::int32_t oldHeight = anchor.height; + std::int32_t logicalPerPixelX = anchor.width / scaled.width; + std::int32_t oldwidth = anchor.width; + anchor.height = lineHeight * logicalPerPixelY; + anchor.width = maxWidth * logicalPerPixelX; + if(oldHeight != anchor.height || oldwidth != anchor.width) { + if(parent) { + UpdatePosition(window, *parent); + } else { + UpdatePosition(window); + } + } + } else if(scaleMode == TextScaleMode::Font) { + //todo + } else if(scaleMode == TextScaleMode::Buffer) { + if constexpr(Scaling && Owning) { + std::uint32_t neededHeight = lines.size() * lineHeight; + if(neededHeight != ScalingBase::bufferHeight || maxWidth != ScalingBase::bufferWidth) { + ScalingBase::bufferHeight = neededHeight; + ScalingBase::bufferWidth = maxWidth; + ScalingBase::bufferUpdated = true; + ScalingBase::scalingBuffer.resize(neededHeight*maxWidth); + } + } + } else { + if constexpr(Scaling) { + lines.resize(ScalingBase::bufferHeight / lines.size()); + } else { + lines.resize(scaled.height / lines.size()); + } + } + } else { + while (!remaining.empty()) { + std::string_view line; + auto newlinePos = remaining.find('\n'); + if (newlinePos != std::string_view::npos) { + line = remaining.substr(0, newlinePos); + remaining = remaining.substr(newlinePos + 1); + } else { + line = remaining; + remaining = ""; + } + + std::uint32_t lineWidth = 0; + std::size_t lastWrapPos = 0; // position of last space that can be used to wrap + std::size_t startPos = 0; + + for (std::size_t i = 0; i < line.size(); ++i) { + char c = line[i]; + + // get width of this character + int advance, lsb; + stbtt_GetCodepointHMetrics(&font.font, c, &advance, &lsb); + lineWidth += (std::uint32_t)(advance * scale); + + // remember last space for wrapping + if (c == ' ') { + lastWrapPos = i; + } + + // if line exceeds width, wrap + if (lineWidth > scaled.width) { + std::size_t wrapPos; + if (lastWrapPos > startPos) { + wrapPos = lastWrapPos; // wrap at last space + } else { + wrapPos = i; // no space, hard wrap + } + + // push the line up to wrapPos + lines.push_back(line.substr(startPos, wrapPos - startPos)); + + // skip any spaces at the beginning of next line + startPos = wrapPos; + while (startPos < line.size() && line[startPos] == ' ') { + ++startPos; + } + + // reset width and i + lineWidth = 0; + i = startPos - 1; // -1 because loop will increment i + } + } + + // add the remaining part of the line + if (startPos < line.size()) { + lines.push_back(line.substr(startPos)); + } + } + + if(scaleMode == TextScaleMode::Element) { + std::int32_t logicalPerPixelY = anchor.height / scaled.height; + std::int32_t oldHeight = anchor.height; + anchor.height = lineHeight * logicalPerPixelY; + if(oldHeight != anchor.height) { + if(parent) { + UpdatePosition(window, *parent); + } else { + UpdatePosition(window); + } + } + } else if(scaleMode == TextScaleMode::Font) { + //todo + } else if(scaleMode == TextScaleMode::Buffer) { + if constexpr(Scaling && Owning) { + std::uint32_t neededHeight = lines.size() * lineHeight; + if(neededHeight != ScalingBase::bufferHeight) { + ScalingBase::bufferHeight = neededHeight; + ScalingBase::bufferUpdated = true; + ScalingBase::scalingBuffer.resize(neededHeight*ScalingBase::bufferWidth); + } + } + } else { + if constexpr(Scaling) { + lines.resize(ScalingBase::bufferHeight / lines.size()); + } else { + lines.resize(scaled.height / lines.size()); + } + } + } + + return lines; + } + void RenderText(Window& window, std::span lines, float size, Pixel_BU8_GU8_RU8_AU8 color, Font& font, TextAlignment alignment = TextAlignment::Left, std::uint32_t offsetX = 0, std::uint32_t offsetY = 0) { + float scale = stbtt_ScaleForPixelHeight(&font.font, size); + int baseline = (int)(font.ascent * scale); + std::uint32_t lineHeight = (font.ascent - font.descent) * scale; + std::uint32_t currentY = baseline; + for(std::string_view line : lines) { + + std::uint32_t lineWidth = 0; + for (const char c : line) { + int advance, lsb; + stbtt_GetCodepointHMetrics(&font.font, c, &advance, &lsb); + lineWidth += (int)(advance * scale); + } + + std::uint32_t startX = 0; + switch (alignment) { + case TextAlignment::Left: + startX = 0; + break; + case TextAlignment::Center: + startX = (scaled.width - lineWidth) / 2; + break; + case TextAlignment::Right: + startX = scaled.width - lineWidth; + break; + } + std::uint32_t x = startX; + + for (std::size_t i = 0; i < line.size(); ++i) { + int codepoint = line[i]; + + int ax; + int lsb; + stbtt_GetCodepointHMetrics(&font.font, codepoint, &ax, &lsb); + + int c_x1, c_y1, c_x2, c_y2; + stbtt_GetCodepointBitmapBox(&font.font, codepoint, scale, scale, &c_x1, &c_y1, &c_x2, &c_y2); + + int w = c_x2 - c_x1; + int h = c_y2 - c_y1; + + std::vector bitmap(w * h); + stbtt_MakeCodepointBitmap(&font.font, bitmap.data(), w, h, w, scale, scale, codepoint); + + // Only render characters that fit within the scaled bounds + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + int bufferX = x + i + c_x1 + offsetX; + int bufferY = currentY + j + c_y1 + offsetY; + + // Only draw pixels that are within our scaled buffer bounds + if constexpr(Scaling) { + if (bufferX >= 0 && bufferX < ScalingBase::bufferWidth && bufferY >= 0 && bufferY < ScalingBase::bufferHeight) { + ScalingBase::scalingBuffer[bufferY * ScalingBase::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]}; + } + } else { + if (bufferX >= 0 && bufferX < (int)scaled.width && bufferY >= 0 && bufferY < (int)scaled.height) { + buffer[bufferY * scaled.width + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]}; + } + } + } + } + + x += (int)(ax * scale); + + if (i + 1 < line.size()) { + x += (int)stbtt_GetCodepointKernAdvance(&font.font, codepoint, line[i+1]); + } + } + currentY += lineHeight; + } + } }; } \ No newline at end of file diff --git a/interfaces/Crafter.Graphics-TextElement.cppm b/interfaces/Crafter.Graphics-TextElement.cppm deleted file mode 100644 index f77f298..0000000 --- a/interfaces/Crafter.Graphics-TextElement.cppm +++ /dev/null @@ -1,51 +0,0 @@ -/* -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 version 3.0 as published by the Free Software Foundation; - -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:TextElement; -import std; -import :RenderingElement; -import :Types; -import :Font; - -export namespace Crafter { - enum class TextAlignment { - Left, - Center, - Right - }; - - enum class VerticalTextAlignment { - Top, - Middle, - Bottom - }; - - enum class TextOverflowMode { - Clip, // Clip text that overflows - Wrap // Wrap text to multiple lines - }; - - class TextElement : public RenderingElement { - private: - void RenderWrappedLine(const std::string_view line, float scale, int baseline, std::uint_fast32_t startY, Pixel_BU8_GU8_RU8_AU8 color, Font& font, TextAlignment alignment); - public: - TextElement(Anchor anchor); - void RenderText(Window& window, const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font, TextAlignment alignment = TextAlignment::Left, VerticalTextAlignment verticalAlignment = VerticalTextAlignment::Top, TextOverflowMode overflowMode = TextOverflowMode::Clip); - }; -} \ No newline at end of file diff --git a/interfaces/Crafter.Graphics-Transform.cppm b/interfaces/Crafter.Graphics-Transform.cppm index 0b338f1..fc8fc8f 100644 --- a/interfaces/Crafter.Graphics-Transform.cppm +++ b/interfaces/Crafter.Graphics-Transform.cppm @@ -24,16 +24,16 @@ import :Types; export namespace Crafter { class Window; struct Anchor { - std::int_fast32_t x; - std::int_fast32_t y; - std::uint_fast32_t width; - std::uint_fast32_t height; - std::int_fast32_t offsetX; - std::int_fast32_t offsetY; - std::int_fast32_t z; + std::int32_t x; + std::int32_t y; + std::uint32_t width; + std::uint32_t height; + std::int32_t offsetX; + std::int32_t offsetY; + std::int32_t z; bool maintainAspectRatio; Anchor() = default; - Anchor(std::int_fast32_t x, std::int_fast32_t y, std::uint_fast32_t width, std::uint_fast32_t height, std::int_fast32_t offsetX, std::int_fast32_t offsetY, std::int_fast32_t z, bool maintainAspectRatio = false); + Anchor(std::int32_t x, std::int32_t y, std::uint32_t width, std::uint32_t height, std::int32_t offsetX, std::int32_t offsetY, std::int32_t z, bool maintainAspectRatio = false); }; class Transform { public: diff --git a/interfaces/Crafter.Graphics-Types.cppm b/interfaces/Crafter.Graphics-Types.cppm index e8776b2..fb00ed9 100644 --- a/interfaces/Crafter.Graphics-Types.cppm +++ b/interfaces/Crafter.Graphics-Types.cppm @@ -21,53 +21,65 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA export module Crafter.Graphics:Types; import std; -namespace Crafter { - export struct MousePoint { - std::int_fast32_t x; - std::int_fast32_t y; +export namespace Crafter { + struct MousePoint { + std::uint32_t x; + std::uint32_t y; + }; + + struct MouseDelta { + std::int64_t x; + std::int64_t y; }; - export struct MouseMoveEvent { + struct MouseMoveEvent { MousePoint lastMousePos; MousePoint currentMousePos; - MousePoint mouseDelta; + MouseDelta mouseDelta; }; - export struct ScaleData { - std::int_fast32_t x; - std::int_fast32_t y; - std::int_fast32_t width; - std::int_fast32_t height; + struct ScaleData { + std::int32_t x; + std::int32_t y; + std::int32_t width; + std::int32_t height; }; - export struct ClipRect { - std::int_fast32_t left; - std::int_fast32_t right; - std::int_fast32_t top; - std::int_fast32_t bottom; + struct ScaleDataBoundless { + std::uint32_t x; + std::uint32_t y; + std::uint32_t width; + std::uint32_t height; + }; + + struct ClipRect { + std::int32_t left; + std::int32_t right; + std::int32_t top; + std::int32_t bottom; }; - export struct __attribute__((packed)) Pixel_BU8_GU8_RU8_AU8 { + struct __attribute__((packed)) Pixel_BU8_GU8_RU8_AU8 { std::uint8_t b; std::uint8_t g; std::uint8_t r; std::uint8_t a; }; - export struct __attribute__((packed)) Pixel_RU8_GU8_BU8_AU8 { + struct __attribute__((packed)) Pixel_RU8_GU8_BU8_AU8 { std::uint8_t r; std::uint8_t g; std::uint8_t b; std::uint8_t a; }; - export struct __attribute__((packed)) Vertex { + struct __attribute__((packed)) Vertex { float x; float y; float z; float w; }; - export struct __attribute__((packed)) VertexUV { + struct __attribute__((packed)) VertexUV { float x; float y; float z; @@ -79,7 +91,7 @@ namespace Crafter { float pad[2]; }; - export struct __attribute__((packed)) VertexRGBA { + struct __attribute__((packed)) VertexRGBA { float x; float y; float z; @@ -91,7 +103,7 @@ namespace Crafter { float a; }; - export struct __attribute__((packed)) HeightRGBA { + struct __attribute__((packed)) HeightRGBA { float height; float pad[3]; @@ -102,97 +114,190 @@ namespace Crafter { float a; }; - export struct FrameTime { + struct FrameTime { std::chrono::time_point now; std::chrono::duration delta; }; - export enum class OpaqueType { + 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; - export constexpr double SCALEDOUBLE = static_cast(std::numeric_limits::max()) / BOUND; - export constexpr double SCALEDOUBLEU = static_cast(std::numeric_limits::max()) / BOUND; - export constexpr std::int_fast32_t SCALEBOUNDLESS = std::numeric_limits::max(); - export constexpr double SCALEDOUBLEBOUNDLESS = static_cast(std::numeric_limits::max()); + constexpr std::int8_t BOUND8 = 9; + constexpr std::int8_t SCALE8 = std::numeric_limits::max() / BOUND8; + constexpr std::uint8_t SCALEBOUNDLESS8 = std::numeric_limits::max(); - export constexpr std::int_fast32_t SCALEBOUNDLESSU = std::numeric_limits::max(); - export constexpr double SCALEDOUBLEBOUNDLESSU = static_cast(std::numeric_limits::max()); + constexpr double SCALEDOUBLE8 = static_cast(std::numeric_limits::max() / BOUND8); + constexpr double SCALEBOUNDLESSDOUBLE8 = static_cast(std::numeric_limits::max()); - export constexpr std::int_fast32_t FractionalToMapped(double f) { - return std::int_fast32_t(f * SCALEDOUBLE); + constexpr std::int16_t BOUND16 = 9; + constexpr std::int16_t SCALE16 = std::numeric_limits::max() / BOUND16; + constexpr std::uint16_t SCALEBOUNDLESS16 = std::numeric_limits::max(); + + constexpr double SCALEDOUBLE16 = static_cast(std::numeric_limits::max() / BOUND16); + constexpr double SCALEBOUNDLESSDOUBLE16 = static_cast(std::numeric_limits::max()); + + constexpr std::int32_t BOUND32 = 9; + constexpr std::int32_t SCALE32 = std::numeric_limits::max() / BOUND32; + constexpr std::uint32_t SCALEBOUNDLESS32 = std::numeric_limits::max(); + + constexpr double SCALEDOUBLE32 = static_cast(std::numeric_limits::max() / BOUND32); + constexpr double SCALEBOUNDLESSDOUBLE32 = static_cast(std::numeric_limits::max()); + + constexpr std::int64_t BOUND64 = 9; + constexpr std::int64_t SCALE64 = std::numeric_limits::max() / BOUND64; + constexpr std::uint64_t SCALEBOUNDLESS64 = std::numeric_limits::max(); + + constexpr double SCALEDOUBLE64 = static_cast(std::numeric_limits::max() / BOUND64); + constexpr double SCALEBOUNDLESSDOUBLE64 = static_cast(std::numeric_limits::max()); + + template + constexpr T FractionalToMapped(double f) requires(std::is_integral_v) { + if constexpr (std::is_same_v || std::is_same_v) { + return T(f * SCALEDOUBLE8); + } else if constexpr (std::is_same_v || std::is_same_v) { + return T(f * SCALEDOUBLE16); + } else if constexpr (std::is_same_v || std::is_same_v) { + return T(f * SCALEDOUBLE32); + } else { + return T(f * SCALEDOUBLE64); + } } - export constexpr std::uint_fast32_t FractionalToMappedU(double f) { - return std::uint_fast32_t(f * SCALEDOUBLEU); + template + constexpr T FractionalToMappedBoundless(double f) requires(std::is_integral_v) { + if constexpr (std::is_same_v || std::is_same_v) { + return T(f * SCALEBOUNDLESSDOUBLE8); + } else if constexpr (std::is_same_v || std::is_same_v) { + return T(f * SCALEBOUNDLESSDOUBLE16); + } else if constexpr (std::is_same_v || std::is_same_v) { + return T(f * SCALEBOUNDLESSDOUBLE32); + } else { + return T(f * SCALEBOUNDLESSDOUBLE64); + } } - export constexpr double MappedToFractional(std::int_fast32_t mapped) { - return static_cast(mapped) / SCALEDOUBLE; + template + constexpr double MappedToFractional(T mapped) requires(std::is_integral_v) { + if constexpr (std::is_same_v || std::is_same_v) { + return mapped / SCALEDOUBLE8; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped / SCALEDOUBLE16; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped / SCALEDOUBLE32; + } else { + return mapped / SCALEDOUBLE64; + } } - export constexpr std::int_fast32_t MappedToPixel(std::int_fast32_t mapped, std::int_fast32_t width) { - return mapped / (SCALE / width); + template + constexpr double MappedToFractionalBoundless(T mapped) requires(std::is_integral_v) { + if constexpr (std::is_same_v || std::is_same_v) { + return mapped / SCALEBOUNDLESSDOUBLE8; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped / SCALEBOUNDLESSDOUBLE16; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped / SCALEBOUNDLESSDOUBLE32; + } else { + return mapped / SCALEBOUNDLESSDOUBLE64; + } } - export constexpr std::int_fast32_t PixelToMapped(std::int_fast32_t pixel, std::int_fast32_t width) { - return pixel * (SCALE / width); + template + constexpr T MappedToAbsolute(T mapped, T2 absolute) requires(std::is_integral_v) { + if constexpr (std::is_same_v || std::is_same_v) { + return static_cast(mapped) * absolute / SCALE8; + } else if constexpr (std::is_same_v || std::is_same_v) { + return static_cast(mapped) * absolute / SCALE16; + } else if constexpr (std::is_same_v || std::is_same_v) { + return static_cast(mapped) * absolute / SCALE32; + } else { + return static_cast<__int128>(mapped) * absolute / SCALE64; + } } - export constexpr std::int_fast32_t RelativeToAbsolute(std::int_fast32_t relative, std::int_fast32_t full) { - return static_cast( - (static_cast<__int128>(relative) * full) / SCALE - ); + template + constexpr T MappedToAbsoluteBoundless(T mapped, T2 absolute) requires(std::is_integral_v) { + if constexpr (std::is_same_v || std::is_same_v) { + return static_cast(mapped) * absolute / SCALEBOUNDLESS8; + } else if constexpr (std::is_same_v || std::is_same_v) { + return static_cast(mapped) * absolute / SCALEBOUNDLESS16; + } else if constexpr (std::is_same_v || std::is_same_v) { + return static_cast(mapped) * absolute / SCALEBOUNDLESS32; + } else { + return static_cast(mapped) * absolute / SCALEBOUNDLESS64; + } } - export constexpr std::int_fast32_t AbsoluteToRelative(std::int_fast32_t absolute, std::int_fast32_t relative) { - return static_cast( - (static_cast<__int128>(absolute) * SCALE) / relative - ); + // template + // constexpr T PixelToMappedBoundless(T pixel, T2 screen) requires(std::is_integral_v) { + // if constexpr (std::is_same_v) { + // return (static_cast(relative) * SCALE8) / (static_cast(absolute) * SCALE8); + // } else if constexpr (std::is_same_v) { + // return (static_cast(relative) * SCALE16) / (static_cast(absolute) * SCALE16); + // } else if constexpr (std::is_same_v) { + // return (static_cast(relative) * SCALE32) / (static_cast(absolute) * SCALE32); + // } else { + // return (static_cast(relative) * SCALE32) / (static_cast(absolute) * SCALE32); + // } + // } + + template + constexpr T AbsoluteToMapped(T absolute, T2 mapped) { + if constexpr (std::is_same_v || std::is_same_v) { + return static_cast(absolute) * SCALE8 / mapped; + } else if constexpr (std::is_same_v || std::is_same_v ) { + return static_cast(absolute) * SCALE16 / mapped; + } else if constexpr (std::is_same_v|| std::is_same_v) { + return static_cast(absolute) * SCALE32 / mapped; + } else { + return static_cast<__int128>(absolute) * SCALE64 / mapped; + } } - export constexpr std::int_fast32_t BoundToBoundless(std::int_fast32_t bound) { - return bound * BOUND; + template + constexpr T AbsoluteToMappedBoundless(T absolute, T2 mapped) { + if constexpr (std::is_same_v || std::is_same_v ) { + return static_cast(absolute) * SCALEBOUNDLESS8 / mapped; + } else if constexpr (std::is_same_v || std::is_same_v) { + return static_cast(absolute) * SCALEBOUNDLESS16 / mapped; + } else if constexpr (std::is_same_v || std::is_same_v) { + return static_cast(absolute) * SCALEBOUNDLESS32 / mapped; + } else { + return static_cast(absolute) * SCALEBOUNDLESS64 / mapped; + } + } + + template + constexpr T BoundToBoundless(T mapped) { + if constexpr (std::is_same_v || std::is_same_v) { + return mapped * BOUND8 * 2; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped * BOUND16 * 2; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped * BOUND32 * 2; + } else { + return mapped * BOUND64 * 2; + } } - export constexpr std::int_fast32_t BoundToBoundlessU(std::int_fast32_t bound) { - return static_cast((bound*2)) * BOUND; + template + constexpr T BoundlessToBound(T mapped) { + if constexpr (std::is_same_v || std::is_same_v ) { + return mapped / 2; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped / 2; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped / 2; + } else { + return mapped / 2; + } } - export constexpr std::int_fast32_t BoundlessToBound(std::int_fast32_t bound) { - return bound / BOUND; - } - - export constexpr std::int_fast32_t BoundlessUToBound(std::uint_fast32_t bound) { - return static_cast(bound / 2) / BOUND; - } - - export constexpr std::int_fast32_t FractionalToMappedBoundless(double f) { - return std::int_fast32_t(f * SCALEDOUBLEBOUNDLESS); - } - - export constexpr std::uint_fast32_t FractionalToMappedBoundlessU(double f) { - return std::uint_fast32_t(f * SCALEDOUBLEBOUNDLESSU); - } - - export constexpr double MappedToFractionalBoundless(std::int_fast32_t mapped) { - return static_cast(mapped) / SCALEDOUBLEBOUNDLESS; - } - - export constexpr std::int_fast32_t MappedToPixelBoundless(std::int_fast32_t mapped, std::int_fast32_t width) { - return mapped / (SCALEBOUNDLESS / width); - } - - export constexpr std::int_fast32_t PixelToMappedBoundless(std::int_fast32_t pixel, std::int_fast32_t width) { - return pixel * (SCALEBOUNDLESS / width); - } - - export enum class CrafterKeys { + enum class CrafterKeys { // Alphabetic keys A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, diff --git a/interfaces/Crafter.Graphics-Window.cppm b/interfaces/Crafter.Graphics-Window.cppm index e5ee46f..36b4937 100644 --- a/interfaces/Crafter.Graphics-Window.cppm +++ b/interfaces/Crafter.Graphics-Window.cppm @@ -47,10 +47,11 @@ import Crafter.Event; export namespace Crafter { class Transform; + class MouseElement; class Window { public: - std::int_fast32_t width; - std::int_fast32_t height; + std::int32_t width; + std::int32_t height; std::chrono::time_point lastFrameBegin; std::vector elements; Event onClose; @@ -61,7 +62,7 @@ export namespace Crafter { float scale; Window() = default; - Window(std::int_fast32_t width, std::int_fast32_t height); + Window(std::int32_t width, std::int32_t height); Window(Window&) = delete; Window(Window&&) = delete; virtual ~Window() = default; @@ -72,13 +73,13 @@ export namespace Crafter { virtual void StopUpdate() = 0; void ScaleElement(Transform& element, Transform& parent); void ScaleElement(Transform& element); - void ScaleMouse(Transform& element, Transform& parent); - void ScaleMouse(Transform& element); + void ScaleMouse(MouseElement& element, Transform& parent); + void ScaleMouse(MouseElement& element); #ifdef CRAFTER_TIMING std::chrono::nanoseconds totalUpdate; std::vector*, std::chrono::nanoseconds>> updateTimings; std::chrono::nanoseconds totalRender; - std::vector> renderTimings; + std::vector> renderTimings; std::chrono::nanoseconds vblank; std::chrono::nanoseconds totalFrame; std::chrono::time_point frameEnd; @@ -110,10 +111,10 @@ export namespace Crafter { Event onMouseMove; Event onMouseEnter; Event onMouseLeave; - Event onMouseScroll; + Event onMouseScroll; MousePoint currentMousePos; MousePoint lastMousePos; - MousePoint mouseDelta; + MouseDelta mouseDelta; bool mouseLeftHeld = false; bool mouseRightHeld = false; std::vector mouseElements; @@ -129,11 +130,11 @@ export namespace Crafter { class WindowFramebuffer : public Window { public: WindowFramebuffer() = default; - WindowFramebuffer(std::uint_fast32_t width, std::uint_fast32_t height); - virtual void Resize(std::uint_fast32_t width, std::uint_fast32_t height) = 0; + WindowFramebuffer(std::uint32_t width, std::uint32_t height); + virtual void Resize(std::uint32_t width, std::uint32_t height) = 0; virtual void Write(Pixel_BU8_GU8_RU8_AU8* pixels) = 0; - virtual void Write(std::uint_fast32_t x, std::uint_fast32_t y, Pixel_BU8_GU8_RU8_AU8 pixel) = 0; - virtual Pixel_BU8_GU8_RU8_AU8 Read(std::uint_fast32_t x, std::uint_fast32_t y) const = 0; + virtual void Write(std::uint32_t x, std::uint32_t y, Pixel_BU8_GU8_RU8_AU8 pixel) = 0; + virtual Pixel_BU8_GU8_RU8_AU8 Read(std::uint32_t x, std::uint32_t y) const = 0; virtual const Pixel_BU8_GU8_RU8_AU8* Read() const = 0; virtual Pixel_BU8_GU8_RU8_AU8* Get() = 0; virtual void Store() = 0; @@ -144,8 +145,8 @@ export namespace Crafter { class WindowWayland final : public WindowKeyboard, public WindowMouse, public WindowFramebuffer, public WindowTitle { public: Pixel_BU8_GU8_RU8_AU8* framebuffer = nullptr; - WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height); - WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height, const std::string_view title); + WindowWayland(std::uint32_t width, std::uint32_t height); + WindowWayland(std::uint32_t width, std::uint32_t height, const std::string_view title); ~WindowWayland(); bool configured = false; wl_shm* shm = nullptr; @@ -173,10 +174,10 @@ export namespace Crafter { void StartUpdate() override; void StopUpdate() override; void SetTitle(const std::string_view title) override; - void Resize(std::uint_fast32_t width, std::uint_fast32_t height) override; + void Resize(std::uint32_t width, std::uint32_t height) override; void Write(Pixel_BU8_GU8_RU8_AU8* pixels) override; - void Write(std::uint_fast32_t x, std::uint_fast32_t y, Pixel_BU8_GU8_RU8_AU8 pixel) override; - Pixel_BU8_GU8_RU8_AU8 Read(std::uint_fast32_t x, std::uint_fast32_t y) const override; + void Write(std::uint32_t x, std::uint32_t y, Pixel_BU8_GU8_RU8_AU8 pixel) override; + Pixel_BU8_GU8_RU8_AU8 Read(std::uint32_t x, std::uint32_t y) const override; const Pixel_BU8_GU8_RU8_AU8* Read() const override; Pixel_BU8_GU8_RU8_AU8* Get() override; void Store() override; diff --git a/interfaces/Crafter.Graphics.cppm b/interfaces/Crafter.Graphics.cppm index 542d787..a39abfd 100644 --- a/interfaces/Crafter.Graphics.cppm +++ b/interfaces/Crafter.Graphics.cppm @@ -24,7 +24,6 @@ export import :Window; export import :Transform; export import :RenderingElement; export import :MouseElement; -export import :TextElement; export import :GridElement; export import :Types; export import :Font; diff --git a/project.json b/project.json index 2cf20dd..fea75fd 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", "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"], + "implementations": ["implementations/Crafter.Graphics-Font", "implementations/Crafter.Graphics-Shm", "implementations/Crafter.Graphics-Window", "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-MouseElement", "interfaces/Crafter.Graphics-Transform", "interfaces/Crafter.Graphics-GridElement"], "type": "library" }, {