mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
Move buffer requests to quadtree; add remove_tile() to quadtree; automatic rerendering after pinch-zoom
This commit is contained in:
parent
435941e932
commit
cc816c04b9
3 changed files with 281 additions and 63 deletions
|
@ -178,7 +178,7 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
|||
|
||||
// Divide up the layer into tiles.
|
||||
do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) {
|
||||
for tiles.each |tile| {
|
||||
for tiles.iter().advance |tile| {
|
||||
let width = tile.screen_rect.size.width;
|
||||
let height = tile.screen_rect.size.height;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ use servo_msg::compositor_msg::{RenderListener, LayerBuffer, LayerBufferSet, Ren
|
|||
use servo_msg::compositor_msg::{ReadyState, ScriptListener};
|
||||
use servo_msg::constellation_msg::{CompositorAck, ConstellationChan};
|
||||
use servo_msg::constellation_msg;
|
||||
use gfx::render_task::{RenderChan, ReRenderMsg, BufferRequest};
|
||||
use gfx::render_task::{RenderChan, ReRenderMsg};
|
||||
|
||||
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
|
||||
use azure::azure::AzGLContext;
|
||||
|
@ -28,6 +28,7 @@ use extra::timer;
|
|||
use geom::matrix::identity;
|
||||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::rect::Rect;
|
||||
use layers::layers::{ARGB32Format, ContainerLayer, ContainerLayerKind, Format};
|
||||
use layers::layers::{ImageData, WithDataFn};
|
||||
use layers::layers::{TextureLayerKind, TextureLayer, TextureManager};
|
||||
|
@ -40,6 +41,7 @@ use servo_util::time::ProfilerChan;
|
|||
use extra::arc;
|
||||
pub use windowing;
|
||||
|
||||
use extra::time::precise_time_s;
|
||||
use compositing::quadtree::Quadtree;
|
||||
mod quadtree;
|
||||
|
||||
|
@ -229,44 +231,21 @@ impl CompositorTask {
|
|||
// FIXME: This should be one-per-layer
|
||||
let quadtree: @mut Option<Quadtree<~LayerBuffer>> = @mut None;
|
||||
|
||||
// Keeps track of if we have performed a zoom event and how recently.
|
||||
let zoom_action = @mut false;
|
||||
let zoom_time = @mut 0f;
|
||||
|
||||
|
||||
let ask_for_tiles: @fn() = || {
|
||||
match *quadtree {
|
||||
Some(ref quad) => {
|
||||
// FIXME: find a better way to get the tile size
|
||||
// currently tiles that need to be updated can be missed
|
||||
let mut tile_size = quad.get_tile_size();
|
||||
let mut tile_request = ~[]; //FIXME: try not to allocate if possible
|
||||
|
||||
let mut y = world_offset.y as uint;
|
||||
while y < world_offset.y as uint + window_size.height &&
|
||||
y <= (page_size.height * *world_zoom) as uint {
|
||||
let mut x = world_offset.x as uint;
|
||||
while x < world_offset.x as uint + window_size.width &&
|
||||
x <= (page_size.width * *world_zoom) as uint {
|
||||
match *(quad.get_tile(x, y, *world_zoom)) {
|
||||
Some(ref current_tile) => {
|
||||
if current_tile.resolution == *world_zoom {
|
||||
x += tile_size;
|
||||
loop; // we already have this tile
|
||||
}
|
||||
}
|
||||
None => {} // fall through
|
||||
}
|
||||
let (tile_screen_pos, tile_page_pos) = quad.get_tile_rect(x, y, *world_zoom);
|
||||
tile_size = tile_screen_pos.size.width;
|
||||
x = tile_screen_pos.origin.x;
|
||||
y = tile_screen_pos.origin.y;
|
||||
|
||||
// TODO: clamp tiles to page bounds
|
||||
// TODO: add null buffer/checkerboard tile to stop a flood of requests
|
||||
debug!("requesting tile: (%?, %?): %?", x, y, tile_size);
|
||||
tile_request.push(BufferRequest(tile_screen_pos, tile_page_pos));
|
||||
|
||||
x += tile_size;
|
||||
}
|
||||
y += tile_size;
|
||||
}
|
||||
Some(ref mut quad) => {
|
||||
let valid = |tile: &~LayerBuffer| -> bool {
|
||||
tile.resolution == *world_zoom
|
||||
};
|
||||
let (tile_request, redisplay) = quad.get_tile_rects(Rect(Point2D(world_offset.x as int,
|
||||
world_offset.y as int),
|
||||
*window_size), valid, *world_zoom);
|
||||
|
||||
if !tile_request.is_empty() {
|
||||
match *render_chan {
|
||||
Some(ref chan) => {
|
||||
|
@ -276,6 +255,8 @@ impl CompositorTask {
|
|||
println("Warning: Compositor: Cannot send tile request, no render chan initialized");
|
||||
}
|
||||
}
|
||||
} else if redisplay {
|
||||
// TODO: move display code to its own closure and call that here
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -297,7 +278,7 @@ impl CompositorTask {
|
|||
let layout_chan_clone = layout_chan.clone();
|
||||
// Hook the windowing system's resize callback up to the resize rate limiter.
|
||||
do window.set_resize_callback |width, height| {
|
||||
let new_size = Size2D(width as uint, height as uint);
|
||||
let new_size = Size2D(width as int, height as int);
|
||||
if *window_size != new_size {
|
||||
debug!("osmain: window resized to %ux%u", width, height);
|
||||
*window_size = new_size;
|
||||
|
@ -402,22 +383,20 @@ impl CompositorTask {
|
|||
*page_size = Size2D(new_size.width as f32, new_size.height as f32);
|
||||
|
||||
let new_layer_buffer_set = new_layer_buffer_set.get();
|
||||
|
||||
// Iterate over the children of the container layer.
|
||||
let mut current_layer_child = root_layer.first_child;
|
||||
|
||||
// Replace the image layer data with the buffer data.
|
||||
// let buffers = util::replace(&mut new_layer_buffer_set.buffers, ~[]);
|
||||
|
||||
for new_layer_buffer_set.buffers.iter().advance |buffer| {
|
||||
// FIXME: Don't copy the buffers here
|
||||
quad.add_tile(buffer.screen_pos.origin.x, buffer.screen_pos.origin.y,
|
||||
*world_zoom, ~buffer.clone());
|
||||
}
|
||||
|
||||
for quad.get_all_tiles().each |buffer| {
|
||||
|
||||
// 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.
|
||||
|
@ -529,6 +508,8 @@ impl CompositorTask {
|
|||
|
||||
// When the user pinch-zooms, scale the layer
|
||||
do window.set_zoom_callback |magnification| {
|
||||
*zoom_action = true;
|
||||
*zoom_time = precise_time_s();
|
||||
let old_world_zoom = *world_zoom;
|
||||
|
||||
// Determine zoom amount
|
||||
|
@ -560,11 +541,6 @@ impl CompositorTask {
|
|||
window_size.height as f32 / -2f32,
|
||||
0.0);
|
||||
root_layer.common.set_transform(zoom_transform);
|
||||
|
||||
// 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();
|
||||
|
||||
*recomposite = true;
|
||||
}
|
||||
|
@ -583,6 +559,13 @@ impl CompositorTask {
|
|||
}
|
||||
|
||||
timer::sleep(&uv_global_loop::get(), 100);
|
||||
|
||||
// If a pinch-zoom happened recently, ask for tiles at the new resolution
|
||||
if *zoom_action && precise_time_s() - *zoom_time > 0.3 {
|
||||
*zoom_action = false;
|
||||
ask_for_tiles();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
self.shutdown_chan.send(())
|
||||
|
|
|
@ -9,6 +9,8 @@ use geom::point::Point2D;
|
|||
use geom::size::Size2D;
|
||||
use geom::rect::Rect;
|
||||
use std::uint::{div_ceil, next_power_of_two};
|
||||
use std::vec::build_sized;
|
||||
use gfx::render_task::BufferRequest;
|
||||
|
||||
/// Parent to all quadtree nodes. Stores variables needed at all levels. All method calls
|
||||
/// at this level are in pixel coordinates.
|
||||
|
@ -69,13 +71,31 @@ 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) -> (Rect<uint>, Rect<f32>) {
|
||||
pub fn get_tile_rect(&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
|
||||
pub fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
||||
self.root.get_all_tiles()
|
||||
}
|
||||
/// Ask a tile to be deleted from the quadtree. This tries to delete a tile that is far from the
|
||||
/// given point in pixel coordinates.
|
||||
pub fn remove_tile(&mut self, x: uint, y: uint, scale: f32) {
|
||||
self.root.remove_tile(x as f32 / scale, y as f32 / scale);
|
||||
}
|
||||
/// Given a window rect in page coordinates and a function to check if an existing tile is "valid"
|
||||
/// (i.e. is the correct resolution), this function returns a list of BufferRequests for tiles that
|
||||
/// need to be rendered. It also returns a boolean if the window needs to be redisplayed, i.e. if
|
||||
/// no tiles need to be rendered, but the display tree needs to be rebuilt. This can occur when the
|
||||
/// user zooms out and cached tiles need to be displayed on top of higher resolution tiles.
|
||||
pub fn get_tile_rects(&mut self, window: Rect<int>, valid: &fn(&T) -> bool, scale: f32) ->
|
||||
(~[BufferRequest], bool) {
|
||||
|
||||
self.root.get_tile_rects(Rect(Point2D(window.origin.x as f32 / scale, window.origin.y as f32 / scale),
|
||||
Size2D(window.size.width as f32 / scale, window.size.height as f32 / scale)),
|
||||
valid, scale, self.max_tile_size as f32 / scale)
|
||||
}
|
||||
|
||||
/// Generate html to visualize the tree
|
||||
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\">";
|
||||
|
@ -125,7 +145,6 @@ impl<T> QuadtreeNode<T> {
|
|||
}
|
||||
|
||||
/// Get all tiles in the tree, parents first.
|
||||
/// FIXME: this could probably be more efficient
|
||||
fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
||||
let mut ret = ~[];
|
||||
|
||||
|
@ -134,7 +153,7 @@ impl<T> QuadtreeNode<T> {
|
|||
None => {}
|
||||
}
|
||||
|
||||
for self.quadrants.each |quad| {
|
||||
for self.quadrants.iter().advance |quad| {
|
||||
match *quad {
|
||||
Some(ref child) => ret = ret + child.get_all_tiles(),
|
||||
None => {}
|
||||
|
@ -154,9 +173,11 @@ impl<T> QuadtreeNode<T> {
|
|||
fail!("Quadtree: Tried to add tile to invalid region");
|
||||
}
|
||||
|
||||
if self.size <= tile_size { // We are the child
|
||||
if self.size <= tile_size { // We are the child
|
||||
self.tile = Some(tile);
|
||||
for [TL, TR, BL, BR].each |quad| {
|
||||
// FIXME: This should be inline, but currently won't compile
|
||||
let quads = [TL, TR, BL, BR];
|
||||
for quads.iter().advance |quad| {
|
||||
self.quadrants[*quad as int] = None;
|
||||
}
|
||||
} else { // Send tile to children
|
||||
|
@ -195,7 +216,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) -> (Rect<uint>, Rect<f32>) {
|
||||
fn get_tile_rect(&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");
|
||||
|
@ -205,8 +226,8 @@ impl<T> QuadtreeNode<T> {
|
|||
let self_x = (self.origin.x * scale).ceil() as uint;
|
||||
let self_y = (self.origin.y * scale).ceil() as uint;
|
||||
let self_size = (self.size * scale).ceil() as uint;
|
||||
return (Rect(Point2D(self_x, self_y), Size2D(self_size, self_size)),
|
||||
Rect(Point2D(self.origin.x, self.origin.y), Size2D(self.size, self.size)));
|
||||
return BufferRequest(Rect(Point2D(self_x, self_y), Size2D(self_size, self_size)),
|
||||
Rect(Point2D(self.origin.x, self.origin.y), Size2D(self.size, self.size)));
|
||||
}
|
||||
|
||||
let index = self.get_quadrant(x,y) as int;
|
||||
|
@ -223,13 +244,224 @@ impl<T> QuadtreeNode<T> {
|
|||
let new_x_pixel = (new_x_page * scale).ceil() as uint;
|
||||
let new_y_pixel = (new_y_page * scale).ceil() as uint;
|
||||
|
||||
(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)))
|
||||
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)))
|
||||
}
|
||||
Some(ref child) => child.get_tile_rect(x, y, scale, tile_size),
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes a tile that is far from the given input point in page coords. Returns true if the child
|
||||
/// has no tiles and needs to be deleted.
|
||||
fn remove_tile(&mut self, x: f32, y: f32) -> bool {
|
||||
match (&self.tile, &self.quadrants) {
|
||||
(&Some(_), &[None, None, None, None]) => {
|
||||
self.tile = None;
|
||||
return true;
|
||||
}
|
||||
(&Some(_), _) => {
|
||||
self.tile = None;
|
||||
return false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// This is a hacky heuristic to find a tile that is "far away". There are better methods.
|
||||
let quad = self.get_quadrant(x, y);
|
||||
let my_child = match quad {
|
||||
TL => {
|
||||
match (&self.quadrants[BR as int], &self.quadrants[BL as int], &self.quadrants[TR as int]) {
|
||||
(&Some(_), _, _) => BR,
|
||||
(&None, &Some(_), _) => BL,
|
||||
(&None, &None, &Some(_)) => TR,
|
||||
_ => TL,
|
||||
}
|
||||
}
|
||||
TR => {
|
||||
match (&self.quadrants[BL as int], &self.quadrants[BR as int], &self.quadrants[TL as int]) {
|
||||
(&Some(_), _, _) => BL,
|
||||
(&None, &Some(_), _) => BR,
|
||||
(&None, &None, &Some(_)) => TL,
|
||||
_ => TR,
|
||||
}
|
||||
}
|
||||
BL => {
|
||||
match (&self.quadrants[TR as int], &self.quadrants[TL as int], &self.quadrants[BR as int]) {
|
||||
(&Some(_), _, _) => TR,
|
||||
(&None, &Some(_), _) => TL,
|
||||
(&None, &None, &Some(_)) => BR,
|
||||
_ => BL,
|
||||
}
|
||||
}
|
||||
BR => {
|
||||
match (&self.quadrants[TL as int], &self.quadrants[TR as int], &self.quadrants[BL as int]) {
|
||||
(&Some(_), _, _) => TL,
|
||||
(&None, &Some(_), _) => TR,
|
||||
(&None, &None, &Some(_)) => BL,
|
||||
_ => BR,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match self.quadrants[my_child as int] {
|
||||
Some(ref mut child) if !child.remove_tile(x, y) => {
|
||||
return false;
|
||||
}
|
||||
Some(_) => {} // fall through
|
||||
None => fail!("Quadtree: child query failure"),
|
||||
}
|
||||
|
||||
// child.remove_tile() returned true
|
||||
self.quadrants[my_child as int] = None;
|
||||
match self.quadrants {
|
||||
[None, None, None, None] => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a window rect in page coordinates and a tile validation function, returns a BufferRequest array
|
||||
/// and a redisplay boolean. See QuadTree function description for more details.
|
||||
fn get_tile_rects(&mut self, window: Rect<f32>, valid: &fn(&T) -> bool, scale: f32, tile_size: f32) ->
|
||||
(~[BufferRequest], bool) {
|
||||
|
||||
let w_x = window.origin.x;
|
||||
let w_y = window.origin.y;
|
||||
let w_width = window.size.width;
|
||||
let w_height = window.size.height;
|
||||
let s_x = self.origin.x;
|
||||
let s_y = self.origin.y;
|
||||
let s_size = self.size;
|
||||
|
||||
if w_x < s_x || w_x + w_width > s_x + s_size
|
||||
|| w_y < s_y || w_y + w_height > s_y + s_size {
|
||||
println(fmt!("window: %?, %?, %?, %?; self: %?, %?, %?", w_x, w_y, w_width, w_height, s_x, s_y, s_size));
|
||||
fail!("Quadtree: tried to query an invalid tile rect");
|
||||
}
|
||||
|
||||
if s_size <= tile_size { // We are the child
|
||||
match self.tile {
|
||||
Some(ref tile) if valid(tile) => {
|
||||
let redisplay = match self.quadrants {
|
||||
[None, None, None, None] => false,
|
||||
_ => true,
|
||||
};
|
||||
if redisplay {
|
||||
// FIXME: This should be inline, but currently won't compile
|
||||
let quads = [TL, TR, BL, BR];
|
||||
for quads.iter().advance |quad| {
|
||||
self.quadrants[*quad as int] = None;
|
||||
}
|
||||
}
|
||||
return (~[], redisplay);
|
||||
}
|
||||
_ => {
|
||||
return (~[self.get_tile_rect(s_x, s_y, scale, tile_size)], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, we either have children or will have children
|
||||
let w_tl_quad = self.get_quadrant(w_x, w_y);
|
||||
let w_br_quad = self.get_quadrant(w_x + w_width, w_y + w_height);
|
||||
|
||||
// Figure out which quadrants the window is in
|
||||
let builder = |push: &fn(Quadrant)| {
|
||||
match (w_tl_quad, w_br_quad) {
|
||||
(tl, br) if tl as int == br as int => {
|
||||
push(tl);
|
||||
}
|
||||
(TL, br) => {
|
||||
push(TL);
|
||||
push(br);
|
||||
match br {
|
||||
BR => {
|
||||
push(TR);
|
||||
push(BL);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
(tl, br) => {
|
||||
push(tl);
|
||||
push(br);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let quads_to_check = build_sized(4, builder);
|
||||
|
||||
let mut ret = ~[];
|
||||
let mut redisplay = false;
|
||||
|
||||
for quads_to_check.iter().advance |quad| {
|
||||
match self.quadrants[*quad as int] {
|
||||
Some(ref mut child) => {
|
||||
// Recurse into child
|
||||
let new_window = match *quad {
|
||||
TL => Rect(window.origin,
|
||||
Size2D(w_width.min(&(s_x + s_size / 2.0 - w_x)),
|
||||
w_height.min(&(s_y + s_size / 2.0 - w_y)))),
|
||||
TR => Rect(Point2D(w_x.max(&(s_x + s_size / 2.0)),
|
||||
w_y),
|
||||
Size2D(w_width.min(&(w_x + w_width - (s_x + s_size / 2.0))),
|
||||
w_height.min(&(s_y + s_size / 2.0 - w_y)))),
|
||||
BL => Rect(Point2D(w_x,
|
||||
w_y.max(&(s_y + s_size / 2.0))),
|
||||
Size2D(w_width.min(&(s_x + s_size / 2.0 - w_x)),
|
||||
w_height.min(&(w_y + w_height - (s_y + s_size / 2.0))))),
|
||||
BR => Rect(Point2D(w_x.max(&(s_x + s_size / 2.0)),
|
||||
w_y.max(&(s_y + s_size / 2.0))),
|
||||
Size2D(w_width.min(&(w_x + w_width - (s_x + s_size / 2.0))),
|
||||
w_height.min(&(w_y + w_height - (s_y + s_size / 2.0))))),
|
||||
|
||||
};
|
||||
let (c_ret, c_redisplay) = child.get_tile_rects(new_window, |x| valid(x), scale, tile_size);
|
||||
ret = ret + c_ret;
|
||||
redisplay = redisplay || c_redisplay;
|
||||
}
|
||||
None => {
|
||||
// Figure out locations of future children
|
||||
let (x_start, y_start, x_end, y_end) = match *quad {
|
||||
TL => (w_x,
|
||||
w_y,
|
||||
(w_x + w_width).min(&(s_x + s_size / 2.0)),
|
||||
(w_y + w_height).min(&(s_y + s_size / 2.0))),
|
||||
TR => (w_x.max(&(s_x + s_size / 2.0)),
|
||||
w_y,
|
||||
(w_x + w_width + tile_size).min(&(s_x + s_size)),
|
||||
(w_y + w_height).min(&(s_y + s_size / 2.0))),
|
||||
BL => (w_x,
|
||||
w_y.max(&(s_y + s_size / 2.0)),
|
||||
(w_x + w_width).min(&(s_x + s_size / 2.0)),
|
||||
(w_y + w_height + tile_size).min(&(s_y + s_size))),
|
||||
BR => (w_x.max(&(s_x + s_size / 2.0)),
|
||||
w_y.max(&(s_y + s_size / 2.0)),
|
||||
(w_x + w_width + tile_size).min(&(s_x + s_size)),
|
||||
(w_y + w_height + tile_size).min(&(s_y + s_size))),
|
||||
};
|
||||
let size = (((x_end - x_start) / tile_size).ceil() *
|
||||
((y_end - y_start) / tile_size).ceil()) as uint;
|
||||
|
||||
let builder = |push: &fn(BufferRequest)| {
|
||||
let mut y = y_start;
|
||||
while y < y_end {
|
||||
let mut x = x_start;
|
||||
while x < x_end {
|
||||
push(self.get_tile_rect(x, y, scale, tile_size));
|
||||
x = x + tile_size;
|
||||
}
|
||||
y = y + tile_size;
|
||||
}
|
||||
};
|
||||
ret = ret + build_sized(size, builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(ret, redisplay)
|
||||
}
|
||||
|
||||
|
||||
/// Generate html to visualize the tree.
|
||||
/// This is really inefficient, but it's for testing only.
|
||||
fn get_html(&self) -> ~str {
|
||||
|
@ -246,7 +478,9 @@ impl<T> QuadtreeNode<T> {
|
|||
[None, None, None, None] => {}
|
||||
_ => {
|
||||
ret = fmt!("%s<table border=1><tr>", ret);
|
||||
for [TL, TR, BL, BR].each |quad| {
|
||||
// FIXME: This should be inline, but currently won't compile
|
||||
let quads = [TL, TR, BL, BR];
|
||||
for quads.iter().advance |quad| {
|
||||
match self.quadrants[*quad as int] {
|
||||
Some(ref child) => {
|
||||
ret = fmt!("%s<td>%s</td>", ret, child.get_html());
|
||||
|
@ -268,6 +502,7 @@ impl<T> QuadtreeNode<T> {
|
|||
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_add_tile() {
|
||||
let mut t = Quadtree::new(50, 30, 20, 20, 10);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue