From e1b1c895b25a71fe26ab5afef9cb465b470bfb99 Mon Sep 17 00:00:00 2001 From: Tomaz Stih Date: Sun, 23 Aug 2015 10:37:19 +0100 Subject: [PATCH] Optimized drawing. --- buddy/Makefile | 2 +- buddy/buddy.c | 86 ++++++++++++++++++++++++++++++++++++++++--- buddy/graphics/rect.c | 24 +++++++----- buddy/include/rect.h | 2 +- buddy/stdwnd.c | 77 ++++++++++++++++++++++++++++++++++---- buddy/temp.depo | 39 ++++++++++++++++++++ buddy/window.c | 35 +++++++++++------- buddy/window.h | 2 + 8 files changed, 228 insertions(+), 39 deletions(-) diff --git a/buddy/Makefile b/buddy/Makefile index 134e506..e24feac 100644 --- a/buddy/Makefile +++ b/buddy/Makefile @@ -9,7 +9,7 @@ ASFLAGS = -xlos -g LD = sdcc LDFLAGS = -mz80 --no-std-crt0 \ --nostdlib --code-loc 0x8032 \ - --data-loc 0xb000 -Wl -b_HEADER=0x8000 + --data-loc 0xc000 -Wl -b_HEADER=0x8000 # Deps. CSRCS = $(wildcard *.c) SSRCS = $(wildcard *.s) diff --git a/buddy/buddy.c b/buddy/buddy.c index 8374f02..da0475c 100644 --- a/buddy/buddy.c +++ b/buddy/buddy.c @@ -37,6 +37,7 @@ void temp_shit() { 35, 213, 160); + w3=window_create( "Window 3", window_desktop, @@ -46,6 +47,7 @@ void temp_shit() { 80, 60, 132); + w4=window_create( "Window 4", window_desktop, @@ -91,7 +93,6 @@ void temp_shit() { 150, 250, 180); - } void buddy_init() { @@ -124,7 +125,7 @@ void buddy_harvest_events() { if (mouse_rect.x0!=mi.x || mouse_rect.y0!=mi.y) { /* coord changed */ /* operation in progress? */ - if (buddy_op.op==BUDDY_OP_MOVING) + if (buddy_op.op==BUDDY_OP_MOVING || buddy_op.op==BUDDY_OP_SIZING) buddy_xor_op_rect(); /* del old rect */ /* first repaint mouse */ @@ -156,6 +157,10 @@ void buddy_dispatch(byte id, word param1, word param2) { boolean lr,ud; byte dx,dy; byte hit=WND_HIT_NONE; + rect_t affectedrect; + rect_t client; + byte num; + rect_t smaller[4]; switch (id) { @@ -175,7 +180,7 @@ void buddy_dispatch(byte id, word param1, word param2) { } /* hit test window for system areas? */ - message_send(affectedwnd,MSG_WND_HITTEST,(word)&hit,0); + message_send(affectedwnd,MSG_WND_HITTEST,(word)&hit,(word)param1<<8|(word)param2); /* store mouse to current operation (whatever) */ buddy_op.mx=(byte)param1; @@ -196,6 +201,34 @@ void buddy_dispatch(byte id, word param1, word param2) { sizeof(rect_t) ); break; + case WND_HIT_RESIZE: /* start window resize operation */ + buddy_op.op=BUDDY_OP_SIZE; + buddy_op.wnd=appwnd; + buddy_op.ix=buddy_op.mx; + buddy_op.iy=buddy_op.my; + yx->copy( + (void*)affectedwnd->graphics->area, + (void*)&(buddy_op.rect), + sizeof(rect_t) + ); + break; + case WND_HIT_CLOSE: + /* hide mouse */ + mouse_hide_cursor(); + + /* remember the rectangle */ + yx->copy( + (void*)appwnd->graphics->area, + (void*)&(affectedrect), + sizeof(rect_t) + ); + message_send(appwnd,MSG_WND_CLOSE,0,0); + window_destroy(appwnd); + window_invalidate(&affectedrect, window_desktop, window_desktop->first_child); + + /* show mouse */ + mouse_show_cursor(mi.x, mi.y, current_cursor); + break; } } break; @@ -206,6 +239,13 @@ void buddy_dispatch(byte id, word param1, word param2) { /* clean last drag */ buddy_xor_op_rect(); + /* store affected rect */ + yx->copy( + (void*)((buddy_op.wnd)->graphics->area), + (void*)&affectedrect, + sizeof(rect_t) + ); + /* move window */ if (lr=(buddy_op.ix > (byte)param1)) dx=buddy_op.ix - (byte)param1; @@ -217,8 +257,26 @@ void buddy_dispatch(byte id, word param1, word param2) { dy=(byte)param2 - buddy_op.iy; window_move(buddy_op.wnd, dx, lr, dy, ud); - /* redraw all for now */ - window_draw(window_desktop); + /* invalidate affected rect */ + window_invalidate(&affectedrect, window_desktop, window_desktop->first_child); + + /* redraw window at new position */ + window_draw(buddy_op.wnd); + + } else if (buddy_op.op==BUDDY_OP_SIZING) { + + /* clean last drag */ + buddy_xor_op_rect(); + + /* get difference between xor rect and window rect */ + rect_intersect(&(buddy_op.rect), (buddy_op.wnd)->graphics->area, &affectedrect); + rect_subtract((buddy_op.wnd)->graphics->area, &affectedrect, smaller, &num); + + /* and invalidate "the difference" */ + while(num) { + window_invalidate(&(smaller[num-1]), window_desktop, window_desktop->first_child); + num--; + } } else { /* find affected window */ @@ -242,9 +300,24 @@ void buddy_dispatch(byte id, word param1, word param2) { if (buddy_op.op==BUDDY_OP_MOVE) /* initial move */ buddy_op.op=BUDDY_OP_MOVING; + if (buddy_op.op==BUDDY_OP_SIZE) /* initial resize */ + buddy_op.op=BUDDY_OP_SIZING; + if (buddy_op.op==BUDDY_OP_MOVING) { /* calculate new position */ - rect_delta_offset(&(buddy_op.rect), buddy_op.mx, (byte)param1, buddy_op.my, (byte)param2); + rect_delta_offset(&(buddy_op.rect), buddy_op.mx, (byte)param1, buddy_op.my, (byte)param2, FALSE); + + /* store new coords */ + buddy_op.mx=(byte)param1; + buddy_op.my=(byte)param2; + + /* and draw */ + buddy_xor_op_rect(); + } + + if (buddy_op.op==BUDDY_OP_SIZING) { + /* calculate new size */ + rect_delta_offset(&(buddy_op.rect), buddy_op.mx, (byte)param1, buddy_op.my, (byte)param2, TRUE); /* store new coords */ buddy_op.mx=(byte)param1; @@ -253,6 +326,7 @@ void buddy_dispatch(byte id, word param1, word param2) { /* and draw */ buddy_xor_op_rect(); } + break; } } diff --git a/buddy/graphics/rect.c b/buddy/graphics/rect.c index 48a2eaf..9fedd77 100644 --- a/buddy/graphics/rect.c +++ b/buddy/graphics/rect.c @@ -143,51 +143,55 @@ void rect_subtract( byte *num) { /* returns actual rects in result */ *num = 0; /* assume */ - if (outer->y1 < inner->y1) { + if (outer->y0 < inner->y0) { result->x0=outer->x0; result->y0=outer->y0; result->x1=outer->x1; - result->y1=inner->y0; + result->y1=inner->y0-1; + (*num)++; result++; } if (inner->y1 < outer->y1) { result->x0=outer->x0; - result->y0=inner->y1; + result->y0=inner->y1+1; result->x1=outer->x1; result->y1=outer->y1; + (*num)++; result++; } if (outer->x0 < inner->x0) { result->x0=outer->x0; result->y0=inner->y0; - result->x1=inner->x0; + result->x1=inner->x0-1; result->y1=inner->y1; + (*num)++; result++; } if (inner->x1 < outer->x1) { - result->x0=inner->x1; + result->x0=inner->x1+1; result->y0=inner->y0; result->x1=outer->x1; result->y1=inner->y1; + (*num)++; result++; } } /* TODO: careful at scren edges */ -void rect_delta_offset(rect_t *rect, byte oldx, byte newx, byte oldy, byte newy) { +void rect_delta_offset(rect_t *rect, byte oldx, byte newx, byte oldy, byte newy, byte size_only) { if (oldx > newx) { /* move left */ - rect->x0 = rect->x0 - (oldx-newx); + if (!size_only) rect->x0 = rect->x0 - (oldx-newx); rect->x1 = rect->x1 - (oldx-newx); } else { /* move right */ - rect->x0 = rect->x0 + (newx-oldx); + if (!size_only) rect->x0 = rect->x0 + (newx-oldx); rect->x1 = rect->x1 + (newx-oldx); } if (oldy > newy) { /* move up */ - rect->y0 = rect->y0 - (oldy-newy); + if (!size_only) rect->y0 = rect->y0 - (oldy-newy); rect->y1 = rect->y1 - (oldy-newy); } else { /* move down */ - rect->y0 = rect->y0 + (newy-oldy); + if (!size_only) rect->y0 = rect->y0 + (newy-oldy); rect->y1 = rect->y1 + (newy-oldy); } } diff --git a/buddy/include/rect.h b/buddy/include/rect.h index d701b76..19f6dbc 100644 --- a/buddy/include/rect.h +++ b/buddy/include/rect.h @@ -23,6 +23,6 @@ extern rect_t* rect_inflate(rect_t* rect, sbyte dx, sbyte dy) __naked; extern rect_t* rect_intersect(rect_t *a, rect_t *b, rect_t *intersect); extern rect_t* rect_rel2abs(rect_t* abs, rect_t* rel, rect_t* out) __naked; extern void rect_subtract(rect_t *outer, rect_t *inner, rect_t *result, byte *num); -extern void rect_delta_offset(rect_t *rect, byte oldx, byte newx, byte oldy, byte newy); +extern void rect_delta_offset(rect_t *rect, byte oldx, byte newx, byte oldy, byte newy, byte size_only); #endif /* _RECT_H */ diff --git a/buddy/stdwnd.c b/buddy/stdwnd.c index 1422608..964216e 100644 --- a/buddy/stdwnd.c +++ b/buddy/stdwnd.c @@ -12,12 +12,22 @@ extern yx_t* yx; result desktop_wnd_proc(window_t* wnd, byte id, word param1, word param2) { - id,param1, param2; + + rect_t clip_rect; + param2; /* unused */ switch(id) { - case MSG_SYS_PAINT: + case MSG_SYS_PAINT: + /* set clip */ + if (param1) { + yx->copy((void*)wnd->graphics->clip,(void*)&clip_rect,sizeof(rect_t)); + yx->copy((void*)param1,(void*)wnd->graphics->clip,sizeof(rect_t)); + } /* clear screen space */ graphics_fill_rect(wnd->graphics,wnd->rect,(byte*)&msk_percent50_8x8, MODE_COPY); + /* restore clip */ + if (param1) + yx->copy((void*)&clip_rect,(void*)wnd->graphics->clip,sizeof(rect_t)); } return SUCCESS; /* we are the desktop!!! */ @@ -35,9 +45,13 @@ void draw_double_frame(window_t *wnd, rect_t *rect) { } result app_wnd_proc(window_t* wnd, byte id, word param1, word param2) { + rect_t *wrct; rect_t title_rect; + rect_t clip_rect; + rect_t client; byte *hit_result; + byte x,y; id, param1, param2; @@ -57,6 +71,12 @@ result app_wnd_proc(window_t* wnd, byte id, word param1, word param2) { return SUCCESS; case MSG_SYS_PAINT: + /* set clip */ + if (param1) { + yx->copy((void*)wnd->graphics->clip,(void*)&clip_rect,sizeof(rect_t)); + yx->copy((void*)param1,(void*)wnd->graphics->clip,sizeof(rect_t)); + } + /* window border */ if (wnd->flags & WF_HASBORDER) draw_double_frame(wnd, wnd->rect); @@ -72,7 +92,16 @@ result app_wnd_proc(window_t* wnd, byte id, word param1, word param2) { } /* client window */ - message_send(wnd->first_child, MSG_WND_PAINT, 0, 0); + if (param1) { + rect_intersect(wnd->first_child->graphics->clip, (rect_t*)param1, &client); + message_send(wnd->first_child, MSG_WND_PAINT, (word)&client, 0); + } else + message_send(wnd->first_child, MSG_WND_PAINT, 0, 0); + + /* restore clip */ + if (param1) + yx->copy((void*)&clip_rect,(void*)wnd->graphics->clip,sizeof(rect_t)); + return SUCCESS; case MSG_WND_SIZE: @@ -82,12 +111,32 @@ result app_wnd_proc(window_t* wnd, byte id, word param1, word param2) { wrct->x1=wrct->x0+APP_WND_MIN_WIDTH-1; if (wrct->y1-wrct->y0+1 < APP_WND_MIN_HEIGHT) wrct->y1=wrct->y0+APP_WND_MIN_HEIGHT-1; + /* update client rect + if (wnd->first_child) { + client.x0=wrct->x0 + APP_WND_BORDER_WIDTH; + client.y0=wrct->y0 + APP_WND_BORDER_HEIGHT + APP_WND_TITLE_HEIGHT - 1; + client.x1=wrct->x1 - APP_WND_BORDER_WIDTH; + client.y1=wrct->y1 - APP_WND_BORDER_HEIGHT; + yx->copy((void*)&client,(void*)wnd->first_child->graphics->area,sizeof(rect_t)); + yx->copy((void*)&client,(void*)wnd->first_child->graphics->clip,sizeof(rect_t)); + //message_send(wnd->first_child,MSG_WND_SIZE,(word)&client,0); + } + */ return SUCCESS; case MSG_WND_HITTEST: - /* always return title for now */ + /* these are absolute coordinates */ hit_result=(byte *)param1; - *hit_result=WND_HIT_TITLE; + y=param2&0x00ff; + x=param2>>8; + + if (x > wnd->graphics->area->x1 - 5 && y > wnd->graphics->area->y1-5) + *hit_result=WND_HIT_RESIZE; + else if (x < wnd->graphics->area->x0 + 8 && y < wnd->graphics->area->y0 + 8) + *hit_result=WND_HIT_CLOSE; + else + *hit_result=WND_HIT_TITLE; + return SUCCESS; } @@ -96,14 +145,26 @@ result app_wnd_proc(window_t* wnd, byte id, word param1, word param2) { } result client_wnd_proc(window_t* wnd, byte id, word param1, word param2) { - id, param1, param2; + + rect_t clip_rect; + + param2; switch(id) { - case MSG_WND_PAINT: + case MSG_WND_PAINT: + /* set clip */ + if (param1) { + yx->copy((void*)wnd->graphics->clip,(void*)&clip_rect,sizeof(rect_t)); + yx->copy((void*)param1,(void*)wnd->graphics->clip,sizeof(rect_t)); + } graphics_fill_rect(wnd->graphics,wnd->rect,(byte*)&msk_empty_8x8, MODE_COPY); + /* restore clip */ + if (param1) + yx->copy((void*)&clip_rect,(void*)wnd->graphics->clip,sizeof(rect_t)); return SUCCESS; - + case MSG_WND_SIZE: + break; } return NOT_PROCESSED; diff --git a/buddy/temp.depo b/buddy/temp.depo index 277a4ad..100e96c 100644 --- a/buddy/temp.depo +++ b/buddy/temp.depo @@ -1,3 +1,42 @@ + +private int FindAffected(Rectangle rect, int i) + { + while (i>=0) + { // Still rects to test? + if (rect.IntersectsWith(_rects[i])) + { + // First get the intersect. + Rectangle intersect; + intersect = new Rectangle(rect.Left, rect.Top, rect.Width, rect.Height); + intersect.Intersect(_rects[i]); + + if (_inters.Count == _interCount) return -1; + _inters.Add(new InterRect() { Rectangle = intersect, Brush = _interBrushes[i] }); + + if (i > 0) // Not last rect? + { + // Now get all subrects. + int n = 0; + List subrects = new List(); + SubRects(rect, intersect, subrects, ref n); + if (n == 0) return i; + + // Remove rect that we already tested. + int minDepth = i - 1; + for (int j = 0; j < n; j++) minDepth = Math.Min(minDepth, FindAffected(subrects[j], i - 1)); + i = minDepth; + } + else + { + return -1; + } + } + else i--; // Test next rect. + } + return i; + } + + /* w1=window_create( diff --git a/buddy/window.c b/buddy/window.c index 83ce7e1..08c7f3f 100644 --- a/buddy/window.c +++ b/buddy/window.c @@ -7,6 +7,7 @@ #include "window.h" #include "stdwnd.h" #include "mouse.h" +#include "masks.h" extern yx_t *yx; @@ -132,24 +133,32 @@ void window_select(window_t *wnd) { /* bring window to the front */ yx->linsert((void **)&(wnd->parent->first_child), (void *)wnd); } -void window_invalidate(window_t* first, rect_t *area) { - +void window_invalidate(rect_t *area, window_t *root, window_t *first) { rect_t intersect; rect_t smaller[4]; byte num; - if (rect_overlap(area, first->rect)) { - rect_intersect(area, first->rect, &intersect); - message_send(first, MSG_SYS_PAINT, (word)&intersect, 0); - first=first->next; - } - if (first==NULL) return; - rect_subtract(area, &intersect, smaller, &num); - while(num) { - window_invalidate(first, &(smaller[num-1])); - num--; + while (first) { + if (rect_overlap(area, first->graphics->area)) { + rect_intersect(area, first->graphics->area, &intersect); + + /* repaint just the affected part */ + message_send(first, MSG_SYS_PAINT, (word)&intersect, 0); + + /* now children */ + rect_subtract(area, &intersect, smaller, &num); + while(num) { + window_invalidate(&(smaller[num-1]), root, first->next); + num--; + } + return; + } else + first=first->next; } -} + + /* now handle root */ + window_invalidate(area, root->parent, root); +} window_t* window_get_app_wnd(window_t *wnd) { if (wnd==window_desktop) return NULL; /* desktop has no app wnd */ diff --git a/buddy/window.h b/buddy/window.h index a96584c..59b93f8 100644 --- a/buddy/window.h +++ b/buddy/window.h @@ -48,10 +48,12 @@ extern window_t *window_create( byte y0, byte x1, byte y1); +extern void window_destroy(window_t *wnd); extern void window_draw(window_t *wnd); extern void window_select(window_t *wnd); extern window_t* window_get_app_wnd(window_t *wnd); extern window_t *window_find_xy(window_t* root, byte absx, byte absy); extern void window_move(window_t *wnd, byte dx, boolean lr, byte dy, boolean ud); +extern void window_invalidate(rect_t *area, window_t *root, window_t *first); #endif /* _WINDOW_H */