From: Andy Spencer Date: Tue, 9 Feb 2010 15:08:07 +0000 (+0000) Subject: Lazy tile splitting X-Git-Tag: v0.4~46 X-Git-Url: http://pileus.org/git/?p=grits;a=commitdiff_plain;h=b5fde541db3eec5aa0b2d7f5b7a0725ad524f84c Lazy tile splitting When a tile is split, only the needed children are loaded. When rendered, the parent tile must render in places of the non-loaded children. --- diff --git a/src/gis-opengl.c b/src/gis-opengl.c index bb20951..4803168 100644 --- a/src/gis-opengl.c +++ b/src/gis-opengl.c @@ -122,12 +122,10 @@ static void _set_visuals(GisOpenGL *opengl) /******************** * Object handleing * ********************/ -static void _draw_tile(GisOpenGL *opengl, GisTile *tile) +static void _draw_tile(GisOpenGL *opengl, GisTile *tile, GList *triangles) { if (!tile || !tile->data) return; - GList *triangles = roam_sphere_get_intersect(opengl->sphere, FALSE, - tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w); if (!triangles) g_warning("GisOpenGL: _draw_tiles - No triangles to draw: edges=%f,%f,%f,%f", tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w); @@ -191,18 +189,41 @@ static void _draw_tile(GisOpenGL *opengl, GisTile *tile) static void _draw_tiles(GisOpenGL *opengl, GisTile *tile) { /* Only draw children if possible */ - gboolean has_children = TRUE; + gboolean has_children = FALSE; GisTile *child; gis_tile_foreach(tile, child) - if (!child || !child->data) - has_children = FALSE; - if (has_children) - /* Only draw children */ - gis_tile_foreach(tile, child) - _draw_tiles(opengl, child); - else - /* No children, draw this tile */ - _draw_tile(opengl, tile); + if (child && child->data) + has_children = TRUE; + + GList *triangles = NULL; + if (has_children) { + /* TODO: simplify this */ + const gdouble rows = G_N_ELEMENTS(tile->children); + const gdouble cols = G_N_ELEMENTS(tile->children[0]); + const gdouble lat_dist = tile->edge.n - tile->edge.s; + const gdouble lon_dist = tile->edge.e - tile->edge.w; + const gdouble lat_step = lat_dist / rows; + const gdouble lon_step = lon_dist / cols; + int row, col; + gis_tile_foreach_index(tile, row, col) { + GisTile *child = tile->children[row][col]; + if (child && child->data) { + _draw_tiles(opengl, child); + } else { + const gdouble n = tile->edge.n-(lat_step*(row+0)); + const gdouble s = tile->edge.n-(lat_step*(row+1)); + const gdouble e = tile->edge.w+(lon_step*(col+1)); + const gdouble w = tile->edge.w+(lon_step*(col+0)); + GList *these = roam_sphere_get_intersect(opengl->sphere, FALSE, n, s, e, w); + triangles = g_list_concat(triangles, these); + } + } + } else { + triangles = roam_sphere_get_intersect(opengl->sphere, FALSE, + tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w); + } + if (triangles) + _draw_tile(opengl, tile, triangles); } static void _draw_marker(GisOpenGL *opengl, GisMarker *marker) @@ -270,6 +291,8 @@ static void _draw_object(GisOpenGL *opengl, GisObject *object) } else if (GIS_IS_CALLBACK(object)) { _draw_callback(opengl, GIS_CALLBACK(object)); } else if (GIS_IS_TILE(object)) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); _draw_tiles(opengl, GIS_TILE(object)); } glPopAttrib(); diff --git a/src/objects/gis-tile.c b/src/objects/gis-tile.c index fe3ff6e..9a2a298 100644 --- a/src/objects/gis-tile.c +++ b/src/objects/gis-tile.c @@ -93,13 +93,14 @@ gchar *gis_tile_get_path(GisTile *child) return g_string_free(path, FALSE); } -static gdouble _gis_tile_get_min_dist(GisTile *tile, - gdouble lat, gdouble lon, gdouble elev) +static gdouble _gis_tile_get_min_dist( + gdouble lat, gdouble lon, gdouble elev, + gdouble n, gdouble s, gdouble e, gdouble w) { - gdouble tlat = lat > tile->edge.n ? tile->edge.n : - lat < tile->edge.s ? tile->edge.s : lat; - gdouble tlon = lon > tile->edge.e ? tile->edge.e : - lon < tile->edge.w ? tile->edge.w : lon; + gdouble tlat = lat > n ? n : + lat < s ? s : lat; + gdouble tlon = lon > e ? e : + lon < w ? w : lon; gdouble telev = 0; // TODO: elevation at rlat,rlon //if (lat == tlat && lon == tlon) // return elev; /* Shortcut? */ @@ -109,21 +110,23 @@ static gdouble _gis_tile_get_min_dist(GisTile *tile, return distd(a, b); } -static gboolean _gis_tile_needs_split(GisTile *tile, - gdouble max_res, gint width, gint height, - gdouble lat, gdouble lon, gdouble elev) +static gboolean _gis_tile_precise( + gdouble lat, gdouble lon, gdouble elev, + gdouble n, gdouble s, gdouble e, gdouble w, + gdouble max_res, gint width, gint height) { - gdouble lat_point = tile->edge.n < 0 ? tile->edge.n : - tile->edge.s > 0 ? tile->edge.s : 0; - gdouble min_dist = _gis_tile_get_min_dist(tile, lat, lon, elev); + gdouble min_dist = _gis_tile_get_min_dist(lat, lon, elev, n, s, e, w); gdouble view_res = MPPX(min_dist); - gdouble lon_dist = tile->edge.e - tile->edge.w; + + gdouble lat_point = n < 0 ? n : s > 0 ? s : 0; + gdouble lon_dist = e - w; gdouble tile_res = ll2m(lon_dist, lat_point)/width; /* This isn't really right, but it helps with memory since we don't (yet?) test if the tile * would be drawn */ gdouble scale = elev / min_dist; view_res /= scale; + //view_res /= 1.4; /* make it a little nicer, not sure why this is needed */ //g_message("tile=(%7.2f %7.2f %7.2f %7.2f) " // "eye=(%9.1f %9.1f %9.1f) " // "elev=%9.1f / dist=%9.1f = %f", @@ -131,9 +134,8 @@ static gboolean _gis_tile_needs_split(GisTile *tile, // lat, lon, elev, // elev, min_dist, scale); - if (tile_res < max_res) - return FALSE; - return view_res < tile_res; + return tile_res < max_res || + tile_res < view_res; } /** @@ -160,23 +162,28 @@ void gis_tile_update(GisTile *root, GisTileLoadFunc load_func, gpointer user_data) { root->atime = time(NULL); - //g_debug("GisTile: update - %p->atime = %u", root, (guint)root->atime); - gdouble lat_dist = root->edge.n - root->edge.s; - gdouble lon_dist = root->edge.e - root->edge.w; - if (_gis_tile_needs_split(root, res, width, height, lat, lon, elev)) { - gdouble lat_step = lat_dist / G_N_ELEMENTS(root->children); - gdouble lon_step = lon_dist / G_N_ELEMENTS(root->children[0]); - int x, y; - gis_tile_foreach_index(root, x, y) { - if (!root->children[x][y]) { - root->children[x][y] = gis_tile_new(root, - root->edge.n-(lat_step*(x+0)), - root->edge.n-(lat_step*(x+1)), - root->edge.w+(lon_step*(y+1)), - root->edge.w+(lon_step*(y+0))); - load_func(root->children[x][y], user_data); + //g_debug("GisTile: update - %p->atime = %u", + // root, (guint)root->atime); + const gdouble rows = G_N_ELEMENTS(root->children); + const gdouble cols = G_N_ELEMENTS(root->children[0]); + const gdouble lat_dist = root->edge.n - root->edge.s; + const gdouble lon_dist = root->edge.e - root->edge.w; + const gdouble lat_step = lat_dist / rows; + const gdouble lon_step = lon_dist / cols; + int row, col; + gis_tile_foreach_index(root, row, col) { + GisTile **child = &root->children[row][col]; + const gdouble n = root->edge.n-(lat_step*(row+0)); + const gdouble s = root->edge.n-(lat_step*(row+1)); + const gdouble e = root->edge.w+(lon_step*(col+1)); + const gdouble w = root->edge.w+(lon_step*(col+0)); + if (!_gis_tile_precise(lat,lon,elev, n,s,e,w, + res,width/cols,height/rows)) { + if (!*child) { + *child = gis_tile_new(root, n,s,e,w); + load_func(*child, user_data); } - gis_tile_update(root->children[x][y], + gis_tile_update(*child, res, width, height, lat, lon, elev, load_func, user_data); diff --git a/src/plugins/elev.c b/src/plugins/elev.c index 3a5c031..5ea94ea 100644 --- a/src/plugins/elev.c +++ b/src/plugins/elev.c @@ -163,8 +163,8 @@ static guint _load_opengl(GdkPixbuf *pixbuf) (alpha ? GL_RGBA : GL_RGB), GL_UNSIGNED_BYTE, pixels); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); g_debug("GisPluginElev: load_opengl %d", opengl); return opengl; diff --git a/src/plugins/map.c b/src/plugins/map.c index 7395ef7..c787224 100644 --- a/src/plugins/map.c +++ b/src/plugins/map.c @@ -88,8 +88,8 @@ static gboolean _load_tile_cb(gpointer _data) (alpha ? GL_RGBA : GL_RGB), GL_UNSIGNED_BYTE, pixels); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glFlush(); tile->data = tex; diff --git a/src/plugins/sat.c b/src/plugins/sat.c index 488a4e5..abe0b24 100644 --- a/src/plugins/sat.c +++ b/src/plugins/sat.c @@ -63,10 +63,10 @@ static gboolean _load_tile_cb(gpointer _data) glPixelStorei(GL_PACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, (alpha ? GL_RGBA : GL_RGB), GL_UNSIGNED_BYTE, pixels); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glFlush(); tile->data = tex; diff --git a/src/roam.c b/src/roam.c index 330c982..94416b9 100644 --- a/src/roam.c +++ b/src/roam.c @@ -851,7 +851,7 @@ static GList *_roam_sphere_get_intersect_rec(RoamTriangle *triangle, GList *list if (debug) g_message("t=%p: %f < %f || %f > %f || %f < %f || %f > %f", triangle, tn, s, ts, n, te, w, tw, e); - if (tn < s || ts > n || te < w || tw > e) { + if (tn <= s || ts >= n || te <= w || tw >= e) { /* No intersect */ if (debug) g_message("no intersect"); return list;