Address pcwalton's nits; automatic rendering after scrolling

This commit is contained in:
eschweic 2013-07-10 17:08:09 -07:00
parent cc816c04b9
commit 8a0878a41c
2 changed files with 99 additions and 93 deletions

View file

@ -235,6 +235,64 @@ impl CompositorTask {
let zoom_action = @mut false;
let zoom_time = @mut 0f;
// Extract tiles from the given quadtree and build and display the render tree.
let build_layer_tree: @fn(&Quadtree<~LayerBuffer>) = |quad: &Quadtree<~LayerBuffer>| {
// Iterate over the children of the container layer.
let mut current_layer_child = root_layer.first_child;
let all_tiles = quad.get_all_tiles();
for all_tiles.iter().advance |buffer| {
let width = buffer.screen_pos.size.width as uint;
let height = buffer.screen_pos.size.height as uint;
debug!("osmain: compositing buffer rect %?", &buffer.rect);
// Find or create a texture layer.
let texture_layer;
current_layer_child = match current_layer_child {
None => {
debug!("osmain: adding new texture layer");
texture_layer = @mut TextureLayer::new(@buffer.draw_target.clone() as @TextureManager,
buffer.screen_pos.size);
root_layer.add_child(TextureLayerKind(texture_layer));
None
}
Some(TextureLayerKind(existing_texture_layer)) => {
texture_layer = existing_texture_layer;
texture_layer.manager = @buffer.draw_target.clone() as @TextureManager;
// Move on to the next sibling.
do current_layer_child.get().with_common |common| {
common.next_sibling
}
}
Some(_) => fail!(~"found unexpected layer kind"),
};
let origin = buffer.rect.origin;
let origin = Point2D(origin.x as f32, origin.y as f32);
// Set the layer's transform.
let transform = identity().translate(origin.x * *world_zoom, origin.y * *world_zoom, 0.0);
let transform = transform.scale(width as f32 * *world_zoom / buffer.resolution, height as f32 * *world_zoom / buffer.resolution, 1.0);
texture_layer.common.set_transform(transform);
}
// Delete leftover layers
while current_layer_child.is_some() {
let trash = current_layer_child.get();
do current_layer_child.get().with_common |common| {
current_layer_child = common.next_sibling;
}
root_layer.remove_child(trash);
}
// Reset zoom
*local_zoom = 1f32;
root_layer.common.set_transform(identity().translate(-world_offset.x,
-world_offset.y,
0.0));
*recomposite = true;
};
let ask_for_tiles: @fn() = || {
match *quadtree {
@ -256,7 +314,7 @@ impl CompositorTask {
}
}
} else if redisplay {
// TODO: move display code to its own closure and call that here
build_layer_tree(quad);
}
}
_ => {
@ -313,11 +371,6 @@ impl CompositorTask {
}
WindowMouseUpEvent(button, layer_mouse_point) => {
// FIXME: this should happen on a scroll/zoom event instead,
// but is here temporarily to prevent request floods to the renderer
ask_for_tiles();
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
}
}
@ -371,17 +424,16 @@ impl CompositorTask {
Some(pipeline_id) => if id != pipeline_id { loop; },
None => { loop; },
}
debug!("osmain: received new frame");
debug!("osmain: received new frame");
let quad;
match *quadtree {
Some(ref mut q) => quad = q,
None => fail!("Compositor: given paint command with no quadtree initialized"),
}
*page_size = Size2D(new_size.width as f32, new_size.height as f32);
let new_layer_buffer_set = new_layer_buffer_set.get();
for new_layer_buffer_set.buffers.iter().advance |buffer| {
// FIXME: Don't copy the buffers here
@ -389,67 +441,12 @@ impl CompositorTask {
*world_zoom, ~buffer.clone());
}
// Iterate over the children of the container layer.
let mut current_layer_child = root_layer.first_child;
*page_size = Size2D(new_size.width as f32, new_size.height as f32);
let all_tiles = quad.get_all_tiles();
for all_tiles.iter().advance |buffer| {
let width = buffer.screen_pos.size.width as uint;
let height = buffer.screen_pos.size.height as uint;
debug!("osmain: compositing buffer rect %?", &buffer.rect);
// Find or create a texture layer.
let texture_layer;
current_layer_child = match current_layer_child {
None => {
debug!("osmain: adding new texture layer");
texture_layer = @mut TextureLayer::new(@buffer.draw_target.clone() as @TextureManager,
buffer.screen_pos.size);
root_layer.add_child(TextureLayerKind(texture_layer));
None
}
Some(TextureLayerKind(existing_texture_layer)) => {
texture_layer = existing_texture_layer;
texture_layer.manager = @buffer.draw_target.clone() as @TextureManager;
// Move on to the next sibling.
do current_layer_child.get().with_common |common| {
common.next_sibling
}
}
Some(_) => fail!(~"found unexpected layer kind"),
};
let origin = buffer.rect.origin;
let origin = Point2D(origin.x as f32, origin.y as f32);
// Set the layer's transform.
let transform = identity().translate(origin.x * *world_zoom, origin.y * *world_zoom, 0.0);
let transform = transform.scale(width as f32 * *world_zoom / buffer.resolution, height as f32 * *world_zoom / buffer.resolution, 1.0);
texture_layer.common.set_transform(transform);
}
// Delete leftover layers
while current_layer_child.is_some() {
let trash = current_layer_child.get();
do current_layer_child.get().with_common |common| {
current_layer_child = common.next_sibling;
}
root_layer.remove_child(trash);
}
// Reset zoom
*local_zoom = 1f32;
root_layer.common.set_transform(identity().translate(-world_offset.x,
-world_offset.y,
0.0));
build_layer_tree(quad);
// TODO: Recycle the old buffers; send them back to the renderer to reuse if
// it wishes.
*recomposite = true;
}
}
}
@ -499,7 +496,7 @@ impl CompositorTask {
// FIXME: ask_for_tiles() should be called here, but currently this sends a flood of requests
// to the renderer, which slows the application dramatically. Instead, ask_for_tiles() is only
// called on a click event.
// ask_for_tiles();
ask_for_tiles();
*recomposite = true;
}

View file

@ -23,12 +23,14 @@ pub struct Quadtree<T> {
struct QuadtreeNode<T> {
/// The tile belonging to this node. Note that parent nodes can have tiles.
tile: Option<T>,
/// The positiong of the node in page coordinates.
/// The position of the node in page coordinates.
origin: Point2D<f32>,
/// The width and hight of the node in page coordinates.
/// The width and height of the node in page coordinates.
size: f32,
/// The node's children.
quadrants: [Option<~QuadtreeNode<T>>, ..4],
/// If this node is marked for rendering
render_flag: bool,
}
priv enum Quadrant {
@ -53,6 +55,7 @@ impl<T> Quadtree<T> {
origin: Point2D(x as f32, y as f32),
size: size as f32,
quadrants: [None, None, None, None],
render_flag: false,
},
max_tile_size: tile_size,
}
@ -71,7 +74,7 @@ impl<T> Quadtree<T> {
self.root.add_tile(x as f32 / scale, y as f32 / scale, tile, self.max_tile_size as f32 / scale);
}
/// Get the tile rect in screen and page coordinates for a given pixel position
pub fn get_tile_rect(&self, x: uint, y: uint, scale: f32) -> BufferRequest {
pub fn get_tile_rect(&mut self, x: uint, y: uint, scale: f32) -> BufferRequest {
self.root.get_tile_rect(x as f32 / scale, y as f32 / scale, scale, self.max_tile_size as f32 / scale)
}
/// Get all the tiles in the tree
@ -96,10 +99,10 @@ impl<T> Quadtree<T> {
valid, scale, self.max_tile_size as f32 / scale)
}
/// Generate html to visualize the tree
/// Generate html to visualize the tree. For debugging purposes only.
pub fn get_html(&self) -> ~str {
let header = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> <html xmlns=\"http://www.w3.org/1999/xhtml\">";
fmt!("%s<body>%s</body></html>", header, self.root.get_html())
static HEADER: &'static str = "<!DOCTYPE html><html>";
fmt!("%s<body>%s</body></html>", HEADER, self.root.get_html())
}
}
@ -112,6 +115,7 @@ impl<T> QuadtreeNode<T> {
origin: Point2D(x, y),
size: size,
quadrants: [None, None, None, None],
render_flag: false,
}
}
@ -149,7 +153,7 @@ impl<T> QuadtreeNode<T> {
let mut ret = ~[];
match self.tile {
Some (ref tile) => ret = ~[tile],
Some(ref tile) => ret = ~[tile],
None => {}
}
@ -180,6 +184,7 @@ impl<T> QuadtreeNode<T> {
for quads.iter().advance |quad| {
self.quadrants[*quad as int] = None;
}
self.render_flag = false;
} else { // Send tile to children
let quad = self.get_quadrant(x, y);
match self.quadrants[quad as int] {
@ -216,7 +221,7 @@ impl<T> QuadtreeNode<T> {
}
/// Get a tile rect in screen and page coords for a given position in page coords
fn get_tile_rect(&self, x: f32, y: f32, scale: f32, tile_size: f32) -> BufferRequest {
fn get_tile_rect(&mut self, x: f32, y: f32, scale: f32, tile_size: f32) -> BufferRequest {
if x >= self.origin.x + self.size || x < self.origin.x
|| y >= self.origin.y + self.size || y < self.origin.y {
fail!("Quadtree: Tried to query a tile rect outside of range");
@ -230,24 +235,25 @@ impl<T> QuadtreeNode<T> {
Rect(Point2D(self.origin.x, self.origin.y), Size2D(self.size, self.size)));
}
let index = self.get_quadrant(x,y) as int;
match self.quadrants[index] {
let quad = self.get_quadrant(x,y);
match self.quadrants[quad as int] {
None => {
// Calculate where the new tile should go
let factor = self.size / tile_size;
let divisor = next_power_of_two(factor.ceil() as uint);
let new_size_page = self.size / (divisor as f32);
let new_size_pixel = (new_size_page * scale).ceil() as uint;
let new_x_page = self.origin.x + new_size_page * ((x - self.origin.x) / new_size_page).floor();
let new_y_page = self.origin.y + new_size_page * ((y - self.origin.y) / new_size_page).floor();
let new_x_pixel = (new_x_page * scale).ceil() as uint;
let new_y_pixel = (new_y_page * scale).ceil() as uint;
BufferRequest(Rect(Point2D(new_x_pixel, new_y_pixel), Size2D(new_size_pixel, new_size_pixel)),
Rect(Point2D(new_x_page, new_y_page), Size2D(new_size_page, new_size_page)))
let new_size = self.size / 2.0;
let new_x = match quad {
TL | BL => self.origin.x,
TR | BR => self.origin.x + new_size,
};
let new_y = match quad {
TL | TR => self.origin.y,
BL | BR => self.origin.y + new_size,
};
let mut c = ~QuadtreeNode::new_child(new_x, new_y, new_size);
c.render_flag = true;
let result = c.get_tile_rect(x, y, scale, tile_size);
self.quadrants[quad as int] = Some(c);
result
}
Some(ref child) => child.get_tile_rect(x, y, scale, tile_size),
Some(ref mut child) => child.get_tile_rect(x, y, scale, tile_size),
}
}
@ -354,6 +360,9 @@ impl<T> QuadtreeNode<T> {
}
return (~[], redisplay);
}
None if self.render_flag => {
return(~[], false);
}
_ => {
return (~[self.get_tile_rect(s_x, s_y, scale, tile_size)], false);
}