rendering element rewrite
This commit is contained in:
parent
4c286e1fd8
commit
3d40256bde
22 changed files with 799 additions and 795 deletions
|
|
@ -18,7 +18,7 @@ int main() {
|
|||
FractionalToMapped(1), // relativeHeight
|
||||
FractionalToMapped(0), // anchorOffsetX
|
||||
FractionalToMapped(0), // anchorOffsetY
|
||||
0, // z
|
||||
0 // z
|
||||
);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
|
@ -26,13 +26,13 @@ int main() {
|
|||
OpaqueType::FullyOpaque,
|
||||
1,
|
||||
1,
|
||||
FractionalToMapped(0.5), // anchorX
|
||||
FractionalToMapped(0.5), // anchorY
|
||||
FractionalToMapped(0), // anchorX
|
||||
FractionalToMapped(0), // anchorY
|
||||
FractionalToMapped(1.0), // relativeSizeX (will be overridden by grid)
|
||||
FractionalToMapped(1.0), // relativeSizeY (will be overridden by grid)
|
||||
FractionalToMapped(0.0), // anchorOffsetX
|
||||
FractionalToMapped(0.0), // anchorOffsetY
|
||||
0, // z
|
||||
0 // z
|
||||
);
|
||||
|
||||
// // Set different colors for each element
|
||||
|
|
|
|||
|
|
@ -6,24 +6,34 @@ using namespace Crafter;
|
|||
int main() {
|
||||
WindowWayland window(1280, 720, "Hello Input!");
|
||||
|
||||
RenderingElement 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(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,
|
||||
2,
|
||||
1,
|
||||
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
|
||||
1
|
||||
);
|
||||
|
||||
MouseElement mouse(window);
|
||||
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);
|
||||
element.children.push_back(&mouse);
|
||||
window.elements.push_back(&element);
|
||||
|
||||
element.buffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}};
|
||||
element.scalingBuffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}};
|
||||
element.UpdatePosition(window);
|
||||
|
||||
EventListener<MousePoint> clickListener(&mouse.onMouseLeftClick, [&mouse, &window](MousePoint point){
|
||||
|
|
|
|||
|
|
@ -7,9 +7,10 @@
|
|||
"dependencies": [
|
||||
{
|
||||
"path":"../../project.json",
|
||||
"configuration":"lib-wayland"
|
||||
"configuration":"lib-wayland-debug"
|
||||
}
|
||||
]
|
||||
],
|
||||
"debug": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,94 +26,42 @@ 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 anchorX, std::int_fast32_t anchorY,
|
||||
std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight,
|
||||
std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY,
|
||||
std::int_fast32_t z)
|
||||
: Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z),
|
||||
columns(columns), rows(rows), spacingX(spacingX), spacingY(spacingY) {
|
||||
GridElement::GridElement(std::uint_fast32_t columns, std::uint_fast32_t rows, std::int_fast32_t spacingX, std::int_fast32_t spacingY, Anchor anchor) : Transform(anchor), columns(columns), rows(rows), spacingX(spacingX), spacingY(spacingY) {
|
||||
|
||||
}
|
||||
|
||||
void GridElement::SetGridSize(std::uint_fast32_t columns, std::uint_fast32_t rows) {
|
||||
this->columns = columns;
|
||||
this->rows = rows;
|
||||
}
|
||||
|
||||
void GridElement::SetSpacing(std::int_fast32_t spacingX, std::int_fast32_t spacingY) {
|
||||
this->spacingX = spacingX;
|
||||
this->spacingY = spacingY;
|
||||
void GridElement::UpdatePositionScaled(Window& window) {
|
||||
std::int_fast32_t cellWidth = SCALE / columns;
|
||||
std::int_fast32_t cellHeight = SCALE / 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) {
|
||||
Transform* child = children[childIndex];
|
||||
|
||||
// Calculate position for this child
|
||||
std::int_fast32_t childX = (cellWidth * col) + (spacingX * col);
|
||||
std::int_fast32_t childY = (cellHeight * row) + (spacingY * row);
|
||||
|
||||
// Apply relative positioning
|
||||
child->anchor.x = childX;
|
||||
child->anchor.y = childY;
|
||||
child->anchor.width = cellWidth;
|
||||
child->anchor.height = cellHeight;
|
||||
|
||||
// Update child position
|
||||
child->UpdatePosition(window, *this);
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GridElement::UpdatePosition(Window& window) {
|
||||
window.ScaleElement(*this);
|
||||
|
||||
// Calculate grid dimensions
|
||||
std::int_fast32_t totalWidth = 0;
|
||||
std::int_fast32_t totalHeight = 0;
|
||||
|
||||
if (columns > 0 && rows > 0) {
|
||||
// Calculate the space available for children based on grid size
|
||||
std::int_fast32_t cellWidth = (relativeWidth - (columns - 1) * spacingX) / columns;
|
||||
std::int_fast32_t cellHeight = (relativeHeight - (rows - 1) * spacingY) / rows;
|
||||
|
||||
// Position each child in the grid
|
||||
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) {
|
||||
Transform* child = children[childIndex];
|
||||
|
||||
// Calculate position for this child
|
||||
std::int_fast32_t childX = anchorOffsetX + (cellWidth * col) + (spacingX * col);
|
||||
std::int_fast32_t childY = anchorOffsetY + (cellHeight * row) + (spacingY * row);
|
||||
|
||||
// Apply relative positioning
|
||||
child->anchorX = childX;
|
||||
child->anchorY = childY;
|
||||
child->relativeWidth = cellWidth;
|
||||
child->relativeHeight = cellHeight;
|
||||
|
||||
// Update child position
|
||||
child->UpdatePosition(window, *this);
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdatePositionScaled(window);
|
||||
}
|
||||
|
||||
void GridElement::UpdatePosition(Window& window, Transform& parent) {
|
||||
window.ScaleElement(*this, parent);
|
||||
// Calculate grid dimensions
|
||||
std::int_fast32_t totalWidth = 0;
|
||||
std::int_fast32_t totalHeight = 0;
|
||||
|
||||
if (columns > 0 && rows > 0) {
|
||||
// Calculate the space available for children based on grid size
|
||||
std::int_fast32_t cellWidth = (relativeWidth - (columns - 1) * spacingX) / columns;
|
||||
std::int_fast32_t cellHeight = (relativeHeight - (rows - 1) * spacingY) / rows;
|
||||
|
||||
// Position each child in the grid
|
||||
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) {
|
||||
Transform* child = children[childIndex];
|
||||
|
||||
// Calculate position for this child
|
||||
std::int_fast32_t childX = anchorOffsetX + (cellWidth * col) + (spacingX * col);
|
||||
std::int_fast32_t childY = anchorOffsetY + (cellHeight * row) + (spacingY * row);
|
||||
|
||||
// Apply relative positioning
|
||||
child->anchorX = childX;
|
||||
child->anchorY = childY;
|
||||
child->relativeWidth = cellWidth;
|
||||
child->relativeHeight = cellHeight;
|
||||
|
||||
// Update child position
|
||||
child->UpdatePosition(window, *this);
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdatePositionScaled(window);
|
||||
}
|
||||
|
|
@ -1,73 +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 as published by the Free Software Foundation; either
|
||||
version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
module;
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "../lib/stb_image.h"
|
||||
module Crafter.Graphics:ImageElement_impl;
|
||||
import :ImageElement;
|
||||
import :RenderingElement;
|
||||
import :Window;
|
||||
import :Types;
|
||||
import std;
|
||||
|
||||
using namespace Crafter;
|
||||
|
||||
ImageElement::ImageElement() : RenderingElementScaling() {
|
||||
|
||||
}
|
||||
|
||||
ImageElement::ImageElement(const std::string_view imagePath, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : RenderingElementScaling(OpaqueType::FullyOpaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
RenderImage(imagePath);
|
||||
}
|
||||
|
||||
void ImageElement::RenderImage(const std::string_view path) {
|
||||
std::filesystem::path abs = std::filesystem::absolute(path);
|
||||
int xSize;
|
||||
int ySize;
|
||||
unsigned char* bgData = stbi_load(abs.string().c_str(), &xSize, &ySize, nullptr, 4);
|
||||
|
||||
ResizeBuffer(xSize, ySize);
|
||||
|
||||
opaque = OpaqueType::FullyOpaque;
|
||||
|
||||
for(std::uint_fast32_t x = 0; x < xSize; x++) {
|
||||
for(std::uint_fast32_t y = 0; y < ySize; y++) {
|
||||
std::uint_fast32_t idx = (x*ySize+y)*4;
|
||||
buffer[x*ySize+y].r = bgData[idx];
|
||||
buffer[x*ySize+y].g = bgData[idx+1];
|
||||
buffer[x*ySize+y].b = bgData[idx+2];
|
||||
buffer[x*ySize+y].a = bgData[idx+3];
|
||||
}
|
||||
}
|
||||
|
||||
for(std::uint_fast32_t i = 0; i < xSize*ySize; i++) {
|
||||
if(buffer[i].a != 255) {
|
||||
opaque = OpaqueType::SemiOpaque;
|
||||
for(std::uint_fast32_t i2 = 0; i2 < xSize*ySize; i2++) {
|
||||
if(buffer[i2].a != 0 && buffer[i2].a != 255) {
|
||||
opaque = OpaqueType::Transparent;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,14 +27,15 @@ import std;
|
|||
|
||||
using namespace Crafter;
|
||||
|
||||
MouseElement::MouseElement(WindowMouse& window, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z) {
|
||||
MouseElement::MouseElement(Anchor anchor, WindowMouse& window) : Transform(anchor) {
|
||||
window.mouseElements.push_back(this);
|
||||
}
|
||||
|
||||
MouseElement::MouseElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z) {
|
||||
MouseElement::MouseElement(Anchor anchor) : Transform(anchor) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MouseElement::UpdatePosition(Window& window) {
|
||||
window.ScaleMouse(*this);
|
||||
for(Transform* child : children) {
|
||||
|
|
|
|||
|
|
@ -1,162 +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 as published by the Free Software Foundation; either
|
||||
version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
module Crafter.Graphics:RenderingElement_impl;
|
||||
import :RenderingElement;
|
||||
import :Window;
|
||||
import :Types;
|
||||
import :Font;
|
||||
import std;
|
||||
|
||||
using namespace Crafter;
|
||||
|
||||
RenderingElement::RenderingElement(OpaqueType opaque) : Transform(), opaque(opaque) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
RenderingElement::RenderingElement(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z), opaque(opaque) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementPreScaled::RenderingElementPreScaled(OpaqueType opaque) : RenderingElement(opaque) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementPreScaled::RenderingElementPreScaled(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z) : RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementScaling::RenderingElementScaling(OpaqueType opaque) : RenderingElement(opaque) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementScaling::RenderingElementScaling(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z) : RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementScaling::RenderingElementScaling(OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z) : bufferWidth(bufferWidth), bufferHeight(bufferHeight), buffer(bufferWidth*bufferHeight), RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RenderingElementPreScaled::UpdatePosition(Window& window) {
|
||||
ScaleData oldScale = scaled;
|
||||
window.ScaleElement(*this);
|
||||
|
||||
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||
bufferScaled.resize(scaled.width * scaled.height);
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
} else if(oldScale.x != scaled.x || oldScale.y != scaled.y) {
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
}
|
||||
|
||||
for(Transform* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingElementPreScaled::UpdatePosition(Window& window, Transform& parent) {
|
||||
ScaleData oldScale = scaled;
|
||||
window.ScaleElement(*this, parent);
|
||||
|
||||
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||
bufferScaled.resize(scaled.width * scaled.height);
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
} else if(oldScale.x != scaled.x || oldScale.y != scaled.y) {
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
}
|
||||
|
||||
for(Transform* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingElementPreScaled::CopyNearestNeighbour(Pixel_BU8_GU8_RU8_AU8* dst, std::uint_fast32_t dstWidth, std::uint_fast32_t dstHeight) const {
|
||||
for (std::uint_fast32_t y = 0; y < dstHeight; y++) {
|
||||
std::uint_fast32_t srcY = y * scaled.height / dstHeight;
|
||||
for (std::uint_fast32_t x = 0; x < dstWidth; x++) {
|
||||
std::uint_fast32_t srcX = x * scaled.width / dstWidth;
|
||||
dst[y * dstWidth + x] = bufferScaled[srcY * scaled.width + srcX];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingElementScaling::CopyNearestNeighbour(Pixel_BU8_GU8_RU8_AU8* dst, std::uint_fast32_t dstWidth, std::uint_fast32_t dstHeight) const {
|
||||
for (std::uint_fast32_t y = 0; y < dstHeight; y++) {
|
||||
std::uint_fast32_t srcY = y * bufferHeight / dstHeight;
|
||||
for (std::uint_fast32_t x = 0; x < dstWidth; x++) {
|
||||
std::uint_fast32_t srcX = x * bufferWidth / dstWidth;
|
||||
dst[y * dstWidth + x] = buffer[srcY * bufferWidth + srcX];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingElementScaling::UpdatePosition(Window& window) {
|
||||
ScaleData oldScale = scaled;
|
||||
std::cout << MappedToFractional(relativeWidth) << std::endl;
|
||||
window.ScaleElement(*this);
|
||||
std::cout << scaled.width << std::endl;
|
||||
|
||||
|
||||
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||
bufferScaled.resize(scaled.width * scaled.height);
|
||||
CopyNearestNeighbour(bufferScaled.data(), scaled.width, scaled.height);
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
} else if(oldScale.x != scaled.x || oldScale.y != scaled.y) {
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
}
|
||||
|
||||
for(Transform* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingElementScaling::UpdatePosition(Window& window, Transform& parent) {
|
||||
ScaleData oldScale = scaled;
|
||||
window.ScaleElement(*this, parent);
|
||||
|
||||
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||
bufferScaled.resize(scaled.width * scaled.height);
|
||||
CopyNearestNeighbour(bufferScaled.data(), scaled.width, scaled.height);
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
} else if(oldScale.x != scaled.x || oldScale.y != scaled.y) {
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
}
|
||||
|
||||
for(Transform* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingElementScaling::ResizeBuffer(std::uint_fast32_t width, std::uint_fast32_t height) {
|
||||
this->bufferWidth = width;
|
||||
this->bufferHeight = height;
|
||||
buffer.resize(width * height);
|
||||
}
|
||||
|
|
@ -1,172 +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 as published by the Free Software Foundation; either
|
||||
version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
module Crafter.Graphics:RenderingElementScalingRotating2D_impl;
|
||||
import :RenderingElement;
|
||||
import :Window;
|
||||
import :Types;
|
||||
import :Font;
|
||||
import std;
|
||||
|
||||
using namespace Crafter;
|
||||
|
||||
RenderingElementScalingRotating2D::RenderingElementScalingRotating2D(OpaqueType opaque) : RenderingElement(opaque), rotation(0) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementScalingRotating2D::RenderingElementScalingRotating2D(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z) : RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z), rotation(0) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementScalingRotating2D::RenderingElementScalingRotating2D(OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::uint_fast32_t rotation, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z)
|
||||
: bufferWidth(bufferWidth), bufferHeight(bufferHeight), buffer(bufferWidth*bufferHeight),
|
||||
rotation(rotation),
|
||||
RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z) {
|
||||
}
|
||||
|
||||
void RenderingElementScalingRotating2D::ResizeBuffer(std::uint_fast32_t width, std::uint_fast32_t height) {
|
||||
this->bufferWidth = width;
|
||||
this->bufferHeight = height;
|
||||
buffer.resize(width * height);
|
||||
}
|
||||
|
||||
void RenderingElementScalingRotating2D::UpdateRotation(std::uint_fast32_t rotation) {
|
||||
rotationUpdated = true;
|
||||
this->rotation = rotation;
|
||||
}
|
||||
|
||||
void RenderingElementScalingRotating2D::UpdateScaledBuffer(ScaleData& scaled) {
|
||||
// Rotation
|
||||
const double rad = (static_cast<double>(rotation) / static_cast<double>(std::numeric_limits<std::uint_fast32_t>::max())) * 2.0 * std::numbers::pi;
|
||||
|
||||
const std::uint_fast32_t dstWidth = scaled.width;
|
||||
const std::uint_fast32_t dstHeight = scaled.height;
|
||||
|
||||
const double rotatedWidth = scaled.width * (std::abs(std::cos(rad)) + std::abs(std::sin(rad)));
|
||||
const double rotatedHeight = scaled.height * (std::abs(std::cos(rad)) + std::abs(std::sin(rad)));
|
||||
|
||||
const std::uint_fast32_t diffX = std::ceil((rotatedWidth - scaled.width)/2);
|
||||
const std::uint_fast32_t diffY = std::ceil((rotatedHeight - scaled.height)/2);
|
||||
|
||||
scaled.width += diffX + diffX;
|
||||
scaled.height += diffY + diffY;
|
||||
|
||||
scaled.x -= diffX;
|
||||
scaled.y -= diffY;
|
||||
|
||||
bufferScaled.clear();
|
||||
bufferScaled.resize(scaled.width * scaled.height);
|
||||
|
||||
// Destination center
|
||||
const double dstCx = (static_cast<double>(scaled.width) - 1.0) * 0.5;
|
||||
const double dstCy = (static_cast<double>(scaled.height) - 1.0) * 0.5;
|
||||
|
||||
// Source center
|
||||
const double srcCx = (static_cast<double>(bufferWidth) - 1.0) * 0.5;
|
||||
const double srcCy = (static_cast<double>(bufferHeight) - 1.0) * 0.5;
|
||||
|
||||
const double c = std::cos(rad);
|
||||
const double s = std::sin(rad);
|
||||
|
||||
// Scale factors (destination → source)
|
||||
const double scaleX = static_cast<double>(bufferWidth) / dstWidth;
|
||||
const double scaleY = static_cast<double>(bufferHeight) / dstHeight;
|
||||
|
||||
for (std::uint_fast32_t yB = 0; yB < scaled.height; ++yB) {
|
||||
for (std::uint_fast32_t xB = 0; xB < scaled.width; ++xB) {
|
||||
|
||||
// ---- Destination pixel relative to center ----
|
||||
const double dx = (static_cast<double>(xB) - dstCx) * scaleX;
|
||||
const double dy = (static_cast<double>(yB) - dstCy) * scaleY;
|
||||
|
||||
// ---- Inverse rotation ----
|
||||
const double sx = (c * dx - s * dy) + srcCx;
|
||||
const double sy = (s * dx + c * dy) + srcCy;
|
||||
|
||||
// ---- Nearest neighbour sampling ----
|
||||
const std::int_fast32_t srcX = static_cast<std::int_fast32_t>(std::round(sx));
|
||||
const std::int_fast32_t srcY = static_cast<std::int_fast32_t>(std::round(sy));
|
||||
|
||||
if (srcX >= 0 && srcX < bufferWidth && srcY >= 0 && srcY < bufferHeight) {
|
||||
bufferScaled[yB * scaled.width + xB] = buffer[srcY * bufferWidth + srcX];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void RenderingElementScalingRotating2D::UpdatePosition(Window& window) {
|
||||
ScaleData oldScale = scaled;
|
||||
window.ScaleElement(*this);
|
||||
|
||||
if(oldScale.width != scaled.width || oldScale.height != scaled.height || rotationUpdated) {
|
||||
UpdateScaledBuffer(scaled);
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
rotationUpdated = false;
|
||||
} else if(oldScale.x != scaled.x || oldScale.y != scaled.y) {
|
||||
|
||||
const double rad = (static_cast<double>(rotation) / static_cast<double>(std::numeric_limits<std::uint_fast32_t>::max())) * 2.0 * std::numbers::pi;
|
||||
|
||||
const double rotatedWidth = scaled.width * (std::abs(std::cos(rad)) + std::abs(std::sin(rad)));
|
||||
const double rotatedHeight = scaled.height * (std::abs(std::cos(rad)) + std::abs(std::sin(rad)));
|
||||
|
||||
scaled.width = static_cast<std::uint_fast32_t>(std::ceil(rotatedWidth));
|
||||
scaled.height = static_cast<std::uint_fast32_t>(std::ceil(rotatedHeight));
|
||||
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
}
|
||||
|
||||
for(Transform* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingElementScalingRotating2D::UpdatePosition(Window& window, Transform& parent) {
|
||||
ScaleData oldScale = scaled;
|
||||
window.ScaleElement(*this, parent);
|
||||
|
||||
if(oldScale.width != scaled.width || oldScale.height != scaled.height || rotationUpdated) {
|
||||
UpdateScaledBuffer(scaled);
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
rotationUpdated = false;
|
||||
} else if(oldScale.x != scaled.x || oldScale.y != scaled.y) {
|
||||
const double rad = (static_cast<double>(rotation) / static_cast<double>(std::numeric_limits<std::uint_fast32_t>::max())) * 2.0 * std::numbers::pi;
|
||||
|
||||
const double rotatedWidth = scaled.width * (std::abs(std::cos(rad)) + std::abs(std::sin(rad)));
|
||||
const double rotatedHeight = scaled.height * (std::abs(std::cos(rad)) + std::abs(std::sin(rad)));
|
||||
|
||||
scaled.width = static_cast<std::uint_fast32_t>(std::ceil(rotatedWidth));
|
||||
scaled.height = static_cast<std::uint_fast32_t>(std::ceil(rotatedHeight));
|
||||
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
}
|
||||
|
||||
for(Transform* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ import std;
|
|||
|
||||
using namespace Crafter;
|
||||
|
||||
TextElement::TextElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z) : RenderingElementPreScaled(OpaqueType::Transparent, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z) {
|
||||
TextElement::TextElement(Anchor anchor): RenderingElement<false, false, false>(anchor, OpaqueType::Transparent) {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ void TextElement::RenderText(Window& window, const std::string_view text, float
|
|||
int baseline = (int)(font.ascent * scale);
|
||||
|
||||
// Clear the scaled buffer
|
||||
for (auto& pixel : bufferScaled) {
|
||||
for (auto& pixel : buffer) {
|
||||
pixel = {0, 0, 0, 0};
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ void TextElement::RenderText(Window& window, const std::string_view text, float
|
|||
|
||||
// Only draw pixels that are within our scaled buffer bounds
|
||||
if (bufferX >= 0 && bufferX < (int)scaled.width && bufferY >= 0 && bufferY < (int)scaled.height) {
|
||||
bufferScaled[bufferY * scaled.width + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
buffer[bufferY * scaled.width + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -288,11 +288,11 @@ void TextElement::RenderText(Window& window, const std::string_view text, float
|
|||
for (std::uint_fast32_t y = 0; y < scaled.height; ++y) {
|
||||
for (std::uint_fast32_t x = 0; x < scaled.width; ++x) {
|
||||
std::uint_fast32_t index = y * scaled.width + x;
|
||||
if (index < bufferScaled.size()) {
|
||||
if (index < buffer.size()) {
|
||||
// Move the pixel vertically
|
||||
std::uint_fast32_t newIndex = (y + verticalOffset) * scaled.width + x;
|
||||
if (newIndex < bufferScaled.size()) {
|
||||
bufferScaled[newIndex] = bufferScaled[index];
|
||||
if (newIndex < buffer.size()) {
|
||||
buffer[newIndex] = buffer[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -355,7 +355,7 @@ void TextElement::RenderWrappedLine(const std::string_view line, float scale, in
|
|||
|
||||
// Only draw pixels that are within our scaled buffer bounds
|
||||
if (bufferX >= 0 && bufferX < (int)scaled.width && bufferY >= 0 && bufferY < (int)scaled.height) {
|
||||
bufferScaled[bufferY * scaled.width + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
buffer[bufferY * scaled.width + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,15 +27,20 @@ import std;
|
|||
|
||||
using namespace Crafter;
|
||||
|
||||
Transform::Transform(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z) : anchorX(anchorX), anchorY(anchorY), relativeWidth(relativeWidth), relativeHeight(relativeHeight), anchorOffsetX(anchorOffsetX), anchorOffsetY(anchorOffsetY), z(z) {
|
||||
|
||||
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): x(x), y(y), width(width), height(height), offsetX(offsetX), offsetY(offsetY), z(z) {
|
||||
|
||||
}
|
||||
|
||||
Transform::Transform(Anchor anchor) : anchor(anchor) {
|
||||
|
||||
}
|
||||
|
||||
void Transform::UpdatePosition(Window& window) {
|
||||
window.ScaleElement(*this);
|
||||
for(Transform* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void Transform::UpdatePosition(Window& window, Transform& parent) {
|
||||
|
|
|
|||
|
|
@ -29,35 +29,35 @@ Window::Window(std::int_fast32_t width, std::int_fast32_t height) : width(width)
|
|||
}
|
||||
|
||||
void Window::ScaleElement(Transform& element) {
|
||||
element.scaled.width = MappedToPixel(element.relativeWidth, width);
|
||||
element.scaled.height = MappedToPixel(element.relativeHeight, height);
|
||||
element.scaled.x = MappedToPixel(element.anchorX, width) - MappedToPixel(element.anchorOffsetX, element.scaled.width);
|
||||
element.scaled.y = MappedToPixel(element.anchorY, height) - MappedToPixel(element.anchorOffsetY, element.scaled.height);
|
||||
element.scaled.width = MappedToPixel(element.anchor.width, width);
|
||||
element.scaled.height = MappedToPixel(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);
|
||||
}
|
||||
|
||||
void Window::ScaleElement(Transform& element, Transform& parent) {
|
||||
element.scaled.width = MappedToPixel(element.relativeWidth, parent.scaled.width);
|
||||
element.scaled.height = MappedToPixel(element.relativeHeight, parent.scaled.height);
|
||||
element.scaled.x = MappedToPixel(element.anchorX, parent.scaled.width) - MappedToPixel(element.anchorOffsetX, element.scaled.width) + parent.scaled.x;
|
||||
element.scaled.y = MappedToPixel(element.anchorY, parent.scaled.height) - MappedToPixel(element.anchorOffsetY, element.scaled.height) + parent.scaled.y;
|
||||
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;
|
||||
}
|
||||
|
||||
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.relativeWidth, PixelToMapped(parent.scaled.width, width)));
|
||||
element.scaled.height = BoundToBoundless(MappedToPixel(element.relativeHeight, PixelToMapped(parent.scaled.height, height)));
|
||||
element.scaled.x = MappedToPixelBoundless(element.anchorX, boundlessWidth) - MappedToPixelBoundless(element.anchorOffsetX, element.scaled.width) + PixelToMappedBoundless(parent.scaled.x, width);
|
||||
element.scaled.y = MappedToPixelBoundless(element.anchorY, boundlessHeight) - MappedToPixelBoundless(element.anchorOffsetY, element.scaled.height) + PixelToMappedBoundless(parent.scaled.y, 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(Transform& element) {
|
||||
// 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.relativeWidth, width));
|
||||
// element.scaled.height = BoundToBoundless(MappedToPixel(element.relativeHeight, height));
|
||||
// element.scaled.x = MappedToPixelBoundless(element.anchorX, boundlessWidth) - MappedToPixelBoundless(element.anchorOffsetX, element.scaled.width) + PixelToMappedBoundless(parent.scaled.x, width);
|
||||
// element.scaled.y = MappedToPixelBoundless(element.anchorY, boundlessHeight) - MappedToPixelBoundless(element.anchorOffsetY, element.scaled.height) + PixelToMappedBoundless(parent.scaled.y, 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);
|
||||
// element.scaled.y = MappedToPixelBoundless(element.anchor.y, boundlessHeight) - MappedToPixelBoundless(element.anchor.offsetY, element.scaled.height) + PixelToMappedBoundless(parent.scaled.y, height);
|
||||
}
|
||||
|
||||
#ifdef CRAFTER_TIMING
|
||||
|
|
@ -107,30 +107,30 @@ void Window::AddDirtyRect(ScaleData scale) {
|
|||
.bottom = std::min(scale.y + scale.height, height),
|
||||
};
|
||||
|
||||
if (rect.left >= rect.right || rect.top >= rect.bottom) {
|
||||
return;
|
||||
}
|
||||
// if (rect.left >= rect.right || rect.top >= rect.bottom) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
for(ClipRect existing : dirtyRects) {
|
||||
//fully enclosed
|
||||
if(rect.left >= existing.left && rect.right <= existing.right && rect.top >= existing.top && rect.bottom <= existing.bottom) {
|
||||
return;
|
||||
}
|
||||
// for(ClipRect existing : dirtyRects) {
|
||||
// //fully enclosed
|
||||
// if(rect.left >= existing.left && rect.right <= existing.right && rect.top >= existing.top && rect.bottom <= existing.bottom) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
//horizontal line
|
||||
if(rect.top == existing.top && rect.bottom == existing.bottom) {
|
||||
existing.left = std::min(rect.left, existing.left);
|
||||
existing.right = std::max(rect.right, existing.right);
|
||||
return;
|
||||
}
|
||||
// //horizontal line
|
||||
// if(rect.top == existing.top && rect.bottom == existing.bottom) {
|
||||
// existing.left = std::min(rect.left, existing.left);
|
||||
// existing.right = std::max(rect.right, existing.right);
|
||||
// return;
|
||||
// }
|
||||
|
||||
//vertical line
|
||||
if(rect.left == existing.left && rect.right == existing.right) {
|
||||
existing.top = std::min(rect.top, existing.top);
|
||||
existing.bottom = std::max(rect.bottom, existing.bottom);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// //vertical line
|
||||
// if(rect.left == existing.left && rect.right == existing.right) {
|
||||
// existing.top = std::min(rect.top, existing.top);
|
||||
// existing.bottom = std::max(rect.bottom, existing.bottom);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
//no overlap
|
||||
dirtyRects.push_back(rect);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ module;
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "../lib/xdg-shell-client-protocol.h"
|
||||
#include "../lib/wayland-xdg-decoration-unstable-v1-client-protocol.h"
|
||||
#include <string.h>
|
||||
|
|
@ -155,7 +154,7 @@ inline void blend_pixel_optimized(Pixel_BU8_GU8_RU8_AU8& dst, const Pixel_BU8_GU
|
|||
}
|
||||
|
||||
void WindowWayland::RenderElement(Transform* transform) {
|
||||
RenderingElement* element = dynamic_cast<RenderingElement*>(transform);
|
||||
RenderingElementBase* element = dynamic_cast<RenderingElementBase*>(transform);
|
||||
if(element) {
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
|
@ -171,7 +170,7 @@ void WindowWayland::RenderElement(Transform* transform) {
|
|||
dirty.right = std::min(element->scaled.x+element->scaled.width, dirty.right);
|
||||
dirty.bottom = std::min(element->scaled.y+element->scaled.height, dirty.bottom);
|
||||
|
||||
const Pixel_BU8_GU8_RU8_AU8* src_buffer = element->bufferScaled.data();
|
||||
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;
|
||||
|
||||
|
|
@ -226,7 +225,7 @@ void WindowWayland::RenderElement(Transform* transform) {
|
|||
#endif
|
||||
}
|
||||
|
||||
std::sort(transform->children.begin(), transform->children.end(), [](Transform* a, Transform* b){ return a->z < b->z; });
|
||||
std::sort(transform->children.begin(), transform->children.end(), [](Transform* a, Transform* b){ return a->anchor.z < b->anchor.z; });
|
||||
for(Transform* child : transform->children) {
|
||||
this->RenderElement(child);
|
||||
}
|
||||
|
|
@ -234,87 +233,107 @@ void WindowWayland::RenderElement(Transform* transform) {
|
|||
|
||||
void WindowWayland::Render() {
|
||||
elements.erase(std::remove(elements.begin(), elements.end(), static_cast<Transform*>(nullptr)), elements.end());
|
||||
std::sort(elements.begin(), elements.end(), [](Transform* a, Transform* b){ return a->z < b->z; });
|
||||
std::sort(elements.begin(), elements.end(), [](Transform* a, Transform* b){ return a->anchor.z < b->anchor.z; });
|
||||
|
||||
std::vector<ClipRect> newClip;
|
||||
//std::vector<ClipRect> newClip;
|
||||
|
||||
for (std::uint_fast32_t i = 0; i < dirtyRects.size(); i++) {
|
||||
ClipRect rect = dirtyRects[i];
|
||||
for (std::uint_fast32_t i2 = i + 1; i2 < dirtyRects.size(); i2++) {
|
||||
ClipRect existing = dirtyRects[i2];
|
||||
if(rect.bottom >= existing.top && rect.top <= existing.top) {
|
||||
newClip.push_back({
|
||||
.left = rect.left,
|
||||
.right = rect.right,
|
||||
.top = rect.top,
|
||||
.bottom = existing.top,
|
||||
});
|
||||
//-| shape
|
||||
if(rect.right > existing.right) {
|
||||
newClip.push_back({
|
||||
.left = existing.right,
|
||||
.right = rect.right,
|
||||
.top = existing.top,
|
||||
.bottom = existing.bottom,
|
||||
});
|
||||
}
|
||||
//|- shape
|
||||
if(rect.left < existing.left) {
|
||||
newClip.push_back({
|
||||
.left = rect.left,
|
||||
.right = existing.left,
|
||||
.top = existing.top,
|
||||
.bottom = existing.bottom,
|
||||
});
|
||||
}
|
||||
//-| or |- shape where rect extends further down
|
||||
if(rect.bottom > existing.bottom) {
|
||||
newClip.push_back({
|
||||
.left = rect.left,
|
||||
.right = rect.right,
|
||||
.top = existing.bottom,
|
||||
.bottom = rect.bottom,
|
||||
});
|
||||
}
|
||||
goto inner;
|
||||
}
|
||||
if (rect.left <= existing.right && rect.right >= existing.left) {
|
||||
newClip.push_back({
|
||||
.left = rect.left,
|
||||
.right = existing.left,
|
||||
.top = rect.top,
|
||||
.bottom = rect.bottom,
|
||||
});
|
||||
if (rect.right > existing.right) {
|
||||
newClip.push_back({
|
||||
.left = existing.right,
|
||||
.right = rect.right,
|
||||
.top = rect.top,
|
||||
.bottom = rect.bottom,
|
||||
});
|
||||
}
|
||||
goto inner;
|
||||
}
|
||||
}
|
||||
newClip.push_back(rect);
|
||||
inner:;
|
||||
}
|
||||
|
||||
dirtyRects = std::move(newClip);
|
||||
|
||||
// for(uint_fast32_t i = 0; i < width*height; i++) {
|
||||
// framebuffer[i] = {0, 0, 0, 255};
|
||||
// for (std::uint_fast32_t i = 0; i < dirtyRects.size(); i++) {
|
||||
// ClipRect rect = dirtyRects[i];
|
||||
// for (std::uint_fast32_t i2 = i + 1; i2 < dirtyRects.size(); i2++) {
|
||||
// ClipRect existing = dirtyRects[i2];
|
||||
// if(rect.bottom >= existing.top && rect.top <= existing.top) {
|
||||
// newClip.push_back({
|
||||
// .left = rect.left,
|
||||
// .right = rect.right,
|
||||
// .top = rect.top,
|
||||
// .bottom = existing.top,
|
||||
// });
|
||||
// //-| shape
|
||||
// if(rect.right > existing.right) {
|
||||
// newClip.push_back({
|
||||
// .left = existing.right,
|
||||
// .right = rect.right,
|
||||
// .top = existing.top,
|
||||
// .bottom = existing.bottom,
|
||||
// });
|
||||
// }
|
||||
// //|- shape
|
||||
// if(rect.left < existing.left) {
|
||||
// newClip.push_back({
|
||||
// .left = rect.left,
|
||||
// .right = existing.left,
|
||||
// .top = existing.top,
|
||||
// .bottom = existing.bottom,
|
||||
// });
|
||||
// }
|
||||
// //-| or |- shape where rect extends further down
|
||||
// if(rect.bottom > existing.bottom) {
|
||||
// newClip.push_back({
|
||||
// .left = rect.left,
|
||||
// .right = rect.right,
|
||||
// .top = existing.bottom,
|
||||
// .bottom = rect.bottom,
|
||||
// });
|
||||
// }
|
||||
// goto inner;
|
||||
// }
|
||||
// if (rect.left <= existing.right && rect.right >= existing.left) {
|
||||
// newClip.push_back({
|
||||
// .left = rect.left,
|
||||
// .right = existing.left,
|
||||
// .top = rect.top,
|
||||
// .bottom = rect.bottom,
|
||||
// });
|
||||
// if (rect.right > existing.right) {
|
||||
// newClip.push_back({
|
||||
// .left = existing.right,
|
||||
// .right = rect.right,
|
||||
// .top = rect.top,
|
||||
// .bottom = rect.bottom,
|
||||
// });
|
||||
// }
|
||||
// goto inner;
|
||||
// }
|
||||
// }
|
||||
// newClip.push_back(rect);
|
||||
// inner:;
|
||||
// }
|
||||
|
||||
//dirtyRects = std::move(newClip);
|
||||
|
||||
// std::memset(framebuffer, 0, width*height*4);
|
||||
|
||||
// std::cout << dirtyRects.size() << std::endl;
|
||||
// for (ClipRect rect : dirtyRects) {
|
||||
// //std::cout << std::format("{}, {}, {}, {}", rect.left, rect.top, rect.right, rect.bottom) << 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++) {
|
||||
// framebuffer[y * width + x].r += 30;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // Color palette
|
||||
// static const std::vector<Pixel_BU8_GU8_RU8_AU8> colors = {
|
||||
// {255, 0, 0, 255}, // red
|
||||
// { 0, 255, 0, 255}, // green
|
||||
// { 0, 0, 255, 255}, // blue
|
||||
// {255, 255, 0, 255}, // yellow
|
||||
// {255, 0, 255, 255}, // magenta
|
||||
// { 0, 255, 255, 255}, // cyan
|
||||
// };
|
||||
|
||||
// std::size_t rectIndex = 0;
|
||||
|
||||
// for (const ClipRect& rect : dirtyRects) {
|
||||
// const Pixel_BU8_GU8_RU8_AU8& color = colors[rectIndex % colors.size()];
|
||||
|
||||
// std::cout << std::format(
|
||||
// "ClipRect {}: [{}, {}, {}, {}] Color = RGBA({}, {}, {}, {})",
|
||||
// rectIndex,
|
||||
// rect.left, rect.top, rect.right, rect.bottom,
|
||||
// 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) {
|
||||
// framebuffer[y * width + x] = color;
|
||||
// }
|
||||
// }
|
||||
|
||||
// ++rectIndex;
|
||||
// }
|
||||
|
||||
if (!dirtyRects.empty()) {
|
||||
for (ClipRect rect : dirtyRects) {
|
||||
|
|
@ -335,11 +354,17 @@ void WindowWayland::Render() {
|
|||
dirtyRects.clear();
|
||||
}
|
||||
|
||||
dirtyRects.clear();
|
||||
wl_surface_damage(surface, 0, 0, width, height);
|
||||
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
wl_surface_commit(surface);
|
||||
wl_surface_commit(surface);
|
||||
wl_surface_damage(surface, 0, 0, 10000, 100000);
|
||||
}
|
||||
|
||||
void WindowWayland::QueueRender() {
|
||||
std::cout << cb << std::endl;
|
||||
if(cb == nullptr) {
|
||||
cb = wl_surface_frame(surface);
|
||||
wl_callback_add_listener(cb, &wl_callback_listener, this);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowWayland::StartUpdate() {
|
||||
|
|
@ -396,6 +421,7 @@ void WindowWayland::wl_surface_frame_done(void* data, struct wl_callback *cb, ui
|
|||
{
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
wl_callback_destroy(cb);
|
||||
cb = nullptr;
|
||||
WindowWayland* window = reinterpret_cast<WindowWayland*>(data);
|
||||
#ifdef CRAFTER_TIMING
|
||||
window->vblank = duration_cast<std::chrono::milliseconds>(start - window->frameEnd);
|
||||
|
|
@ -413,18 +439,18 @@ void WindowWayland::wl_surface_frame_done(void* data, struct wl_callback *cb, ui
|
|||
window->totalUpdate += entry.second;
|
||||
}
|
||||
#endif
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto renderStart = std::chrono::high_resolution_clock::now();
|
||||
window->renderTimings.clear();
|
||||
#endif
|
||||
window->Render();
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto renderEnd = std::chrono::high_resolution_clock::now();
|
||||
window->totalRender = renderEnd - renderStart;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto renderStart = std::chrono::high_resolution_clock::now();
|
||||
window->renderTimings.clear();
|
||||
#endif
|
||||
window->Render();
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto renderEnd = std::chrono::high_resolution_clock::now();
|
||||
window->totalRender = renderEnd - renderStart;
|
||||
#endif
|
||||
|
||||
#ifdef CRAFTER_TIMING
|
||||
window->frameEnd = std::chrono::high_resolution_clock::now();
|
||||
|
||||
|
|
@ -557,6 +583,132 @@ void WindowWayland::keyboard_leave(void *data, wl_keyboard *keyboard, uint32_t s
|
|||
|
||||
}
|
||||
|
||||
CrafterKeys keysym_to_crafter_key(xkb_keysym_t sym)
|
||||
{
|
||||
switch (sym)
|
||||
{
|
||||
// Alphabet
|
||||
case XKB_KEY_a: return CrafterKeys::A;
|
||||
case XKB_KEY_b: return CrafterKeys::B;
|
||||
case XKB_KEY_c: return CrafterKeys::C;
|
||||
case XKB_KEY_d: return CrafterKeys::D;
|
||||
case XKB_KEY_e: return CrafterKeys::E;
|
||||
case XKB_KEY_f: return CrafterKeys::F;
|
||||
case XKB_KEY_g: return CrafterKeys::G;
|
||||
case XKB_KEY_h: return CrafterKeys::H;
|
||||
case XKB_KEY_i: return CrafterKeys::I;
|
||||
case XKB_KEY_j: return CrafterKeys::J;
|
||||
case XKB_KEY_k: return CrafterKeys::K;
|
||||
case XKB_KEY_l: return CrafterKeys::L;
|
||||
case XKB_KEY_m: return CrafterKeys::M;
|
||||
case XKB_KEY_n: return CrafterKeys::N;
|
||||
case XKB_KEY_o: return CrafterKeys::O;
|
||||
case XKB_KEY_p: return CrafterKeys::P;
|
||||
case XKB_KEY_q: return CrafterKeys::Q;
|
||||
case XKB_KEY_r: return CrafterKeys::R;
|
||||
case XKB_KEY_s: return CrafterKeys::S;
|
||||
case XKB_KEY_t: return CrafterKeys::T;
|
||||
case XKB_KEY_u: return CrafterKeys::U;
|
||||
case XKB_KEY_v: return CrafterKeys::V;
|
||||
case XKB_KEY_w: return CrafterKeys::W;
|
||||
case XKB_KEY_x: return CrafterKeys::X;
|
||||
case XKB_KEY_y: return CrafterKeys::Y;
|
||||
case XKB_KEY_z: return CrafterKeys::Z;
|
||||
|
||||
// Numbers
|
||||
case XKB_KEY_0: return CrafterKeys::_0;
|
||||
case XKB_KEY_1: return CrafterKeys::_1;
|
||||
case XKB_KEY_2: return CrafterKeys::_2;
|
||||
case XKB_KEY_3: return CrafterKeys::_3;
|
||||
case XKB_KEY_4: return CrafterKeys::_4;
|
||||
case XKB_KEY_5: return CrafterKeys::_5;
|
||||
case XKB_KEY_6: return CrafterKeys::_6;
|
||||
case XKB_KEY_7: return CrafterKeys::_7;
|
||||
case XKB_KEY_8: return CrafterKeys::_8;
|
||||
case XKB_KEY_9: return CrafterKeys::_9;
|
||||
|
||||
// Function keys
|
||||
case XKB_KEY_F1: return CrafterKeys::F1;
|
||||
case XKB_KEY_F2: return CrafterKeys::F2;
|
||||
case XKB_KEY_F3: return CrafterKeys::F3;
|
||||
case XKB_KEY_F4: return CrafterKeys::F4;
|
||||
case XKB_KEY_F5: return CrafterKeys::F5;
|
||||
case XKB_KEY_F6: return CrafterKeys::F6;
|
||||
case XKB_KEY_F7: return CrafterKeys::F7;
|
||||
case XKB_KEY_F8: return CrafterKeys::F8;
|
||||
case XKB_KEY_F9: return CrafterKeys::F9;
|
||||
case XKB_KEY_F10: return CrafterKeys::F10;
|
||||
case XKB_KEY_F11: return CrafterKeys::F11;
|
||||
case XKB_KEY_F12: return CrafterKeys::F12;
|
||||
|
||||
// Control keys
|
||||
case XKB_KEY_Escape: return CrafterKeys::Escape;
|
||||
case XKB_KEY_Tab: return CrafterKeys::Tab;
|
||||
case XKB_KEY_Return: return CrafterKeys::Enter;
|
||||
case XKB_KEY_space: return CrafterKeys::Space;
|
||||
case XKB_KEY_BackSpace: return CrafterKeys::Backspace;
|
||||
case XKB_KEY_Delete: return CrafterKeys::Delete;
|
||||
case XKB_KEY_Insert: return CrafterKeys::Insert;
|
||||
case XKB_KEY_Home: return CrafterKeys::Home;
|
||||
case XKB_KEY_End: return CrafterKeys::End;
|
||||
case XKB_KEY_Page_Up: return CrafterKeys::PageUp;
|
||||
case XKB_KEY_Page_Down: return CrafterKeys::PageDown;
|
||||
case XKB_KEY_Caps_Lock: return CrafterKeys::CapsLock;
|
||||
case XKB_KEY_Num_Lock: return CrafterKeys::NumLock;
|
||||
case XKB_KEY_Scroll_Lock:return CrafterKeys::ScrollLock;
|
||||
|
||||
// Modifiers
|
||||
case XKB_KEY_Shift_L: return CrafterKeys::LeftShift;
|
||||
case XKB_KEY_Shift_R: return CrafterKeys::RightShift;
|
||||
case XKB_KEY_Control_L: return CrafterKeys::LeftCtrl;
|
||||
case XKB_KEY_Control_R: return CrafterKeys::RightCtrl;
|
||||
case XKB_KEY_Alt_L: return CrafterKeys::LeftAlt;
|
||||
case XKB_KEY_Alt_R: return CrafterKeys::RightAlt;
|
||||
case XKB_KEY_Super_L: return CrafterKeys::LeftSuper;
|
||||
case XKB_KEY_Super_R: return CrafterKeys::RightSuper;
|
||||
|
||||
// Arrows
|
||||
case XKB_KEY_Up: return CrafterKeys::Up;
|
||||
case XKB_KEY_Down: return CrafterKeys::Down;
|
||||
case XKB_KEY_Left: return CrafterKeys::Left;
|
||||
case XKB_KEY_Right: return CrafterKeys::Right;
|
||||
|
||||
// Keypad
|
||||
case XKB_KEY_KP_0: return CrafterKeys::keypad_0;
|
||||
case XKB_KEY_KP_1: return CrafterKeys::keypad_1;
|
||||
case XKB_KEY_KP_2: return CrafterKeys::keypad_2;
|
||||
case XKB_KEY_KP_3: return CrafterKeys::keypad_3;
|
||||
case XKB_KEY_KP_4: return CrafterKeys::keypad_4;
|
||||
case XKB_KEY_KP_5: return CrafterKeys::keypad_5;
|
||||
case XKB_KEY_KP_6: return CrafterKeys::keypad_6;
|
||||
case XKB_KEY_KP_7: return CrafterKeys::keypad_7;
|
||||
case XKB_KEY_KP_8: return CrafterKeys::keypad_8;
|
||||
case XKB_KEY_KP_9: return CrafterKeys::keypad_9;
|
||||
case XKB_KEY_KP_Enter: return CrafterKeys::keypad_enter;
|
||||
case XKB_KEY_KP_Add: return CrafterKeys::keypad_plus;
|
||||
case XKB_KEY_KP_Subtract: return CrafterKeys::keypad_minus;
|
||||
case XKB_KEY_KP_Multiply: return CrafterKeys::keypad_multiply;
|
||||
case XKB_KEY_KP_Divide: return CrafterKeys::keypad_divide;
|
||||
case XKB_KEY_KP_Decimal: return CrafterKeys::keypad_decimal;
|
||||
|
||||
// Punctuation
|
||||
case XKB_KEY_grave: return CrafterKeys::grave;
|
||||
case XKB_KEY_minus: return CrafterKeys::minus;
|
||||
case XKB_KEY_equal: return CrafterKeys::equal;
|
||||
case XKB_KEY_bracketleft: return CrafterKeys::bracket_left;
|
||||
case XKB_KEY_bracketright:return CrafterKeys::bracket_right;
|
||||
case XKB_KEY_backslash: return CrafterKeys::backslash;
|
||||
case XKB_KEY_semicolon: return CrafterKeys::semicolon;
|
||||
case XKB_KEY_apostrophe: return CrafterKeys::quote;
|
||||
case XKB_KEY_comma: return CrafterKeys::comma;
|
||||
case XKB_KEY_period: return CrafterKeys::period;
|
||||
case XKB_KEY_slash: return CrafterKeys::slash;
|
||||
|
||||
default:
|
||||
return CrafterKeys::CrafterKeysMax;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowWayland::keyboard_key(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
|
||||
WindowWayland* window = reinterpret_cast<WindowWayland*>(data);
|
||||
|
||||
|
|
@ -566,33 +718,22 @@ void WindowWayland::keyboard_key(void *data, wl_keyboard *keyboard, uint32_t ser
|
|||
|
||||
xkb_keycode_t keycode = key + 8;
|
||||
xkb_keysym_t keysym = xkb_state_key_get_one_sym(window->xkb_state, keycode);
|
||||
CrafterKeys crafterKey = keysym_to_crafter_key(keysym);
|
||||
|
||||
char utf8[8] = {0};
|
||||
int len = xkb_keysym_to_utf8(keysym, utf8, sizeof(utf8));
|
||||
if (len != 0) {
|
||||
char keypress = utf8[0];
|
||||
if(state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
if(window->heldkeys[keypress]) {
|
||||
window->onKeyHold[keypress].Invoke();
|
||||
window->onAnyKeyHold.Invoke(keypress);
|
||||
} else{
|
||||
window->heldkeys[keypress] = true;
|
||||
window->onKeyDown[keypress].Invoke();
|
||||
window->onAnyKeyDown.Invoke(keypress);
|
||||
}
|
||||
} else{
|
||||
window->heldkeys[keypress] = false;
|
||||
window->onKeyUp[keypress].Invoke();
|
||||
window->onAnyKeyUp.Invoke(keypress);
|
||||
}
|
||||
|
||||
} else {
|
||||
// // fallback for keys like Return, Escape, etc.
|
||||
// char name[64];
|
||||
// if (xkb_keysym_get_name(keysym, name, sizeof(name)) > 0) {
|
||||
// printf("Key %s pressed (non-printable or multi-char)\n", name);
|
||||
// }
|
||||
}
|
||||
if(state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
if(window->heldkeys[static_cast<std::uint8_t>(crafterKey)]) {
|
||||
window->onKeyHold[static_cast<std::uint8_t>(crafterKey)].Invoke();
|
||||
window->onAnyKeyHold.Invoke(crafterKey);
|
||||
} else{
|
||||
window->heldkeys[static_cast<std::uint8_t>(crafterKey)] = true;
|
||||
window->onKeyDown[static_cast<std::uint8_t>(crafterKey)].Invoke();
|
||||
window->onAnyKeyDown.Invoke(crafterKey);
|
||||
}
|
||||
} else{
|
||||
window->heldkeys[static_cast<std::uint8_t>(crafterKey)] = false;
|
||||
window->onKeyUp[static_cast<std::uint8_t>(crafterKey)].Invoke();
|
||||
window->onAnyKeyUp.Invoke(crafterKey);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowWayland::keyboard_modifiers(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
|
||||
|
|
|
|||
|
|
@ -31,18 +31,8 @@ export namespace Crafter {
|
|||
std::int_fast32_t spacingY;
|
||||
|
||||
public:
|
||||
GridElement(std::uint_fast32_t columns = 1, std::uint_fast32_t rows = 1,
|
||||
std::int_fast32_t spacingX = 0, std::int_fast32_t spacingY = 0,
|
||||
std::int_fast32_t anchorX = FractionalToMapped(0.5),
|
||||
std::int_fast32_t anchorY = FractionalToMapped(0.5),
|
||||
std::uint_fast32_t relativeWidth = FractionalToMapped(1),
|
||||
std::uint_fast32_t relativeHeight = FractionalToMapped(1),
|
||||
std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5),
|
||||
std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5),
|
||||
std::int_fast32_t z = 0);
|
||||
|
||||
void SetGridSize(std::uint_fast32_t columns, std::uint_fast32_t rows);
|
||||
void SetSpacing(std::int_fast32_t spacingX, std::int_fast32_t spacingY);
|
||||
GridElement(std::uint_fast32_t columns, std::uint_fast32_t rows, std::int_fast32_t spacingX, std::int_fast32_t spacingY, Anchor anchor);
|
||||
void UpdatePositionScaled(Window& window);
|
||||
void UpdatePosition(Window& window) override;
|
||||
void UpdatePosition(Window& window, Transform& parent) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,33 +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:ImageElement;
|
||||
import std;
|
||||
import :RenderingElement;
|
||||
import :Types;
|
||||
|
||||
export namespace Crafter {
|
||||
class ImageElement : public RenderingElementScaling {
|
||||
public:
|
||||
ImageElement();
|
||||
ImageElement(const std::string_view imagePath, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
|
||||
|
||||
void RenderImage(const std::string_view path);
|
||||
};
|
||||
}
|
||||
|
|
@ -38,10 +38,8 @@ export namespace Crafter {
|
|||
Event<MousePoint> onMouseRightRelease;
|
||||
Event<MousePoint> onMouseLeftRelease;
|
||||
|
||||
MouseElement(WindowMouse& window, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0);
|
||||
MouseElement(std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0);
|
||||
MouseElement(MouseElement&) = delete;
|
||||
MouseElement& operator=(MouseElement&) = delete;
|
||||
MouseElement(Anchor anchor);
|
||||
MouseElement(Anchor anchor, WindowMouse& window);
|
||||
void UpdatePosition(Window& window) override;
|
||||
void UpdatePosition(Window& window, Transform& parent) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,10 +17,14 @@ License along with this library; if not, write to the Free Software
|
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
module;
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "../lib/stb_image.h"
|
||||
export module Crafter.Graphics:RenderingElement;
|
||||
import std;
|
||||
import :Transform;
|
||||
import :Types;
|
||||
import :Window;
|
||||
|
||||
export namespace Crafter {
|
||||
enum class OpaqueType {
|
||||
|
|
@ -29,66 +33,355 @@ export namespace Crafter {
|
|||
Transparent // Color blending is used
|
||||
};
|
||||
|
||||
class Window;
|
||||
class RenderingElement : public Transform {
|
||||
public:
|
||||
std::vector<Pixel_BU8_GU8_RU8_AU8> bufferScaled;
|
||||
OpaqueType opaque = OpaqueType::Transparent;
|
||||
|
||||
RenderingElement(OpaqueType opaque = OpaqueType::Transparent);
|
||||
RenderingElement(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z);
|
||||
RenderingElement(RenderingElement&) = delete;
|
||||
RenderingElement& operator=(RenderingElement&) = delete;
|
||||
};
|
||||
|
||||
class RenderingElementPreScaled : public RenderingElement {
|
||||
public:
|
||||
RenderingElementPreScaled(OpaqueType opaque = OpaqueType::Transparent);
|
||||
RenderingElementPreScaled(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z);
|
||||
RenderingElementPreScaled(RenderingElementPreScaled&) = delete;
|
||||
RenderingElementPreScaled& operator=(RenderingElementPreScaled&) = delete;
|
||||
|
||||
void CopyNearestNeighbour(Pixel_BU8_GU8_RU8_AU8* dst, std::uint_fast32_t dstWidth, std::uint_fast32_t dstHeight) const;
|
||||
void UpdatePosition(Window& window) override;
|
||||
void UpdatePosition(Window& window, Transform& parent) override;
|
||||
};
|
||||
|
||||
class RenderingElementScaling: public RenderingElement {
|
||||
public:
|
||||
std::vector<Pixel_BU8_GU8_RU8_AU8> buffer;
|
||||
struct RenderElementScalingOwning {
|
||||
std::vector<Pixel_BU8_GU8_RU8_AU8> scalingBuffer;
|
||||
std::uint_fast32_t bufferWidth;
|
||||
std::uint_fast32_t bufferHeight;
|
||||
|
||||
RenderingElementScaling(OpaqueType opaque = OpaqueType::Transparent);
|
||||
RenderingElementScaling(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z);
|
||||
RenderingElementScaling(OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0);
|
||||
RenderingElementScaling(RenderingElementScaling&) = delete;
|
||||
RenderingElementScaling& operator=(RenderingElementScaling&) = delete;
|
||||
|
||||
void ResizeBuffer(std::uint_fast32_t width, std::uint_fast32_t height);
|
||||
void CopyNearestNeighbour(Pixel_BU8_GU8_RU8_AU8* dst, std::uint_fast32_t dstWidth, std::uint_fast32_t dstHeight) const;
|
||||
void UpdatePosition(Window& window) override;
|
||||
void UpdatePosition(Window& window, Transform& parent) override;
|
||||
bool bufferUpdated = true;
|
||||
RenderElementScalingOwning() = default;
|
||||
RenderElementScalingOwning(std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight) : scalingBuffer(bufferWidth*bufferHeight), bufferWidth(bufferWidth), bufferHeight(bufferHeight) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class RenderingElementScalingRotating2D : public RenderingElement {
|
||||
public:
|
||||
std::vector<Pixel_BU8_GU8_RU8_AU8> buffer;
|
||||
struct RenderElementScalingNonOwning {
|
||||
Pixel_BU8_GU8_RU8_AU8* scalingBuffer;
|
||||
std::uint_fast32_t bufferWidth;
|
||||
std::uint_fast32_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) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
struct RenderElementRotating {
|
||||
std::uint_fast32_t rotation;
|
||||
bool rotationUpdated = true;
|
||||
RenderElementRotating() = default;
|
||||
RenderElementRotating(std::uint_fast32_t rotation) : rotation(rotation) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct EmptyScalingBase {};
|
||||
struct EmptyRotatingBase {};
|
||||
|
||||
template<bool Scaling, bool Owning>
|
||||
using ScalingBase =
|
||||
std::conditional_t<
|
||||
Scaling,
|
||||
std::conditional_t<Owning,
|
||||
RenderElementScalingOwning,
|
||||
RenderElementScalingNonOwning>,
|
||||
EmptyScalingBase
|
||||
>;
|
||||
|
||||
template<bool Rotating>
|
||||
using RotatingBase =
|
||||
std::conditional_t<
|
||||
Rotating,
|
||||
RenderElementRotating,
|
||||
EmptyRotatingBase
|
||||
>;
|
||||
|
||||
class RenderingElementBase : public Transform {
|
||||
public:
|
||||
std::vector<Pixel_BU8_GU8_RU8_AU8> buffer;
|
||||
OpaqueType opaque;
|
||||
RenderingElementBase(Anchor anchor, OpaqueType opaque) : Transform(anchor), opaque(opaque) {
|
||||
scaled.width = 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<bool Scaling, bool Owning, bool Rotating> requires ((!Rotating || Scaling) && (!Owning || Scaling))
|
||||
class RenderingElement : public RenderingElementBase, public ScalingBase<Scaling, Owning>, public RotatingBase<Rotating> {
|
||||
public:
|
||||
RenderingElement() = default;
|
||||
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, const std::string_view imagePath) : Transform(anchor) {
|
||||
LoadImage(imagePath);
|
||||
}
|
||||
RenderingElement(Anchor anchor, const std::string_view imagePath, std::uint_fast32_t rotation) requires(Rotating) : Transform(anchor), RotatingBase<Rotating>(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<Rotating>(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<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::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::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(RenderingElement&) = delete;
|
||||
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<true, Owning>::bufferHeight / scaled.height;
|
||||
for (std::uint_fast32_t x = 0; x < scaled.width; x++) {
|
||||
std::uint_fast32_t srcX = x * ScalingBase<true, Owning>::bufferWidth / scaled.width;
|
||||
buffer[y * scaled.width + x] = ScalingBase<true, Owning>::scalingBuffer[srcY * ScalingBase<true, Owning>::bufferWidth + srcX];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 std::uint_fast32_t dstWidth = scaled.width;
|
||||
const std::uint_fast32_t dstHeight = scaled.height;
|
||||
|
||||
const double c2 = std::abs(std::cos(rad));
|
||||
const double s2 = std::abs(std::sin(rad));
|
||||
|
||||
const double rotatedWidth = dstWidth * c2 + dstHeight * s2;
|
||||
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::uint_fast32_t diffY = static_cast<std::uint_fast32_t>(std::ceil((rotatedHeight - dstHeight) * 0.5));
|
||||
|
||||
scaled.width += diffX + diffX;
|
||||
scaled.height += diffY + diffY;
|
||||
|
||||
scaled.x -= diffX;
|
||||
scaled.y -= diffY;
|
||||
|
||||
ScalingBase<true, Owning>::scalingBuffer.clear();
|
||||
ScalingBase<true, Owning>::scalingBuffer.resize(scaled.width * scaled.height);
|
||||
|
||||
// Destination center
|
||||
const double dstCx = (static_cast<double>(scaled.width) - 1.0) * 0.5;
|
||||
const double dstCy = (static_cast<double>(scaled.height) - 1.0) * 0.5;
|
||||
|
||||
// Source center
|
||||
const double srcCx = (static_cast<double>(ScalingBase<true, Owning>::bufferWidth) - 1.0) * 0.5;
|
||||
const double srcCy = (static_cast<double>(ScalingBase<true, Owning>::bufferHeight) - 1.0) * 0.5;
|
||||
|
||||
const double c = std::cos(rad);
|
||||
const double s = std::sin(rad);
|
||||
|
||||
// Scale factors (destination → source)
|
||||
const double scaleX = static_cast<double>(ScalingBase<true, Owning>::bufferWidth) / dstWidth;
|
||||
const double scaleY = static_cast<double>(ScalingBase<true, Owning>::bufferHeight) / dstHeight;
|
||||
|
||||
for (std::uint_fast32_t yB = 0; yB < scaled.height; ++yB) {
|
||||
for (std::uint_fast32_t xB = 0; xB < scaled.width; ++xB) {
|
||||
|
||||
// ---- Destination pixel relative to center ----
|
||||
const double dx = (static_cast<double>(xB) - dstCx) * scaleX;
|
||||
const double dy = (static_cast<double>(yB) - dstCy) * scaleY;
|
||||
|
||||
// ---- Inverse rotation ----
|
||||
const double sx = (c * dx - s * dy) + srcCx;
|
||||
const double sy = (s * dx + c * dy) + srcCy;
|
||||
|
||||
// ---- Nearest neighbour sampling ----
|
||||
const std::int_fast32_t srcX = static_cast<std::int_fast32_t>(std::round(sx));
|
||||
const std::int_fast32_t srcY = static_cast<std::int_fast32_t>(std::round(sy));
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RenderingElementScalingRotating2D(OpaqueType opaque = OpaqueType::Transparent);
|
||||
RenderingElementScalingRotating2D(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z);
|
||||
RenderingElementScalingRotating2D(OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::uint_fast32_t rotationAngle = 0, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0);
|
||||
RenderingElementScalingRotating2D(RenderingElementScalingRotating2D&) = delete;
|
||||
RenderingElementScalingRotating2D& operator=(RenderingElementScalingRotating2D&) = delete;
|
||||
|
||||
void UpdateRotation(std::uint_fast32_t newRotation);
|
||||
void ResizeBuffer(std::uint_fast32_t width, std::uint_fast32_t height);
|
||||
void UpdateScaledBuffer(ScaleData& data);
|
||||
void UpdatePosition(Window& window) override;
|
||||
void UpdatePosition(Window& window, Transform& parent) override;
|
||||
void UpdatePosition(Window& window, ScaleData oldScale) {
|
||||
if constexpr(Scaling && !Rotating) {
|
||||
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||
buffer.resize(scaled.width * scaled.height);
|
||||
ScaleNearestNeighbor();
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
} else if(oldScale.x != scaled.x || oldScale.y != scaled.y) {
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
if(ScalingBase<true, Owning>::bufferUpdated) {
|
||||
ScaleNearestNeighbor();
|
||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
||||
}
|
||||
} else if(ScalingBase<true, Owning>::bufferUpdated) {
|
||||
ScaleNearestNeighbor();
|
||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
||||
}
|
||||
} else if constexpr(Rotating) {
|
||||
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||
buffer.resize(scaled.width * scaled.height);
|
||||
ScaleNearestNeighbor();
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
} else if(oldScale.x != scaled.x || oldScale.y != scaled.y) {
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
if(ScalingBase<true, Owning>::bufferUpdated) {
|
||||
ScaleRotating();
|
||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
||||
RotatingBase<true>::rotationUpdated = false;
|
||||
}
|
||||
} else if(ScalingBase<true, Owning>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
||||
ScaleRotating();
|
||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
||||
RotatingBase<true>::rotationUpdated = false;
|
||||
}
|
||||
} else {
|
||||
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||
buffer.resize(scaled.width * scaled.height);
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
}
|
||||
if(oldScale.x != scaled.x || oldScale.y != scaled.y) {
|
||||
window.AddDirtyRect(oldScale);
|
||||
window.AddDirtyRect(scaled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePosition(Window& window) override {
|
||||
ScaleData oldScale = scaled;
|
||||
window.ScaleElement(*this);
|
||||
UpdatePosition(window, oldScale);
|
||||
for(Transform* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePosition(Window& window, Transform& parent) override {
|
||||
ScaleData oldScale = scaled;
|
||||
window.ScaleElement(*this, parent);
|
||||
UpdatePosition(window, oldScale);
|
||||
for(Transform* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadImage(const std::string_view imagePath) {
|
||||
std::filesystem::path abs = std::filesystem::absolute(imagePath);
|
||||
int xSize;
|
||||
int ySize;
|
||||
unsigned char* bgData = stbi_load(abs.string().c_str(), &xSize, &ySize, nullptr, 4);
|
||||
|
||||
if constexpr(Scaling && !Owning) {
|
||||
ScalingBase<true, false>::bufferUpdated = true;
|
||||
} else if constexpr(Scaling && Owning) {
|
||||
ScalingBase<true, true>::bufferWidth = xSize;
|
||||
ScalingBase<true, true>::bufferHeight = ySize;
|
||||
ScalingBase<true, true>::bufferUpdated = true;
|
||||
} else {
|
||||
buffer.resize(xSize*ySize);
|
||||
}
|
||||
|
||||
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;
|
||||
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].b = bgData[idx+2];
|
||||
ScalingBase<true, Owning>::calingBuffer[x*ySize+y].a = bgData[idx+3];
|
||||
}
|
||||
}
|
||||
|
||||
for(std::uint_fast32_t i = 0; i < xSize*ySize; i++) {
|
||||
if(ScalingBase<true, Owning>::scalingBuffer[i].a != 255) {
|
||||
opaque = OpaqueType::SemiOpaque;
|
||||
for(std::uint_fast32_t i2 = 0; i2 < xSize*ySize; i2++) {
|
||||
if(ScalingBase<true, Owning>::scalingBuffer[i2].a != 0 && ScalingBase<true, Owning>::scalingBuffer[i2].a != 255) {
|
||||
opaque = OpaqueType::Transparent;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
buffer[x*ySize+y].r = bgData[idx];
|
||||
buffer[x*ySize+y].g = bgData[idx+1];
|
||||
buffer[x*ySize+y].b = bgData[idx+2];
|
||||
buffer[x*ySize+y].a = bgData[idx+3];
|
||||
}
|
||||
}
|
||||
|
||||
for(std::uint_fast32_t i = 0; i < xSize*ySize; i++) {
|
||||
if(buffer[i].a != 255) {
|
||||
opaque = OpaqueType::SemiOpaque;
|
||||
for(std::uint_fast32_t i2 = 0; i2 < xSize*ySize; i2++) {
|
||||
if(buffer[i2].a != 0 && buffer[i2].a != 255) {
|
||||
opaque = OpaqueType::Transparent;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void LoadImageNoOpaqueCheck(const std::string_view imagePath) {
|
||||
std::filesystem::path abs = std::filesystem::absolute(imagePath);
|
||||
int xSize;
|
||||
int ySize;
|
||||
unsigned char* bgData = stbi_load(abs.string().c_str(), &xSize, &ySize, nullptr, 4);
|
||||
|
||||
|
||||
if constexpr(Scaling && !Owning) {
|
||||
ScalingBase<true, false>::bufferUpdated = true;
|
||||
} else if constexpr(Scaling && Owning) {
|
||||
ScalingBase<true, true>::bufferWidth = xSize;
|
||||
ScalingBase<true, true>::bufferHeight = ySize;
|
||||
ScalingBase<true, true>::bufferUpdated = true;
|
||||
} else {
|
||||
buffer.resize(xSize*ySize);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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].b = bgData[idx+2];
|
||||
ScalingBase<true, Owning>::scalingBuffer[x*ySize+y].a = bgData[idx+3];
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
buffer[x*ySize+y].r = bgData[idx];
|
||||
buffer[x*ySize+y].g = bgData[idx+1];
|
||||
buffer[x*ySize+y].b = bgData[idx+2];
|
||||
buffer[x*ySize+y].a = bgData[idx+3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -41,11 +41,11 @@ export namespace Crafter {
|
|||
Wrap // Wrap text to multiple lines
|
||||
};
|
||||
|
||||
class TextElement : public RenderingElementPreScaled {
|
||||
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(std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0);
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
|
@ -23,19 +23,25 @@ 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;
|
||||
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);
|
||||
};
|
||||
class Transform {
|
||||
public:
|
||||
std::int_fast32_t z;
|
||||
std::int_fast32_t anchorX;
|
||||
std::int_fast32_t anchorY;
|
||||
std::int_fast32_t anchorOffsetX;
|
||||
std::int_fast32_t anchorOffsetY;
|
||||
std::uint_fast32_t relativeWidth;
|
||||
std::uint_fast32_t relativeHeight;
|
||||
Anchor anchor;
|
||||
ScaleData scaled;
|
||||
std::vector<Transform*> children;
|
||||
Transform(std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0);
|
||||
Transform(Anchor anchor);
|
||||
Transform(Transform&) = delete;
|
||||
Transform(Transform&&) = delete;
|
||||
Transform& operator=(Transform&) = delete;
|
||||
virtual ~Transform() = default;
|
||||
virtual void UpdatePosition(Window& window);
|
||||
|
|
|
|||
|
|
@ -139,10 +139,20 @@ namespace Crafter {
|
|||
return pixel * (SCALE / width);
|
||||
}
|
||||
|
||||
export constexpr std::int_fast32_t RelativeToAbsolute(std::int_fast32_t relative, std::int_fast32_t full) {
|
||||
return static_cast<std::int_fast32_t>(
|
||||
(static_cast<__int128>(relative) * full) / SCALE
|
||||
);
|
||||
}
|
||||
|
||||
export constexpr std::int_fast32_t BoundToBoundless(std::int_fast32_t bound) {
|
||||
return bound * BOUND;
|
||||
}
|
||||
|
||||
export constexpr std::int_fast32_t BoundlessToBound(std::int_fast32_t bound) {
|
||||
return bound / BOUND;
|
||||
}
|
||||
|
||||
export constexpr std::int_fast32_t FractionalToMappedBoundless(double f) {
|
||||
return std::int_fast32_t(f * SCALEDOUBLEBOUNDLESS);
|
||||
}
|
||||
|
|
@ -162,4 +172,47 @@ namespace Crafter {
|
|||
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
|
||||
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,
|
||||
|
||||
// Numeric keys
|
||||
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9,
|
||||
|
||||
// Function keys
|
||||
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
||||
|
||||
// Control keys
|
||||
Escape, Tab, Enter, Space, Backspace, Delete, Insert,
|
||||
Home, End, PageUp, PageDown, CapsLock, NumLock, ScrollLock,
|
||||
|
||||
// Modifier keys
|
||||
LeftShift, RightShift, LeftCtrl, RightCtrl,
|
||||
LeftAlt, RightAlt, LeftSuper, RightSuper,
|
||||
|
||||
// Arrow keys
|
||||
Up, Down, Left, Right,
|
||||
|
||||
// Keypad keys
|
||||
keypad_0, keypad_1, keypad_2, keypad_3, keypad_4,
|
||||
keypad_5, keypad_6, keypad_7, keypad_8, keypad_9,
|
||||
keypad_enter, keypad_plus, keypad_minus, keypad_multiply,
|
||||
keypad_divide, keypad_decimal,
|
||||
|
||||
// Punctuation and special keys
|
||||
grave, minus, equal, bracket_left, bracket_right,
|
||||
backslash, semicolon, quote, comma, period, slash,
|
||||
print_screen, pause, menu,
|
||||
|
||||
// Additional keys
|
||||
volume_up, volume_down, volume_mute,
|
||||
media_play, media_stop, media_prev, media_next,
|
||||
browser_back, browser_forward, browser_refresh,
|
||||
browser_stop, browser_search, browser_home,
|
||||
launch_mail, launch_calculator, launch_media_player,
|
||||
|
||||
CrafterKeysMax
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ import Crafter.Event;
|
|||
|
||||
export namespace Crafter {
|
||||
class Transform;
|
||||
class RenderingElement;
|
||||
class Window {
|
||||
public:
|
||||
std::int_fast32_t width;
|
||||
|
|
@ -76,7 +75,7 @@ export namespace Crafter {
|
|||
std::chrono::nanoseconds totalUpdate;
|
||||
std::vector<std::pair<const EventListener<FrameTime>*, std::chrono::nanoseconds>> updateTimings;
|
||||
std::chrono::nanoseconds totalRender;
|
||||
std::vector<std::tuple<const RenderingElement*, std::uint_fast32_t, std::uint_fast32_t, std::chrono::nanoseconds>> renderTimings;
|
||||
std::vector<std::tuple<const Transform*, std::uint_fast32_t, std::uint_fast32_t, std::chrono::nanoseconds>> renderTimings;
|
||||
std::chrono::nanoseconds vblank;
|
||||
std::chrono::nanoseconds totalFrame;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> frameEnd;
|
||||
|
|
@ -87,13 +86,13 @@ export namespace Crafter {
|
|||
|
||||
class WindowKeyboard {
|
||||
public:
|
||||
bool heldkeys[255] = {};
|
||||
Event<void> onKeyDown[255];
|
||||
Event<void> onKeyHold[255];
|
||||
Event<void> onKeyUp[255];
|
||||
Event<char> onAnyKeyDown;
|
||||
Event<char> onAnyKeyHold;
|
||||
Event<char> onAnyKeyUp;
|
||||
bool heldkeys[static_cast<std::uint32_t>(CrafterKeys::CrafterKeysMax)] = {};
|
||||
Event<void> onKeyDown[static_cast<std::uint32_t>(CrafterKeys::CrafterKeysMax)];
|
||||
Event<void> onKeyHold[static_cast<std::uint32_t>(CrafterKeys::CrafterKeysMax)];
|
||||
Event<void> onKeyUp[static_cast<std::uint32_t>(CrafterKeys::CrafterKeysMax)];
|
||||
Event<CrafterKeys> onAnyKeyDown;
|
||||
Event<CrafterKeys> onAnyKeyHold;
|
||||
Event<CrafterKeys> onAnyKeyUp;
|
||||
};
|
||||
|
||||
class MouseElement;
|
||||
|
|
@ -138,7 +137,6 @@ export namespace Crafter {
|
|||
};
|
||||
|
||||
#ifdef CRAFTER_GRAPHICS_WAYLAND
|
||||
class RenderingElement;
|
||||
class WindowWayland final : public WindowKeyboard, public WindowMouse, public WindowFramebuffer, public WindowTitle {
|
||||
public:
|
||||
Pixel_BU8_GU8_RU8_AU8* framebuffer = nullptr;
|
||||
|
|
@ -162,6 +160,7 @@ export namespace Crafter {
|
|||
xkb_state* xkb_state;
|
||||
void RenderElement(Transform* transform);
|
||||
void Render() override;
|
||||
void QueueRender();
|
||||
void StartSync() override;
|
||||
void StartUpdate() override;
|
||||
void StopUpdate() override;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ export import :Window;
|
|||
export import :Transform;
|
||||
export import :RenderingElement;
|
||||
export import :MouseElement;
|
||||
export import :ImageElement;
|
||||
export import :TextElement;
|
||||
export import :GridElement;
|
||||
export import :Types;
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
"configurations": [
|
||||
{
|
||||
"name": "base",
|
||||
"implementations": ["implementations/Crafter.Graphics-Font", "implementations/Crafter.Graphics-Shm", "implementations/Crafter.Graphics-Window", "implementations/Crafter.Graphics-RenderingElement", "implementations/Crafter.Graphics-RenderingElementScalingRotating2D", "implementations/Crafter.Graphics-TextElement", "implementations/Crafter.Graphics-ImageElement", "implementations/Crafter.Graphics-MouseElement", "implementations/Crafter.Graphics-Transform", "implementations/Crafter.Graphics-GridElement"],
|
||||
"interfaces": ["interfaces/Crafter.Graphics-Window", "interfaces/Crafter.Graphics", "interfaces/Crafter.Graphics-Types", "interfaces/Crafter.Graphics-Font", "interfaces/Crafter.Graphics-Shm", "interfaces/Crafter.Graphics-Animation", "interfaces/Crafter.Graphics-RenderingElement", "interfaces/Crafter.Graphics-TextElement", "interfaces/Crafter.Graphics-ImageElement", "interfaces/Crafter.Graphics-MouseElement", "interfaces/Crafter.Graphics-Transform", "interfaces/Crafter.Graphics-GridElement"],
|
||||
"implementations": ["implementations/Crafter.Graphics-Font", "implementations/Crafter.Graphics-Shm", "implementations/Crafter.Graphics-Window", "implementations/Crafter.Graphics-TextElement", "implementations/Crafter.Graphics-MouseElement", "implementations/Crafter.Graphics-Transform", "implementations/Crafter.Graphics-GridElement"],
|
||||
"interfaces": ["interfaces/Crafter.Graphics-Window", "interfaces/Crafter.Graphics", "interfaces/Crafter.Graphics-Types", "interfaces/Crafter.Graphics-Font", "interfaces/Crafter.Graphics-Shm", "interfaces/Crafter.Graphics-Animation", "interfaces/Crafter.Graphics-RenderingElement", "interfaces/Crafter.Graphics-TextElement", "interfaces/Crafter.Graphics-MouseElement", "interfaces/Crafter.Graphics-Transform", "interfaces/Crafter.Graphics-GridElement"],
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue