selective clearing
This commit is contained in:
parent
483131062f
commit
9bb36c990d
7 changed files with 98 additions and 30 deletions
|
|
@ -6,7 +6,7 @@ using namespace Crafter;
|
||||||
int main() {
|
int main() {
|
||||||
WindowWayland window(1280, 720, "Hello Input!");
|
WindowWayland window(1280, 720, "Hello Input!");
|
||||||
|
|
||||||
RenderingElement element(
|
RenderingElementScaling element(
|
||||||
true, //opaque, wether the element is opague or semi-transparant
|
true, //opaque, wether the element is opague or semi-transparant
|
||||||
2, //bufferWidth: the width of this elements pixel buffer
|
2, //bufferWidth: the width of this elements pixel buffer
|
||||||
1, //bufferHeight: the height of this elements pixel buffer
|
1, //bufferHeight: the height of this elements pixel buffer
|
||||||
|
|
@ -21,6 +21,7 @@ int main() {
|
||||||
);
|
);
|
||||||
|
|
||||||
window.elements.push_back(&element);
|
window.elements.push_back(&element);
|
||||||
|
element.buffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}};
|
||||||
element.UpdatePosition(window);
|
element.UpdatePosition(window);
|
||||||
|
|
||||||
Animation<std::tuple<std::int_fast32_t>> anim({
|
Animation<std::tuple<std::int_fast32_t>> anim({
|
||||||
|
|
@ -39,7 +40,6 @@ int main() {
|
||||||
window.LogTiming();
|
window.LogTiming();
|
||||||
});
|
});
|
||||||
|
|
||||||
element.buffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}};
|
|
||||||
window.StartUpdate();
|
window.StartUpdate();
|
||||||
window.StartSync();
|
window.StartSync();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,24 +59,36 @@ RenderingElementScaling::RenderingElementScaling(bool opaque, std::uint_fast32_t
|
||||||
|
|
||||||
|
|
||||||
void RenderingElementPreScaled::UpdatePosition(Window& window) {
|
void RenderingElementPreScaled::UpdatePosition(Window& window) {
|
||||||
std::uint_fast32_t oldWidth = scaled.width;
|
ScaleData oldScale = scaled;
|
||||||
std::uint_fast32_t oldHeight = scaled.height;
|
|
||||||
window.ScaleElement(*this);
|
window.ScaleElement(*this);
|
||||||
if(oldWidth != scaled.width || oldHeight && scaled.height) {
|
|
||||||
|
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||||
bufferScaled.resize(scaled.width * 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) {
|
for(Transform* child : children) {
|
||||||
child->UpdatePosition(window, *this);
|
child->UpdatePosition(window, *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingElementPreScaled::UpdatePosition(Window& window, Transform& parent) {
|
void RenderingElementPreScaled::UpdatePosition(Window& window, Transform& parent) {
|
||||||
std::uint_fast32_t oldWidth = scaled.width;
|
ScaleData oldScale = scaled;
|
||||||
std::uint_fast32_t oldHeight = scaled.height;
|
|
||||||
window.ScaleElement(*this, parent);
|
window.ScaleElement(*this, parent);
|
||||||
if(oldWidth != scaled.width || oldHeight && scaled.height) {
|
|
||||||
|
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||||
bufferScaled.resize(scaled.width * 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) {
|
for(Transform* child : children) {
|
||||||
child->UpdatePosition(window, *this);
|
child->UpdatePosition(window, *this);
|
||||||
}
|
}
|
||||||
|
|
@ -103,26 +115,39 @@ void RenderingElementScaling::CopyNearestNeighbour(Pixel_BU8_GU8_RU8_AU8* dst, s
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingElementScaling::UpdatePosition(Window& window) {
|
void RenderingElementScaling::UpdatePosition(Window& window) {
|
||||||
std::uint_fast32_t oldWidth = scaled.width;
|
ScaleData oldScale = scaled;
|
||||||
std::uint_fast32_t oldHeight = scaled.height;
|
|
||||||
window.ScaleElement(*this);
|
window.ScaleElement(*this);
|
||||||
if(oldWidth != scaled.width || oldHeight && scaled.height) {
|
|
||||||
|
|
||||||
|
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||||
bufferScaled.resize(scaled.width * scaled.height);
|
bufferScaled.resize(scaled.width * scaled.height);
|
||||||
CopyNearestNeighbour(bufferScaled.data(), 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) {
|
for(Transform* child : children) {
|
||||||
child->UpdatePosition(window, *this);
|
child->UpdatePosition(window, *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingElementScaling::UpdatePosition(Window& window, Transform& parent) {
|
void RenderingElementScaling::UpdatePosition(Window& window, Transform& parent) {
|
||||||
std::uint_fast32_t oldWidth = scaled.width;
|
ScaleData oldScale = scaled;
|
||||||
std::uint_fast32_t oldHeight = scaled.height;
|
|
||||||
window.ScaleElement(*this, parent);
|
window.ScaleElement(*this, parent);
|
||||||
if(oldWidth != scaled.width || oldHeight && scaled.height) {
|
|
||||||
|
if(oldScale.width != scaled.width || oldScale.height != scaled.height) {
|
||||||
bufferScaled.resize(scaled.width * scaled.height);
|
bufferScaled.resize(scaled.width * scaled.height);
|
||||||
CopyNearestNeighbour(bufferScaled.data(), 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) {
|
for(Transform* child : children) {
|
||||||
child->UpdatePosition(window, *this);
|
child->UpdatePosition(window, *this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@ TextElement::TextElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, s
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextElement::RenderText(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 color, Font& font, TextAlignment alignment, VerticalTextAlignment verticalAlignment, TextOverflowMode overflowMode) {
|
void TextElement::RenderText(Window& window, const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 color, Font& font, TextAlignment alignment, VerticalTextAlignment verticalAlignment, TextOverflowMode overflowMode) {
|
||||||
|
window.AddDirtyRect(scaled);
|
||||||
// Calculate the actual size needed for the text
|
// Calculate the actual size needed for the text
|
||||||
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
||||||
int baseline = (int)(font.ascent * scale);
|
int baseline = (int)(font.ascent * scale);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
module Crafter.Graphics:Window_impl;
|
module Crafter.Graphics:Window_impl;
|
||||||
import :Window;
|
import :Window;
|
||||||
import :Transform;
|
import :Transform;
|
||||||
|
|
@ -25,7 +24,7 @@ import std;
|
||||||
|
|
||||||
using namespace Crafter;
|
using namespace Crafter;
|
||||||
|
|
||||||
Window::Window(std::uint_fast32_t width, std::uint_fast32_t height) : width(width), height(height) {
|
Window::Window(std::int_fast32_t width, std::int_fast32_t height) : width(width), height(height) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,4 +96,32 @@ void Window::LogTiming() {
|
||||||
duration_cast<std::chrono::milliseconds>(max)) << std::endl;
|
duration_cast<std::chrono::milliseconds>(max)) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool Overlaps(const ScaleData& rect1, const ScaleData& rect2) {
|
||||||
|
return !(rect1.x + rect1.width <= rect2.x || rect2.x + rect2.width <= rect1.x || rect1.y + rect1.height <= rect2.y || rect2.y + rect2.height <= rect1.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScaleData MergeRects(const ScaleData& rect1, const ScaleData& rect2) {
|
||||||
|
ScaleData merged;
|
||||||
|
merged.x = std::min(rect1.x, rect2.x);
|
||||||
|
merged.y = std::min(rect1.y, rect2.y);
|
||||||
|
merged.width = std::max(rect1.x + rect1.width, rect2.x + rect2.width) - merged.x;
|
||||||
|
merged.height = std::max(rect1.y + rect1.height, rect2.y + rect2.height) - merged.y;
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::AddDirtyRect(ScaleData rect) {
|
||||||
|
bool merged = false;
|
||||||
|
for (auto& existingRect : dirtyRects) {
|
||||||
|
if (Overlaps(existingRect, rect)) {
|
||||||
|
existingRect = MergeRects(existingRect, rect);
|
||||||
|
merged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!merged) {
|
||||||
|
dirtyRects.push_back(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -192,7 +192,6 @@ void WindowWayland::RenderElement(Transform* transform) {
|
||||||
|
|
||||||
// Bounds check for source buffer
|
// Bounds check for source buffer
|
||||||
if (src_x >= 0 && src_x < static_cast<std::int_fast32_t>(src_width) && src_y >= 0 && src_y < static_cast<std::int_fast32_t>(src_height)) {
|
if (src_x >= 0 && src_x < static_cast<std::int_fast32_t>(src_width) && src_y >= 0 && src_y < static_cast<std::int_fast32_t>(src_height)) {
|
||||||
|
|
||||||
// Direct copy for opaque elements (skip blending)
|
// Direct copy for opaque elements (skip blending)
|
||||||
framebuffer[y * width + x] = src_buffer[src_y * src_width + src_x];
|
framebuffer[y * width + x] = src_buffer[src_y * src_width + src_x];
|
||||||
}
|
}
|
||||||
|
|
@ -232,15 +231,27 @@ void WindowWayland::Render() {
|
||||||
elements.erase(std::remove(elements.begin(), elements.end(), static_cast<Transform*>(nullptr)), elements.end());
|
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->z < b->z; });
|
||||||
|
|
||||||
// Clear screen efficiently using memset
|
if (!dirtyRects.empty()) {
|
||||||
memset(framebuffer, 0, width * height * sizeof(Pixel_BU8_GU8_RU8_AU8));
|
for (const ScaleData& rect : dirtyRects) {
|
||||||
|
for (std::int_fast32_t y = rect.y; y < rect.y + rect.height && y < height; y++) {
|
||||||
for(Transform* child : elements) {
|
for (std::int_fast32_t x = rect.x; x < rect.x + rect.width && x < width; x++) {
|
||||||
RenderElement(child);
|
framebuffer[y * width + x] = {0, 0, 0, 0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Transform* child : elements) {
|
||||||
|
RenderElement(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ScaleData& rect : dirtyRects) {
|
||||||
|
wl_surface_damage(surface, rect.x, rect.y, rect.width, rect.height);
|
||||||
|
}
|
||||||
|
dirtyRects.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wl_surface_attach(surface, buffer, 0, 0);
|
wl_surface_attach(surface, buffer, 0, 0);
|
||||||
wl_surface_damage(surface, 0, 0, width, height);
|
|
||||||
wl_surface_commit(surface);
|
wl_surface_commit(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,7 +278,7 @@ void WindowWayland::Write(Pixel_BU8_GU8_RU8_AU8* pixels) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowWayland::Write(std::uint_fast32_t x, std::uint_fast32_t y, Pixel_BU8_GU8_RU8_AU8 pixel) {
|
void WindowWayland::Write(std::uint_fast32_t x, std::uint_fast32_t y, Pixel_BU8_GU8_RU8_AU8 pixel) {
|
||||||
framebuffer[y * width + x] = pixel;
|
framebuffer[y * width + x] = pixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pixel_BU8_GU8_RU8_AU8 WindowWayland::Read(std::uint_fast32_t x, std::uint_fast32_t y) const{
|
Pixel_BU8_GU8_RU8_AU8 WindowWayland::Read(std::uint_fast32_t x, std::uint_fast32_t y) const{
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,6 @@ export namespace Crafter {
|
||||||
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);
|
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:
|
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, bool ignoreScaling = false);
|
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, bool ignoreScaling = false);
|
||||||
void RenderText(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);
|
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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -48,16 +48,20 @@ export namespace Crafter {
|
||||||
class RenderingElement;
|
class RenderingElement;
|
||||||
class Window {
|
class Window {
|
||||||
public:
|
public:
|
||||||
std::uint_fast32_t width;
|
std::int_fast32_t width;
|
||||||
std::uint_fast32_t height;
|
std::int_fast32_t height;
|
||||||
std::chrono::time_point<std::chrono::high_resolution_clock> lastFrameBegin;
|
std::chrono::time_point<std::chrono::high_resolution_clock> lastFrameBegin;
|
||||||
std::vector<Transform*> elements;
|
std::vector<Transform*> elements;
|
||||||
Event<void> onClose;
|
Event<void> onClose;
|
||||||
Event<FrameTime> onUpdate;
|
Event<FrameTime> onUpdate;
|
||||||
bool open = true;
|
bool open = true;
|
||||||
bool updating = false;
|
bool updating = false;
|
||||||
|
|
||||||
|
std::vector<ScaleData> dirtyRects;
|
||||||
|
void AddDirtyRect(ScaleData rect);
|
||||||
|
|
||||||
Window() = default;
|
Window() = default;
|
||||||
Window(std::uint_fast32_t width, std::uint_fast32_t height);
|
Window(std::int_fast32_t width, std::int_fast32_t height);
|
||||||
Window(Window&) = delete;
|
Window(Window&) = delete;
|
||||||
Window(Window&&) = delete;
|
Window(Window&&) = delete;
|
||||||
virtual ~Window() = default;
|
virtual ~Window() = default;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue