def tile_is_visible(cr, tx, ty, clip_region, sparse, translation_only): if not sparse: return True # it is worth checking whether this tile really will be visible # (to speed up the L-shaped expose event during scrolling) # (speedup clearly visible; slowdown measurable when always executing this code) N = tiledsurface.N if translation_only: x, y = cr.user_to_device(tx*N, ty*N) bbox = (int(x), int(y), N, N) else: corners = [(tx*N, ty*N), ((tx+1)*N, ty*N), (tx*N, (ty+1)*N), ((tx+1)*N, (ty+1)*N)] corners = [cr.user_to_device(x_, y_) for (x_, y_) in corners] bbox = helpers.rotated_rectangle_bbox(corners) if pygtkcompat.USE_GTK3: c_r = gdk.Rectangle() c_r.x, c_r.y, c_r.width, c_r.height = clip_region bb_r = gdk.Rectangle() bb_r.x, bb_r.y, bb_r.width, bb_r.height = bbox intersects, isect_r = gdk.rectangle_intersect(bb_r, c_r) if not intersects: return False else: if clip_region.rect_in(bbox) == gdk.OVERLAP_RECTANGLE_OUT: return False return True
def tile_is_visible(self, tx, ty, transformation, clip_region, sparse, translation_only): if not sparse: return True # it is worth checking whether this tile really will be visible # (to speed up the L-shaped expose event during scrolling) # (speedup clearly visible; slowdown measurable when always executing this code) N = tiledsurface.N if translation_only: x, y = transformation.transform_point(tx * N, ty * N) bbox = (int(x), int(y), N, N) else: corners = [(tx * N, ty * N), ((tx + 1) * N, ty * N), (tx * N, (ty + 1) * N), ((tx + 1) * N, (ty + 1) * N)] corners = [ transformation.transform_point(x_, y_) for (x_, y_) in corners ] bbox = helpers.rotated_rectangle_bbox(corners) c_r = gdk.Rectangle() c_r.x, c_r.y, c_r.width, c_r.height = clip_region bb_r = gdk.Rectangle() bb_r.x, bb_r.y, bb_r.width, bb_r.height = bbox intersects, isect_r = gdk.rectangle_intersect(bb_r, c_r) return intersects
def canvas_modified_cb(self, x, y, w, h): if not self.get_window(): return if w == 0 and h == 0: # Full redraw (used when background has changed). #print 'full redraw' self.queue_draw() return # Create an expose event with the event bbox rotated/zoomed. corners = [(x, y), (x+w, y), (x, y+h), (x+w, y+h)] corners = [self.model_to_display(x, y) for (x, y) in corners] self.queue_draw_area(*helpers.rotated_rectangle_bbox(corners))
def canvas_modified_cb(self, x, y, w, h): if not self.get_window(): return if w == 0 and h == 0: # Full redraw (used when background has changed). #logger.debug('Full redraw') self.queue_draw() return # Create an expose event with the event bbox rotated/zoomed. corners = [(x, y), (x + w, y), (x, y + h), (x + w, y + h)] corners = [self.model_to_display(x, y) for (x, y) in corners] self.queue_draw_area(*helpers.rotated_rectangle_bbox(corners))
def canvas_modified_cb(self, model, x, y, w, h): """Handles area redraw notifications from the underlying model""" if not self.get_window(): return if w == 0 and h == 0: # Full redraw (used when background has changed). #logger.debug('Full redraw') self.queue_draw() return # Create an expose event with the event bbox rotated/zoomed. corners = [(x, y), (x+w, y), (x, y+h), (x+w, y+h)] corners = [self.model_to_display(x, y) for (x, y) in corners] self.queue_draw_area(*helpers.rotated_rectangle_bbox(corners))
def canvas_modified_cb(self, x1, y1, w, h): if not self.window: return if w == 0 and h == 0: # Full redraw (used when background has changed). #print 'full redraw' self.queue_draw() return if self.is_translation_only(): x, y = self.model_to_display(x1, y1) self.queue_draw_area(int(x), int(y), w, h) else: # Create an expose event with the event bbox rotated/zoomed. # OPTIMIZE: This is estimated to cause at least twice as much # rendering work as neccessary. # Transform 4 bbox corners to screen coordinates. corners = [(x1, y1), (x1+w-1, y1), (x1, y1+h-1), (x1+w-1, y1+h-1)] corners = [self.model_to_display(x, y) for (x, y) in corners] self.queue_draw_area(*helpers.rotated_rectangle_bbox(corners))
def _tile_is_visible(self, tx, ty, transformation, clip_region, translation_only): """Tests whether an individual tile is visible. This is sometimes worth doing during rendering, but not always. Currently we use _render_get_clip_region()'s sparse flag to determine whether this is necessary. The original logic for this function was documented as... > it is worth checking whether this tile really will be visible > (to speed up the L-shaped expose event during scrolling) > (speedup clearly visible; slowdown measurable when always > executing this code) but I'm not 100% certain that GTK3 does panning redraws this way. So perhaps this method is uneccessary? """ N = tiledsurface.N if translation_only: x, y = transformation.transform_point(tx * N, ty * N) bbox = (int(x), int(y), N, N) else: corners = [ (tx * N, ty * N), ((tx + 1) * N, ty * N), (tx * N, (ty + 1) * N), ((tx + 1) * N, (ty + 1) * N), ] corners = [ transformation.transform_point(x_, y_) for (x_, y_) in corners ] bbox = helpers.rotated_rectangle_bbox(corners) c_r = gdk.Rectangle() c_r.x, c_r.y, c_r.width, c_r.height = clip_region bb_r = gdk.Rectangle() bb_r.x, bb_r.y, bb_r.width, bb_r.height = bbox intersects, isect_r = gdk.rectangle_intersect(bb_r, c_r) return intersects
def tile_is_visible(self, tx, ty, transformation, clip_region, sparse, translation_only): if not sparse: return True # it is worth checking whether this tile really will be visible # (to speed up the L-shaped expose event during scrolling) # (speedup clearly visible; slowdown measurable when always executing this code) N = tiledsurface.N if translation_only: x, y = transformation.transform_point(tx*N, ty*N) bbox = (int(x), int(y), N, N) else: corners = [(tx*N, ty*N), ((tx+1)*N, ty*N), (tx*N, (ty+1)*N), ((tx+1)*N, (ty+1)*N)] corners = [transformation.transform_point(x_, y_) for (x_, y_) in corners] bbox = helpers.rotated_rectangle_bbox(corners) c_r = gdk.Rectangle() c_r.x, c_r.y, c_r.width, c_r.height = clip_region bb_r = gdk.Rectangle() bb_r.x, bb_r.y, bb_r.width, bb_r.height = bbox intersects, isect_r = gdk.rectangle_intersect(bb_r, c_r) return intersects
def _tile_is_visible(self, tx, ty, transformation, clip_region, translation_only): """Tests whether an individual tile is visible. This is sometimes worth doing during rendering, but not always. Currently we use _render_get_clip_region()'s sparse flag to determine whether this is necessary. The original logic for this function was documented as... > it is worth checking whether this tile really will be visible > (to speed up the L-shaped expose event during scrolling) > (speedup clearly visible; slowdown measurable when always > executing this code) but I'm not 100% certain that GTK3 does panning redraws this way. So perhaps this method is uneccessary? """ N = tiledsurface.N if translation_only: x, y = transformation.transform_point(tx*N, ty*N) bbox = (int(x), int(y), N, N) else: corners = [ (tx*N, ty*N), ((tx+1)*N, ty*N), (tx*N, (ty+1)*N), ((tx+1)*N, (ty+1)*N), ] corners = [ transformation.transform_point(x_, y_) for (x_, y_) in corners ] bbox = helpers.rotated_rectangle_bbox(corners) c_r = gdk.Rectangle() c_r.x, c_r.y, c_r.width, c_r.height = clip_region bb_r = gdk.Rectangle() bb_r.x, bb_r.y, bb_r.width, bb_r.height = bbox intersects, isect_r = gdk.rectangle_intersect(bb_r, c_r) return intersects
def canvas_modified_cb(self, x1, y1, w, h): if not self.window: return if w == 0 and h == 0: # full redraw (used when background has changed) #print 'full redraw' self.queue_draw() return cr = self.get_model_coordinates_cairo_context() if self.is_translation_only(): x, y = cr.user_to_device(x1, y1) self.queue_draw_area(int(x), int(y), w, h) else: # create an expose event with the event bbox rotated/zoomed # OPTIMIZE: this is estimated to cause at least twice more rendering work than neccessary # transform 4 bbox corners to screen coordinates corners = [(x1, y1), (x1+w-1, y1), (x1, y1+h-1), (x1+w-1, y1+h-1)] corners = [cr.user_to_device(x, y) for (x, y) in corners] self.queue_draw_area(*helpers.rotated_rectangle_bbox(corners))
def canvas_modified_cb(self, x1, y1, w, h): if not self.window: return if w == 0 and h == 0: # full redraw (used when background has changed) #print 'full redraw' self.queue_draw() return cr = self.get_model_coordinates_cairo_context() if self.is_translation_only(): x, y = cr.user_to_device(x1, y1) self.queue_draw_area(int(x), int(y), w, h) else: # create an expose event with the event bbox rotated/zoomed # OPTIMIZE: this is estimated to cause at least twice more rendering work than neccessary # transform 4 bbox corners to screen coordinates corners = [(x1, y1), (x1 + w - 1, y1), (x1, y1 + h - 1), (x1 + w - 1, y1 + h - 1)] corners = [cr.user_to_device(x, y) for (x, y) in corners] self.queue_draw_area(*helpers.rotated_rectangle_bbox(corners))
def _tile_is_visible(self, tx, ty, transformation, clip_rect, translation_only): """Tests whether an individual tile is visible. This is sometimes worth doing during rendering, but not always. Currently we use _render_get_clip_region()'s sparse flag to determine whether this is necessary. The original logic for this function was documented as... > it is worth checking whether this tile really will be visible > (to speed up the L-shaped expose event during scrolling) > (speedup clearly visible; slowdown measurable when always > executing this code) I'm not 100% certain that GTK3 does panning redraws this way, so perhaps this method is uneccessary for those? However this method is always used when rendering during painting, or other activities that send partial updates. """ N = tiledsurface.N if translation_only: x, y = transformation.transform_point(tx*N, ty*N) bbox = (int(x), int(y), N, N) else: corners = [ (tx*N, ty*N), ((tx+1)*N, ty*N), (tx*N, (ty+1)*N), ((tx+1)*N, (ty+1)*N), ] corners = [ transformation.transform_point(x_, y_) for (x_, y_) in corners ] bbox = helpers.rotated_rectangle_bbox(corners) tile_rect = helpers.Rect(*bbox) return clip_rect.overlaps(tile_rect)
def render_execute(self, cr, surface, sparse, mipmap_level, gdk_clip_region): translation_only = self.is_translation_only() model_bbox = surface.x, surface.y, surface.w, surface.h #print 'model bbox', model_bbox # not sure if it is a good idea to clip so tightly # has no effect right now because device_bbox is always smaller cr.rectangle(*model_bbox) cr.clip() layers = self.get_visible_layers() if self.visualize_rendering: surface.pixbuf.fill((int(random.random()*0xff)<<16)+0x00000000) tiles = surface.get_tiles() background = None if self.current_layer_solo: background = self.neutral_background_pixbuf layers = [self.doc.layer] # this is for hiding instead #layers.pop(self.doc.layer_idx) if self.overlay_layer: idx = layers.index(self.doc.layer) layers.insert(idx+1, self.overlay_layer) for tx, ty in tiles: if sparse: # it is worth checking whether this tile really will be visible # (to speed up the L-shaped expose event during scrolling) # (speedup clearly visible; slowdown measurable when always executing this code) N = tiledsurface.N if translation_only: x, y = cr.user_to_device(tx*N, ty*N) bbox = (int(x), int(y), N, N) else: #corners = [(tx*N, ty*N), ((tx+1)*N-1, ty*N), (tx*N, (ty+1)*N-1), ((tx+1)*N-1, (ty+1)*N-1)] # same problem as above: cairo needs to know one extra pixel for interpolation corners = [(tx*N-1, ty*N-1), ((tx+1)*N, ty*N-1), (tx*N-1, (ty+1)*N), ((tx+1)*N, (ty+1)*N)] corners = [cr.user_to_device(x_, y_) for (x_, y_) in corners] bbox = gdk.Rectangle(*helpers.rotated_rectangle_bbox(corners)) if gdk_clip_region.rect_in(bbox) == gdk.OVERLAP_RECTANGLE_OUT: continue dst = surface.get_tile_memory(tx, ty) self.doc.blit_tile_into(dst, False, tx, ty, mipmap_level, layers, background) if translation_only: # not sure why, but using gdk directly is notably faster than the same via cairo x, y = cr.user_to_device(surface.x, surface.y) self.window.draw_pixbuf(None, surface.pixbuf, 0, 0, int(x), int(y), dither=gdk.RGB_DITHER_MAX) else: #print 'Position (screen coordinates):', cr.user_to_device(surface.x, surface.y) cr.set_source_pixbuf(surface.pixbuf, round(surface.x), round(surface.y)) pattern = cr.get_source() # We could set interpolation mode here (eg nearest neighbour) #pattern.set_filter(cairo.FILTER_NEAREST) # 1.6s #pattern.set_filter(cairo.FILTER_FAST) # 2.0s #pattern.set_filter(cairo.FILTER_GOOD) # 3.1s #pattern.set_filter(cairo.FILTER_BEST) # 3.1s #pattern.set_filter(cairo.FILTER_BILINEAR) # 3.1s if self.scale > 3.0: # pixelize at high zoom-in levels pattern.set_filter(cairo.FILTER_NEAREST) cr.paint() if self.doc.frame_enabled: # Draw a overlay for all the area outside the "document area" cr.save() cr.set_source_rgba(0.25, 0.25, 0.25, 1.0) cr.set_operator(cairo.OPERATOR_OVER) mipmap_factor = 2**mipmap_level frame = self.doc.get_frame() cr.rectangle(frame[0]/mipmap_factor, frame[1]/mipmap_factor, frame[2]/mipmap_factor, frame[3]/mipmap_factor) cr.rectangle(*model_bbox) cr.set_fill_rule(cairo.FILL_RULE_EVEN_ODD) cr.fill() cr.restore() if self.visualize_rendering: # visualize painted bboxes (blue) cr.set_source_rgba(0, 0, random.random(), 0.4) cr.paint()
def render_execute(self, cr, surface, sparse, mipmap_level, gdk_clip_region): translation_only = self.is_translation_only() model_bbox = surface.x, surface.y, surface.w, surface.h #print 'model bbox', model_bbox # not sure if it is a good idea to clip so tightly # has no effect right now because device_bbox is always smaller cr.rectangle(*model_bbox) cr.clip() layers = self.get_visible_layers() if self.visualize_rendering: surface.pixbuf.fill((int(random.random() * 0xff) << 16) + 0x00000000) tiles = surface.get_tiles() background = None if self.current_layer_solo: background = self.neutral_background_pixbuf layers = [self.doc.layer] # this is for hiding instead #layers.pop(self.doc.layer_idx) if self.overlay_layer: idx = layers.index(self.doc.layer) layers.insert(idx + 1, self.overlay_layer) for tx, ty in tiles: if sparse: # it is worth checking whether this tile really will be visible # (to speed up the L-shaped expose event during scrolling) # (speedup clearly visible; slowdown measurable when always executing this code) N = tiledsurface.N if translation_only: x, y = cr.user_to_device(tx * N, ty * N) bbox = (int(x), int(y), N, N) else: #corners = [(tx*N, ty*N), ((tx+1)*N-1, ty*N), (tx*N, (ty+1)*N-1), ((tx+1)*N-1, (ty+1)*N-1)] # same problem as above: cairo needs to know one extra pixel for interpolation corners = [(tx * N - 1, ty * N - 1), ((tx + 1) * N, ty * N - 1), (tx * N - 1, (ty + 1) * N), ((tx + 1) * N, (ty + 1) * N)] corners = [ cr.user_to_device(x_, y_) for (x_, y_) in corners ] bbox = gdk.Rectangle( *helpers.rotated_rectangle_bbox(corners)) if gdk_clip_region.rect_in(bbox) == gdk.OVERLAP_RECTANGLE_OUT: continue dst = surface.get_tile_memory(tx, ty) self.doc.blit_tile_into(dst, tx, ty, mipmap_level, layers, background) if translation_only: # not sure why, but using gdk directly is notably faster than the same via cairo x, y = cr.user_to_device(surface.x, surface.y) self.window.draw_pixbuf(None, surface.pixbuf, 0, 0, int(x), int(y), dither=gdk.RGB_DITHER_MAX) else: #print 'Position (screen coordinates):', cr.user_to_device(surface.x, surface.y) cr.set_source_pixbuf(surface.pixbuf, round(surface.x), round(surface.y)) pattern = cr.get_source() # We could set interpolation mode here (eg nearest neighbour) #pattern.set_filter(cairo.FILTER_NEAREST) # 1.6s #pattern.set_filter(cairo.FILTER_FAST) # 2.0s #pattern.set_filter(cairo.FILTER_GOOD) # 3.1s #pattern.set_filter(cairo.FILTER_BEST) # 3.1s #pattern.set_filter(cairo.FILTER_BILINEAR) # 3.1s if self.scale > 3.0: # pixelize at high zoom-in levels pattern.set_filter(cairo.FILTER_NEAREST) cr.paint() if self.doc.frame_enabled: # Draw a semi-transparent black overlay for # all the area outside the "document area" cr.save() cr.set_source_rgba(0, 0, 0, 0.6) cr.set_operator(cairo.OPERATOR_OVER) mipmap_factor = 2**mipmap_level frame = self.doc.get_frame() cr.rectangle(frame[0] / mipmap_factor, frame[1] / mipmap_factor, frame[2] / mipmap_factor, frame[3] / mipmap_factor) cr.rectangle(*model_bbox) cr.set_fill_rule(cairo.FILL_RULE_EVEN_ODD) cr.fill() cr.restore() if self.visualize_rendering: # visualize painted bboxes (blue) cr.set_source_rgba(0, 0, random.random(), 0.4) cr.paint()