rendertarget multi frame rewrite
This commit is contained in:
parent
7f46ac13fa
commit
2b22c16ce7
13 changed files with 225 additions and 276 deletions
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
Crafter®.Graphics
|
||||
Copyright (C) 2026 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:GridElement_impl;
|
||||
import :GridElement;
|
||||
import :Rendertarget;
|
||||
import :Types;
|
||||
import std;
|
||||
|
||||
using namespace Crafter;
|
||||
|
||||
GridElement::GridElement(std::uint32_t columns, std::uint32_t rows, std::int32_t spacingX, std::int32_t spacingY, std::int32_t paddingX, std::int32_t paddingY, Anchor2D anchor) : Transform2D(anchor), columns(columns), rows(rows), spacingX(spacingX), spacingY(spacingY), paddingX(paddingX), paddingY(paddingY) {
|
||||
|
||||
}
|
||||
|
||||
void GridElement::UpdatePositionScaled(RendertargetBase& window) {
|
||||
std::int32_t cellWidth = (paddingX * 2) - (spacingX * (columns - 1)) / columns;
|
||||
std::int32_t cellHeight = (paddingY * 2) - (spacingY * (rows - 1)) / rows;
|
||||
|
||||
std::size_t childIndex = 0;
|
||||
for (std::uint32_t row = 0; row < rows && childIndex < children.size(); ++row) {
|
||||
for (std::uint32_t col = 0; col < columns && childIndex < children.size(); ++col) {
|
||||
Transform2D* child = children[childIndex];
|
||||
|
||||
// Calculate position for this child
|
||||
std::int32_t childX = (cellWidth * col) + (spacingX * col) + paddingX;
|
||||
|
||||
std::int32_t childY = (cellHeight * row) + (spacingY * row) + paddingY;
|
||||
|
||||
// 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(RendertargetBase& window, Transform2D& parent) {
|
||||
ScaleElement(parent);
|
||||
UpdatePositionScaled(window);
|
||||
}
|
||||
|
|
@ -31,33 +31,3 @@ using namespace Crafter;
|
|||
Anchor2D::Anchor2D(float x, float y, float width, float height, float offsetX, float offsetY, std::int32_t z, bool maintainAspectRatio): x(x), y(y), width(width), height(height), offsetX(offsetX), offsetY(offsetY), z(z), maintainAspectRatio(maintainAspectRatio) {
|
||||
|
||||
}
|
||||
|
||||
Transform2D::Transform2D(Anchor2D anchor) : anchor(anchor) {
|
||||
|
||||
}
|
||||
|
||||
void Transform2D::UpdatePosition(RendertargetBase& window, Transform2D& parent) {
|
||||
ScaleElement(parent);
|
||||
for(Transform2D* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void Transform2D::ScaleElement(Transform2D& parent) {
|
||||
if(anchor.maintainAspectRatio) {
|
||||
if(parent.scaled.size.x > parent.scaled.size.y) {
|
||||
scaled.size.x = anchor.width * parent.scaled.size.y;
|
||||
scaled.size.y = anchor.height * parent.scaled.size.y;
|
||||
} else {
|
||||
scaled.size.x = anchor.width * parent.scaled.size.x;
|
||||
scaled.size.y = anchor.height * parent.scaled.size.x;
|
||||
}
|
||||
} else {
|
||||
|
||||
scaled.size.x = anchor.width * parent.scaled.size.x;
|
||||
scaled.size.y = anchor.height * parent.scaled.size.y;
|
||||
}
|
||||
|
||||
scaled.position.x = parent.scaled.position.x + (anchor.x * parent.scaled.size.x - anchor.offsetX * scaled.size.x);
|
||||
scaled.position.y = parent.scaled.position.y + (anchor.y * parent.scaled.size.y - anchor.offsetY * scaled.size.y);
|
||||
}
|
||||
|
|
@ -420,8 +420,8 @@ Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height
|
|||
}
|
||||
|
||||
// Map the shared memory file
|
||||
renderer.buffer = reinterpret_cast<Vector<std::uint8_t, 4, 4>*>(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
if (renderer.buffer == MAP_FAILED) {
|
||||
renderer.buffer[0] = reinterpret_cast<Vector<std::uint8_t, 4, 4>*>(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
if (renderer.buffer[0] == MAP_FAILED) {
|
||||
throw std::runtime_error("mmap failed");
|
||||
}
|
||||
|
||||
|
|
@ -562,13 +562,13 @@ void Window::SetTitle(const std::string_view title) {
|
|||
}
|
||||
|
||||
void Window::SetCusorImage(std::uint16_t sizeX, std::uint16_t sizeY) {
|
||||
new (&cursorRenderer) Rendertarget<std::uint8_t, 4, 4>(sizeX, sizeY);
|
||||
new (&cursorRenderer) Rendertarget<std::uint8_t, 4, 4, 1>(sizeX, sizeY);
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||
if(cursorSurface == nullptr) {
|
||||
cursorSurface = wl_compositor_create_surface(Device::compositor);
|
||||
} else {
|
||||
wl_buffer_destroy(cursorWlBuffer);
|
||||
munmap(cursorRenderer.buffer, cursorBufferOldSize);
|
||||
munmap(cursorRenderer.buffer[0], cursorBufferOldSize);
|
||||
}
|
||||
|
||||
int stride = sizeX * 4;
|
||||
|
|
@ -581,8 +581,8 @@ void Window::SetCusorImage(std::uint16_t sizeX, std::uint16_t sizeY) {
|
|||
throw std::runtime_error(std::format("creating a buffer file for {}B failed", size));
|
||||
}
|
||||
|
||||
cursorRenderer.buffer = reinterpret_cast<Vector<std::uint8_t, 4, 4>*>(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
if (cursorRenderer.buffer == MAP_FAILED) {
|
||||
cursorRenderer.buffer[0] = reinterpret_cast<Vector<std::uint8_t, 4, 4>*>(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
if (cursorRenderer.buffer[0] == MAP_FAILED) {
|
||||
throw std::runtime_error("mmap failed");
|
||||
}
|
||||
|
||||
|
|
@ -607,9 +607,9 @@ void Window::SetCusorImageDefault() {
|
|||
}
|
||||
|
||||
void Window::UpdateCursorImage() {
|
||||
cursorRenderer.Render();
|
||||
cursorRenderer.Render(0);
|
||||
for(std::uint32_t i = 0; i < cursorBufferOldSize / 4; i++) {
|
||||
std::swap(cursorRenderer.buffer[i].b, cursorRenderer.buffer[i].r);
|
||||
std::swap(cursorRenderer.buffer[0][i].b, cursorRenderer.buffer[0][i].r);
|
||||
}
|
||||
wl_surface_attach(cursorSurface, cursorWlBuffer, 0, 0);
|
||||
wl_surface_damage(cursorSurface, 0, 0, 9999999, 99999999);
|
||||
|
|
@ -686,9 +686,7 @@ void Window::Update() {
|
|||
|
||||
void Window::Render() {
|
||||
#ifdef CRAFTER_GRAPHICS_RENDERER_SOFTWARE
|
||||
// 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->anchor.z < b->anchor.z; });
|
||||
renderer.Render();
|
||||
renderer.Render(0);
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
wl_surface_commit(surface);
|
||||
|
|
|
|||
29
interfaces/Crafter.Graphics-ForwardDeclarations.cppm
Normal file
29
interfaces/Crafter.Graphics-ForwardDeclarations.cppm
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
Crafter®.Graphics
|
||||
Copyright (C) 2026 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:ForwardDeclarations;
|
||||
import std;
|
||||
|
||||
export namespace Crafter {
|
||||
template<std::uint8_t Frames = 1>
|
||||
struct RendertargetBase;
|
||||
|
||||
struct GridElement;
|
||||
struct Window;
|
||||
}
|
||||
|
|
@ -20,19 +20,52 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
export module Crafter.Graphics:GridElement;
|
||||
import std;
|
||||
import :Transform2D;
|
||||
import :Types;
|
||||
import :ForwardDeclarations;
|
||||
|
||||
export namespace Crafter {
|
||||
class GridElement : public Transform2D {
|
||||
public:
|
||||
struct GridElement : Transform2D {
|
||||
std::uint32_t columns;
|
||||
std::uint32_t rows;
|
||||
std::int32_t spacingX;
|
||||
std::int32_t spacingY;
|
||||
std::int32_t paddingX;
|
||||
std::int32_t paddingY;
|
||||
GridElement(std::uint32_t columns, std::uint32_t rows, std::int32_t spacingX, std::int32_t spacingY, std::int32_t paddingX, std::int32_t paddingY, Anchor2D anchor);
|
||||
void UpdatePositionScaled(RendertargetBase& window);
|
||||
void UpdatePosition(RendertargetBase& window, Transform2D& parent) override;
|
||||
GridElement(std::uint32_t columns, std::uint32_t rows, std::int32_t spacingX, std::int32_t spacingY, std::int32_t paddingX, std::int32_t paddingY, Anchor2D anchor) : Transform2D(anchor), columns(columns), rows(rows), spacingX(spacingX), spacingY(spacingY), paddingX(paddingX), paddingY(paddingY) {
|
||||
|
||||
}
|
||||
template<std::uint8_t Frames>
|
||||
void UpdatePositionImpl(RendertargetBase<Frames>& window, Transform2D& parent) {
|
||||
ScaleElement(parent);
|
||||
std::int32_t cellWidth = (paddingX * 2) - (spacingX * (columns - 1)) / columns;
|
||||
std::int32_t cellHeight = (paddingY * 2) - (spacingY * (rows - 1)) / rows;
|
||||
|
||||
std::size_t childIndex = 0;
|
||||
for (std::uint32_t row = 0; row < rows && childIndex < this->children.size(); ++row) {
|
||||
for (std::uint32_t col = 0; col < columns && childIndex < this->children.size(); ++col) {
|
||||
Transform2D* child = this->children[childIndex];
|
||||
|
||||
// Calculate position for this child
|
||||
std::int32_t childX = (cellWidth * col) + (spacingX * col) + paddingX;
|
||||
|
||||
std::int32_t childY = (cellHeight * row) + (spacingY * row) + paddingY;
|
||||
|
||||
// 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 UpdatePosition(RendertargetBase<1>& window, Transform2D& parent) override {
|
||||
UpdatePositionImpl<1>(window, parent);
|
||||
}
|
||||
void UpdatePosition(RendertargetBase<3>& window, Transform2D& parent) override {
|
||||
UpdatePositionImpl<3>(window, parent);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -20,11 +20,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
export module Crafter.Graphics:MouseElement;
|
||||
import std;
|
||||
import Crafter.Event;
|
||||
import :Types;
|
||||
import :Transform2D;
|
||||
import :ForwardDeclarations;
|
||||
|
||||
export namespace Crafter {
|
||||
class Window;
|
||||
struct MouseElement : Transform2D {
|
||||
Event<void> onMouseMove;
|
||||
Event<void> onMouseEnter;
|
||||
|
|
|
|||
|
|
@ -29,31 +29,31 @@ import :Types;
|
|||
import :Window;
|
||||
|
||||
export namespace Crafter {
|
||||
template<bool Scaling, bool Owning, bool Rotating, std::uint8_t Alignment = 0> requires ((!Rotating || Scaling) && (!Owning || Scaling))
|
||||
struct RenderingElement2D : RenderingElement2DBase, ScalingBase<Scaling, Owning, Alignment>, RotatingBase<Rotating> {
|
||||
template<bool Scaling, bool Owning, bool Rotating, std::uint8_t Alignment = 0, std::uint8_t Frames = 1> requires ((!Rotating || Scaling) && (!Owning || Scaling))
|
||||
struct RenderingElement2D : RenderingElement2DBase<Frames>, ScalingBase<Scaling, Owning, Alignment>, RotatingBase<Rotating> {
|
||||
RenderingElement2D() = default;
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque) : RenderingElement2DBase(anchor, opaque) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque) : RenderingElement2DBase<Frames>(anchor, opaque) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElement2DBase(anchor, opaque), RotatingBase<Rotating>(rotation) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElement2DBase<Frames>(anchor, opaque), RotatingBase<Rotating>(rotation) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4, Alignment>* scalingBuffer) requires(Scaling && !Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight, scalingBuffer) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4, Alignment>* scalingBuffer) requires(Scaling && !Owning) : RenderingElement2DBase<Frames>(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight, scalingBuffer) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4, Alignment>* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight, scalingBuffer), RotatingBase<Rotating>(rotation) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4, Alignment>* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElement2DBase<Frames>(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight, scalingBuffer), RotatingBase<Rotating>(rotation) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElement2DBase<Frames>(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, std::uint32_t rotation) requires(Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight) , RotatingBase<Rotating>(rotation) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, std::uint32_t rotation) requires(Owning && Rotating) : RenderingElement2DBase<Frames>(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight) , RotatingBase<Rotating>(rotation) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4, Alignment>>& texture) requires(!Owning && Scaling) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning, Alignment>(texture.pixels.data(), texture.sizeX, texture.sizeY) {
|
||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4, Alignment>>& texture) requires(!Owning && Scaling) : RenderingElement2DBase<Frames>(anchor, texture.opaque), ScalingBase<Scaling, Owning, Alignment>(texture.pixels.data(), texture.sizeX, texture.sizeY) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4, Alignment>>& texture, std::uint32_t rotation) requires(!Owning && Scaling && Rotating) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning, Alignment>(texture.pixels.data(), texture.sizeX, texture.sizeY), RotatingBase<Rotating>(rotation) {
|
||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4, Alignment>>& texture, std::uint32_t rotation) requires(!Owning && Scaling && Rotating) : RenderingElement2DBase<Frames>(anchor, texture.opaque), ScalingBase<Scaling, Owning, Alignment>(texture.pixels.data(), texture.sizeX, texture.sizeY), RotatingBase<Rotating>(rotation) {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -61,18 +61,18 @@ export namespace Crafter {
|
|||
RenderingElement2D& operator=(RenderingElement2D&) = delete;
|
||||
|
||||
void ScaleNearestNeighbor() requires(Scaling) {
|
||||
for (std::uint32_t y = 0; y < scaled.size.y; y++) {
|
||||
std::uint32_t srcY = y * ScalingBase<true, Owning, Alignment>::bufferHeight / scaled.size.y;
|
||||
for (std::uint32_t x = 0; x < scaled.size.x; x++) {
|
||||
std::uint32_t srcX = x * ScalingBase<true, Owning, Alignment>::bufferWidth / scaled.size.x;
|
||||
buffer[y * scaled.size.x + x] = ScalingBase<true, Owning, Alignment>::scalingBuffer[srcY * ScalingBase<true, Owning, Alignment>::bufferWidth + srcX];
|
||||
for (std::uint32_t y = 0; y < this->scaled.size.y; y++) {
|
||||
std::uint32_t srcY = y * ScalingBase<true, Owning, Alignment>::bufferHeight / this->scaled.size.y;
|
||||
for (std::uint32_t x = 0; x < this->scaled.size.x; x++) {
|
||||
std::uint32_t srcX = x * ScalingBase<true, Owning, Alignment>::bufferWidth / this->scaled.size.x;
|
||||
this->buffer[y * this->scaled.size.x + x] = ScalingBase<true, Owning, Alignment>::scalingBuffer[srcY * ScalingBase<true, Owning, Alignment>::bufferWidth + srcX];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScaleRotating() requires(Scaling) {
|
||||
const std::uint32_t dstWidth = scaled.size.x;
|
||||
const std::uint32_t dstHeight = scaled.size.y;
|
||||
const float dstWidth = this->scaled.size.x;
|
||||
const float dstHeight = this->scaled.size.y;
|
||||
|
||||
const float c2 = std::abs(std::cos(RotatingBase<true>::rotation));
|
||||
const float s2 = std::abs(std::sin(RotatingBase<true>::rotation));
|
||||
|
|
@ -80,25 +80,25 @@ export namespace Crafter {
|
|||
const float rotatedWidth = dstWidth * c2 + dstHeight * s2;
|
||||
const float rotatedHeight = dstWidth * s2 + dstHeight * c2;
|
||||
|
||||
const std::uint32_t diffX = static_cast<std::uint32_t>(std::ceil((rotatedWidth - dstWidth) * 0.5));
|
||||
const std::uint32_t diffY = static_cast<std::uint32_t>(std::ceil((rotatedHeight - dstHeight) * 0.5));
|
||||
const float diffX = std::ceil((rotatedWidth - dstWidth) * 0.5);
|
||||
const float diffY = std::ceil((rotatedHeight - dstHeight) * 0.5);
|
||||
|
||||
scaled.size.x += diffX + diffX;
|
||||
scaled.size.y += diffY + diffY;
|
||||
this->scaled.size.x += diffX + diffX;
|
||||
this->scaled.size.y += diffY + diffY;
|
||||
|
||||
scaled.position.x -= diffX;
|
||||
scaled.position.y -= diffY;
|
||||
this->scaled.position.x -= diffX;
|
||||
this->scaled.position.y -= diffY;
|
||||
|
||||
buffer.clear();
|
||||
buffer.resize(scaled.size.x * scaled.size.y);
|
||||
this->buffer.clear();
|
||||
this->buffer.resize(this->scaled.size.x * this->scaled.size.y);
|
||||
|
||||
// Destination center
|
||||
const float dstCx = (static_cast<float>(scaled.size.x) - 1.0) * 0.5;
|
||||
const float dstCy = (static_cast<float>(scaled.size.y) - 1.0) * 0.5;
|
||||
const float dstCx = (this->scaled.size.x - 1.0) * 0.5;
|
||||
const float dstCy = (this->scaled.size.y - 1.0) * 0.5;
|
||||
|
||||
// Source center
|
||||
const float srcCx = (static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferWidth) - 1.0) * 0.5;
|
||||
const float srcCy = (static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferHeight) - 1.0) * 0.5;
|
||||
const float srcCx = (ScalingBase<true, Owning, Alignment>::bufferWidth - 1.0) * 0.5;
|
||||
const float srcCy = (ScalingBase<true, Owning, Alignment>::bufferHeight - 1.0) * 0.5;
|
||||
|
||||
const float c = std::cos(RotatingBase<true>::rotation);
|
||||
const float s = std::sin(RotatingBase<true>::rotation);
|
||||
|
|
@ -107,8 +107,8 @@ export namespace Crafter {
|
|||
const float scaleX = static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferWidth) / dstWidth;
|
||||
const float scaleY = static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferHeight) / dstHeight;
|
||||
|
||||
for (std::uint32_t yB = 0; yB < scaled.size.y; ++yB) {
|
||||
for (std::uint32_t xB = 0; xB < scaled.size.x; ++xB) {
|
||||
for (std::uint32_t yB = 0; yB < this->scaled.size.y; ++yB) {
|
||||
for (std::uint32_t xB = 0; xB < this->scaled.size.x; ++xB) {
|
||||
|
||||
// ---- Destination pixel relative to center ----
|
||||
const float dx = (static_cast<float>(xB) - dstCx) * scaleX;
|
||||
|
|
@ -123,74 +123,37 @@ export namespace Crafter {
|
|||
const std::int32_t srcY = static_cast<std::int32_t>(std::round(sy));
|
||||
|
||||
if (srcX >= 0 && srcX < ScalingBase<true, Owning, Alignment>::bufferWidth && srcY >= 0 && srcY < ScalingBase<true, Owning, Alignment>::bufferHeight) {
|
||||
buffer[yB * scaled.size.x + xB] = ScalingBase<true, Owning, Alignment>::scalingBuffer[srcY * ScalingBase<true, Owning, Alignment>::bufferWidth + srcX];
|
||||
this->buffer[yB * this->scaled.size.x + xB] = ScalingBase<true, Owning, Alignment>::scalingBuffer[srcY * ScalingBase<true, Owning, Alignment>::bufferWidth + srcX];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePosition(RendertargetBase& renderer, ScaleData2D oldScale) {
|
||||
|
||||
void UpdatePosition(RendertargetBase<Frames>& window, Transform2D& parent) override {
|
||||
ScaleData2D oldScale = this->scaled;
|
||||
this->ScaleElement(parent);
|
||||
if constexpr(Scaling && !Rotating) {
|
||||
if(oldScale.size.x != scaled.size.x || oldScale.size.y != scaled.size.y) {
|
||||
buffer.resize(scaled.size.x * scaled.size.y);
|
||||
if(oldScale.size.x != this->scaled.size.x || oldScale.size.y != this->scaled.size.y) {
|
||||
this->buffer.resize(this->scaled.size.x * this->scaled.size.y);
|
||||
ScaleNearestNeighbor();
|
||||
renderer.AddDirtyRect(oldScale);
|
||||
renderer.AddDirtyRect(scaled);
|
||||
} else if(oldScale.position.x != scaled.position.x || oldScale.position.y != scaled.position.y) {
|
||||
renderer.AddDirtyRect(oldScale);
|
||||
renderer.AddDirtyRect(scaled);
|
||||
if(ScalingBase<true, Owning, Alignment>::bufferUpdated) {
|
||||
ScaleNearestNeighbor();
|
||||
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||
}
|
||||
} else if(ScalingBase<true, Owning, Alignment>::bufferUpdated) {
|
||||
ScaleNearestNeighbor();
|
||||
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||
renderer.AddDirtyRect(scaled);
|
||||
}
|
||||
} else if constexpr(Rotating) {
|
||||
if(oldScale.size.x != scaled.size.x || oldScale.size.y != scaled.size.y) {
|
||||
buffer.resize(scaled.size.x * scaled.size.y);
|
||||
if(oldScale.size.x != this->scaled.size.x || oldScale.size.y != this->scaled.size.y) {
|
||||
this->buffer.resize(this->scaled.size.x * this->scaled.size.y);
|
||||
ScaleRotating();
|
||||
renderer.AddDirtyRect(oldScale);
|
||||
renderer.AddDirtyRect(scaled);
|
||||
} else if(oldScale.position.x != scaled.position.x || oldScale.position.y != scaled.position.y) {
|
||||
renderer.AddDirtyRect(oldScale);
|
||||
renderer.AddDirtyRect(scaled);
|
||||
if(ScalingBase<true, Owning, Alignment>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
||||
ScaleRotating();
|
||||
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||
RotatingBase<true>::rotationUpdated = false;
|
||||
}
|
||||
} else if(ScalingBase<true, Owning, Alignment>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
||||
ScaleRotating();
|
||||
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||
RotatingBase<true>::rotationUpdated = false;
|
||||
renderer.AddDirtyRect(scaled);
|
||||
}
|
||||
} else {
|
||||
if(oldScale.size.x != scaled.size.x || oldScale.size.y != scaled.size.y) {
|
||||
buffer.resize(scaled.size.x * scaled.size.y);
|
||||
renderer.AddDirtyRect(oldScale);
|
||||
renderer.AddDirtyRect(scaled);
|
||||
}
|
||||
if(oldScale.position.x != scaled.position.x || oldScale.position.y != scaled.position.y) {
|
||||
renderer.AddDirtyRect(oldScale);
|
||||
renderer.AddDirtyRect(scaled);
|
||||
if(oldScale.size.x != this->scaled.size.x || oldScale.size.y != this->scaled.size.y) {
|
||||
this->buffer.resize(this->scaled.size.x * this->scaled.size.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePosition(RendertargetBase& window, Transform2D& parent) override {
|
||||
ScaleData2D oldScale = scaled;
|
||||
ScaleElement(parent);
|
||||
UpdatePosition(window, oldScale);
|
||||
for(Transform2D* child : children) {
|
||||
for(Transform2D* child : this->children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string_view> ResizeText(RendertargetBase& window, Transform2D& parent, const std::string_view text, float& size, Font& font, TextOverflowMode overflowMode = TextOverflowMode::Clip, TextScaleMode scaleMode = TextScaleMode::None) {
|
||||
std::vector<std::string_view> ResizeText(RendertargetBase<Frames>& window, Transform2D& parent, const std::string_view text, float& size, Font& font, std::uint8_t frame, TextOverflowMode overflowMode = TextOverflowMode::Clip, TextScaleMode scaleMode = TextScaleMode::None) {
|
||||
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
||||
int baseline = (int)(font.ascent * scale);
|
||||
|
||||
|
|
@ -225,40 +188,29 @@ export namespace Crafter {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if(scaleMode == TextScaleMode::Element) {
|
||||
std::int32_t logicalPerPixelY = anchor.height / scaled.size.y;
|
||||
std::int32_t oldHeight = anchor.height;
|
||||
std::int32_t logicalPerPixelX = anchor.width / scaled.size.x;
|
||||
std::int32_t oldwidth = anchor.width;
|
||||
anchor.height = lineHeight * logicalPerPixelY;
|
||||
anchor.width = maxWidth * logicalPerPixelX;
|
||||
if(oldHeight != anchor.height || oldwidth != anchor.width) {
|
||||
std::int32_t logicalPerPixelY = this->anchor.height / this->scaled.size.y;
|
||||
std::int32_t oldHeight = this->anchor.height;
|
||||
std::int32_t logicalPerPixelX = this->anchor.width / this->scaled.size.x;
|
||||
std::int32_t oldwidth = this->anchor.width;
|
||||
this->anchor.height = lineHeight * logicalPerPixelY;
|
||||
this->anchor.width = maxWidth * logicalPerPixelX;
|
||||
if(oldHeight != this->anchor.height || oldwidth != this->anchor.width) {
|
||||
UpdatePosition(window, parent);
|
||||
}
|
||||
} else if(scaleMode == TextScaleMode::Font) {
|
||||
float lineHeightPerFont = lineHeight / size;
|
||||
float lineWidthPerFont = maxWidth / size;
|
||||
|
||||
float maxFontHeight = scaled.size.y / lineHeightPerFont;
|
||||
float maxFontWidth = scaled.size.x / lineWidthPerFont;
|
||||
float maxFontHeight = this->scaled.size.y / lineHeightPerFont;
|
||||
float maxFontWidth = this->scaled.size.x / lineWidthPerFont;
|
||||
|
||||
size = std::min(maxFontHeight, maxFontWidth);
|
||||
} else if(scaleMode == TextScaleMode::Buffer) {
|
||||
if constexpr(Scaling && Owning) {
|
||||
std::uint32_t neededHeight = lines.size() * lineHeight;
|
||||
if(neededHeight != ScalingBase<true, true>::bufferHeight || maxWidth != ScalingBase<true, true>::bufferWidth) {
|
||||
ScalingBase<true, true>::bufferHeight = neededHeight;
|
||||
ScalingBase<true, true>::bufferWidth = maxWidth;
|
||||
ScalingBase<true, true>::bufferUpdated = true;
|
||||
ScalingBase<true, Owning, Alignment>::scalingBuffer.resize(neededHeight*maxWidth);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if constexpr(Scaling) {
|
||||
lines.resize(ScalingBase<true, Owning, Alignment>::bufferHeight / lines.size());
|
||||
} else {
|
||||
lines.resize(scaled.size.y / lines.size());
|
||||
lines.resize(this->scaled.size.y / lines.size());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -291,7 +243,7 @@ export namespace Crafter {
|
|||
}
|
||||
|
||||
// if line exceeds width, wrap
|
||||
if (lineWidth > scaled.size.x) {
|
||||
if (lineWidth > this->scaled.size.x) {
|
||||
std::size_t wrapPos;
|
||||
if (lastWrapPos > startPos) {
|
||||
wrapPos = lastWrapPos; // wrap at last space
|
||||
|
|
@ -321,36 +273,27 @@ export namespace Crafter {
|
|||
}
|
||||
|
||||
if(scaleMode == TextScaleMode::Element) {
|
||||
float logicalPerPixelY = anchor.height / scaled.size.y;
|
||||
float oldHeight = anchor.height;
|
||||
anchor.height = lineHeight * logicalPerPixelY;
|
||||
if(oldHeight != anchor.height) {
|
||||
float logicalPerPixelY = this->anchor.height / this->scaled.size.y;
|
||||
float oldHeight = this->anchor.height;
|
||||
this->anchor.height = lineHeight * logicalPerPixelY;
|
||||
if(oldHeight != this->anchor.height) {
|
||||
UpdatePosition(window, parent);
|
||||
}
|
||||
} else if(scaleMode == TextScaleMode::Font) {
|
||||
float lineHeightPerFont = lineHeight / size;
|
||||
size = scaled.size.y / lineHeightPerFont;
|
||||
} else if(scaleMode == TextScaleMode::Buffer) {
|
||||
if constexpr(Scaling && Owning) {
|
||||
float neededHeight = lines.size() * lineHeight;
|
||||
if(neededHeight != ScalingBase<true, true>::bufferHeight) {
|
||||
ScalingBase<true, true>::bufferHeight = neededHeight;
|
||||
ScalingBase<true, true>::bufferUpdated = true;
|
||||
ScalingBase<true, Owning, Alignment>::scalingBuffer.resize(neededHeight*ScalingBase<true, true>::bufferWidth);
|
||||
}
|
||||
}
|
||||
size = this->scaled.size.y / lineHeightPerFont;
|
||||
} else {
|
||||
if constexpr(Scaling) {
|
||||
lines.resize(ScalingBase<true, Owning, Alignment>::bufferHeight / lines.size());
|
||||
} else {
|
||||
lines.resize(scaled.size.y / lines.size());
|
||||
lines.resize(this->scaled.size.y / lines.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
void RenderText(std::span<const std::string_view> lines, float size, Vector<std::uint8_t, 4> color, Font& font, TextAlignment alignment = TextAlignment::Left, std::uint32_t offsetX = 0, std::uint32_t offsetY = 0, OpaqueType opaque = OpaqueType::FullyOpaque) {
|
||||
void RenderText(std::span<const std::string_view> lines, float size, Vector<std::uint8_t, 4> color, Font& font, std::uint8_t frame, TextAlignment alignment = TextAlignment::Left, std::uint32_t offsetX = 0, std::uint32_t offsetY = 0, OpaqueType opaque = OpaqueType::FullyOpaque) {
|
||||
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
||||
int baseline = (int)(font.ascent * scale);
|
||||
std::uint32_t lineHeight = (font.ascent - font.descent) * scale;
|
||||
|
|
@ -370,10 +313,10 @@ export namespace Crafter {
|
|||
x = 0;
|
||||
break;
|
||||
case TextAlignment::Center:
|
||||
x = (scaled.size.x - lineWidth) / 2;
|
||||
x = (this->scaled.size.x - lineWidth) / 2;
|
||||
break;
|
||||
case TextAlignment::Right:
|
||||
x = scaled.size.x - lineWidth;
|
||||
x = this->scaled.size.x - lineWidth;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -407,8 +350,8 @@ export namespace Crafter {
|
|||
ScalingBase<true, Owning, Alignment>::scalingBuffer[bufferY * ScalingBase<true, Owning, Alignment>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
} else {
|
||||
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||
buffer[bufferY * scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
if (bufferX >= 0 && bufferX < (int)this->scaled.size.x && bufferY >= 0 && bufferY < (int)this->scaled.size.y) {
|
||||
this->buffer[bufferY * this->scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -427,10 +370,10 @@ export namespace Crafter {
|
|||
ScalingBase<true, Owning, Alignment>::scalingBuffer[bufferY * ScalingBase<true, Owning, Alignment>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
} else {
|
||||
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||
if (bufferX >= 0 && bufferX < (int)this->scaled.size.x && bufferY >= 0 && bufferY < (int)this->scaled.size.y) {
|
||||
std::uint8_t alpha = bitmap[j * w + i];
|
||||
if(alpha != 0) {
|
||||
buffer[bufferY * scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
this->buffer[bufferY * this->scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -450,20 +393,20 @@ export namespace Crafter {
|
|||
ScalingBase<true, Owning, Alignment>::scalingBuffer[bufferY * ScalingBase<true, Owning, Alignment>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
} else {
|
||||
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||
if (bufferX >= 0 && bufferX < (int)this->scaled.size.x && bufferY >= 0 && bufferY < (int)this->scaled.size.y) {
|
||||
std::uint8_t alpha = bitmap[j * w + i];
|
||||
|
||||
if(alpha == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector<std::uint8_t, 4, Alignment> dst = buffer[bufferY * scaled.size.x + bufferX];
|
||||
Vector<std::uint8_t, 4, Alignment> dst = this->buffer[bufferY * this->scaled.size.x + bufferX];
|
||||
|
||||
float srcA = (alpha / 255.0f) * (color.a / 255.0f);
|
||||
float dstA = dst.a / 255.0f;
|
||||
|
||||
float outA = srcA + dstA * (1.0f - srcA);
|
||||
buffer[bufferY * scaled.size.x + bufferX] = Vector<std::uint8_t, 4, Alignment>(
|
||||
this->buffer[bufferY * this->scaled.size.x + bufferX] = Vector<std::uint8_t, 4, Alignment>(
|
||||
static_cast<std::uint8_t>((color.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<std::uint8_t>((color.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<std::uint8_t>((color.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA),
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ export namespace Crafter {
|
|||
std::vector<Vector<std::uint8_t, 4, Alignment>> scalingBuffer;
|
||||
std::uint32_t bufferWidth;
|
||||
std::uint32_t bufferHeight;
|
||||
bool bufferUpdated = true;
|
||||
RenderElement2DScalingOwning() = default;
|
||||
RenderElement2DScalingOwning(std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(bufferWidth*bufferHeight), bufferWidth(bufferWidth), bufferHeight(bufferHeight) {
|
||||
|
||||
|
|
@ -59,7 +58,6 @@ export namespace Crafter {
|
|||
Vector<std::uint8_t, 4, Alignment>* scalingBuffer;
|
||||
std::uint32_t bufferWidth;
|
||||
std::uint32_t bufferHeight;
|
||||
bool bufferUpdated = true;
|
||||
RenderElement2DScalingNonOwning() = default;
|
||||
RenderElement2DScalingNonOwning(Vector<std::uint8_t, 4, Alignment>* scalingBuffer, std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(scalingBuffer), bufferWidth(bufferWidth), bufferHeight(bufferHeight) {
|
||||
|
||||
|
|
@ -68,7 +66,6 @@ export namespace Crafter {
|
|||
|
||||
struct RenderElement2DRotating {
|
||||
float rotation;
|
||||
bool rotationUpdated = true;
|
||||
RenderElement2DRotating() = default;
|
||||
RenderElement2DRotating(float rotation) : rotation(rotation) {
|
||||
|
||||
|
|
@ -97,14 +94,20 @@ export namespace Crafter {
|
|||
EmptyRotatingBase
|
||||
>;
|
||||
|
||||
template<std::uint8_t Frames = 1>
|
||||
struct RenderingElement2DBase : Transform2D {
|
||||
ScaleData2D oldScale[Frames];
|
||||
std::vector<Vector<std::uint8_t, 4>> buffer;
|
||||
OpaqueType opaque;
|
||||
RenderingElement2DBase(Anchor2D anchor) : Transform2D(anchor) {
|
||||
scaled.size.x = 0;
|
||||
for(std::uint8_t i = 0; i < Frames; i++) {
|
||||
this->scaled[i].size.x = 0;
|
||||
}
|
||||
}
|
||||
RenderingElement2DBase(Anchor2D anchor, OpaqueType opaque) : Transform2D(anchor), opaque(opaque) {
|
||||
scaled.size.x = 0;
|
||||
for(std::uint8_t i = 0; i < Frames; i++) {
|
||||
this->scaled[i].size.x = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import :Transform2D;
|
|||
import :RenderingElement2DBase;
|
||||
|
||||
export namespace Crafter {
|
||||
template<std::uint8_t Frames>
|
||||
struct RendertargetBase {
|
||||
#ifdef CRAFTER_TIMING
|
||||
std::vector<std::tuple<const Transform*, std::uint32_t, std::uint32_t, std::chrono::nanoseconds>> renderTimings;
|
||||
|
|
@ -33,7 +34,7 @@ export namespace Crafter {
|
|||
std::int32_t sizeX;
|
||||
std::int32_t sizeY;
|
||||
std::vector<Transform2D*> elements;
|
||||
std::vector<ClipRect> dirtyRects;
|
||||
std::vector<ClipRect> dirtyRects[Frames];
|
||||
RendertargetBase() = default;
|
||||
RendertargetBase(std::int16_t sizeX, std::int16_t sizeY) : sizeX(sizeX), sizeY(sizeY), transform({0, 0, 1, 1, 0, 0, 0}){
|
||||
transform.scaled.size.x = sizeX;
|
||||
|
|
@ -42,19 +43,21 @@ export namespace Crafter {
|
|||
transform.scaled.position.y = 0;
|
||||
}
|
||||
void AddDirtyRect(ScaleData2D scale) {
|
||||
dirtyRects.emplace_back(std::max(scale.position.x, std::int32_t(0)), std::min(scale.position.x + scale.size.x, sizeX), std::max(scale.position.y, std::int32_t(0)), std::min(scale.position.y + scale.size.y, sizeY));
|
||||
for(std::uint8_t i = 0; i < Frames; i++) {
|
||||
dirtyRects[i].emplace_back(std::max(scale.position.x, std::int32_t(0)), std::min(scale.position.x + scale.size.x, sizeX), std::max(scale.position.y, std::int32_t(0)), std::min(scale.position.y + scale.size.y, sizeY));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, std::uint8_t Channels, std::uint8_t Alignment>
|
||||
struct Rendertarget : RendertargetBase {
|
||||
Vector<T, Channels, Alignment>* buffer;
|
||||
template<typename T, std::uint8_t Channels, std::uint8_t Alignment, std::uint8_t Frames>
|
||||
struct Rendertarget : RendertargetBase<Frames> {
|
||||
Vector<T, Channels, Alignment>* buffer[Frames];
|
||||
Rendertarget() = default;
|
||||
Rendertarget(std::int16_t sizeX, std::int16_t sizeY) : RendertargetBase(sizeX, sizeY) {
|
||||
Rendertarget(std::int16_t sizeX, std::int16_t sizeY) : RendertargetBase<Frames>(sizeX, sizeY) {
|
||||
|
||||
}
|
||||
void RenderElement(Transform2D* elementTransform) {
|
||||
RenderingElement2DBase* element = dynamic_cast<RenderingElement2DBase*>(elementTransform);
|
||||
void RenderElement(Transform2D* elementTransform, std::uint8_t frame) {
|
||||
RenderingElement2DBase<Frames>* element = dynamic_cast<RenderingElement2DBase<Frames>*>(elementTransform);
|
||||
if(element) {
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
|
@ -64,7 +67,7 @@ export namespace Crafter {
|
|||
return;
|
||||
}
|
||||
|
||||
for(ClipRect dirty : dirtyRects) {
|
||||
for(ClipRect dirty : this->dirtyRects[frame]) {
|
||||
dirty.left = std::max(element->scaled.position.x, dirty.left);
|
||||
dirty.top = std::max(element->scaled.position.y, dirty.top);
|
||||
dirty.right = std::min(element->scaled.position.x+element->scaled.size.x, dirty.right);
|
||||
|
|
@ -82,7 +85,7 @@ export namespace Crafter {
|
|||
for (std::int32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int32_t src_x = x - element->scaled.position.x;
|
||||
|
||||
buffer[y * sizeX + x] = src_buffer[src_y * src_width + src_x];
|
||||
this->buffer[frame][y * this->sizeX + x] = src_buffer[src_y * src_width + src_x];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -99,7 +102,7 @@ export namespace Crafter {
|
|||
if (src_pixel.a == 0) {
|
||||
continue;
|
||||
}
|
||||
buffer[y * sizeX + x] = src_pixel;
|
||||
this->buffer[frame][y * this->sizeX + x] = src_pixel;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -111,7 +114,7 @@ export namespace Crafter {
|
|||
for (std::int32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int32_t src_x = x - element->scaled.position.x;
|
||||
Vector<T, Channels, Alignment> src = src_buffer[src_y * src_width + src_x];
|
||||
Vector<T, Channels, Alignment> dst = buffer[y * sizeX + x];
|
||||
Vector<T, Channels, Alignment> dst = buffer[frame][y * this->sizeX + x];
|
||||
|
||||
if(src.a == 0) {
|
||||
continue;
|
||||
|
|
@ -121,7 +124,7 @@ export namespace Crafter {
|
|||
float dstA = dst.a / 255.0f;
|
||||
|
||||
float outA = srcA + dstA * (1.0f - srcA);
|
||||
buffer[y * sizeX + x] = Vector<T, Channels, Alignment>(
|
||||
this->buffer[frame][y * this->sizeX + x] = Vector<T, Channels, Alignment>(
|
||||
static_cast<T>((src.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<T>((src.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<T>((src.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA),
|
||||
|
|
@ -139,12 +142,11 @@ export namespace Crafter {
|
|||
}
|
||||
std::sort(elementTransform->children.begin(), elementTransform->children.end(), [](Transform2D* a, Transform2D* b){ return a->anchor.z < b->anchor.z; });
|
||||
for(Transform2D* child : elementTransform->children) {
|
||||
this->RenderElement(child);
|
||||
this->RenderElement(child, frame);
|
||||
}
|
||||
}
|
||||
void Render() {
|
||||
elements.erase(std::remove(elements.begin(), elements.end(), static_cast<Transform2D*>(nullptr)), elements.end());
|
||||
std::sort(elements.begin(), elements.end(), [](Transform2D* a, Transform2D* b){ return a->anchor.z < b->anchor.z; });
|
||||
void Render(std::uint8_t frame) {
|
||||
std::sort(this->elements.begin(), this->elements.end(), [](Transform2D* a, Transform2D* b){ return a->anchor.z < b->anchor.z; });
|
||||
|
||||
//std::vector<ClipRect> newClip;
|
||||
// for (std::uint32_t i = 0; i < dirtyRects.size(); i++) {
|
||||
|
|
@ -245,19 +247,19 @@ export namespace Crafter {
|
|||
// ++rectIndex;
|
||||
// }
|
||||
|
||||
if (!dirtyRects.empty()) {
|
||||
for (ClipRect rect : dirtyRects) {
|
||||
if (!this->dirtyRects[frame].empty()) {
|
||||
for (ClipRect rect : this->dirtyRects[frame]) {
|
||||
for (std::int32_t y = rect.top; y < rect.bottom; y++) {
|
||||
for (std::int32_t x = rect.left; x < rect.right; x++) {
|
||||
buffer[y * sizeX + x] = {0, 0, 0, 0};
|
||||
this->buffer[frame][y * this->sizeX + x] = {0, 0, 0, 0};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Transform2D* child : elements) {
|
||||
RenderElement(child);
|
||||
for(Transform2D* child : this->elements) {
|
||||
RenderElement(child, frame);
|
||||
}
|
||||
dirtyRects.clear();
|
||||
this->dirtyRects[frame].clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
export module Crafter.Graphics:Transform2D;
|
||||
import std;
|
||||
import :Types;
|
||||
import :ForwardDeclarations;
|
||||
|
||||
export namespace Crafter {
|
||||
struct RendertargetBase;
|
||||
struct Anchor2D {
|
||||
float x;
|
||||
float y;
|
||||
|
|
@ -35,17 +35,51 @@ export namespace Crafter {
|
|||
Anchor2D() = default;
|
||||
Anchor2D(float x, float y, float width, float height, float offsetX, float offsetY, std::int32_t z, bool maintainAspectRatio = false);
|
||||
};
|
||||
|
||||
struct Transform2D {
|
||||
Anchor2D anchor;
|
||||
ScaleData2D scaled;
|
||||
std::vector<Transform2D*> children;
|
||||
Transform2D() = default;
|
||||
Transform2D(Anchor2D anchor);
|
||||
Transform2D(Anchor2D anchor) : anchor(anchor) {
|
||||
|
||||
}
|
||||
Transform2D(Transform2D&) = delete;
|
||||
Transform2D(Transform2D&&) = delete;
|
||||
Transform2D& operator=(Transform2D&) = delete;
|
||||
virtual ~Transform2D() = default;
|
||||
void ScaleElement(Transform2D& parent);
|
||||
virtual void UpdatePosition(RendertargetBase& window, Transform2D& parent);
|
||||
|
||||
virtual void UpdatePosition(RendertargetBase<1>& window, Transform2D& parent) {
|
||||
ScaleElement(parent);
|
||||
for(Transform2D* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UpdatePosition(RendertargetBase<3>& window, Transform2D& parent) {
|
||||
ScaleElement(parent);
|
||||
for(Transform2D* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void ScaleElement(Transform2D& parent) {
|
||||
if(anchor.maintainAspectRatio) {
|
||||
if(parent.scaled.size.x > parent.scaled.size.y) {
|
||||
scaled.size.x = anchor.width * parent.scaled.size.y;
|
||||
scaled.size.y = anchor.height * parent.scaled.size.y;
|
||||
} else {
|
||||
scaled.size.x = anchor.width * parent.scaled.size.x;
|
||||
scaled.size.y = anchor.height * parent.scaled.size.x;
|
||||
}
|
||||
} else {
|
||||
|
||||
scaled.size.x = anchor.width * parent.scaled.size.x;
|
||||
scaled.size.y = anchor.height * parent.scaled.size.y;
|
||||
}
|
||||
|
||||
scaled.position.x = parent.scaled.position.x + (anchor.x * parent.scaled.size.x - anchor.offsetX * scaled.size.x);
|
||||
scaled.position.y = parent.scaled.position.y + (anchor.y * parent.scaled.size.y - anchor.offsetY * scaled.size.y);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ export namespace Crafter {
|
|||
bool mouseRightHeld = false;
|
||||
std::vector<MouseElement*> mouseElements;
|
||||
std::vector<MouseElement*> pendingMouseElements;
|
||||
Rendertarget<std::uint8_t, 4, 4> cursorRenderer;
|
||||
Rendertarget<std::uint8_t, 4, 4, 1> cursorRenderer;
|
||||
|
||||
Window() = default;
|
||||
Window(std::uint32_t width, std::uint32_t height);
|
||||
|
|
@ -130,7 +130,7 @@ export namespace Crafter {
|
|||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||
float scale;
|
||||
#ifdef CRAFTER_GRAPHICS_RENDERER_SOFTWARE
|
||||
Rendertarget<std::uint8_t, 4, 4> renderer;
|
||||
Rendertarget<std::uint8_t, 4, 4, 1> renderer;
|
||||
#endif
|
||||
bool configured = false;
|
||||
xdg_toplevel* xdgToplevel = nullptr;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export import :Font;
|
|||
export import :Animation;
|
||||
export import :Mesh;
|
||||
export import :Rendertarget;
|
||||
export import :ForwardDeclarations;
|
||||
|
||||
#ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN
|
||||
export import :Device;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
"implementations/Crafter.Graphics-Window",
|
||||
"implementations/Crafter.Graphics-MouseElement",
|
||||
"implementations/Crafter.Graphics-Transform2D",
|
||||
"implementations/Crafter.Graphics-GridElement",
|
||||
"implementations/Crafter.Graphics-Device",
|
||||
"implementations/Crafter.Graphics-Mesh",
|
||||
"implementations/Crafter.Graphics-RenderingElement3D"
|
||||
|
|
@ -36,7 +35,8 @@
|
|||
"interfaces/Crafter.Graphics-ImageVulkan",
|
||||
"interfaces/Crafter.Graphics-SamplerVulkan",
|
||||
"interfaces/Crafter.Graphics-DescriptorSetLayoutVulkan",
|
||||
"interfaces/Crafter.Graphics-Rendertarget"
|
||||
"interfaces/Crafter.Graphics-Rendertarget",
|
||||
"interfaces/Crafter.Graphics-ForwardDeclarations"
|
||||
],
|
||||
"type": "library"
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue