]> Pileus Git - grits/blobdiff - src/gis-opengl.c
Add preliminary support for points/markers
[grits] / src / gis-opengl.c
index 7114dfa3de942ea29e68eeaf416b2270a4a867ec..0352fce0a75ba8713390b46a165052af0fd9a93a 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "gis-opengl.h"
 #include "roam.h"
-#include "wms.h"
 
 #define FOV_DIST   2000.0
 #define MPPX(dist) (4*dist/FOV_DIST)
@@ -86,6 +85,7 @@ static void set_visuals(GisOpenGL *self)
        gdouble rg   = MAX(0, 1-(elev/20000));
        gdouble blue = MAX(0, 1-(elev/50000));
        glClearColor(MIN(0.65,rg), MIN(0.65,rg), MIN(1,blue), 1.0f);
+       glColor4f(1, 1, 1, 1);
 
        glDisable(GL_ALPHA_TEST);
 
@@ -105,6 +105,8 @@ static void set_visuals(GisOpenGL *self)
 
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        //glShadeModel(GL_FLAT);
+
+       roam_sphere_update_view(self->sphere);
 }
 
 
@@ -196,6 +198,7 @@ static gboolean on_key_press(GisOpenGL *self, GdkEventKey *event, gpointer _)
        gis_view_get_location(self->view, &lat, &lon, &elev);
        pan = MIN(elev/(EARTH_R/2), 30);
        guint kv = event->keyval;
+       gdk_threads_leave();
        if      (kv == GDK_Left  || kv == GDK_h) gis_view_pan(self->view,  0,  -pan, 0);
        else if (kv == GDK_Down  || kv == GDK_j) gis_view_pan(self->view, -pan, 0,   0);
        else if (kv == GDK_Up    || kv == GDK_k) gis_view_pan(self->view,  pan, 0,   0);
@@ -214,32 +217,45 @@ static gboolean on_key_press(GisOpenGL *self, GdkEventKey *event, gpointer _)
        else if (kv == GDK_p) roam_sphere_merge_one(self->sphere);
        else if (kv == GDK_r) roam_sphere_split_merge(self->sphere);
        else if (kv == GDK_u) roam_sphere_update_errors(self->sphere);
+       gdk_threads_enter();
        gtk_widget_queue_draw(GTK_WIDGET(self));
+#else
+       gdk_threads_enter();
 #endif
 
        return TRUE;
 }
 
+static gboolean _update_errors_cb(gpointer sphere)
+{
+       roam_sphere_update_errors(sphere);
+       return FALSE;
+}
 static void on_view_changed(GisView *view,
                gdouble _1, gdouble _2, gdouble _3, GisOpenGL *self)
 {
        g_debug("GisOpenGL: on_view_changed");
+       gdk_threads_enter();
        gis_opengl_begin(self);
        set_visuals(self);
 #ifndef ROAM_DEBUG
-       roam_sphere_update_errors(self->sphere);
+       g_idle_add_full(G_PRIORITY_HIGH_IDLE+30, _update_errors_cb, self->sphere, NULL);
+       //roam_sphere_update_errors(self->sphere);
 #endif
        gis_opengl_redraw(self);
        gis_opengl_end(self);
+       gdk_threads_leave();
 }
 
 static gboolean on_idle(GisOpenGL *self)
 {
        //g_debug("GisOpenGL: on_idle");
+       gdk_threads_enter();
        gis_opengl_begin(self);
        if (roam_sphere_split_merge(self->sphere))
                gis_opengl_redraw(self);
        gis_opengl_end(self);
+       gdk_threads_leave();
        return TRUE;
 }
 
@@ -272,6 +288,123 @@ void gis_opengl_center_position(GisOpenGL *self, gdouble lat, gdouble lon, gdoub
        glTranslatef(0, 0, elev2rad(elev));
 }
 
+void gis_opengl_project(GisOpenGL *self,
+               gdouble lat, gdouble lon, gdouble elev,
+               gdouble *px, gdouble *py, gdouble *pz)
+{
+       gdouble x, y, z;
+       lle2xyz(lat, lon, elev, &x, &y, &z);
+       gluProject(x, y, z,
+               self->sphere->view->model,
+               self->sphere->view->proj,
+               self->sphere->view->view,
+               px, py, pz);
+}
+
+void gis_opengl_render_tile(GisOpenGL *self, GisTile *tile)
+{
+       if (!tile || !tile->data)
+               return;
+       GList *triangles = roam_sphere_get_intersect(self->sphere,
+                       tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
+       if (!triangles)
+               g_warning("GisOpenGL: render_tiles - No triangles to draw: edges=%f,%f,%f,%f",
+                       tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
+       //g_message("rendering %4d triangles for tile edges=%7.2f,%7.2f,%7.2f,%7.2f",
+       //              g_list_length(triangles), tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
+       for (GList *cur = triangles; cur; cur = cur->next) {
+               RoamTriangle *tri = cur->data;
+
+               gdouble lat[3] = {tri->p.r->lat, tri->p.m->lat, tri->p.l->lat};
+               gdouble lon[3] = {tri->p.r->lon, tri->p.m->lon, tri->p.l->lon};
+
+               if (lon[0] < -90 || lon[1] < -90 || lon[2] < -90) {
+                       if (lon[0] > 90) lon[0] -= 360;
+                       if (lon[1] > 90) lon[1] -= 360;
+                       if (lon[2] > 90) lon[2] -= 360;
+               }
+
+               gdouble n = tile->edge.n;
+               gdouble s = tile->edge.s;
+               gdouble e = tile->edge.e;
+               gdouble w = tile->edge.w;
+
+               gdouble londist = e - w;
+               gdouble latdist = n - s;
+
+               gdouble xy[][3] = {
+                       {(lon[0]-w)/londist, 1-(lat[0]-s)/latdist},
+                       {(lon[1]-w)/londist, 1-(lat[1]-s)/latdist},
+                       {(lon[2]-w)/londist, 1-(lat[2]-s)/latdist},
+               };
+
+               glEnable(GL_TEXTURE_2D);
+               glBindTexture(GL_TEXTURE_2D, *(guint*)tile->data);
+               glBegin(GL_TRIANGLES);
+               glNormal3dv(tri->p.r->norm); glTexCoord2dv(xy[0]); glVertex3dv((double*)tri->p.r);
+               glNormal3dv(tri->p.m->norm); glTexCoord2dv(xy[1]); glVertex3dv((double*)tri->p.m);
+               glNormal3dv(tri->p.l->norm); glTexCoord2dv(xy[2]); glVertex3dv((double*)tri->p.l);
+               glEnd();
+       }
+       g_list_free(triangles);
+}
+
+void gis_opengl_render_tiles(GisOpenGL *opengl, GisTile *tile)
+{
+       /* Only render children if possible */
+       gboolean has_children = TRUE;
+       GisTile *child;
+       gis_tile_foreach(tile, child)
+               if (!child || !child->data)
+                       has_children = FALSE;
+       if (has_children)
+               /* Only render children */
+               gis_tile_foreach(tile, child)
+                       gis_opengl_render_tiles(opengl, child);
+       else
+               /* No children, render this tile */
+               gis_opengl_render_tile(opengl, tile);
+}
+
+void gis_opengl_set_height_func(GisOpenGL *self, GisTile *tile,
+               RoamHeightFunc height_func, gpointer user_data, gboolean update)
+{
+       if (!tile)
+               return;
+       /* TODO: get points? */
+       GList *triangles = roam_sphere_get_intersect(self->sphere,
+                       tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
+       for (GList *cur = triangles; cur; cur = cur->next) {
+               RoamTriangle *tri = cur->data;
+               RoamPoint *points[] = {tri->p.l, tri->p.m, tri->p.r, tri->split};
+               for (int i = 0; i < G_N_ELEMENTS(points); i++) {
+                       points[i]->height_func = height_func;
+                       points[i]->height_data = user_data;
+                       roam_point_update_height(points[i]);
+               }
+       }
+       g_list_free(triangles);
+}
+
+static void _gis_opengl_clear_height_func_rec(RoamTriangle *root)
+{
+       if (!root)
+               return;
+       RoamPoint *points[] = {root->p.l, root->p.m, root->p.r, root->split};
+       for (int i = 0; i < G_N_ELEMENTS(points); i++) {
+               points[i]->height_func = NULL;
+               points[i]->height_data = NULL;
+               roam_point_update_height(points[i]);
+       }
+       _gis_opengl_clear_height_func_rec(root->kids[0]);
+       _gis_opengl_clear_height_func_rec(root->kids[1]);
+}
+void gis_opengl_clear_height_func(GisOpenGL *self)
+{
+       for (int i = 0; i < G_N_ELEMENTS(self->sphere->roots); i++)
+               _gis_opengl_clear_height_func_rec(self->sphere->roots[i]);
+}
+
 void gis_opengl_redraw(GisOpenGL *self)
 {
        g_debug("GisOpenGL: redraw");
@@ -331,7 +464,8 @@ static void gis_opengl_init(GisOpenGL *self)
        g_object_set(self, "can-focus", TRUE, NULL);
 
 #ifndef ROAM_DEBUG
-       self->sm_source = g_timeout_add(10, (GSourceFunc)on_idle, self);
+       self->sm_source[0] = g_timeout_add_full(G_PRIORITY_HIGH_IDLE+30, 33,  (GSourceFunc)on_idle, self, NULL);
+       self->sm_source[1] = g_timeout_add_full(G_PRIORITY_HIGH_IDLE+10, 500, (GSourceFunc)on_idle, self, NULL);
 #endif
 
        g_signal_connect(self, "realize",            G_CALLBACK(on_realize),      NULL);
@@ -353,9 +487,13 @@ static void gis_opengl_dispose(GObject *_self)
 {
        g_debug("GisOpenGL: dispose");
        GisOpenGL *self = GIS_OPENGL(_self);
-       if (self->sm_source) {
-               g_source_remove(self->sm_source);
-               self->sm_source = 0;
+       if (self->sm_source[0]) {
+               g_source_remove(self->sm_source[0]);
+               self->sm_source[0] = 0;
+       }
+       if (self->sm_source[1]) {
+               g_source_remove(self->sm_source[1]);
+               self->sm_source[1] = 0;
        }
        if (self->sphere) {
                roam_sphere_free(self->sphere);