the great text and type rewrite

This commit is contained in:
Jorijn van der Graaf 2025-12-30 23:28:38 +01:00
commit d0cc3ad16a
15 changed files with 628 additions and 318 deletions

View file

@ -8,12 +8,12 @@ int main() {
RenderingElement<true, true, false> element( RenderingElement<true, true, false> element(
{ {
FractionalToMapped(0.5), //anchorX: relative position where this elements x anchor (top-left) is placed to its parent x anchor FractionalToMapped<std::int32_t>(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<std::int32_t>(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<std::int32_t>(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<std::int32_t>(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<std::int32_t>(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<std::int32_t>(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 0 //z: this elements Z position
}, },
OpaqueType::FullyOpaque, OpaqueType::FullyOpaque,
@ -21,32 +21,23 @@ int main() {
1 1
); );
MouseElement mouse({ MouseElement mouse(window);
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);
element.children.push_back(&mouse); element.children.push_back(&mouse);
window.elements.push_back(&element); window.elements.push_back(&element);
element.scalingBuffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}}; element.scalingBuffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}};
element.UpdatePosition(window); element.UpdatePosition(window);
EventListener<MousePoint> clickListener(&mouse.onMouseLeftClick, [&mouse, &window](MousePoint point){ EventListener<MousePoint> clickListener(&mouse.onMouseLeftClick, [&mouse, &window](MousePoint point) {
// Print the coordinates where the user clicked relative to the element's top left corner. // Print the coordinates where the user clicked relative to the element's top left corner.
std::println("Clicked on Mapped X:{} Y:{}!\nClicked on Fraction X:{} Y:{}!\nClicked on Screen X:{} Y:{}!\n",
//Mapped space //Mapped space
std::cout << std::format("Clicked on Mapped X:{} Y:{}!", point.x, point.y) << std::endl; point.x, point.y,
// Fraction space
// Fraction space MappedToFractionalBoundless(point.x), MappedToFractionalBoundless(point.y),
std::cout << std::format("Clicked on Fraction X:{} Y:{}!", MappedToFractionalBoundless(point.x), MappedToFractionalBoundless(point.y)) << std::endl; // Screen space
MappedToAbsoluteBoundless(point.x, MappedToAbsoluteBoundless(mouse.mouseScaled.width, window.width)), MappedToAbsoluteBoundless(point.y, MappedToAbsoluteBoundless(mouse.mouseScaled.width, window.height))
// 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;
}); });
window.Render(); window.Render();

View file

@ -26,23 +26,23 @@ import std;
using namespace Crafter; 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) { void GridElement::UpdatePositionScaled(Window& window) {
std::int_fast32_t cellWidth = (SCALE - (paddingX * 2) - (spacingX * (columns - 1))) / columns; std::int32_t cellWidth = (SCALE32 - (paddingX * 2) - (spacingX * (columns - 1))) / columns;
std::int_fast32_t cellHeight = (SCALE - (paddingY * 2) - (spacingY * (rows - 1))) / rows; std::int32_t cellHeight = (SCALE32 - (paddingY * 2) - (spacingY * (rows - 1))) / rows;
std::size_t childIndex = 0; std::size_t childIndex = 0;
for (std::uint_fast32_t row = 0; row < rows && childIndex < children.size(); ++row) { for (std::uint32_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 col = 0; col < columns && childIndex < children.size(); ++col) {
Transform* child = children[childIndex]; Transform* child = children[childIndex];
// Calculate position for this child // 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 // Apply relative positioning
child->anchor.x = childX; child->anchor.x = childX;

View file

@ -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<std::uint32_t>(0), FractionalToMapped<std::uint32_t>(0), FractionalToMapped<std::uint32_t>(1), FractionalToMapped<std::uint32_t>(1), FractionalToMapped<std::uint32_t>(0), FractionalToMapped<std::uint32_t>(0), 0}) {
window.mouseElements.push_back(this); 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<std::uint32_t>(0), FractionalToMapped<std::uint32_t>(0), FractionalToMapped<std::uint32_t>(1), FractionalToMapped<std::uint32_t>(1), FractionalToMapped<std::uint32_t>(0), FractionalToMapped<std::uint32_t>(0), 0}) {
} }
void MouseElement::UpdatePosition(Window& window) { void MouseElement::UpdatePosition(Window& window) {
window.ScaleMouse(*this); window.ScaleMouse(*this);
window.ScaleElement(*this);
for(Transform* child : children) { for(Transform* child : children) {
child->UpdatePosition(window, *this); child->UpdatePosition(window, *this);
} }
@ -53,6 +54,7 @@ void MouseElement::UpdatePosition(Window& window) {
void MouseElement::UpdatePosition(Window& window, Transform& parent) { void MouseElement::UpdatePosition(Window& window, Transform& parent) {
window.ScaleMouse(*this, parent); window.ScaleMouse(*this, parent);
window.ScaleElement(*this, parent);
for(Transform* child : children) { for(Transform* child : children) {
child->UpdatePosition(window, *this); child->UpdatePosition(window, *this);
} }

View file

@ -28,7 +28,7 @@ import std;
using namespace Crafter; 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) {
} }

View file

@ -20,51 +20,59 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
module Crafter.Graphics:Window_impl; module Crafter.Graphics:Window_impl;
import :Window; import :Window;
import :Transform; import :Transform;
import :MouseElement;
import std; import std;
using namespace Crafter; 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) { void Window::ScaleElement(Transform& element) {
if(element.anchor.maintainAspectRatio) { if(element.anchor.maintainAspectRatio) {
if(width > height) { if(width > height) {
element.scaled.width = MappedToPixel(element.anchor.width, height); element.scaled.width = MappedToAbsolute(element.anchor.width, height);
element.scaled.height = MappedToPixel(element.anchor.height, height); element.scaled.height = MappedToAbsolute(element.anchor.height, height);
} else { } else {
element.scaled.width = MappedToPixel(element.anchor.width, width); element.scaled.width = MappedToAbsolute(element.anchor.width, width);
element.scaled.height = MappedToPixel(element.anchor.height, width); element.scaled.height = MappedToAbsolute(element.anchor.height, width);
} }
} else { } else {
element.scaled.width = MappedToPixel(element.anchor.width, width); element.scaled.width = MappedToAbsolute(element.anchor.width, width);
element.scaled.height = MappedToPixel(element.anchor.height, height); 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.x = MappedToAbsolute(element.anchor.x, width) - MappedToAbsolute(element.anchor.offsetX, element.scaled.width);
element.scaled.y = MappedToPixel(element.anchor.y, height) - MappedToPixel(element.anchor.offsetY, element.scaled.height); element.scaled.y = MappedToAbsolute(element.anchor.y, height) - MappedToAbsolute(element.anchor.offsetY, element.scaled.height);
} }
void Window::ScaleElement(Transform& element, Transform& parent) { void Window::ScaleElement(Transform& element, Transform& parent) {
element.scaled.width = MappedToPixel(element.anchor.width, parent.scaled.width); element.scaled.width = MappedToAbsolute(element.anchor.width, parent.scaled.width);
element.scaled.height = MappedToPixel(element.anchor.height, parent.scaled.height); element.scaled.height = MappedToAbsolute(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.x = MappedToAbsolute(element.anchor.x, parent.scaled.width) - MappedToAbsolute(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.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) { void Window::ScaleMouse(MouseElement& element, Transform& parent) {
std::int_fast32_t boundlessWidth = PixelToMappedBoundless(parent.scaled.width, width); // element.scaled.width = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.width), parent.scaled.width);
std::int_fast32_t boundlessHeight = PixelToMappedBoundless(parent.scaled.height, height); // element.scaled.height = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.height), parent.scaled.height);
element.scaled.width = BoundToBoundless(MappedToPixel(element.anchor.width, PixelToMapped(parent.scaled.width, width))); // 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.height = BoundToBoundless(MappedToPixel(element.anchor.height, PixelToMapped(parent.scaled.height, height))); // element.scaled.y = MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.y), parent.scaled.height) - MappedToAbsoluteBoundless(BoundToBoundless(element.anchor.offsetY), element.scaled.height) + BoundToBoundless(parent.scaled.y);
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); 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) { void Window::ScaleMouse(MouseElement& element) {
// std::int_fast32_t boundlessWidth = PixelToMappedBoundless(parent.scaled.width, width); // std::int32_t boundlessWidth = PixelToMappedBoundless(parent.scaled.width, width);
// std::int_fast32_t boundlessHeight = PixelToMappedBoundless(parent.scaled.height, height); // std::int32_t boundlessHeight = PixelToMappedBoundless(parent.scaled.height, height);
// element.scaled.width = BoundToBoundless(MappedToPixel(element.anchor.width, width)); // element.scaled.width = BoundToBoundless(MappedToPixel(element.anchor.width, width));
// element.scaled.height = BoundToBoundless(MappedToPixel(element.anchor.height, height)); // 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); // 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<const void*>(entry.first), duration_cast<std::chrono::microseconds>(entry.second)) << std::endl; std::cout << std::format("\t{} {}", reinterpret_cast<const void*>(entry.first), duration_cast<std::chrono::microseconds>(entry.second)) << std::endl;
} }
std::cout << std::format("Render: {}", duration_cast<std::chrono::milliseconds>(totalRender)) << std::endl; std::cout << std::format("Render: {}", duration_cast<std::chrono::milliseconds>(totalRender)) << std::endl;
for (const std::tuple<const RenderingElement*, std::uint_fast32_t, std::uint_fast32_t, std::chrono::nanoseconds>& entry : renderTimings) { for (const std::tuple<const RenderingElement*, std::uint32_t, std::uint32_t, std::chrono::nanoseconds>& entry : renderTimings) {
std::cout << std::format("\t{} {}x{} {}", reinterpret_cast<const void*>(std::get<0>(entry)), std::get<1>(entry), std::get<2>(entry), duration_cast<std::chrono::microseconds>(std::get<3>(entry))) << std::endl; std::cout << std::format("\t{} {}x{} {}", reinterpret_cast<const void*>(std::get<0>(entry)), std::get<1>(entry), std::get<2>(entry), duration_cast<std::chrono::microseconds>(std::get<3>(entry))) << std::endl;
} }
std::cout << std::format("Total: {}", duration_cast<std::chrono::milliseconds>(totalUpdate+totalRender)) << std::endl; std::cout << std::format("Total: {}", duration_cast<std::chrono::milliseconds>(totalUpdate+totalRender)) << std::endl;
@ -112,9 +120,9 @@ void Window::LogTiming() {
void Window::AddDirtyRect(ScaleData scale) { void Window::AddDirtyRect(ScaleData scale) {
ClipRect rect { 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), .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), .bottom = std::min(scale.y + scale.height, height),
}; };

View file

@ -49,11 +49,11 @@ import Crafter.Event;
using namespace Crafter; 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); display = wl_display_connect(NULL);
if (display == NULL) { if (display == NULL) {
std::cerr << "failed to create display" << std::endl; 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); 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()); 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); dirty.bottom = std::min(element->scaled.y+element->scaled.height, dirty.bottom);
const Pixel_BU8_GU8_RU8_AU8* src_buffer = element->buffer.data(); const Pixel_BU8_GU8_RU8_AU8* src_buffer = element->buffer.data();
std::int_fast32_t src_width = element->scaled.width; std::int32_t src_width = element->scaled.width;
std::int_fast32_t src_height = element->scaled.height; std::int32_t src_height = element->scaled.height;
switch (element->opaque) { switch (element->opaque) {
case OpaqueType::FullyOpaque: case OpaqueType::FullyOpaque:
// For fully opaque, just copy pixels directly // For fully opaque, just copy pixels directly
for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) { for (std::int32_t y = dirty.top; y < dirty.bottom; y++) {
std::int_fast32_t src_y = y - element->scaled.y; std::int32_t src_y = y - element->scaled.y;
for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) { for (std::int32_t x = dirty.left; x < dirty.right; x++) {
std::int_fast32_t src_x = x - element->scaled.x; std::int32_t src_x = x - element->scaled.x;
framebuffer[y * width + x] = src_buffer[src_y * src_width + src_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: case OpaqueType::SemiOpaque:
// For semi-opaque, we can avoid blending when alpha is 0 or 255 // 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++) { for (std::int32_t y = dirty.top; y < dirty.bottom; y++) {
std::int_fast32_t src_y = y - element->scaled.y; std::int32_t src_y = y - element->scaled.y;
for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) { for (std::int32_t x = dirty.left; x < dirty.right; x++) {
std::int_fast32_t src_x = x - element->scaled.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]; Pixel_BU8_GU8_RU8_AU8 src_pixel = src_buffer[src_y * src_width + src_x];
if (src_pixel.a == 0) { if (src_pixel.a == 0) {
@ -218,11 +218,11 @@ void WindowWayland::RenderElement(Transform* transform) {
case OpaqueType::Transparent: case OpaqueType::Transparent:
// For transparent, always perform blending // For transparent, always perform blending
for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) { for (std::int32_t y = dirty.top; y < dirty.bottom; y++) {
std::int_fast32_t src_y = y - element->scaled.y; std::int32_t src_y = y - element->scaled.y;
for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) { for (std::int32_t x = dirty.left; x < dirty.right; x++) {
std::int_fast32_t src_x = x - element->scaled.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]); blend_pixel_optimized(framebuffer[y * width + x], src_buffer[src_y * src_width + src_x]);
} }
} }
@ -248,9 +248,9 @@ void WindowWayland::Render() {
//std::vector<ClipRect> newClip; //std::vector<ClipRect> 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]; // 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]; // ClipRect existing = dirtyRects[i2];
// if(rect.bottom >= existing.top && rect.top <= existing.top) { // if(rect.bottom >= existing.top && rect.top <= existing.top) {
// newClip.push_back({ // newClip.push_back({
@ -337,8 +337,8 @@ void WindowWayland::Render() {
// color.r, color.g, color.b, color.a // color.r, color.g, color.b, color.a
// ) << std::endl; // ) << std::endl;
// for (std::int_fast32_t y = rect.top; y < rect.bottom; ++y) { // for (std::int32_t y = rect.top; y < rect.bottom; ++y) {
// for (std::int_fast32_t x = rect.left; x < rect.right; ++x) { // for (std::int32_t x = rect.left; x < rect.right; ++x) {
// framebuffer[y * width + x] = color; // framebuffer[y * width + x] = color;
// } // }
// } // }
@ -348,8 +348,8 @@ void WindowWayland::Render() {
if (!dirtyRects.empty()) { if (!dirtyRects.empty()) {
for (ClipRect rect : dirtyRects) { for (ClipRect rect : dirtyRects) {
for (std::int_fast32_t y = rect.top; y < rect.bottom; y++) { for (std::int32_t y = rect.top; y < rect.bottom; y++) {
for (std::int_fast32_t x = rect.left; x < rect.right; x++) { for (std::int32_t x = rect.left; x < rect.right; x++) {
framebuffer[y * width + x] = {0, 0, 0, 0}; 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()); 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)); 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; 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]; 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) { 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<WindowWayland*>(data); WindowWayland* window = reinterpret_cast<WindowWayland*>(data);
if (button == BTN_LEFT) { if (button == BTN_LEFT) {
if(state == WL_POINTER_BUTTON_STATE_PRESSED) { if(state == WL_POINTER_BUTTON_STATE_PRESSED) {
window->mouseLeftHeld = true; window->mouseLeftHeld = true;
window->onMouseLeftClick.Invoke(window->currentMousePos); window->onMouseLeftClick.Invoke(window->currentMousePos);
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(element) { 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) { 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({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.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); window->onMouseLeftRelease.Invoke(window->currentMousePos);
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(element) { 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) { 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({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.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); window->onMouseRightClick.Invoke(window->currentMousePos);
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(element) { 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) { 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({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.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); window->onMouseRightRelease.Invoke(window->currentMousePos);
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(element) { 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) { 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({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.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) { 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<WindowWayland*>(data); WindowWayland* window = reinterpret_cast<WindowWayland*>(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<std::uint32_t>((wl_fixed_to_double(surface_x) * window->scale) / window->width), FractionalToMappedBoundless<std::uint32_t>((wl_fixed_to_double(surface_y) * window->scale) / window->height)};
window->lastMousePos = window->currentMousePos; window->lastMousePos = window->currentMousePos;
window->currentMousePos = pos; window->currentMousePos = pos;
window->mouseDelta = {window->currentMousePos.x-window->lastMousePos.x, window->currentMousePos.y-window->lastMousePos.y}; window->mouseDelta = {window->currentMousePos.x-window->lastMousePos.x, window->currentMousePos.y-window->lastMousePos.y};
window->onMouseMove.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); window->onMouseMove.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta});
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(element) { 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) { 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({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.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->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)) { 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({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.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) { } 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({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.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*) { void WindowWayland::PointerListenerHandleLeave(void* data, wl_pointer*, std::uint32_t, wl_surface*) {
WindowWayland* window = reinterpret_cast<WindowWayland*>(data); WindowWayland* window = reinterpret_cast<WindowWayland*>(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) { void WindowWayland::PointerListenerHandleAxis(void*, wl_pointer*, std::uint32_t, std::uint32_t, wl_fixed_t value) {

View file

@ -25,13 +25,13 @@ import :Types;
export namespace Crafter { export namespace Crafter {
class GridElement : public Transform { class GridElement : public Transform {
public: public:
std::uint_fast32_t columns; std::uint32_t columns;
std::uint_fast32_t rows; std::uint32_t rows;
std::int_fast32_t spacingX; std::int32_t spacingX;
std::int_fast32_t spacingY; std::int32_t spacingY;
std::int_fast32_t paddingX; std::int32_t paddingX;
std::int_fast32_t paddingY; std::int32_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); 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 UpdatePositionScaled(Window& window);
void UpdatePosition(Window& window) override; void UpdatePosition(Window& window) override;
void UpdatePosition(Window& window, Transform& parent) override; void UpdatePosition(Window& window, Transform& parent) override;

View file

@ -37,6 +37,7 @@ export namespace Crafter {
Event<MousePoint> onMouseLeftHold; Event<MousePoint> onMouseLeftHold;
Event<MousePoint> onMouseRightRelease; Event<MousePoint> onMouseRightRelease;
Event<MousePoint> onMouseLeftRelease; Event<MousePoint> onMouseLeftRelease;
ScaleDataBoundless mouseScaled;
MouseElement(); MouseElement();
MouseElement(WindowMouse& window); MouseElement(WindowMouse& window);

View file

@ -20,41 +20,61 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
module; module;
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "../lib/stb_image.h" #include "../lib/stb_image.h"
#include "../lib/stb_truetype.h"
export module Crafter.Graphics:RenderingElement; export module Crafter.Graphics:RenderingElement;
import std; import std;
import :Transform; import :Transform;
import :Font;
import :Types; import :Types;
import :Image; import :Image;
import :Window; import :Window;
export namespace Crafter { export namespace Crafter {
enum class TextAlignment {
Left,
Center,
Right
};
enum class TextOverflowMode {
Clip,
Wrap
};
enum class TextScaleMode {
None,
Font,
Element,
Buffer
};
struct RenderElementScalingOwning { struct RenderElementScalingOwning {
std::vector<Pixel_BU8_GU8_RU8_AU8> scalingBuffer; std::vector<Pixel_BU8_GU8_RU8_AU8> scalingBuffer;
std::uint_fast32_t bufferWidth; std::uint32_t bufferWidth;
std::uint_fast32_t bufferHeight; std::uint32_t bufferHeight;
bool bufferUpdated = true; bool bufferUpdated = true;
RenderElementScalingOwning() = default; 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 { struct RenderElementScalingNonOwning {
Pixel_BU8_GU8_RU8_AU8* scalingBuffer; Pixel_BU8_GU8_RU8_AU8* scalingBuffer;
std::uint_fast32_t bufferWidth; std::uint32_t bufferWidth;
std::uint_fast32_t bufferHeight; std::uint32_t bufferHeight;
bool bufferUpdated = true; bool bufferUpdated = true;
RenderElementScalingNonOwning() = default; 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 { struct RenderElementRotating {
std::uint_fast32_t rotation; std::uint32_t rotation;
bool rotationUpdated = true; bool rotationUpdated = true;
RenderElementRotating() = default; 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) : RenderingElementBase(anchor, opaque) {
} }
RenderingElement(Anchor anchor, OpaqueType opaque, std::uint_fast32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase<Rotating>(rotation) { RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase<Rotating>(rotation) {
} }
RenderingElement(Anchor anchor, const std::string_view imagePath) : RenderingElementBase(anchor) { RenderingElement(Anchor anchor, const std::string_view imagePath) : RenderingElementBase(anchor) {
LoadImage(imagePath); LoadImage(imagePath);
} }
RenderingElement(Anchor anchor, const std::string_view imagePath, std::uint_fast32_t rotation) requires(Rotating) : RenderingElementBase(anchor), RotatingBase<Rotating>(rotation) { RenderingElement(Anchor anchor, const std::string_view imagePath, std::uint32_t rotation) requires(Rotating) : RenderingElementBase(anchor), RotatingBase<Rotating>(rotation) {
LoadImage(imagePath); LoadImage(imagePath);
} }
RenderingElement(Anchor anchor, const std::string_view imagePath, OpaqueType opaque) : RenderingElementBase(anchor, opaque) { RenderingElement(Anchor anchor, const std::string_view imagePath, OpaqueType opaque) : RenderingElementBase(anchor, opaque) {
LoadImageNoOpaqueCheck(imagePath); LoadImageNoOpaqueCheck(imagePath);
} }
RenderingElement(Anchor anchor, const std::string_view imagePath, OpaqueType opaque, std::uint_fast32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase<Rotating>(rotation) { RenderingElement(Anchor anchor, const std::string_view imagePath, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase<Rotating>(rotation) {
LoadImageNoOpaqueCheck(imagePath); 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<Scaling, Owning>(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<Scaling, Owning>(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<Scaling, Owning>(bufferWidth, bufferHeight, scalingBuffer), RotatingBase<Rotating>(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<Scaling, Owning>(bufferWidth, bufferHeight, scalingBuffer), RotatingBase<Rotating>(rotation) {
} }
RenderingElement(Anchor anchor, OpaqueType opaque, Image& image) requires(Scaling && !Owning) : RenderingElementBase(anchor, opaque), ScalingBase<Scaling, Owning>(image.buffer.data(), image.width, image.height) { RenderingElement(Anchor anchor, OpaqueType opaque, Image& image) requires(Scaling && !Owning) : RenderingElementBase(anchor, opaque), ScalingBase<Scaling, Owning>(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<Scaling, Owning>(image.buffer.data(), image.width, image.height), RotatingBase<Rotating>(rotation) { RenderingElement(Anchor anchor, OpaqueType opaque, Image& image, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElementBase(anchor, opaque), ScalingBase<Scaling, Owning>(image.buffer.data(), image.width, image.height), RotatingBase<Rotating>(rotation) {
} }
RenderingElement(Anchor anchor, Image& image) requires(Scaling && !Owning) : RenderingElementBase(anchor, image.opaque), ScalingBase<Scaling, Owning>(image.buffer.data(), image.width, image.height) { RenderingElement(Anchor anchor, Image& image) requires(Scaling && !Owning) : RenderingElementBase(anchor, image.opaque), ScalingBase<Scaling, Owning>(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<Scaling, Owning>(image.buffer.data(), image.width, image.height), RotatingBase<Rotating>(rotation) { RenderingElement(Anchor anchor, Image& image, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElementBase(anchor, image.opaque), ScalingBase<Scaling, Owning>(image.buffer.data(), image.width, image.height), RotatingBase<Rotating>(rotation) {
} }
RenderingElement(Anchor anchor, OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight) requires(Owning) : RenderingElementBase(anchor, opaque), ScalingBase<Scaling, Owning>(bufferWidth, bufferHeight) { RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElementBase(anchor, opaque), ScalingBase<Scaling, Owning>(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<Scaling, Owning>(bufferWidth, bufferHeight) , RotatingBase<Rotating>(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<Scaling, Owning>(bufferWidth, bufferHeight) , RotatingBase<Rotating>(rotation) {
} }
@ -150,20 +170,20 @@ export namespace Crafter {
RenderingElement& operator=(RenderingElement&) = delete; RenderingElement& operator=(RenderingElement&) = delete;
void ScaleNearestNeighbor() requires(Scaling) { void ScaleNearestNeighbor() requires(Scaling) {
for (std::uint_fast32_t y = 0; y < scaled.height; y++) { for (std::uint32_t y = 0; y < scaled.height; y++) {
std::uint_fast32_t srcY = y * ScalingBase<true, Owning>::bufferHeight / scaled.height; std::uint32_t srcY = y * ScalingBase<true, Owning>::bufferHeight / scaled.height;
for (std::uint_fast32_t x = 0; x < scaled.width; x++) { for (std::uint32_t x = 0; x < scaled.width; x++) {
std::uint_fast32_t srcX = x * ScalingBase<true, Owning>::bufferWidth / scaled.width; std::uint32_t srcX = x * ScalingBase<true, Owning>::bufferWidth / scaled.width;
buffer[y * scaled.width + x] = ScalingBase<true, Owning>::scalingBuffer[srcY * ScalingBase<true, Owning>::bufferWidth + srcX]; buffer[y * scaled.width + x] = ScalingBase<true, Owning>::scalingBuffer[srcY * ScalingBase<true, Owning>::bufferWidth + srcX];
} }
} }
} }
void ScaleRotating() requires(Scaling) { void ScaleRotating() requires(Scaling) {
const double rad = (static_cast<double>(RotatingBase<true>::rotation) / static_cast<double>(std::numeric_limits<std::uint_fast32_t>::max())) * 2.0 * std::numbers::pi; const double rad = (static_cast<double>(RotatingBase<true>::rotation) / static_cast<double>(std::numeric_limits<std::uint32_t>::max())) * 2.0 * std::numbers::pi;
const std::uint_fast32_t dstWidth = scaled.width; const std::uint32_t dstWidth = scaled.width;
const std::uint_fast32_t dstHeight = scaled.height; const std::uint32_t dstHeight = scaled.height;
const double c2 = std::abs(std::cos(rad)); const double c2 = std::abs(std::cos(rad));
const double s2 = std::abs(std::sin(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 rotatedWidth = dstWidth * c2 + dstHeight * s2;
const double rotatedHeight = dstWidth * s2 + dstHeight * c2; const double rotatedHeight = dstWidth * s2 + dstHeight * c2;
const std::uint_fast32_t diffX = static_cast<std::uint_fast32_t>(std::ceil((rotatedWidth - dstWidth) * 0.5)); const std::uint32_t diffX = static_cast<std::uint32_t>(std::ceil((rotatedWidth - dstWidth) * 0.5));
const std::uint_fast32_t diffY = static_cast<std::uint_fast32_t>(std::ceil((rotatedHeight - dstHeight) * 0.5)); const std::uint32_t diffY = static_cast<std::uint32_t>(std::ceil((rotatedHeight - dstHeight) * 0.5));
scaled.width += diffX + diffX; scaled.width += diffX + diffX;
scaled.height += diffY + diffY; scaled.height += diffY + diffY;
@ -198,8 +218,8 @@ export namespace Crafter {
const double scaleX = static_cast<double>(ScalingBase<true, Owning>::bufferWidth) / dstWidth; const double scaleX = static_cast<double>(ScalingBase<true, Owning>::bufferWidth) / dstWidth;
const double scaleY = static_cast<double>(ScalingBase<true, Owning>::bufferHeight) / dstHeight; const double scaleY = static_cast<double>(ScalingBase<true, Owning>::bufferHeight) / dstHeight;
for (std::uint_fast32_t yB = 0; yB < scaled.height; ++yB) { for (std::uint32_t yB = 0; yB < scaled.height; ++yB) {
for (std::uint_fast32_t xB = 0; xB < scaled.width; ++xB) { for (std::uint32_t xB = 0; xB < scaled.width; ++xB) {
// ---- Destination pixel relative to center ---- // ---- Destination pixel relative to center ----
const double dx = (static_cast<double>(xB) - dstCx) * scaleX; const double dx = (static_cast<double>(xB) - dstCx) * scaleX;
@ -210,8 +230,8 @@ export namespace Crafter {
const double sy = (s * dx + c * dy) + srcCy; const double sy = (s * dx + c * dy) + srcCy;
// ---- Nearest neighbour sampling ---- // ---- Nearest neighbour sampling ----
const std::int_fast32_t srcX = static_cast<std::int_fast32_t>(std::round(sx)); const std::int32_t srcX = static_cast<std::int32_t>(std::round(sx));
const std::int_fast32_t srcY = static_cast<std::int_fast32_t>(std::round(sy)); const std::int32_t srcY = static_cast<std::int32_t>(std::round(sy));
if (srcX >= 0 && srcX < ScalingBase<true, Owning>::bufferWidth && srcY >= 0 && srcY < ScalingBase<true, Owning>::bufferHeight) { if (srcX >= 0 && srcX < ScalingBase<true, Owning>::bufferWidth && srcY >= 0 && srcY < ScalingBase<true, Owning>::bufferHeight) {
buffer[yB * scaled.width + xB] = ScalingBase<true, Owning>::scalingBuffer[srcY * ScalingBase<true, Owning>::bufferWidth + srcX]; buffer[yB * scaled.width + xB] = ScalingBase<true, Owning>::scalingBuffer[srcY * ScalingBase<true, Owning>::bufferWidth + srcX];
@ -308,9 +328,9 @@ export namespace Crafter {
opaque = OpaqueType::FullyOpaque; opaque = OpaqueType::FullyOpaque;
if constexpr(Scaling) { if constexpr(Scaling) {
for(std::uint_fast32_t x = 0; x < xSize; x++) { for(std::uint32_t x = 0; x < xSize; x++) {
for(std::uint_fast32_t y = 0; y < ySize; y++) { for(std::uint32_t y = 0; y < ySize; y++) {
std::uint_fast32_t idx = (x*ySize+y)*4; std::uint32_t idx = (x*ySize+y)*4;
ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].r = bgData[idx]; ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].r = bgData[idx];
ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].g = bgData[idx+1]; ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].g = bgData[idx+1];
ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].b = bgData[idx+2]; ScalingBase<true, Owning>::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<true, Owning>::scalingBuffer[i].a != 255) { if(ScalingBase<true, Owning>::scalingBuffer[i].a != 255) {
opaque = OpaqueType::SemiOpaque; 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<true, Owning>::scalingBuffer[i2].a != 0 && ScalingBase<true, Owning>::scalingBuffer[i2].a != 255) { if(ScalingBase<true, Owning>::scalingBuffer[i2].a != 0 && ScalingBase<true, Owning>::scalingBuffer[i2].a != 255) {
opaque = OpaqueType::Transparent; opaque = OpaqueType::Transparent;
return; return;
@ -331,9 +351,9 @@ export namespace Crafter {
} }
} }
} else { } else {
for(std::uint_fast32_t x = 0; x < xSize; x++) { for(std::uint32_t x = 0; x < xSize; x++) {
for(std::uint_fast32_t y = 0; y < ySize; y++) { for(std::uint32_t y = 0; y < ySize; y++) {
std::uint_fast32_t idx = (x*ySize+y)*4; std::uint32_t idx = (x*ySize+y)*4;
buffer[x*ySize+y].r = bgData[idx]; buffer[x*ySize+y].r = bgData[idx];
buffer[x*ySize+y].g = bgData[idx+1]; buffer[x*ySize+y].g = bgData[idx+1];
buffer[x*ySize+y].b = bgData[idx+2]; 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) { if(buffer[i].a != 255) {
opaque = OpaqueType::SemiOpaque; 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) { if(buffer[i2].a != 0 && buffer[i2].a != 255) {
opaque = OpaqueType::Transparent; opaque = OpaqueType::Transparent;
return; return;
@ -375,9 +395,9 @@ export namespace Crafter {
if constexpr(Scaling) { if constexpr(Scaling) {
for(std::uint_fast32_t x = 0; x < xSize; x++) { for(std::uint32_t x = 0; x < xSize; x++) {
for(std::uint_fast32_t y = 0; y < ySize; y++) { for(std::uint32_t y = 0; y < ySize; y++) {
std::uint_fast32_t idx = (x*ySize+y)*4; std::uint32_t idx = (x*ySize+y)*4;
ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].r = bgData[idx]; ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].r = bgData[idx];
ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].g = bgData[idx+1]; ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].g = bgData[idx+1];
ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].b = bgData[idx+2]; ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].b = bgData[idx+2];
@ -385,9 +405,9 @@ export namespace Crafter {
} }
} }
} else { } else {
for(std::uint_fast32_t x = 0; x < xSize; x++) { for(std::uint32_t x = 0; x < xSize; x++) {
for(std::uint_fast32_t y = 0; y < ySize; y++) { for(std::uint32_t y = 0; y < ySize; y++) {
std::uint_fast32_t idx = (x*ySize+y)*4; std::uint32_t idx = (x*ySize+y)*4;
buffer[x*ySize+y].r = bgData[idx]; buffer[x*ySize+y].r = bgData[idx];
buffer[x*ySize+y].g = bgData[idx+1]; buffer[x*ySize+y].g = bgData[idx+1];
buffer[x*ySize+y].b = bgData[idx+2]; buffer[x*ySize+y].b = bgData[idx+2];
@ -396,5 +416,238 @@ export namespace Crafter {
} }
} }
} }
std::vector<std::string_view> 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<std::string_view> 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<true, true>::bufferHeight || maxWidth != ScalingBase<true, true>::bufferWidth) {
ScalingBase<true, true>::bufferHeight = neededHeight;
ScalingBase<true, true>::bufferWidth = maxWidth;
ScalingBase<true, true>::bufferUpdated = true;
ScalingBase<true, Owning>::scalingBuffer.resize(neededHeight*maxWidth);
}
}
} else {
if constexpr(Scaling) {
lines.resize(ScalingBase<true, Owning>::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<true, true>::bufferHeight) {
ScalingBase<true, true>::bufferHeight = neededHeight;
ScalingBase<true, true>::bufferUpdated = true;
ScalingBase<true, Owning>::scalingBuffer.resize(neededHeight*ScalingBase<true, true>::bufferWidth);
}
}
} else {
if constexpr(Scaling) {
lines.resize(ScalingBase<true, Owning>::bufferHeight / lines.size());
} else {
lines.resize(scaled.height / lines.size());
}
}
}
return lines;
}
void RenderText(Window& window, std::span<const std::string_view> 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<unsigned char> 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<true, Owning>::bufferWidth && bufferY >= 0 && bufferY < ScalingBase<true, Owning>::bufferHeight) {
ScalingBase<true, Owning>::scalingBuffer[bufferY * ScalingBase<true, Owning>::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;
}
}
}; };
} }

View file

@ -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<false, false, false> {
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);
};
}

View file

@ -24,16 +24,16 @@ import :Types;
export namespace Crafter { export namespace Crafter {
class Window; class Window;
struct Anchor { struct Anchor {
std::int_fast32_t x; std::int32_t x;
std::int_fast32_t y; std::int32_t y;
std::uint_fast32_t width; std::uint32_t width;
std::uint_fast32_t height; std::uint32_t height;
std::int_fast32_t offsetX; std::int32_t offsetX;
std::int_fast32_t offsetY; std::int32_t offsetY;
std::int_fast32_t z; std::int32_t z;
bool maintainAspectRatio; bool maintainAspectRatio;
Anchor() = default; 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 { class Transform {
public: public:

View file

@ -21,53 +21,65 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
export module Crafter.Graphics:Types; export module Crafter.Graphics:Types;
import std; import std;
namespace Crafter { export namespace Crafter {
export struct MousePoint { struct MousePoint {
std::int_fast32_t x; std::uint32_t x;
std::int_fast32_t y; std::uint32_t y;
};
struct MouseDelta {
std::int64_t x;
std::int64_t y;
}; };
export struct MouseMoveEvent { struct MouseMoveEvent {
MousePoint lastMousePos; MousePoint lastMousePos;
MousePoint currentMousePos; MousePoint currentMousePos;
MousePoint mouseDelta; MouseDelta mouseDelta;
}; };
export struct ScaleData { struct ScaleData {
std::int_fast32_t x; std::int32_t x;
std::int_fast32_t y; std::int32_t y;
std::int_fast32_t width; std::int32_t width;
std::int_fast32_t height; std::int32_t height;
}; };
export struct ClipRect { struct ScaleDataBoundless {
std::int_fast32_t left; std::uint32_t x;
std::int_fast32_t right; std::uint32_t y;
std::int_fast32_t top; std::uint32_t width;
std::int_fast32_t bottom; 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 b;
std::uint8_t g; std::uint8_t g;
std::uint8_t r; std::uint8_t r;
std::uint8_t a; 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 r;
std::uint8_t g; std::uint8_t g;
std::uint8_t b; std::uint8_t b;
std::uint8_t a; std::uint8_t a;
}; };
export struct __attribute__((packed)) Vertex { struct __attribute__((packed)) Vertex {
float x; float x;
float y; float y;
float z; float z;
float w; float w;
}; };
export struct __attribute__((packed)) VertexUV { struct __attribute__((packed)) VertexUV {
float x; float x;
float y; float y;
float z; float z;
@ -79,7 +91,7 @@ namespace Crafter {
float pad[2]; float pad[2];
}; };
export struct __attribute__((packed)) VertexRGBA { struct __attribute__((packed)) VertexRGBA {
float x; float x;
float y; float y;
float z; float z;
@ -91,7 +103,7 @@ namespace Crafter {
float a; float a;
}; };
export struct __attribute__((packed)) HeightRGBA { struct __attribute__((packed)) HeightRGBA {
float height; float height;
float pad[3]; float pad[3];
@ -102,97 +114,190 @@ namespace Crafter {
float a; float a;
}; };
export struct FrameTime { struct FrameTime {
std::chrono::time_point<std::chrono::high_resolution_clock> now; std::chrono::time_point<std::chrono::high_resolution_clock> now;
std::chrono::duration<double> delta; std::chrono::duration<double> delta;
}; };
export enum class OpaqueType { enum class OpaqueType {
FullyOpaque, // All pixels have A of 255 FullyOpaque, // All pixels have A of 255
SemiOpaque, // All pixels have A of 0 or 255 (no blending needed) SemiOpaque, // All pixels have A of 0 or 255 (no blending needed)
Transparent // Color blending is used Transparent // Color blending is used
}; };
export constexpr std::int_fast32_t BOUND = 9;
export constexpr std::int_fast32_t SCALE = std::numeric_limits<std::int_fast32_t>::max() / BOUND;
export constexpr double SCALEDOUBLE = static_cast<double>(std::numeric_limits<std::int_fast32_t>::max()) / BOUND;
export constexpr double SCALEDOUBLEU = static_cast<double>(std::numeric_limits<std::uint_fast32_t>::max()) / BOUND;
export constexpr std::int_fast32_t SCALEBOUNDLESS = std::numeric_limits<std::int_fast32_t>::max(); constexpr std::int8_t BOUND8 = 9;
export constexpr double SCALEDOUBLEBOUNDLESS = static_cast<double>(std::numeric_limits<std::int_fast32_t>::max()); constexpr std::int8_t SCALE8 = std::numeric_limits<std::int8_t>::max() / BOUND8;
constexpr std::uint8_t SCALEBOUNDLESS8 = std::numeric_limits<std::uint8_t>::max();
export constexpr std::int_fast32_t SCALEBOUNDLESSU = std::numeric_limits<std::uint_fast32_t>::max(); constexpr double SCALEDOUBLE8 = static_cast<double>(std::numeric_limits<std::int8_t>::max() / BOUND8);
export constexpr double SCALEDOUBLEBOUNDLESSU = static_cast<double>(std::numeric_limits<std::uint_fast32_t>::max()); constexpr double SCALEBOUNDLESSDOUBLE8 = static_cast<double>(std::numeric_limits<std::uint8_t>::max());
export constexpr std::int_fast32_t FractionalToMapped(double f) { constexpr std::int16_t BOUND16 = 9;
return std::int_fast32_t(f * SCALEDOUBLE); constexpr std::int16_t SCALE16 = std::numeric_limits<std::int16_t>::max() / BOUND16;
constexpr std::uint16_t SCALEBOUNDLESS16 = std::numeric_limits<std::uint16_t>::max();
constexpr double SCALEDOUBLE16 = static_cast<double>(std::numeric_limits<std::int16_t>::max() / BOUND16);
constexpr double SCALEBOUNDLESSDOUBLE16 = static_cast<double>(std::numeric_limits<std::uint16_t>::max());
constexpr std::int32_t BOUND32 = 9;
constexpr std::int32_t SCALE32 = std::numeric_limits<std::int32_t>::max() / BOUND32;
constexpr std::uint32_t SCALEBOUNDLESS32 = std::numeric_limits<std::uint32_t>::max();
constexpr double SCALEDOUBLE32 = static_cast<double>(std::numeric_limits<std::int32_t>::max() / BOUND32);
constexpr double SCALEBOUNDLESSDOUBLE32 = static_cast<double>(std::numeric_limits<std::uint32_t>::max());
constexpr std::int64_t BOUND64 = 9;
constexpr std::int64_t SCALE64 = std::numeric_limits<std::int64_t>::max() / BOUND64;
constexpr std::uint64_t SCALEBOUNDLESS64 = std::numeric_limits<std::uint64_t>::max();
constexpr double SCALEDOUBLE64 = static_cast<double>(std::numeric_limits<std::int64_t>::max() / BOUND64);
constexpr double SCALEBOUNDLESSDOUBLE64 = static_cast<double>(std::numeric_limits<std::uint64_t>::max());
template <typename T>
constexpr T FractionalToMapped(double f) requires(std::is_integral_v<T>) {
if constexpr (std::is_same_v<T, std::int8_t> || std::is_same_v<T, std::uint8_t>) {
return T(f * SCALEDOUBLE8);
} else if constexpr (std::is_same_v<T, std::int16_t> || std::is_same_v<T, std::uint16_t>) {
return T(f * SCALEDOUBLE16);
} else if constexpr (std::is_same_v<T, std::int32_t> || std::is_same_v<T, std::uint32_t>) {
return T(f * SCALEDOUBLE32);
} else {
return T(f * SCALEDOUBLE64);
}
} }
export constexpr std::uint_fast32_t FractionalToMappedU(double f) { template <typename T>
return std::uint_fast32_t(f * SCALEDOUBLEU); constexpr T FractionalToMappedBoundless(double f) requires(std::is_integral_v<T>) {
if constexpr (std::is_same_v<T, std::uint8_t> || std::is_same_v<T, std::int8_t>) {
return T(f * SCALEBOUNDLESSDOUBLE8);
} else if constexpr (std::is_same_v<T, std::uint16_t> || std::is_same_v<T, std::int16_t>) {
return T(f * SCALEBOUNDLESSDOUBLE16);
} else if constexpr (std::is_same_v<T, std::uint32_t> || std::is_same_v<T, std::int32_t>) {
return T(f * SCALEBOUNDLESSDOUBLE32);
} else {
return T(f * SCALEBOUNDLESSDOUBLE64);
}
} }
export constexpr double MappedToFractional(std::int_fast32_t mapped) { template <typename T>
return static_cast<double>(mapped) / SCALEDOUBLE; constexpr double MappedToFractional(T mapped) requires(std::is_integral_v<T>) {
if constexpr (std::is_same_v<T, std::int8_t> || std::is_same_v<T, std::uint8_t>) {
return mapped / SCALEDOUBLE8;
} else if constexpr (std::is_same_v<T, std::int16_t> || std::is_same_v<T, std::uint16_t>) {
return mapped / SCALEDOUBLE16;
} else if constexpr (std::is_same_v<T, std::int32_t> || std::is_same_v<T, std::uint32_t>) {
return mapped / SCALEDOUBLE32;
} else {
return mapped / SCALEDOUBLE64;
}
} }
export constexpr std::int_fast32_t MappedToPixel(std::int_fast32_t mapped, std::int_fast32_t width) { template <typename T>
return mapped / (SCALE / width); constexpr double MappedToFractionalBoundless(T mapped) requires(std::is_integral_v<T>) {
if constexpr (std::is_same_v<T, std::uint8_t> || std::is_same_v<T, std::int8_t>) {
return mapped / SCALEBOUNDLESSDOUBLE8;
} else if constexpr (std::is_same_v<T, std::uint16_t> || std::is_same_v<T, std::int16_t>) {
return mapped / SCALEBOUNDLESSDOUBLE16;
} else if constexpr (std::is_same_v<T, std::uint32_t> || std::is_same_v<T, std::int32_t>) {
return mapped / SCALEBOUNDLESSDOUBLE32;
} else {
return mapped / SCALEBOUNDLESSDOUBLE64;
}
} }
export constexpr std::int_fast32_t PixelToMapped(std::int_fast32_t pixel, std::int_fast32_t width) { template <typename T, typename T2>
return pixel * (SCALE / width); constexpr T MappedToAbsolute(T mapped, T2 absolute) requires(std::is_integral_v<T>) {
if constexpr (std::is_same_v<T, std::int8_t> || std::is_same_v<T, std::uint8_t>) {
return static_cast<std::int16_t>(mapped) * absolute / SCALE8;
} else if constexpr (std::is_same_v<T, std::int16_t> || std::is_same_v<T, std::uint16_t>) {
return static_cast<std::int32_t>(mapped) * absolute / SCALE16;
} else if constexpr (std::is_same_v<T, std::int32_t> || std::is_same_v<T, std::uint32_t>) {
return static_cast<std::int64_t>(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) { template <typename T, typename T2>
return static_cast<std::int_fast32_t>( constexpr T MappedToAbsoluteBoundless(T mapped, T2 absolute) requires(std::is_integral_v<T>) {
(static_cast<__int128>(relative) * full) / SCALE if constexpr (std::is_same_v<T, std::uint8_t> || std::is_same_v<T, std::int8_t>) {
); return static_cast<std::uint16_t>(mapped) * absolute / SCALEBOUNDLESS8;
} else if constexpr (std::is_same_v<T, std::uint16_t> || std::is_same_v<T, std::int16_t>) {
return static_cast<std::uint32_t>(mapped) * absolute / SCALEBOUNDLESS16;
} else if constexpr (std::is_same_v<T, std::uint32_t> || std::is_same_v<T, std::int32_t>) {
return static_cast<std::uint64_t>(mapped) * absolute / SCALEBOUNDLESS32;
} else {
return static_cast<unsigned __int128>(mapped) * absolute / SCALEBOUNDLESS64;
}
} }
export constexpr std::int_fast32_t AbsoluteToRelative(std::int_fast32_t absolute, std::int_fast32_t relative) { // template <typename T, typename T2>
return static_cast<std::int_fast32_t>( // constexpr T PixelToMappedBoundless(T pixel, T2 screen) requires(std::is_integral_v<T>) {
(static_cast<__int128>(absolute) * SCALE) / relative // if constexpr (std::is_same_v<T, std::uint8_t>) {
); // return (static_cast<std::uint16_t>(relative) * SCALE8) / (static_cast<std::uint16_t>(absolute) * SCALE8);
// } else if constexpr (std::is_same_v<T, std::uint16_t>) {
// return (static_cast<std::uint32_t>(relative) * SCALE16) / (static_cast<std::uint32_t>(absolute) * SCALE16);
// } else if constexpr (std::is_same_v<T, std::uint32_t>) {
// return (static_cast<std::uint64_t>(relative) * SCALE32) / (static_cast<std::uint64_t>(absolute) * SCALE32);
// } else {
// return (static_cast<unsigned __int128>(relative) * SCALE32) / (static_cast<unsigned __int128>(absolute) * SCALE32);
// }
// }
template <typename T, typename T2>
constexpr T AbsoluteToMapped(T absolute, T2 mapped) {
if constexpr (std::is_same_v<T, std::int8_t> || std::is_same_v<T, std::uint8_t>) {
return static_cast<std::int16_t>(absolute) * SCALE8 / mapped;
} else if constexpr (std::is_same_v<T, std::int16_t> || std::is_same_v<T, std::uint16_t> ) {
return static_cast<std::int32_t>(absolute) * SCALE16 / mapped;
} else if constexpr (std::is_same_v<T, std::int32_t>|| std::is_same_v<T, std::uint32_t>) {
return static_cast<std::int64_t>(absolute) * SCALE32 / mapped;
} else {
return static_cast<__int128>(absolute) * SCALE64 / mapped;
}
} }
export constexpr std::int_fast32_t BoundToBoundless(std::int_fast32_t bound) { template <typename T, typename T2>
return bound * BOUND; constexpr T AbsoluteToMappedBoundless(T absolute, T2 mapped) {
if constexpr (std::is_same_v<T, std::uint8_t> || std::is_same_v<T, std::int8_t> ) {
return static_cast<std::uint16_t>(absolute) * SCALEBOUNDLESS8 / mapped;
} else if constexpr (std::is_same_v<T, std::uint16_t> || std::is_same_v<T, std::int16_t>) {
return static_cast<std::uint32_t>(absolute) * SCALEBOUNDLESS16 / mapped;
} else if constexpr (std::is_same_v<T, std::uint32_t> || std::is_same_v<T, std::int32_t>) {
return static_cast<std::uint64_t>(absolute) * SCALEBOUNDLESS32 / mapped;
} else {
return static_cast<unsigned __int128>(absolute) * SCALEBOUNDLESS64 / mapped;
}
}
template <typename T>
constexpr T BoundToBoundless(T mapped) {
if constexpr (std::is_same_v<T, std::uint8_t> || std::is_same_v<T, std::int8_t>) {
return mapped * BOUND8 * 2;
} else if constexpr (std::is_same_v<T, std::uint16_t> || std::is_same_v<T, std::int16_t>) {
return mapped * BOUND16 * 2;
} else if constexpr (std::is_same_v<T, std::uint32_t> || std::is_same_v<T, std::int32_t>) {
return mapped * BOUND32 * 2;
} else {
return mapped * BOUND64 * 2;
}
} }
export constexpr std::int_fast32_t BoundToBoundlessU(std::int_fast32_t bound) { template <typename T>
return static_cast<std::uint_fast32_t>((bound*2)) * BOUND; constexpr T BoundlessToBound(T mapped) {
if constexpr (std::is_same_v<T, std::uint8_t> || std::is_same_v<T, std::int8_t> ) {
return mapped / 2;
} else if constexpr (std::is_same_v<T, std::uint16_t> || std::is_same_v<T, std::int16_t>) {
return mapped / 2;
} else if constexpr (std::is_same_v<T, std::uint32_t> || std::is_same_v<T, std::int32_t>) {
return mapped / 2;
} else {
return mapped / 2;
}
} }
export constexpr std::int_fast32_t BoundlessToBound(std::int_fast32_t bound) { enum class CrafterKeys {
return bound / BOUND;
}
export constexpr std::int_fast32_t BoundlessUToBound(std::uint_fast32_t bound) {
return static_cast<std::int_fast32_t>(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<double>(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 {
// Alphabetic keys // Alphabetic keys
A, B, C, D, E, F, G, H, I, J, K, L, M, 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, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,

View file

@ -47,10 +47,11 @@ import Crafter.Event;
export namespace Crafter { export namespace Crafter {
class Transform; class Transform;
class MouseElement;
class Window { class Window {
public: public:
std::int_fast32_t width; std::int32_t width;
std::int_fast32_t height; std::int32_t height;
std::chrono::time_point<std::chrono::high_resolution_clock> lastFrameBegin; std::chrono::time_point<std::chrono::high_resolution_clock> lastFrameBegin;
std::vector<Transform*> elements; std::vector<Transform*> elements;
Event<void> onClose; Event<void> onClose;
@ -61,7 +62,7 @@ export namespace Crafter {
float scale; float scale;
Window() = default; 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;
Window(Window&&) = delete; Window(Window&&) = delete;
virtual ~Window() = default; virtual ~Window() = default;
@ -72,13 +73,13 @@ export namespace Crafter {
virtual void StopUpdate() = 0; virtual void StopUpdate() = 0;
void ScaleElement(Transform& element, Transform& parent); void ScaleElement(Transform& element, Transform& parent);
void ScaleElement(Transform& element); void ScaleElement(Transform& element);
void ScaleMouse(Transform& element, Transform& parent); void ScaleMouse(MouseElement& element, Transform& parent);
void ScaleMouse(Transform& element); void ScaleMouse(MouseElement& element);
#ifdef CRAFTER_TIMING #ifdef CRAFTER_TIMING
std::chrono::nanoseconds totalUpdate; std::chrono::nanoseconds totalUpdate;
std::vector<std::pair<const EventListener<FrameTime>*, std::chrono::nanoseconds>> updateTimings; std::vector<std::pair<const EventListener<FrameTime>*, std::chrono::nanoseconds>> updateTimings;
std::chrono::nanoseconds totalRender; std::chrono::nanoseconds totalRender;
std::vector<std::tuple<const Transform*, std::uint_fast32_t, std::uint_fast32_t, std::chrono::nanoseconds>> renderTimings; std::vector<std::tuple<const Transform*, std::uint32_t, std::uint32_t, std::chrono::nanoseconds>> renderTimings;
std::chrono::nanoseconds vblank; std::chrono::nanoseconds vblank;
std::chrono::nanoseconds totalFrame; std::chrono::nanoseconds totalFrame;
std::chrono::time_point<std::chrono::high_resolution_clock> frameEnd; std::chrono::time_point<std::chrono::high_resolution_clock> frameEnd;
@ -110,10 +111,10 @@ export namespace Crafter {
Event<MouseMoveEvent> onMouseMove; Event<MouseMoveEvent> onMouseMove;
Event<MouseMoveEvent> onMouseEnter; Event<MouseMoveEvent> onMouseEnter;
Event<MouseMoveEvent> onMouseLeave; Event<MouseMoveEvent> onMouseLeave;
Event<std::uint_fast32_t> onMouseScroll; Event<std::uint32_t> onMouseScroll;
MousePoint currentMousePos; MousePoint currentMousePos;
MousePoint lastMousePos; MousePoint lastMousePos;
MousePoint mouseDelta; MouseDelta mouseDelta;
bool mouseLeftHeld = false; bool mouseLeftHeld = false;
bool mouseRightHeld = false; bool mouseRightHeld = false;
std::vector<MouseElement*> mouseElements; std::vector<MouseElement*> mouseElements;
@ -129,11 +130,11 @@ export namespace Crafter {
class WindowFramebuffer : public Window { class WindowFramebuffer : public Window {
public: public:
WindowFramebuffer() = default; WindowFramebuffer() = default;
WindowFramebuffer(std::uint_fast32_t width, std::uint_fast32_t height); WindowFramebuffer(std::uint32_t width, std::uint32_t height);
virtual void Resize(std::uint_fast32_t width, std::uint_fast32_t height) = 0; 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(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 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::uint_fast32_t x, std::uint_fast32_t y) const = 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 const Pixel_BU8_GU8_RU8_AU8* Read() const = 0;
virtual Pixel_BU8_GU8_RU8_AU8* Get() = 0; virtual Pixel_BU8_GU8_RU8_AU8* Get() = 0;
virtual void Store() = 0; virtual void Store() = 0;
@ -144,8 +145,8 @@ export namespace Crafter {
class WindowWayland final : public WindowKeyboard, public WindowMouse, public WindowFramebuffer, public WindowTitle { class WindowWayland final : public WindowKeyboard, public WindowMouse, public WindowFramebuffer, public WindowTitle {
public: public:
Pixel_BU8_GU8_RU8_AU8* framebuffer = nullptr; Pixel_BU8_GU8_RU8_AU8* framebuffer = nullptr;
WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height); WindowWayland(std::uint32_t width, std::uint32_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, const std::string_view title);
~WindowWayland(); ~WindowWayland();
bool configured = false; bool configured = false;
wl_shm* shm = nullptr; wl_shm* shm = nullptr;
@ -173,10 +174,10 @@ export namespace Crafter {
void StartUpdate() override; void StartUpdate() override;
void StopUpdate() override; void StopUpdate() override;
void SetTitle(const std::string_view title) 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(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; void Write(std::uint32_t x, std::uint32_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; 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; const Pixel_BU8_GU8_RU8_AU8* Read() const override;
Pixel_BU8_GU8_RU8_AU8* Get() override; Pixel_BU8_GU8_RU8_AU8* Get() override;
void Store() override; void Store() override;

View file

@ -24,7 +24,6 @@ export import :Window;
export import :Transform; export import :Transform;
export import :RenderingElement; export import :RenderingElement;
export import :MouseElement; export import :MouseElement;
export import :TextElement;
export import :GridElement; export import :GridElement;
export import :Types; export import :Types;
export import :Font; export import :Font;

View file

@ -3,8 +3,8 @@
"configurations": [ "configurations": [
{ {
"name": "base", "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"], "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-TextElement", "interfaces/Crafter.Graphics-MouseElement", "interfaces/Crafter.Graphics-Transform", "interfaces/Crafter.Graphics-GridElement"], "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" "type": "library"
}, },
{ {