Compare commits
2 commits
7bbb107c5e
...
c9fadb3779
| Author | SHA1 | Date | |
|---|---|---|---|
| c9fadb3779 | |||
| 9a25340287 |
7 changed files with 262 additions and 4 deletions
33
examples/HelloAnimationcopy/main.cpp
Normal file
33
examples/HelloAnimationcopy/main.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import Crafter.Event;
|
||||||
|
import Crafter.Graphics;
|
||||||
|
import std;
|
||||||
|
using namespace Crafter;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
WindowWayland window(200, 200, "Hello Input!");
|
||||||
|
|
||||||
|
RenderingElementScalingRotating2D element(
|
||||||
|
OpaqueType::FullyOpaque, //opaque, wether the element is opague or semi-transparant
|
||||||
|
1, //bufferWidth: the width of this elements pixel buffer
|
||||||
|
1, //bufferHeight: the height of this elements pixel buffer
|
||||||
|
FractionalToMappedBoundlessU(0.125),
|
||||||
|
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.1), //relativeSizeX: the relative x size this element should be scaled to compared to its parent
|
||||||
|
FractionalToMapped(0.1), //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
|
||||||
|
false //ignoreScaling: wether this element ignores the scaling of the window, if true its size will be scaled according to the window scale
|
||||||
|
);
|
||||||
|
|
||||||
|
window.elements.push_back(&element);
|
||||||
|
element.buffer = {{255, 0, 0 ,255}};
|
||||||
|
element.UpdatePosition(window);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//window.StartUpdate();
|
||||||
|
window.Render();
|
||||||
|
window.StartSync();
|
||||||
|
}
|
||||||
15
examples/HelloAnimationcopy/project.json
Normal file
15
examples/HelloAnimationcopy/project.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "crafter-graphics",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "executable",
|
||||||
|
"implementations": ["main"],
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"path":"../../project.json",
|
||||||
|
"configuration":"lib-wayland-timing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
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, bool ignoreScaling) : RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling), rotation(0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderingElementScalingRotating2D::RenderingElementScalingRotating2D(OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::uint_fast32_t rotation, double scaleX, double scaleY, 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)
|
||||||
|
: bufferWidth(bufferWidth), bufferHeight(bufferHeight), buffer(bufferWidth*bufferHeight),
|
||||||
|
rotation(rotation),
|
||||||
|
RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::uint_fast32_t dstWidth = scaled.width;
|
||||||
|
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)));
|
||||||
|
|
||||||
|
scaled.width = static_cast<std::uint_fast32_t>(std::ceil(rotatedWidth));
|
||||||
|
scaled.height = static_cast<std::uint_fast32_t>(std::ceil(rotatedHeight));
|
||||||
|
|
||||||
|
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 ----
|
||||||
|
double dx = static_cast<double>(xB) - dstCx;
|
||||||
|
double dy = static_cast<double>(yB) - dstCy;
|
||||||
|
|
||||||
|
// ---- Inverse scale ----
|
||||||
|
dx *= scaleX;
|
||||||
|
dy *= scaleY;
|
||||||
|
|
||||||
|
// ---- Inverse rotation ----
|
||||||
|
double sx = c * dx - s * dy;
|
||||||
|
double sy = s * dx + c * dy;
|
||||||
|
|
||||||
|
// ---- Move into source space ----
|
||||||
|
sx += srcCx;
|
||||||
|
sy += 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];
|
||||||
|
} else {
|
||||||
|
bufferScaled[yB * scaled.width + xB] = {0, 0, 0, 0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
std::cout << scaled.width << std::endl;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -302,9 +302,9 @@ void WindowWayland::Render() {
|
||||||
|
|
||||||
dirtyRects = std::move(newClip);
|
dirtyRects = std::move(newClip);
|
||||||
|
|
||||||
// for(uint_fast32_t i = 0; i < width*height; i++) {
|
for(uint_fast32_t i = 0; i < width*height; i++) {
|
||||||
// framebuffer[i] = {0, 0, 0, 255};
|
framebuffer[i] = {0, 0, 0, 255};
|
||||||
// }
|
}
|
||||||
|
|
||||||
// std::cout << dirtyRects.size() << std::endl;
|
// std::cout << dirtyRects.size() << std::endl;
|
||||||
// for (ClipRect rect : dirtyRects) {
|
// for (ClipRect rect : dirtyRects) {
|
||||||
|
|
|
||||||
|
|
@ -70,4 +70,25 @@ export namespace Crafter {
|
||||||
void UpdatePosition(Window& window) override;
|
void UpdatePosition(Window& window) override;
|
||||||
void UpdatePosition(Window& window, Transform& parent) override;
|
void UpdatePosition(Window& window, Transform& parent) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RenderingElementScalingRotating2D : public RenderingElement {
|
||||||
|
public:
|
||||||
|
std::vector<Pixel_BU8_GU8_RU8_AU8> buffer;
|
||||||
|
std::uint_fast32_t bufferWidth;
|
||||||
|
std::uint_fast32_t bufferHeight;
|
||||||
|
std::uint_fast32_t rotation;
|
||||||
|
bool rotationUpdated = true;
|
||||||
|
|
||||||
|
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, bool ignoreScaling);
|
||||||
|
RenderingElementScalingRotating2D(OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::uint_fast32_t rotationAngle = 0, double scaleX = 1.0, double scaleY = 1.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, bool ignoreScaling = false);
|
||||||
|
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;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -111,14 +111,22 @@ namespace Crafter {
|
||||||
export constexpr std::int_fast32_t BOUND = 9;
|
export constexpr std::int_fast32_t BOUND = 9;
|
||||||
export constexpr std::int_fast32_t SCALE = std::numeric_limits<std::int_fast32_t>::max() / BOUND;
|
export constexpr std::int_fast32_t SCALE = std::numeric_limits<std::int_fast32_t>::max() / BOUND;
|
||||||
export constexpr double SCALEDOUBLE = static_cast<double>(std::numeric_limits<std::int_fast32_t>::max()) / BOUND;
|
export constexpr double SCALEDOUBLE = static_cast<double>(std::numeric_limits<std::int_fast32_t>::max()) / BOUND;
|
||||||
|
export constexpr double SCALEDOUBLEU = static_cast<double>(std::numeric_limits<std::uint_fast32_t>::max()) / BOUND;
|
||||||
|
|
||||||
export constexpr std::int_fast32_t SCALEBOUNDLESS = std::numeric_limits<std::int_fast32_t>::max();
|
export constexpr std::int_fast32_t SCALEBOUNDLESS = std::numeric_limits<std::int_fast32_t>::max();
|
||||||
export constexpr double SCALEDOUBLEBOUNDLESS = static_cast<double>(std::numeric_limits<std::int_fast32_t>::max());
|
export constexpr double SCALEDOUBLEBOUNDLESS = static_cast<double>(std::numeric_limits<std::int_fast32_t>::max());
|
||||||
|
|
||||||
|
export constexpr std::int_fast32_t SCALEBOUNDLESSU = std::numeric_limits<std::uint_fast32_t>::max();
|
||||||
|
export constexpr double SCALEDOUBLEBOUNDLESSU = static_cast<double>(std::numeric_limits<std::uint_fast32_t>::max());
|
||||||
|
|
||||||
export constexpr std::int_fast32_t FractionalToMapped(double f) {
|
export constexpr std::int_fast32_t FractionalToMapped(double f) {
|
||||||
return std::int_fast32_t(f * SCALEDOUBLE);
|
return std::int_fast32_t(f * SCALEDOUBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export constexpr std::uint_fast32_t FractionalToMappedU(double f) {
|
||||||
|
return std::uint_fast32_t(f * SCALEDOUBLEU);
|
||||||
|
}
|
||||||
|
|
||||||
export constexpr double MappedToFractional(std::int_fast32_t mapped) {
|
export constexpr double MappedToFractional(std::int_fast32_t mapped) {
|
||||||
return static_cast<double>(mapped) / SCALEDOUBLE;
|
return static_cast<double>(mapped) / SCALEDOUBLE;
|
||||||
}
|
}
|
||||||
|
|
@ -139,6 +147,10 @@ namespace Crafter {
|
||||||
return std::int_fast32_t(f * SCALEDOUBLEBOUNDLESS);
|
return std::int_fast32_t(f * SCALEDOUBLEBOUNDLESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export constexpr std::uint_fast32_t FractionalToMappedBoundlessU(double f) {
|
||||||
|
return std::uint_fast32_t(f * SCALEDOUBLEBOUNDLESSU);
|
||||||
|
}
|
||||||
|
|
||||||
export constexpr double MappedToFractionalBoundless(std::int_fast32_t mapped) {
|
export constexpr double MappedToFractionalBoundless(std::int_fast32_t mapped) {
|
||||||
return static_cast<double>(mapped) / SCALEDOUBLEBOUNDLESS;
|
return static_cast<double>(mapped) / SCALEDOUBLEBOUNDLESS;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "base",
|
"name": "base",
|
||||||
"implementations": ["implementations/Crafter.Graphics-Font", "implementations/Crafter.Graphics-Shm", "implementations/Crafter.Graphics-Window", "implementations/Crafter.Graphics-RenderingElement", "implementations/Crafter.Graphics-TextElement", "implementations/Crafter.Graphics-ImageElement", "implementations/Crafter.Graphics-MouseElement", "implementations/Crafter.Graphics-Transform", "implementations/Crafter.Graphics-GridElement"],
|
"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"],
|
"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"],
|
||||||
"type": "library"
|
"type": "library"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue