diff --git a/roo_e/src/gui/gui.c b/roo_e/src/gui/gui.c index 1bf55dc..d931c40 100644 --- a/roo_e/src/gui/gui.c +++ b/roo_e/src/gui/gui.c @@ -70,9 +70,11 @@ static void guiDeleteListProcess(void) { void guiEventsDo(void) { EventT event = { 0 }; +#ifndef NEW_RENDERER // Paint desktop. surfaceSet(__guiBackBuffer); surfaceClear(GUI_CYAN); +#endif // Read mouse & keyboard. platformEventGet(&event); @@ -80,6 +82,11 @@ void guiEventsDo(void) { // Handle GUI window manager and widgets. wmUpdate(&event); +#ifdef NEW_RENDERER + // Draw. + wmRender(); +#endif + // Paint mouse pointer. surfaceSet(__guiBackBuffer); surfaceBlitWithTransparency(event.x - _mouseHotspot[_mouseCurrent].x, event.y - _mouseHotspot[_mouseCurrent].y, _mousePointer[_mouseCurrent], _mouseTransparency); diff --git a/roo_e/src/gui/wmwindow.c b/roo_e/src/gui/wmwindow.c index 82fe6cb..45fa1eb 100644 --- a/roo_e/src/gui/wmwindow.c +++ b/roo_e/src/gui/wmwindow.c @@ -29,15 +29,15 @@ typedef struct DamageListS { - RectT rect; - SurfaceT *surface; + RectT rect; + WindowT *window; } DamageListT; uint8_t __MAGIC_WINDOW = 0; -static WindowT **_windowList = NULL; +static WindowT **_windowList = NULL; // Windows are stored bottom-to-top order. static WindowT *_windowTop = NULL; static int16_t _iconCount = 0; @@ -525,6 +525,9 @@ static void windowPaint(struct WidgetS *widget, ...) { mode = va_arg(args, int); va_end(args); + // ***TODO*** Icon needs to be cached in a surface so we can calculate + // damaged areas for rendering. + if (mode == WINDOW_PAINT_ICONS) { // Are we minimized? if (w->flags & WIN_IS_ICON) { @@ -556,7 +559,9 @@ static void windowPaint(struct WidgetS *widget, ...) { // Did a widget or the window chrome need redrawn? 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 } } } @@ -656,6 +661,283 @@ static WidgetT *windowWidgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int1 } +void wmRender(void) { + int16_t i; + int16_t j; + int16_t k; + int16_t x2; + int16_t y2; + WindowT *win = NULL; + WindowT *win2 = NULL; + RectT *rect; + RectT **rects = NULL; + DamageListT **damageList = NULL; + DamageListT *damageItem = NULL; + uint8_t found; + + // ***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 + // we just draw the desktop and then window contents. + + // Draw the desktop. + surfaceSet(__guiBackBuffer); + surfaceClear(GUI_CYAN); + + // Do we have windows? + if (arrlen(_windowList) > 0) { + + // Calculate visible rectangle list. + // + // Start with the top window and divide it into smaller rectangles + // using the edges of every other window. Add these to the "damage + // list". + // + // Then iterate through the remaining windows from top to bottom + // dividing them with the edges of every other window. When finished + // with each window, compare the list of new rectangles to the existing + // damage list. Add any rectangles that are not already there. + // + // Finally do the same as the remaining windows with the entire screen. + + // Iterate over all windows, top to bottom. + for (i=arrlen(_windowList)-1; i>=-1; i--) { + + // New rectangle. + NEW(RectT, rect); + + // Are we comparing the desktop? + if (i == -1) { + // 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. + if (rect->x < 0) rect->x = 0; + if (rect->y < 0) rect->y = 0; + 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. + arrput(rects, rect); + + // 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; kbase.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; kx == 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); + + } // Window list. + + // Merge adjacent damage areas. + // For areas to be adjacent they need matching X coordinates with a + // shared Y coordinate or matching Y coordinates with a shared X as + // well as matching surfaces. For each such pair, merge them and + // search again. + do { + found = 0; + for (i=0; iwindow != damageList[j]->window) { + // No. Can't be merged. + continue; + } + + // Matching X? + if ((damageList[i]->rect.x == damageList[j]->rect.x) && (damageList[i]->rect.x2 == damageList[j]->rect.x2)) { + // Is i over j? + if (damageList[i]->rect.y2 == damageList[j]->rect.y) { + // Merge them! + damageList[i]->rect.y2 = damageList[j]->rect.y2; + DEL(damageList[j]); + arrdel(damageList, j); + found = 1; + break; + } + // Is j over i? + if (damageList[j]->rect.y2 == damageList[i]->rect.y) { + // Merge them! + damageList[j]->rect.y2 = damageList[i]->rect.y2; + DEL(damageList[i]); + arrdel(damageList, i); + found = 1; + break; + } + } + + // Matching Y? + if ((damageList[i]->rect.y == damageList[j]->rect.y) && (damageList[i]->rect.y2 == damageList[j]->rect.y2)) { + // Is i left of j? + if (damageList[i]->rect.x2 == damageList[j]->rect.x) { + // Merge them! + damageList[i]->rect.x2 = damageList[j]->rect.x2; + DEL(damageList[j]); + arrdel(damageList, j); + found = 1; + break; + } + // Is j left of i? + if (damageList[j]->rect.x2 == damageList[i]->rect.x) { + // Merge them! + damageList[j]->rect.x2 = damageList[i]->rect.x2; + DEL(damageList[i]); + arrdel(damageList, i); + found = 1; + break; + } + } + + } + if (found) break; + } + } while (found == 1); + + // Draw the damage list. + i = 1; + for (k=0; kwindow != NULL) { + surfaceBox( + damageList[k]->window->bounds.x, damageList[k]->window->bounds.y, + damageList[k]->window->bounds.x2, damageList[k]->window->bounds.y2, + GUI_RED); + } + */ + + if (damageList[k]->window != NULL) { + // 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 { + // Desktop. + //surfaceBoxFilled(damageList[k]->rect.x, damageList[k]->rect.y, damageList[k]->rect.x2, damageList[k]->rect.y2, GUI_CYAN); + } + + /* + // ***DEBUG*** + surfaceBox(damageList[k]->rect.x + 1, damageList[k]->rect.y + 1, damageList[k]->rect.x2 - 1, damageList[k]->rect.y2 - 1, i); + i++; + if (i > 15) i = 1; + if ((i == GUI_BLACK) || (i == GUI_CYAN) || (i == GUI_LIGHTGRAY)) i++; + */ + } + + // Delete damage list. + while (arrlen(damageList) > 0) { + DEL(damageList[0]); + arrdel(damageList, 0); + } + arrfree(damageList); + + } // Do we have windows? +} + + void wmShutdown(void) { uint16_t i; @@ -672,8 +954,6 @@ void wmStartup(void) { void wmUpdate(EventT *event) { int16_t i; - int16_t j; - int16_t k; PointT widgetLocal; int16_t x2; int16_t y2; @@ -681,12 +961,6 @@ void wmUpdate(EventT *event) { WidgetT *widget; WidgetT *widgetOver = NULL; WindowT *win = NULL; - WindowT *win2 = NULL; - RectT *rect; - RectT **rects = NULL; - DamageListT **damageList = NULL; - DamageListT *damageItem = NULL; - uint8_t found; ClickRawInputT rawEvent = { 0 }; static uint8_t resizing = 0; static PointT resizeOffset = { 0 }; @@ -929,159 +1203,6 @@ void wmUpdate(EventT *event) { break; } // Left button processing. - - // Calculate visible rectangle list. - // - // Start with the top window and divide it into smaller rectangles - // using the edges of every other window. Add these to the "damage - // list". - // - // Then iterate through the remaining windows from top to bottom - // dividing them with the edges of every other window. When finished - // with each window, compare the list of new rectangles to the existing - // damage list. Add any rectangles that are not already there. - // - // Finally do the same as the remaining windows with the entire screen. - - // Iterate over all windows, top to bottom. - for (i=0; i<=arrlen(_windowList); i++) { - - // New rectangle. - NEW(RectT, rect); - - // Are we comparing the desktop? - if (i == arrlen(_windowList)) { - // 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 - 1; - rect->y2 = win->base.r.y + win->base.r.h - 1; - } - - // Add this window to the rectangle list. - arrput(rects, rect); - - // Iterate over all the other windows. - for (j=0; jbase.r.x + win2->base.r.w - 1; - y2 = win2->base.r.y + win2->base.r.h - 1; - - // 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; kbase.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); - } - } - - } - } - - // Add rectangles to the damage list. Clear rectangle list. - while (arrlen(rects) > 0) { - found = 0; - // Is this the top window? - if (i != 0) { - // No. Compare rectangles to existing damage list. - for (k=0; kx == 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); - //memcpy(&damageItem->rect, &rects[0], sizeof(RectT)); - damageItem->rect.x = rects[0]->x; - damageItem->rect.y = rects[0]->y; - damageItem->rect.x2 = rects[0]->x2; - damageItem->rect.y2 = rects[0]->y2; - if (win != NULL) { - damageItem->surface = win->cached; - } else { - damageItem->surface = NULL; - } - arrput(damageList, damageItem); - } - - // Delete this rect. - DEL(rects[0]); - arrdel(rects, 0); - } - arrfree(rects); - - //***DEBUG*** Draw the damage list. - surfaceSet(__guiBackBuffer); - for (k=0; krect.x, damageList[k]->rect.y, damageList[k]->rect.x2, damageList[k]->rect.y2, GUI_RED); - } - - // Delete damage list. - while (arrlen(damageList) > 0) { - DEL(damageList[0]); - arrdel(damageList, 0); - } - arrfree(damageList); - } - } // Do we have windows? } diff --git a/roo_e/src/gui/wmwindow.h b/roo_e/src/gui/wmwindow.h index 3fddcb1..a1794f4 100644 --- a/roo_e/src/gui/wmwindow.h +++ b/roo_e/src/gui/wmwindow.h @@ -64,7 +64,7 @@ typedef struct WindowS { ScrollableT *scroll; // Window contents and scroll bars. RectWT restore; // Size of window if they restore from maximized. PointT restoreOffset; // Scroll position if they restore from maximized. - RectT bounds; // Inside edge of window frame. + 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. } WindowT; @@ -81,6 +81,7 @@ RegisterT *windowRegister(uint8_t magic); void windowResize(WindowT *win, uint16_t width, uint16_t height); +void wmRender(void); void wmShutdown(void); void wmStartup(void); void wmUpdate(EventT *event); diff --git a/roo_e/src/os.h b/roo_e/src/os.h index 5ce4428..d2d15a7 100644 --- a/roo_e/src/os.h +++ b/roo_e/src/os.h @@ -29,6 +29,8 @@ #define MEMORY_CHECK_ENABLED +#define NEW_RENDERER + #include #include