From 356288ce8d826204e629a452ad1edc1b845d116c Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 27 Apr 2009 11:12:25 +0000 Subject: SCI: Rewrote dirty rect code to use Common::List svn-id: r40156 --- engines/sci/gfx/gfx_state_internal.h | 2 +- engines/sci/gfx/gfx_widgets.cpp | 97 ++++++++++++++---------------------- engines/sci/gfx/operations.cpp | 82 ++++++++++++------------------ engines/sci/gfx/operations.h | 22 ++++---- 4 files changed, 78 insertions(+), 125 deletions(-) (limited to 'engines/sci/gfx') diff --git a/engines/sci/gfx/gfx_state_internal.h b/engines/sci/gfx/gfx_state_internal.h index 75ac6ea27f..ab4ad0ab68 100644 --- a/engines/sci/gfx/gfx_state_internal.h +++ b/engines/sci/gfx/gfx_state_internal.h @@ -294,7 +294,7 @@ typedef int gfxw_rect_op(GfxContainer *, rect_t, int); struct GfxContainer : public GfxWidget { rect_t zone; /* The writeable zone (absolute) for contained objects */ - gfx_dirty_rect_t *_dirty; /* List of dirty rectangles */ + DirtyRectList _dirtyRects; /* List of dirty rectangles */ GfxWidget *_contents; GfxWidget **_nextpp; /* Pointer to the 'next' pointer in the last entry in contents */ diff --git a/engines/sci/gfx/gfx_widgets.cpp b/engines/sci/gfx/gfx_widgets.cpp index 395436908a..f7fcc189e9 100644 --- a/engines/sci/gfx/gfx_widgets.cpp +++ b/engines/sci/gfx/gfx_widgets.cpp @@ -991,18 +991,14 @@ static int _w_gfxwop_container_print_contents(const char *name, GfxWidget *widge } void GfxContainer::print(int indentation) const { - gfx_dirty_rect_t *dirty; - sciprintf(" viszone=((%d,%d),(%dx%d))\n", zone.x, zone.y, zone.width, zone.height); indent(indentation); sciprintf("--dirty:\n"); - dirty = _dirty; - while (dirty) { + for (DirtyRectList::const_iterator dirty = _dirtyRects.begin(); dirty != _dirtyRects.end(); ++dirty) { indent(indentation + 1); - sciprintf("dirty(%d,%d, (%dx%d))\n", dirty->rect.x, dirty->rect.y, dirty->rect.width, dirty->rect.height); - dirty = dirty->next; + sciprintf("dirty(%d,%d, (%dx%d))\n", dirty->x, dirty->y, dirty->width, dirty->height); } _w_gfxwop_container_print_contents("contents", _contents, indentation); @@ -1014,7 +1010,6 @@ GfxContainer::GfxContainer(rect_t area, gfxw_widget_type_t type_) _bounds = zone = area; _contents = NULL; _nextpp = &_contents; - _dirty = NULL; free_tagged = NULL; free_contents = NULL; @@ -1025,13 +1020,6 @@ GfxContainer::GfxContainer(rect_t area, gfxw_widget_type_t type_) _flags |= GFXW_FLAG_VISIBLE | GFXW_FLAG_CONTAINER; } -static void recursively_free_dirty_rects(gfx_dirty_rect_t *dirty) { - if (dirty) { - recursively_free_dirty_rects(dirty->next); - free(dirty); - } -} - static int _gfxw_dirty_rect_overlaps_normal_rect(rect_t port_zone, rect_t bounds, rect_t dirty) { bounds.x += port_zone.x; bounds.y += port_zone.y; @@ -1041,7 +1029,6 @@ static int _gfxw_dirty_rect_overlaps_normal_rect(rect_t port_zone, rect_t bounds static int _gfxwop_container_draw_contents(GfxWidget *widget, GfxWidget *contents) { GfxContainer *container = (GfxContainer *)widget; - gfx_dirty_rect_t *dirty = container->_dirty; GfxState *gfx_state = (widget->_visual) ? widget->_visual->_gfxState : ((GfxVisual *) widget)->_gfxState; int draw_ports; rect_t nullzone = {0, 0, 0, 0}; @@ -1049,17 +1036,18 @@ static int _gfxwop_container_draw_contents(GfxWidget *widget, GfxWidget *content if (!contents) return 0; - while (dirty) { + DirtyRectList::iterator dirty = container->_dirtyRects.begin(); + while (dirty != container->_dirtyRects.end()) { GfxWidget *seeker = contents; while (seeker) { if (_gfxw_dirty_rect_overlaps_normal_rect(GFXW_IS_CONTAINER(seeker) ? nullzone : container->zone, // Containers have absolute coordinates, reflect this. - seeker->_bounds, dirty->rect)) { + seeker->_bounds, *dirty)) { if (GFXW_IS_CONTAINER(seeker)) {// Propagate dirty rectangles /upwards/ - DDIRTY(stderr, "container_draw_contents: propagate upwards (%d,%d,%d,%d ,0)\n", GFX_PRINT_RECT(dirty->rect)); - ((GfxContainer *)seeker)->add_dirty_abs((GfxContainer *)seeker, dirty->rect, 0); + DDIRTY(stderr, "container_draw_contents: propagate upwards (%d,%d,%d,%d ,0)\n", GFX_PRINT_RECT(*dirty)); + ((GfxContainer *)seeker)->add_dirty_abs((GfxContainer *)seeker, *dirty, 0); } seeker->_flags |= GFXW_FLAG_DIRTY; @@ -1068,21 +1056,23 @@ static int _gfxwop_container_draw_contents(GfxWidget *widget, GfxWidget *content seeker = seeker->_next; } - dirty = dirty->next; + ++dirty; } // The draw loop is executed twice: Once for normal data, and once for ports. for (draw_ports = 0; draw_ports < 2; draw_ports++) { - dirty = container->_dirty; - while (dirty) { + dirty = container->_dirtyRects.begin(); + while (dirty != container->_dirtyRects.end()) { GfxWidget *seeker = contents; - while (seeker && (draw_ports || !GFXW_IS_PORT(seeker))) { - rect_t small_rect; - byte draw_noncontainers; + // FIXME: Ugly hack to check whether this is the last dirty rect or not + DirtyRectList::iterator next = dirty; + ++next; + const bool isLastDirtyRect = (next == container->_dirtyRects.end()); - memcpy(&small_rect, &(dirty->rect), sizeof(rect_t)); - draw_noncontainers = !_gfxop_clip(&small_rect, container->_bounds); + while (seeker && (draw_ports || !GFXW_IS_PORT(seeker))) { + rect_t small_rect = *dirty; + bool draw_noncontainers = !_gfxop_clip(&small_rect, container->_bounds); if (seeker->_flags & GFXW_FLAG_DIRTY) { @@ -1095,13 +1085,13 @@ static int _gfxwop_container_draw_contents(GfxWidget *widget, GfxWidget *content if (draw_noncontainers || GFXW_IS_CONTAINER(seeker)) seeker->draw(Common::Point(container->zone.x, container->zone.y)); - if (!dirty->next) + if (isLastDirtyRect) seeker->_flags &= ~GFXW_FLAG_DIRTY; } seeker = seeker->_next; } - dirty = dirty->next; + ++dirty; } } // Remember that the dirty rects should be freed afterwards! @@ -1118,8 +1108,7 @@ GfxContainer::~GfxContainer() { seeker = next; } - recursively_free_dirty_rects(_dirty); - _dirty = NULL; + _dirtyRects.clear(); } void GfxContainer::tag() { @@ -1237,7 +1226,7 @@ static int _gfxwop_container_add_dirty(GfxContainer *container, rect_t dirty, in #endif DDIRTY(stderr, "Effectively adding dirty %d,%d,%d,%d %d to ID %d\n", GFX_PRINT_RECT(dirty), propagate, container->_ID); - container->_dirty = gfxdr_add_dirty(container->_dirty, dirty, GFXW_DIRTY_STRATEGY); + gfxdr_add_dirty(container->_dirtyRects, dirty, GFXW_DIRTY_STRATEGY); return 0; } @@ -1266,16 +1255,14 @@ int GfxList::draw(const Common::Point &pos) { DRAW_ASSERT(this, GFXW_LIST); _gfxwop_container_draw_contents(this, _contents); - recursively_free_dirty_rects(_dirty); - _dirty = NULL; _flags &= ~GFXW_FLAG_DIRTY; } else { DRAW_ASSERT(this, GFXW_SORTED_LIST); _gfxwop_container_draw_contents(this, _contents); - recursively_free_dirty_rects(_dirty); - _dirty = NULL; } + _dirtyRects.clear(); + return 0; } @@ -1417,24 +1404,20 @@ GfxList::GfxList(rect_t area, bool sorted) int GfxVisual::draw(const Common::Point &pos) { DRAW_ASSERT(this, GFXW_VISUAL); - gfx_dirty_rect_t *dirty = _dirty; - while (dirty) { - int err = gfxop_clear_box(_gfxState, dirty->rect); + for (DirtyRectList::iterator dirty = _dirtyRects.begin(); dirty != _dirtyRects.end(); ++dirty) { + int err = gfxop_clear_box(_gfxState, *dirty); if (err) { - GFXERROR("Error while clearing dirty rect (%d,%d,(%dx%d))\n", dirty->rect.x, - dirty->rect.y, dirty->rect.width, dirty->rect.height); + GFXERROR("Error while clearing dirty rect (%d,%d,(%dx%d))\n", dirty->x, + dirty->y, dirty->width, dirty->height); if (err == GFX_FATAL) return err; } - - dirty = dirty->next; } _gfxwop_container_draw_contents(this, _contents); - recursively_free_dirty_rects(_dirty); - _dirty = NULL; + _dirtyRects.clear(); _flags &= ~GFXW_FLAG_DIRTY; return 0; @@ -1499,16 +1482,6 @@ static int _visual_find_free_ID(GfxVisual *visual) { return id; } -static int _gfxwop_add_dirty_rects(GfxContainer *dest, gfx_dirty_rect_t *src) { - DDIRTY(stderr, "Adding multiple dirty to #%d\n", dest->_ID); - if (src) { - dest->_dirty = gfxdr_add_dirty(dest->_dirty, src->rect, GFXW_DIRTY_STRATEGY); - _gfxwop_add_dirty_rects(dest, src->next); - } - - return 0; -} - //*** Ports *** int GfxPort::draw(const Common::Point &pos) { @@ -1516,18 +1489,22 @@ int GfxPort::draw(const Common::Point &pos) { if (_decorations) { DDIRTY(stderr, "Getting/applying deco dirty (multi)\n"); - _gfxwop_add_dirty_rects(GFXWC(_decorations), _dirty); + + DDIRTY(stderr, "Adding multiple dirty to #%d\n", _decorations->_ID); + for (DirtyRectList::iterator dirty = _dirtyRects.begin(); dirty != _dirtyRects.end(); ++dirty) { + gfxdr_add_dirty(_decorations->_dirtyRects, *dirty, GFXW_DIRTY_STRATEGY); + } + if (_decorations->draw(gfxw_point_zero)) { - _decorations->_dirty = NULL; + _decorations->_dirtyRects.clear(); return 1; // error } - _decorations->_dirty = NULL; + _decorations->_dirtyRects.clear(); } _gfxwop_container_draw_contents(this, _contents); - recursively_free_dirty_rects(_dirty); - _dirty = NULL; + _dirtyRects.clear(); _flags &= ~GFXW_FLAG_DIRTY; return 0; diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp index ca4724d7fc..d5b6153b1e 100644 --- a/engines/sci/gfx/operations.cpp +++ b/engines/sci/gfx/operations.cpp @@ -296,17 +296,7 @@ static int _gfxop_update_box(GfxState *state, rect_t box) { return GFX_OK; } -static gfx_dirty_rect_t *_rect_create(rect_t box) { - gfx_dirty_rect_t *rect; - - rect = (gfx_dirty_rect_t *)sci_malloc(sizeof(gfx_dirty_rect_t)); - rect->next = NULL; - rect->rect = box; - - return rect; -} - -gfx_dirty_rect_t *gfxdr_add_dirty(gfx_dirty_rect_t *base, rect_t box, int strategy) { +void gfxdr_add_dirty(DirtyRectList &list, rect_t box, int strategy) { if (box.width < 0) { box.x += box.width; box.width = - box.width; @@ -321,46 +311,41 @@ gfx_dirty_rect_t *gfxdr_add_dirty(gfx_dirty_rect_t *base, rect_t box, int strate GFX_PRINT_RECT(box)); #endif if (_gfxop_clip(&box, gfx_rect(0, 0, 320, 200))) - return base; + return; switch (strategy) { case GFXOP_DIRTY_FRAMES_ONE: - if (base) { - Common::Rect tmp = toCommonRect(base->rect); + if (!list.empty()) { + Common::Rect tmp = toCommonRect(list.front()); tmp.extend(toCommonRect(box)); - base->rect = toSCIRect(tmp); + list.front() = toSCIRect(tmp); } else { - base = _rect_create(box); + list.push_back(box); } break; case GFXOP_DIRTY_FRAMES_CLUSTERS: { - gfx_dirty_rect_t **rectp = &(base); - - while (*rectp) { - if (gfx_rects_overlap((*rectp)->rect, box)) { - gfx_dirty_rect_t *next = (*rectp)->next; + DirtyRectList::iterator dirty = list.begin(); + while (dirty != list.end()) { + if (gfx_rects_overlap(*dirty, box)) { Common::Rect tmp = toCommonRect(box); - tmp.extend(toCommonRect((*rectp)->rect)); + tmp.extend(toCommonRect(*dirty)); box = toSCIRect(tmp); - free(*rectp); - *rectp = next; + dirty = list.erase(dirty); } else - rectp = &((*rectp)->next); + ++dirty; } - *rectp = _rect_create(box); + list.push_back(box); - } - break; + } + break; default: GFXERROR("Attempt to use invalid dirty frame mode %d!\nPlease refer to gfx_options.h.", strategy); } - - return base; } static void _gfxop_add_dirty(GfxState *state, rect_t box) { @@ -368,9 +353,9 @@ static void _gfxop_add_dirty(GfxState *state, rect_t box) { return; #ifdef CUSTOM_GRAPHICS_OPTIONS - state->dirty_rects = gfxdr_add_dirty(state->dirty_rects, box, state->options->dirty_frames); + gfxdr_add_dirty(state->_dirtyRects, box, state->options->dirty_frames); #else - state->dirty_rects = gfxdr_add_dirty(state->dirty_rects, box, GFXOP_DIRTY_FRAMES_CLUSTERS); + gfxdr_add_dirty(state->_dirtyRects, box, GFXOP_DIRTY_FRAMES_CLUSTERS); #endif } @@ -389,24 +374,21 @@ static void _gfxop_add_dirty_x(GfxState *state, rect_t box) { _gfxop_add_dirty(state, box); } -static int _gfxop_clear_dirty_rec(GfxState *state, gfx_dirty_rect_t *rect) { - int retval; +static int _gfxop_clear_dirty_rec(GfxState *state, DirtyRectList &dirtyRects) { + int retval = GFX_OK; - if (!rect) - return GFX_OK; + DirtyRectList::iterator dirty = dirtyRects.begin(); + while (dirty != dirtyRects.end()) { -#ifdef GFXOP_DEBUG_DIRTY - fprintf(stderr, "\tClearing dirty (%d %d %d %d)\n", - GFX_PRINT_RECT(rect->rect)); -#endif - if (!state->fullscreen_override) - retval = _gfxop_update_box(state, rect->rect); - else - retval = GFX_OK; - - retval |= _gfxop_clear_dirty_rec(state, rect->next); + #ifdef GFXOP_DEBUG_DIRTY + fprintf(stderr, "\tClearing dirty (%d %d %d %d)\n", GFX_PRINT_RECT(*dirty)); + #endif + if (!state->fullscreen_override) + retval |= _gfxop_update_box(state, *dirty); + ++dirty; + } + dirtyRects.clear(); - free(rect); return retval; } @@ -435,7 +417,7 @@ int gfxop_init(int version, GfxState *state, gfx_options_t *options, ResourceMan state->pic_nr = -1; // Set background pic number to an invalid value state->tag_mode = 0; state->pic_port_bounds = gfx_rect(0, 10, 320, 190); - state->dirty_rects = NULL; + state->_dirtyRects.clear(); do { if (!state->driver->init(state->driver, xfact, yfact, color_depth)) @@ -1106,9 +1088,7 @@ int gfxop_update(GfxState *state) { BASIC_CHECKS(GFX_FATAL); - retval = _gfxop_clear_dirty_rec(state, state->dirty_rects); - - state->dirty_rects = NULL; + retval = _gfxop_clear_dirty_rec(state, state->_dirtyRects); if (state->fullscreen_override) { // We've been asked to re-draw the active full-screen image, essentially. diff --git a/engines/sci/gfx/operations.h b/engines/sci/gfx/operations.h index 949bc262ea..d9890001a6 100644 --- a/engines/sci/gfx/operations.h +++ b/engines/sci/gfx/operations.h @@ -85,10 +85,7 @@ enum gfx_box_shade_t { }; -struct gfx_dirty_rect_t { - rect_t rect; - gfx_dirty_rect_t *next; -}; +typedef Common::List DirtyRectList; struct GfxState { @@ -129,7 +126,7 @@ struct GfxState { gfxr_pic_t *pic, *pic_unscaled; /* The background picture and its unscaled equivalent */ rect_t pic_port_bounds; /* Picture port bounds */ - gfx_dirty_rect_t *dirty_rects; /* Dirty rectangles */ + DirtyRectList _dirtyRects; /* Dirty rectangles */ }; @@ -637,14 +634,13 @@ int gfxop_free_pixmap(GfxState *state, gfx_pixmap_t *pxm); /* Dirty rectangle operations */ /******************************/ -gfx_dirty_rect_t *gfxdr_add_dirty(gfx_dirty_rect_t *base, rect_t box, int strategy); -/* Adds a dirty rectangle to 'base' according to a strategy -** Parameters: (gfx_dirty_rect_t *) base: The base rectangle to add to, or NULL -** (rect_t) box: The dirty frame to add -** (int) strategy: The dirty frame heuristic to use (see gfx_options.h) -** Returns : (gfx_dirty_rect_t *) an appropriate singly-linked dirty rectangle -** result cluster -*/ +/** + * Adds a dirty rectangle to 'base' according to a strategy. + * @param list the list to add to + * @param box the dirty frame to addable + * @param strategy the dirty frame heuristic to use (see gfx_options.h) + */ +void gfxdr_add_dirty(DirtyRectList &list, rect_t box, int strategy); int _gfxop_clip(rect_t *rect, rect_t clipzone); /* Clips a rectangle against another one -- cgit v1.2.3