]> Pileus Git - grits/blobdiff - src/roam.c
Add cube GtkGL example
[grits] / src / roam.c
index 21b1393c6c902b0202d045ffed0821826840934c..e58cd1d6e3bbf34f99d555cbbe87dd3f359ce62d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2010 Andy Spencer <andy753421@gmail.com>
+ * Copyright (C) 2009-2011 Andy Spencer <andy753421@gmail.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,8 +21,8 @@
  *
  * A spherical version of the Realtime Optimally-Adapting Meshes (ROAM)
  * algorithm is use for drawing the surface of the planet. ROAM provide a
- * continuous level-of-detail mesh of the planet which is used by #GisOpenGL
- * when drawing surface textures for GisTiles.
+ * continuous level-of-detail mesh of the planet which is used by #GritsOpenGL
+ * when drawing surface textures for GritsTiles.
  *
  * This implementation of the ROAM algorithm is based on an octahedron as the
  * base model.
 #include <glib.h>
 #include <math.h>
 #include <string.h>
-#include <GL/gl.h>
-#include <GL/glu.h>
 
+#include "gtkgl.h"
 #include "gpqueue.h"
-#include "gis-util.h"
+#include "grits-util.h"
 #include "roam.h"
 
 /*
@@ -206,27 +205,10 @@ RoamTriangle *roam_triangle_new(RoamPoint *l, RoamPoint *m, RoamPoint *r,
        //              triangle->split->lat, l->lat);
 
        /* Update normal */
-       double pa[3];
-       double pb[3];
-       pa[0] = triangle->p.l->x - triangle->p.m->x;
-       pa[1] = triangle->p.l->y - triangle->p.m->y;
-       pa[2] = triangle->p.l->z - triangle->p.m->z;
-
-       pb[0] = triangle->p.r->x - triangle->p.m->x;
-       pb[1] = triangle->p.r->y - triangle->p.m->y;
-       pb[2] = triangle->p.r->z - triangle->p.m->z;
-
-       triangle->norm[0] = pa[1] * pb[2] - pa[2] * pb[1];
-       triangle->norm[1] = pa[2] * pb[0] - pa[0] * pb[2];
-       triangle->norm[2] = pa[0] * pb[1] - pa[1] * pb[0];
-
-       double total = sqrt(triangle->norm[0] * triangle->norm[0] +
-                           triangle->norm[1] * triangle->norm[1] +
-                           triangle->norm[2] * triangle->norm[2]);
-
-       triangle->norm[0] /= total;
-       triangle->norm[1] /= total;
-       triangle->norm[2] /= total;
+       crossd3((gdouble*)triangle->p.l,
+               (gdouble*)triangle->p.m,
+               (gdouble*)triangle->p.r, triangle->norm);
+       normd(triangle->norm);
 
        /* Store bounding box, for get_intersect */
        RoamPoint *p[] = {l,m,r};
@@ -319,7 +301,6 @@ static void roam_triangle_sync_neighbors(RoamTriangle *neigh, RoamTriangle *old,
        if      (neigh->t.l == old) neigh->t.l = new;
        else if (neigh->t.b == old) neigh->t.b = new;
        else if (neigh->t.r == old) neigh->t.r = new;
-       else g_assert_not_reached();
 }
 
 static gboolean roam_triangle_visible(RoamTriangle *triangle, RoamSphere *sphere)
@@ -338,6 +319,20 @@ static gboolean roam_triangle_visible(RoamTriangle *triangle, RoamSphere *sphere
                 l->pz < 1 && m->pz < 1 && r->pz < 1;
 }
 
+static gboolean roam_triangle_backface(RoamTriangle *triangle, RoamSphere *sphere)
+{
+       RoamPoint *l = triangle->p.l;
+       RoamPoint *m = triangle->p.m;
+       RoamPoint *r = triangle->p.r;
+       roam_point_update_projection(l, sphere->view);
+       roam_point_update_projection(m, sphere->view);
+       roam_point_update_projection(r, sphere->view);
+       double size = -( l->px * (m->py - r->py) +
+                        m->px * (r->py - l->py) +
+                        r->px * (l->py - m->py) ) / 2.0;
+       return size < 0;
+}
+
 /**
  * roam_triangle_update_errors:
  * @triangle: the triangle
@@ -375,6 +370,12 @@ void roam_triangle_update_errors(RoamTriangle *triangle, RoamSphere *sphere)
 
                /* Size < 0 == backface */
                triangle->error *= size;
+
+               /* Give some preference to "edge" faces */
+               if (roam_triangle_backface(triangle->t.l, sphere) ||
+                   roam_triangle_backface(triangle->t.b, sphere) ||
+                   roam_triangle_backface(triangle->t.r, sphere))
+                       triangle->error *= 50;
        }
 }
 
@@ -554,6 +555,11 @@ void roam_diamond_merge(RoamDiamond *diamond, RoamSphere *sphere)
        b->kids[0] = b->kids[1] = NULL;
 
        /* Add original triangles */
+       roam_triangle_sync_neighbors(s->t.l, sl, s);
+       roam_triangle_sync_neighbors(s->t.r, sr, s);
+       roam_triangle_sync_neighbors(b->t.l, bl, b);
+       roam_triangle_sync_neighbors(b->t.r, br, b);
+
        roam_triangle_add(s, sl->t.b, b, sr->t.b, sphere);
        roam_triangle_add(b, bl->t.b, s, br->t.b, sphere);
 
@@ -625,6 +631,7 @@ RoamSphere *roam_sphere_new()
        sphere->polys       = 8;
        sphere->triangles   = g_pqueue_new((GCompareDataFunc)tri_cmp, NULL);
        sphere->diamonds    = g_pqueue_new((GCompareDataFunc)dia_cmp, NULL);
+       sphere->view        = g_new0(RoamView, 1);
 
        RoamPoint *vertexes[] = {
                roam_point_new( 90,   0,  0), // 0 (North)
@@ -678,8 +685,6 @@ RoamSphere *roam_sphere_new()
  */
 void roam_sphere_update_view(RoamSphere *sphere)
 {
-       if (!sphere->view)
-               sphere->view = g_new0(RoamView, 1);
        glGetDoublev (GL_MODELVIEW_MATRIX,  sphere->view->model);
        glGetDoublev (GL_PROJECTION_MATRIX, sphere->view->proj);
        glGetIntegerv(GL_VIEWPORT,          sphere->view->view);
@@ -695,11 +700,15 @@ void roam_sphere_update_view(RoamSphere *sphere)
 void roam_sphere_update_errors(RoamSphere *sphere)
 {
        g_debug("RoamSphere: update_errors - polys=%d", sphere->polys);
+
+       static int version = 0;
+       if (version == sphere->view->version)
+               return;
+       version = sphere->view->version;
+
        GPtrArray *tris = g_pqueue_get_array(sphere->triangles);
        GPtrArray *dias = g_pqueue_get_array(sphere->diamonds);
 
-       roam_sphere_update_view(sphere);
-
        for (int i = 0; i < tris->len; i++) {
                RoamTriangle *triangle = tris->pdata[i];
                roam_triangle_update_errors(triangle, sphere);
@@ -753,6 +762,7 @@ void roam_sphere_merge_one(RoamSphere *sphere)
 gint roam_sphere_split_merge(RoamSphere *sphere)
 {
        gint iters = 0, max_iters = 500;
+       //gint target = 20000;
        //gint target = 4000;
        gint target = 2000;
        //gint target = 500;