summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugingui/guievent.h7
-rw-r--r--plugingui/nativewindow.h4
-rw-r--r--plugingui/nativewindow_win32.cc5
-rw-r--r--plugingui/nativewindow_win32.h2
-rw-r--r--plugingui/nativewindow_x11.cc61
-rw-r--r--plugingui/nativewindow_x11.h5
-rw-r--r--plugingui/widget.cc1
-rw-r--r--plugingui/window.cc79
8 files changed, 115 insertions, 49 deletions
diff --git a/plugingui/guievent.h b/plugingui/guievent.h
index 2d4cc6f..11a7b9b 100644
--- a/plugingui/guievent.h
+++ b/plugingui/guievent.h
@@ -174,5 +174,12 @@ public:
using EventQueue = std::list<std::shared_ptr<Event>>;
+struct Rect
+{
+ std::size_t x1;
+ std::size_t y1;
+ std::size_t x2;
+ std::size_t y2;
+};
} // GUI::
diff --git a/plugingui/nativewindow.h b/plugingui/nativewindow.h
index 7b7fd39..c6ca7c8 100644
--- a/plugingui/nativewindow.h
+++ b/plugingui/nativewindow.h
@@ -29,6 +29,8 @@
#include <string>
#include <memory>
#include <queue>
+#include <tuple>
+#include <vector>
#include "guievent.h"
@@ -70,7 +72,7 @@ public:
virtual void setCaption(const std::string &caption) = 0;
//! Draw the internal rendering buffer to the window buffer.
- virtual void redraw() = 0;
+ virtual void redraw(const Rect& dirty_rect) = 0;
//! Toggle capture mouse mode.
virtual void grabMouse(bool grab) = 0;
diff --git a/plugingui/nativewindow_win32.cc b/plugingui/nativewindow_win32.cc
index 669ec13..dce14cc 100644
--- a/plugingui/nativewindow_win32.cc
+++ b/plugingui/nativewindow_win32.cc
@@ -384,12 +384,13 @@ void NativeWindowWin32::hide()
ShowWindow(m_hwnd, SW_HIDE);
}
-void NativeWindowWin32::redraw()
+void NativeWindowWin32::redraw(const Rect& dirty_rect)
{
// Send WM_PAINT message. Buffer transfering is handled in MessageHandler.
if(parent_window == nullptr)
{
- RedrawWindow(m_hwnd, nullptr, nullptr, RDW_ERASE|RDW_INVALIDATE);
+ RECT rect = {dirty_rect.x1, dirty_rect.y1, dirty_rect.x2, dirty_rect.y2 };
+ RedrawWindow(m_hwnd, &rect, nullptr, RDW_INVALIDATE);
UpdateWindow(m_hwnd);
}
else
diff --git a/plugingui/nativewindow_win32.h b/plugingui/nativewindow_win32.h
index 69324e3..630d853 100644
--- a/plugingui/nativewindow_win32.h
+++ b/plugingui/nativewindow_win32.h
@@ -52,7 +52,7 @@ public:
void show() override;
void setCaption(const std::string &caption) override;
void hide() override;
- void redraw() override;
+ void redraw(const Rect& dirty_rect) override;
void grabMouse(bool grab) override;
EventQueue getEvents() override;
diff --git a/plugingui/nativewindow_x11.cc b/plugingui/nativewindow_x11.cc
index 80c0e81..1482d47 100644
--- a/plugingui/nativewindow_x11.cc
+++ b/plugingui/nativewindow_x11.cc
@@ -223,18 +223,23 @@ void NativeWindowX11::hide()
XUnmapWindow(display, xwindow);
}
-void NativeWindowX11::redraw()
+void NativeWindowX11::redraw(const Rect& dirty_rect)
{
if(display == nullptr)
{
return;
}
- updateImageFromBuffer();
- XShmPutImage(display, xwindow, gc, image, 0, 0, 0, 0,
- std::min(image->width, (int)window.width()),
- std::min(image->height, (int)window.height()), false);
+ auto x1 = dirty_rect.x1;
+ auto y1 = dirty_rect.y1;
+ auto x2 = dirty_rect.x2;
+ auto y2 = dirty_rect.y2;
+ updateImageFromBuffer(x1, y1, x2, y2);
+
+ XShmPutImage(display, xwindow, gc, image, x1, y1, x1, y1,
+ std::min((std::size_t)image->width, (x2 - x1)),
+ std::min((std::size_t)image->height, (y2 - y1)), false);
XFlush(display);
}
@@ -510,7 +515,8 @@ void NativeWindowX11::deallocateShmImage()
shmdt(shm_info.shmaddr);
}
-void NativeWindowX11::updateImageFromBuffer()
+void NativeWindowX11::updateImageFromBuffer(std::size_t x1, std::size_t y1,
+ std::size_t x2, std::size_t y2)
{
//DEBUG(x11, "depth: %d", depth);
@@ -527,50 +533,47 @@ void NativeWindowX11::updateImageFromBuffer()
std::size_t new_width = ((width / step_size) + 1) * step_size;
std::size_t new_height = ((height / step_size) + 1) * step_size;
allocateShmImage(new_width, new_height);
+ x1 = 0;
+ y1 = 0;
+ x2 = width;
+ y2 = height;
}
auto stride = image->width;
std::uint8_t* pixel_buffer = (std::uint8_t*)window.wpixbuf.buf;
-
if(depth >= 24) // RGB 888 format
{
std::uint32_t* shm_addr = (std::uint32_t*)shm_info.shmaddr;
- std::size_t x_stride = 0;
- std::size_t x_pos = 0;
- for(std::size_t y = 0; y < height; ++y)
+ for(std::size_t y = y1; y < y2; ++y)
{
- for(std::size_t x = 0; x < width; ++x)
+ for(std::size_t x = x1; x < x2; ++x)
{
- const std::uint8_t red = pixel_buffer[x_pos * 3];
- const std::uint8_t green = pixel_buffer[x_pos * 3 + 1];
- const std::uint8_t blue = pixel_buffer[x_pos * 3 + 2];
- shm_addr[x_stride] = (red << 16) | (green << 8) | blue;
- ++x_pos;
- ++x_stride;
+ const std::size_t pin = y * width + x;
+ const std::size_t pout = y * stride + x;
+ const std::uint8_t red = pixel_buffer[pin * 3];
+ const std::uint8_t green = pixel_buffer[pin * 3 + 1];
+ const std::uint8_t blue = pixel_buffer[pin * 3 + 2];
+ shm_addr[pout] = (red << 16) | (green << 8) | blue;
}
- x_stride += (stride - width);
}
}
else if(depth >= 15) // RGB 565 format
{
std::uint16_t* shm_addr = (std::uint16_t*)shm_info.shmaddr;
- std::size_t x_stride = 0;
- std::size_t x_pos = 0;
- for(std::size_t y = 0; y < height; ++y)
+ for(std::size_t y = y1; y < y2; ++y)
{
- for(std::size_t x = 0; x < width; ++x)
+ for(std::size_t x = x1; x < x2; ++x)
{
- const std::uint8_t red = pixel_buffer[x_pos * 3];
- const std::uint8_t green = pixel_buffer[x_pos * 3 + 1];
- const std::uint8_t blue = pixel_buffer[x_pos * 3 + 2];
- shm_addr[x_stride] = (red << 11) | (green << 5) | blue;
- ++x_pos;
- ++x_stride;
+ const std::size_t pin = y * width + x;
+ const std::size_t pout = y * stride + x;
+ const std::uint8_t red = pixel_buffer[pin * 3];
+ const std::uint8_t green = pixel_buffer[pin * 3 + 1];
+ const std::uint8_t blue = pixel_buffer[pin * 3 + 2];
+ shm_addr[pout] = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
}
- x_stride += (stride - width);
}
}
}
diff --git a/plugingui/nativewindow_x11.h b/plugingui/nativewindow_x11.h
index f98f151..1604734 100644
--- a/plugingui/nativewindow_x11.h
+++ b/plugingui/nativewindow_x11.h
@@ -54,7 +54,7 @@ public:
void show() override;
void hide() override;
void setCaption(const std::string &caption) override;
- void redraw() override;
+ void redraw(const Rect& dirty_rect) override;
void grabMouse(bool grab) override;
EventQueue getEvents() override;
@@ -69,7 +69,8 @@ private:
void deallocateShmImage();
//! Copy data from the pixel buffer into the shared memory
- void updateImageFromBuffer();
+ void updateImageFromBuffer(std::size_t x1, std::size_t y1,
+ std::size_t x2, std::size_t y2);
XShmSegmentInfo shm_info;
XImage* image{nullptr};
diff --git a/plugingui/widget.cc b/plugingui/widget.cc
index 239c233..7d92a22 100644
--- a/plugingui/widget.cc
+++ b/plugingui/widget.cc
@@ -212,6 +212,7 @@ std::vector<PixelBufferAlpha*> Widget::getPixelBuffers()
if(dirty)
{
repaintEvent(nullptr);
+ pixbuf.dirty = true;
dirty = false;
}
diff --git a/plugingui/window.cc b/plugingui/window.cc
index 44c8e12..e2a5b58 100644
--- a/plugingui/window.cc
+++ b/plugingui/window.cc
@@ -26,6 +26,8 @@
*/
#include "window.h"
+#include <cstring>
+
#include "painter.h"
#ifndef PUGL
@@ -224,39 +226,88 @@ bool Window::updateBuffer()
return false;
}
- for(const auto& pixelBuffer : getPixelBuffers())
+ bool has_dirty_rect{false};
+ Rect dirty_rect;
+
+ auto pixel_buffers = getPixelBuffers();
+ for(auto& pixel_buffer : pixel_buffers)
{
- size_t updateWidth = pixelBuffer->width;
- size_t updateHeight = pixelBuffer->height;
+ if(pixel_buffer->dirty)
+ {
+ auto x1 = (std::size_t)pixel_buffer->x;
+ auto x2 = (std::size_t)(pixel_buffer->x + pixel_buffer->width);
+ auto y1 = (std::size_t)pixel_buffer->y;
+ auto y2 = (std::size_t)(pixel_buffer->y + pixel_buffer->height);
+
+ pixel_buffer->dirty = false;
+ if(!has_dirty_rect)
+ {
+ // Insert this area:
+ dirty_rect = {x1, y1, x2, y2};
+ has_dirty_rect = true;
+ }
+ else
+ {
+ // Expand existing area:
+ auto x1_0 = dirty_rect.x1;
+ auto y1_0 = dirty_rect.y1;
+ auto x2_0 = dirty_rect.x2;
+ auto y2_0 = dirty_rect.y2;
+ dirty_rect = {
+ (x1_0 < x1) ? x1_0 : x1,
+ (y1_0 < y1) ? y1_0 : y1,
+ (x2_0 > x2) ? x2_0 : x2,
+ (y2_0 > y2) ? y2_0 : y2
+ };
+ }
+ }
+ }
+
+ for(auto& pixel_buffer : pixel_buffers)
+ {
+ int update_width = pixel_buffer->width;
+ int update_height = pixel_buffer->height;
// Skip buffer if not inside window.
- if((wpixbuf.width < pixelBuffer->x) || (wpixbuf.height < pixelBuffer->y))
+ if(((int)wpixbuf.width < pixel_buffer->x) ||
+ ((int)wpixbuf.height < pixel_buffer->y))
{
continue;
}
- if(updateWidth > (wpixbuf.width - pixelBuffer->x))
+ if(update_width > ((int)wpixbuf.width - pixel_buffer->x))
{
- updateWidth = (wpixbuf.width - pixelBuffer->x);
+ update_width = ((int)wpixbuf.width - pixel_buffer->x);
}
- if(updateHeight > (wpixbuf.height - pixelBuffer->y))
+ if(update_height > ((int)wpixbuf.height - pixel_buffer->y))
{
- updateHeight = (wpixbuf.height - pixelBuffer->y);
+ update_height = ((int)wpixbuf.height - pixel_buffer->y);
}
- unsigned char r,g,b,a;
- for(size_t y = 0; y < updateHeight; y++)
+ std::uint8_t r, g, b, a;
+
+ auto from_x = (int)dirty_rect.x1 - pixel_buffer->x;
+ from_x = std::max(0, from_x);
+ auto from_y = (int)dirty_rect.y1 - pixel_buffer->y;
+ from_y = std::max(0, from_y);
+
+ auto to_x = (int)dirty_rect.x2 - pixel_buffer->x;
+ to_x = std::min(to_x, (int)update_width);
+ auto to_y = (int)dirty_rect.y2 - pixel_buffer->y;
+ to_y = std::min(to_y, (int)update_height);
+
+ for(int y = from_y; y < to_y; y++)
{
- for(size_t x = 0; x < updateWidth; x++)
+ for(int x = from_x; x < to_x; x++)
{
- pixelBuffer->pixel(x, y, &r, &g, &b, &a);
- wpixbuf.setPixel(x + pixelBuffer->x, y + pixelBuffer->y, r, g, b, a);
+ pixel_buffer->pixel(x, y, &r, &g, &b, &a);
+ wpixbuf.setPixel(x + pixel_buffer->x, y + pixel_buffer->y, r, g, b, a);
}
}
}
- native->redraw();
+ native->redraw(dirty_rect);
needs_redraw = false;
return true;