Icons working with damage renderer!

This commit is contained in:
Scott Duensing 2024-04-14 19:25:32 -05:00
parent ac60a82c65
commit 272978b9ad
4 changed files with 183 additions and 162 deletions

View file

@ -70,22 +70,14 @@ static void guiDeleteListProcess(void) {
void guiEventsDo(void) { void guiEventsDo(void) {
EventT event = { 0 }; EventT event = { 0 };
#ifndef NEW_RENDERER
// Paint desktop.
surfaceSet(__guiBackBuffer);
surfaceClear(GUI_CYAN);
#endif
// Read mouse & keyboard. // Read mouse & keyboard.
platformEventGet(&event); platformEventGet(&event);
// Handle GUI window manager and widgets. // Handle GUI window manager and widgets.
wmUpdate(&event); wmUpdate(&event);
#ifdef NEW_RENDERER
// Draw. // Draw.
wmRender(); wmRender();
#endif
// Paint mouse pointer. // Paint mouse pointer.
surfaceSet(__guiBackBuffer); surfaceSet(__guiBackBuffer);

View file

@ -257,6 +257,9 @@ WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *titl
visibleSize.x = win->bounds.x2 - win->bounds.x + 1; visibleSize.x = win->bounds.x2 - win->bounds.x + 1;
visibleSize.y = win->bounds.y2 - win->bounds.y + 1; visibleSize.y = win->bounds.y2 - win->bounds.y + 1;
// Create icon surface.
win->icon = surfaceCreate(ICON_SIZE, ICON_SIZE);
// If the window is resizable, we need to get two more arguments for the content size. // If the window is resizable, we need to get two more arguments for the content size.
if (win->flags & WIN_RESIZE) { if (win->flags & WIN_RESIZE) {
va_start(args, flags); va_start(args, flags);
@ -313,6 +316,8 @@ static void windowDestroy(struct WidgetS *widget, ...) {
arrfree(window->base.children); arrfree(window->base.children);
// Free cached surface. // Free cached surface.
if (window->cached) surfaceDestroy(&window->cached); if (window->cached) surfaceDestroy(&window->cached);
// Free icon surface.
surfaceDestroy(&window->icon);
// Delete the window. // Delete the window.
DEL(window); DEL(window);
// Fixup focus. // Fixup focus.
@ -531,22 +536,20 @@ static void windowPaint(struct WidgetS *widget, ...) {
if (mode == WINDOW_PAINT_ICONS) { if (mode == WINDOW_PAINT_ICONS) {
// Are we minimized? // Are we minimized?
if (w->flags & WIN_IS_ICON) { if (w->flags & WIN_IS_ICON) {
// Draw iconized version of contents. There are too many counters here but it's the only way it worked reliably. // Render icon into window's icon surface.
yi = (surfaceHeightGet(w->scroll->area) - 1) / ICON_SIZE; surfaceSet(w->icon);
xi = (surfaceWidthGet(w->scroll->area) - 1) / ICON_SIZE; yi = (surfaceHeightGet(w->scroll->area) - 1) / ICON_SIZE; // Y Sample increment.
py = videoDisplayHeightGet() - ICON_SIZE; xi = (surfaceWidthGet(w->scroll->area) - 1) / ICON_SIZE; // X Sample increment.
y = 0; y = 0;
x = 0; x = 0;
for (yc=0; yc<ICON_SIZE; yc++) { for (yc=0; yc<ICON_SIZE; yc++) {
y += yi; y += yi;
px = (ICON_SIZE + 1) * _iconCount;
for (xc=0; xc<ICON_SIZE; xc++) { for (xc=0; xc<ICON_SIZE; xc++) {
x += xi; x += xi;
surfacePixelSet(px++, py, surfacePixelGet(w->scroll->area, x, y)); surfacePixelSet(xc, yc, surfacePixelGet(w->scroll->area, x, y));
} }
py++;
} }
_iconCount++; surfaceBox(0, 0, ICON_SIZE - 1, ICON_SIZE - 1, GUI_BLACK);
} }
} else { // WINDOW_PAINT_ICONS } else { // WINDOW_PAINT_ICONS
// Are we not minimized? // Are we not minimized?
@ -558,10 +561,6 @@ static void windowPaint(struct WidgetS *widget, ...) {
} }
// Did a widget or the window chrome need redrawn? // Did a widget or the window chrome need redrawn?
if (x || widgetChildrenDirty(widget)) windowCache(w, x); if (x || widgetChildrenDirty(widget)) windowCache(w, x);
// By now we have a valid cached window. Blit it.
#ifndef NEW_RENDERER
surfaceBlit(w->base.r.x, w->base.r.y, 0, 0, w->base.r.w, w->base.r.h, w->cached);
#endif
} }
} }
} }
@ -662,23 +661,41 @@ static WidgetT *windowWidgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int1
void wmRender(void) { void wmRender(void) {
uint8_t found;
uint8_t pass;
int16_t i; int16_t i;
int16_t j; int16_t j;
int16_t k; int16_t k;
int16_t x2; int16_t x2;
int16_t y2; int16_t y2;
WidgetT *widget = NULL;
WindowT *win = NULL; WindowT *win = NULL;
WindowT *win2 = NULL; WindowT *win2 = NULL;
RectT *rect; RectT *rect = NULL;
RectT **rects = NULL; RectT **rects = NULL;
DamageListT **damageList = NULL; DamageListT **damageList = NULL;
DamageListT *damageItem = NULL; DamageListT *damageItem = NULL;
uint8_t found;
// ***TODO*** We still calculate the desktop in the damage list below. // ***TODO*** We still calculate the desktop in the damage list below.
// There's some odd off-by-one when rendering that needs fixed. For now // There's some odd off-by-one when rendering that needs fixed. For now
// we just draw the desktop and then window contents. // we just draw the desktop and then window contents.
// Update all minimized windows.
surfaceSet(__guiBackBuffer);
for (i=0; i<arrlen(_windowList); i++) {
widget = (WidgetT *)_windowList[i];
widget->reg->paint(widget, WINDOW_PAINT_ICONS);
}
// Update all windows.
for (i=0; i<arrlen(_windowList); i++) {
widget = (WidgetT *)_windowList[i];
widget->reg->paint(widget, WINDOW_PAINT_NORMAL);
}
// This is global so we can click on them later.
_iconCount = 0;
// Draw the desktop. // Draw the desktop.
surfaceSet(__guiBackBuffer); surfaceSet(__guiBackBuffer);
surfaceClear(GUI_CYAN); surfaceClear(GUI_CYAN);
@ -699,133 +716,152 @@ void wmRender(void) {
// //
// Finally do the same as the remaining windows with the entire screen. // Finally do the same as the remaining windows with the entire screen.
// Iterate over all windows, top to bottom. // Make two passes over the window list. First for regular windows,
for (i=arrlen(_windowList)-1; i>=-1; i--) { // second for iconized windows.
for (pass=0; pass<2; pass++) {
// New rectangle. // Iterate over all windows, top to bottom.
NEW(RectT, rect); for (i=arrlen(_windowList)-1; i>=0-pass; i--) {
// Are we comparing the desktop? // Is this the desktop?
if (i == -1) { win = (i == -1) ? NULL : (WindowT *)_windowList[i];
// Yes. Fake a window.
win = NULL;
rect->x = 0;
rect->y = 0;
rect->x2 = videoDisplayWidthGet() - 1;
rect->y2 = videoDisplayHeightGet() - 1;
} else {
// Get this window.
win = (WindowT *)_windowList[i];
rect->x = win->base.r.x;
rect->y = win->base.r.y;
rect->x2 = win->base.r.x + win->base.r.w;
rect->y2 = win->base.r.y + win->base.r.h;
}
// Clip to screen bounds. // Skip windows depending on pass and window state.
if (rect->x < 0) rect->x = 0; if ((pass == 0) && (win->flags & WIN_IS_ICON)) continue;
if (rect->y < 0) rect->y = 0; if ((pass == 1) && (win != NULL) && !(win->flags & WIN_IS_ICON)) continue;
if (rect->x2 > videoDisplayWidthGet() - 1) rect->x2 = videoDisplayWidthGet() - 1;
if (rect->y2 > videoDisplayHeightGet() - 1) rect->y2 = videoDisplayHeightGet() - 1;
// Add this window to the rectangle list. // New rectangle.
arrput(rects, rect); NEW(RectT, rect);
// Iterate over all the other windows to slice this window. // Are we comparing the desktop?
for (j=arrlen(_windowList)-1; j>=0; j--) { if (win == NULL) {
win2 = (WindowT *)_windowList[j]; // Yes. Fake a window.
if (win != win2) { rect->x = 0;
rect->y = 0;
// Get win2 extents. rect->x2 = videoDisplayWidthGet() - 1;
x2 = win2->base.r.x + win2->base.r.w; rect->y2 = videoDisplayHeightGet() - 1;
y2 = win2->base.r.y + win2->base.r.h; } else {
// Get this window.
// Check the edges of this window against all the if (win->flags & WIN_IS_ICON) {
// rectangles in the current rectangle list. Split rect->x = _iconCount * (ICON_SIZE + 1);
// and create new rectangles on any lines that intersect. rect->y = videoDisplayHeightGet() - ICON_SIZE;
for (k=0; k<arrlen(rects); k++) { rect->x2 = rect->x + ICON_SIZE;
// Compare Window Top rect->y2 = rect->y + ICON_SIZE;
if ((win2->base.r.y > rects[k]->y) && (win2->base.r.y < rects[k]->y2)) { _iconCount++;
NEW(RectT, rect); } else {
rect->x = rects[k]->x; rect->x = win->base.r.x;
rect->x2 = rects[k]->x2; rect->y = win->base.r.y;
rect->y2 = rects[k]->y2; rect->x2 = win->base.r.x + win->base.r.w;
rects[k]->y2 = win2->base.r.y; rect->y2 = win->base.r.y + win->base.r.h;
rect->y = win2->base.r.y;
arrput(rects, rect);
}
// Compare Window Bottom
if ((y2 > rects[k]->y) && (y2 < rects[k]->y2)) {
NEW(RectT, rect);
rect->x = rects[k]->x;
rect->x2 = rects[k]->x2;
rect->y2 = rects[k]->y2;
rects[k]->y2 = y2;
rect->y = y2;
arrput(rects, rect);
}
// Compare Window Left
if ((win2->base.r.x > rects[k]->x) && (win2->base.r.x < rects[k]->x2)) {
NEW(RectT, rect);
rect->y = rects[k]->y;
rect->x2 = rects[k]->x2;
rect->y2 = rects[k]->y2;
rects[k]->x2 = win2->base.r.x;
rect->x = win2->base.r.x;
arrput(rects, rect);
}
// Compare Window Right
if ((x2 > rects[k]->x) && (x2 < rects[k]->x2)) {
NEW(RectT, rect);
rect->y = rects[k]->y;
rect->x2 = rects[k]->x2;
rect->y2 = rects[k]->y2;
rects[k]->x2 = x2;
rect->x = x2;
arrput(rects, rect);
}
}
}
} // Other windows.
// Add rectangles to the damage list. Clear rectangle list.
while (arrlen(rects) > 0) {
found = 0;
// Is this the top window?
if (i != arrlen(_windowList)) {
// No. Compare rectangles to existing damage list.
for (k=0; k<arrlen(damageList); k++) {
if ((rects[0]->x == damageList[k]->rect.x ) &&
(rects[0]->y == damageList[k]->rect.y ) &&
(rects[0]->x2 == damageList[k]->rect.x2) &&
(rects[0]->y2 == damageList[k]->rect.y2)) {
// We already have this. Skip it.
found = 1;
break;
}
} }
} }
// Do we have this section of the screen yet? // Clip to screen bounds.
if (!found) { if (rect->x < 0) rect->x = 0;
// Nope! Add it. if (rect->y < 0) rect->y = 0;
NEW(DamageListT, damageItem); if (rect->x2 > videoDisplayWidthGet() - 1) rect->x2 = videoDisplayWidthGet() - 1;
damageItem->rect.x = rects[0]->x; if (rect->y2 > videoDisplayHeightGet() - 1) rect->y2 = videoDisplayHeightGet() - 1;
damageItem->rect.y = rects[0]->y;
damageItem->rect.x2 = rects[0]->x2; // Add this window to the rectangle list.
damageItem->rect.y2 = rects[0]->y2; arrput(rects, rect);
damageItem->window = win;
arrput(damageList, damageItem); // Iterate over all the other windows to slice this window.
for (j=arrlen(_windowList)-1; j>=0; j--) {
win2 = (WindowT *)_windowList[j];
if (win != win2) {
// Get win2 extents.
x2 = win2->base.r.x + win2->base.r.w;
y2 = win2->base.r.y + win2->base.r.h;
// Check the edges of this window against all the
// rectangles in the current rectangle list. Split
// and create new rectangles on any lines that intersect.
for (k=0; k<arrlen(rects); k++) {
// Compare Window Top
if ((win2->base.r.y > rects[k]->y) && (win2->base.r.y < rects[k]->y2)) {
NEW(RectT, rect);
rect->x = rects[k]->x;
rect->x2 = rects[k]->x2;
rect->y2 = rects[k]->y2;
rects[k]->y2 = win2->base.r.y;
rect->y = win2->base.r.y;
arrput(rects, rect);
}
// Compare Window Bottom
if ((y2 > rects[k]->y) && (y2 < rects[k]->y2)) {
NEW(RectT, rect);
rect->x = rects[k]->x;
rect->x2 = rects[k]->x2;
rect->y2 = rects[k]->y2;
rects[k]->y2 = y2;
rect->y = y2;
arrput(rects, rect);
}
// Compare Window Left
if ((win2->base.r.x > rects[k]->x) && (win2->base.r.x < rects[k]->x2)) {
NEW(RectT, rect);
rect->y = rects[k]->y;
rect->x2 = rects[k]->x2;
rect->y2 = rects[k]->y2;
rects[k]->x2 = win2->base.r.x;
rect->x = win2->base.r.x;
arrput(rects, rect);
}
// Compare Window Right
if ((x2 > rects[k]->x) && (x2 < rects[k]->x2)) {
NEW(RectT, rect);
rect->y = rects[k]->y;
rect->x2 = rects[k]->x2;
rect->y2 = rects[k]->y2;
rects[k]->x2 = x2;
rect->x = x2;
arrput(rects, rect);
}
}
}
} // Other windows.
// Add rectangles to the damage list. Clear rectangle list.
while (arrlen(rects) > 0) {
found = 0;
// Is this the top window?
if (i != arrlen(_windowList)) {
// No. Compare rectangles to existing damage list.
for (k=0; k<arrlen(damageList); k++) {
if ((rects[0]->x == damageList[k]->rect.x ) &&
(rects[0]->y == damageList[k]->rect.y ) &&
(rects[0]->x2 == damageList[k]->rect.x2) &&
(rects[0]->y2 == damageList[k]->rect.y2)) {
// We already have this. Skip it.
found = 1;
break;
}
}
}
// Do we have this section of the screen yet?
if (!found) {
// Nope! Add it.
NEW(DamageListT, damageItem);
damageItem->rect.x = rects[0]->x;
damageItem->rect.y = rects[0]->y;
damageItem->rect.x2 = rects[0]->x2;
damageItem->rect.y2 = rects[0]->y2;
damageItem->window = win;
arrput(damageList, damageItem);
}
// Delete this rect.
DEL(rects[0]);
arrdel(rects, 0);
} }
arrfree(rects);
// Delete this rect. } // Window list.
DEL(rects[0]);
arrdel(rects, 0);
}
arrfree(rects);
} // Window list. } // Pass.
// Merge adjacent damage areas. // Merge adjacent damage areas.
// For areas to be adjacent they need matching X coordinates with a // For areas to be adjacent they need matching X coordinates with a
@ -906,13 +942,22 @@ void wmRender(void) {
*/ */
if (damageList[k]->window != NULL) { if (damageList[k]->window != NULL) {
// Window content. // Icon or Window?
surfaceBlit( if (damageList[k]->window->flags & WIN_IS_ICON) {
damageList[k]->rect.x, damageList[k]->rect.y, // Icon.
damageList[k]->rect.x - damageList[k]->window->base.r.x, damageList[k]->rect.y - damageList[k]->window->base.r.y, surfaceBlit(
damageList[k]->rect.x2 - damageList[k]->rect.x, damageList[k]->rect.x, damageList[k]->rect.y,
damageList[k]->rect.y2 - damageList[k]->rect.y, 0, 0,
damageList[k]->window->cached); ICON_SIZE, ICON_SIZE,
damageList[k]->window->icon);
} else {
// Window content.
surfaceBlit(
damageList[k]->rect.x, damageList[k]->rect.y,
damageList[k]->rect.x - damageList[k]->window->base.r.x, damageList[k]->rect.y - damageList[k]->window->base.r.y,
damageList[k]->rect.x2 - damageList[k]->rect.x, damageList[k]->rect.y2 - damageList[k]->rect.y,
damageList[k]->window->cached);
}
} else { } else {
// Desktop. // Desktop.
//surfaceBoxFilled(damageList[k]->rect.x, damageList[k]->rect.y, damageList[k]->rect.x2, damageList[k]->rect.y2, GUI_CYAN); //surfaceBoxFilled(damageList[k]->rect.x, damageList[k]->rect.y, damageList[k]->rect.x2, damageList[k]->rect.y2, GUI_CYAN);
@ -974,21 +1019,6 @@ void wmUpdate(EventT *event) {
// Mouse is always the default pointer unless something changes it for this frame. // Mouse is always the default pointer unless something changes it for this frame.
guiMousePointerSet(MOUSE_POINTER); guiMousePointerSet(MOUSE_POINTER);
// Paint all minimized windows.
surfaceSet(__guiBackBuffer);
_iconCount = 0;
for (i=0; i<arrlen(_windowList); i++) {
widget = (WidgetT *)_windowList[i];
widget->reg->paint(widget, WINDOW_PAINT_ICONS);
}
// Paint all windows.
for (i=0; i<arrlen(_windowList); i++) {
surfaceSet(__guiBackBuffer);
widget = (WidgetT *)_windowList[i];
widget->reg->paint(widget, WINDOW_PAINT_NORMAL);
}
// Get top window. // Get top window.
win = _windowTop; win = _windowTop;

View file

@ -66,6 +66,7 @@ typedef struct WindowS {
PointT restoreOffset; // Scroll position if they restore from maximized. PointT restoreOffset; // Scroll position if they restore from maximized.
RectT bounds; // Window contents in screen space. Does not include titlebar or window chrome. RectT bounds; // Window contents in screen space. Does not include titlebar or window chrome.
SurfaceT *cached; // Once rendered, keep a cached copy for faster redrawing. SurfaceT *cached; // Once rendered, keep a cached copy for faster redrawing.
SurfaceT *icon; // Needed for damaged region drawing.
} WindowT; } WindowT;

View file

@ -29,8 +29,6 @@
#define MEMORY_CHECK_ENABLED #define MEMORY_CHECK_ENABLED
#define NEW_RENDERER
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>