clean up flip code a bit. working on an eventual clean bit of code +
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sat, 21 May 2011 01:38:02 +0000 (01:38 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sat, 21 May 2011 01:38:02 +0000 (01:38 +0000)
algorithm.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/elementary@59557 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/bin/test_flip_page.c

index 6fc89b9..c286ee4 100644 (file)
 #endif
 #ifndef ELM_LIB_QUICKLAUNCH
 
+//#define PAGEMESH 1
+
 typedef struct _State State;
 typedef struct _Slice Slice;
 
+typedef struct _Vertex2 Vertex2;
+typedef struct _Vertex3 Vertex3;
+
 struct _State
 {
-   Evas_Object *orig, *win, *base;
+   Evas_Object *orig, *win;
    Evas_Coord down_x, down_y;
    Eina_Bool  down : 1;
    Evas_Coord x, y;
+   Slice *base;
    Eina_List *slices;
 };
 
 struct _Slice
 {
    Evas_Object *obj;
+   // (0)---(1)
+   //  |     |
+   //  |     |
+   // (3)---(2)
+   double u[4], v[4];
+   double x[4], y[4], z[4];
+};
+
+struct _Vertex2
+{
+   double x, y;
+};
+
+struct _Vertex3
+{
+   double x, y, z;
 };
 
 static State state =
 {
-   NULL, NULL, NULL,
+   NULL, NULL,
    0, 0,
    0,
    0, 0,
    NULL,
+   NULL
 };
 
-#define RES 8
+#define RES 32
+
+static Slice *
+_slice_new(State *st)
+{
+   Slice *sl;
+   
+   sl = calloc(1, sizeof(Slice));
+   if (!sl) return NULL;
+   sl->obj = evas_object_image_add(evas_object_evas_get(st->win));
+   evas_object_image_smooth_scale_set(sl->obj, 0);
+   evas_object_pass_events_set(sl->obj, 1);
+   evas_object_image_source_set(sl->obj, st->orig);
+   evas_object_show(sl->obj);
+   return sl;
+}
+
+static void
+_slice_free(Slice *sl)
+{
+   evas_object_del(sl->obj);
+   free(sl);
+}
+
+static void
+_slice_apply(Slice *sl, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
+{
+   Evas_Map *m;
+   int i;
+   
+   m = evas_map_new(4);
+   evas_map_smooth_set(m, 0);
+
+   for (i = 0; i < 4; i++)
+     {
+        evas_map_point_coord_set(m, i, x + sl->x[i], y + sl->y[i], sl->z[i]);
+        evas_map_point_image_uv_set(m, i, sl->u[i] , sl->v[i]);
+        evas_map_point_color_set(m, i, 255, 255, 255, 255);
+     }
+   
+   evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 512);
+
+/*
+   // FIXME: lighting should be manual with pt 0 and 3 being white and
+   // 2 and 3 matching the
+   evas_map_util_3d_lighting(m,
+                             0  , 0  , -1000,
+                             255, 255, 255,
+                             20 , 20 , 20);
+ */
+   
+   evas_object_map_enable_set(sl->obj, EINA_TRUE);
+   evas_object_image_fill_set(sl->obj, 0, 0, w, h);
+   evas_object_map_set(sl->obj, m);
+   evas_map_free(m);
+}
+
+static void
+_slice_xyz(Slice *sl, 
+           double x1, double y1, double z1,
+           double x2, double y2, double z2,
+           double x3, double y3, double z3,
+           double x4, double y4, double z4)
+{
+   sl->x[0] = x1; sl->y[0] = y1; sl->z[0] = z1;
+   sl->x[1] = x2; sl->y[1] = y2; sl->z[1] = z2;
+   sl->x[2] = x3; sl->y[2] = y3; sl->z[2] = z3;
+   sl->x[3] = x4; sl->y[3] = y4; sl->z[3] = z4;
+}
+
+static void
+_slice_uv(Slice *sl, 
+           double u1, double v1,
+           double u2, double v2,
+           double u3, double v3,
+           double u4, double v4)
+{
+   sl->u[0] = u1; sl->v[0] = v1;
+   sl->u[1] = u2; sl->v[1] = v2;
+   sl->u[2] = u3; sl->v[2] = v3;
+   sl->u[3] = u4; sl->v[3] = v4;
+}
+
+#ifdef PAGEMESH
+static Evas_Object *sl_rho, *sl_theta, *sl_A;
+
+static void 
+_deform_point(Vertex2 *vi, Vertex3 *vo, double rho, double theta, double A)
+{
+   // ^Y
+   // |
+   // |    X
+   // +---->
+   // theta == cone angle (0 -> PI/2)
+   // A     == distance of cone apex from origin
+   // rho   == angle of cone from vertical axis (...-PI/2 to PI/2...)
+   Vertex3  v1;   // First stage of the deformation
+   double R, r, beta;
+   
+   // Radius of the circle circumscribed by vertex (vi->x, vi->y) around A
+   // on the x-y plane
+   R = sqrt(vi->x * vi->x + pow(vi->y - A, 2)); 
+   // Now get the radius of the cone cross section intersected by our vertex
+   // in 3D space.
+   r = R * sin(theta);                       
+   // Angle subtended by arc |ST| on the cone cross section.
+   beta = asin(vi->x / R) / sin(theta);       
+   
+   // *** MAGIC!!! ***
+   v1.x = r * sin(beta);
+   v1.y = R + A - r * (1 - cos(beta)) * sin(theta); 
+   v1.z = r * (1 - cos(beta)) * cos(theta);
+   
+   // Apply a basic rotation transform around the y axis to rotate the curled
+   // page. These two steps could be combined through simple substitution,
+   // but are left separate to keep the math simple for debugging and
+   // illustrative purposes.
+   vo->x = (v1.x * cos(rho)) - (v1.z * sin(rho));
+   vo->y = v1.y;
+   vo->z = (v1.x * sin(rho)) + (v1.z * cos(rho));
+}
+
+static void
+_test(void)
+{
+   static Eina_List *pts = NULL;
+   Evas_Object *o;
+   Evas_Map *m;
+   int i, j, k;
+   Evas_Coord x, y, w, h;
+   State *st = &state;
+   
+   EINA_LIST_FREE(pts, o) evas_object_del(o);
+   
+   evas_object_geometry_get(st->orig, &x, &y, &w, &h); 
+  for (j = 0; j < h; j += 20)
+     {
+        for (i = 0; i < w; i += 20)
+          {
+             Vertex2 vi;
+             Vertex3 vo;
+             double rho, theta, A, n;
+             
+             vi.x = i;
+             vi.y = j;
+             rho = elm_slider_value_get(sl_rho);
+             A = elm_slider_value_get(sl_A);
+             theta = elm_slider_value_get(sl_theta);
+             
+             _deform_point(&vi, &vo, rho, theta, A);
+             
+             o = evas_object_image_add(evas_object_evas_get(st->win));
+             evas_object_image_smooth_scale_set(o, 0);
+             evas_object_pass_events_set(o, 1);
+             evas_object_image_source_set(o, st->orig);
+             evas_object_show(o);
+             
+             m = evas_map_new(4);
+             evas_map_smooth_set(m, 0);
+             
+             k = 0;
+             evas_map_point_coord_set(m, k, x + vo.x, y + vo.y, -vo.z);
+             evas_map_point_image_uv_set(m, k, 0 , 0);
+             evas_map_point_color_set(m, k, 255, 255, 255, 255);
+             k++;
+             evas_map_point_coord_set(m, k, x + vo.x + 10, y + vo.y, -vo.z);
+             evas_map_point_image_uv_set(m, k, w , 0);
+             evas_map_point_color_set(m, k, 255, 255, 255, 255);
+             k++;
+             evas_map_point_coord_set(m, k, x + vo.x + 10, y + vo.y + 10, -vo.z);
+             evas_map_point_image_uv_set(m, k, w , h);
+             evas_map_point_color_set(m, k, 255, 255, 255, 255);
+             k++;
+             evas_map_point_coord_set(m, k, x + vo.x, y + vo.y + 10, -vo.z);
+             evas_map_point_image_uv_set(m, k, 0 , h);
+             evas_map_point_color_set(m, k, 255, 255, 255, 255);
+             k++;
+             
+             evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 512);
+             
+             evas_object_map_enable_set(o, EINA_TRUE);
+             evas_object_image_fill_set(o, 0, 0, w, h);
+             evas_object_map_set(o, m);
+             evas_map_free(m);
+             
+             pts = eina_list_append(pts, o);
+          }
+     }
+}
+
+static void
+_sl_ch(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   _test();
+}
+#endif   
 
 static void
 _slice_update(State *st)
@@ -38,7 +256,6 @@ _slice_update(State *st)
    Evas_Coord x1, y1, x2, y2, mx, my, px, rx, ry, prx, pry, dst, dx, dy, pdst;
    Evas_Coord x, y, w, h;
    int i;
-   Evas_Map *m;
    Slice *sl;
    int rad;
 
@@ -55,75 +272,35 @@ _slice_update(State *st)
    if (my < 0) my = 0;
    else if (my >= h) my = h - 1;
 
-   if (!st->base)
-     {
-        st->base = evas_object_image_add(evas_object_evas_get(st->win));
-        evas_object_image_smooth_scale_set(st->base, 0);
-        evas_object_image_fill_set(st->base, 0, 0, w, h);
-        evas_object_pass_events_set(st->base, 1);
-        evas_object_image_source_set(st->base, st->orig);
-        evas_object_show(st->base);
-     }
-
-   m = evas_map_new(4);
-   evas_map_smooth_set(m, 0);
-
-   evas_map_point_coord_set(m,    0, x     , y    , 0);
-   evas_map_point_coord_set(m,    1, x + mx, y    , 0);
-   evas_map_point_coord_set(m,    2, x + mx, y + h, 0);
-   evas_map_point_coord_set(m,    3, x     , y + h, 0);
-
-   evas_map_point_image_uv_set(m, 0, 0 , 0);
-   evas_map_point_image_uv_set(m, 1, mx, 0);
-   evas_map_point_image_uv_set(m, 2, mx, h);
-   evas_map_point_image_uv_set(m, 3, 0 , h);
-
-   evas_map_point_color_set(m, 0, 255, 255, 255, 255);
-   evas_map_point_color_set(m, 1, 255, 255, 255, 255);
-   evas_map_point_color_set(m, 2, 255, 255, 255, 255);
-   evas_map_point_color_set(m, 3, 255, 255, 255, 255);
-
-/*
-   // FIXME: lighting should be manual with pt 0 and 3 being white and
-   // 2 and 3 matching the
-   evas_map_util_3d_lighting(m,
-                             0  , 0  , -1000,
-                             255, 255, 255,
-                             20 , 20 , 20);
- */
-   evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 512);
-
-   evas_object_map_enable_set(st->base, 1);
-   evas_object_map_set(st->base, m);
-   evas_map_free(m);
-
-   EINA_LIST_FREE(st->slices, sl)
-     {
-        evas_object_del(sl->obj);
-        free(sl);
-     }
+   if (!st->base) st->base = _slice_new(st);
+   sl = st->base;
+   
+   _slice_xyz(sl,
+              0,  0,  0,
+              mx, 0,  0,
+              mx, h,  0,
+              0,  h,  0);
+   _slice_uv(sl,
+             0,  0,
+             mx, 0,
+             mx, h,
+             0,  h);
+   _slice_apply(sl, x, y, w, h);
+   
+   EINA_LIST_FREE(st->slices, sl) _slice_free(sl);
 
    // cylinder radius is width / 8
    rad = (w - mx) / 4;
    if (rad < (w / 16)) rad = (w / 16);
    if (rad > (w / 8)) rad = w / 8;
 
-   rad = w / 12;
+   rad = w / 10;
 
    px = mx;
    prx = 0;
    pry = rad;
    for (i = 1; i < RES; i++)
      {
-        sl = calloc(1, sizeof(Slice));
-        st->slices = eina_list_append(st->slices, sl);
-        sl->obj = evas_object_image_add(evas_object_evas_get(st->win));
-        evas_object_image_smooth_scale_set(sl->obj, 0);
-        evas_object_image_fill_set(sl->obj, 0, 0, w, h);
-        evas_object_pass_events_set(sl->obj, 1);
-        evas_object_image_source_set(sl->obj, st->orig);
-        evas_object_show(sl->obj);
-
         rx = (double)rad * sin((i * M_PI) / RES);
         ry = (double)rad * cos((i * M_PI) / RES);
         dx = rx - prx;
@@ -138,68 +315,41 @@ _slice_update(State *st)
           }
         if (dst <= 0) break;
 
-        m = evas_map_new(4);
-        evas_map_smooth_set(m, 0);
-
-        evas_map_point_coord_set(m,    0, x + mx + prx, y    , 0 - (rad - pry));
-        evas_map_point_coord_set(m,    1, x + mx + rx , y    , 0 - (rad - ry ));
-        evas_map_point_coord_set(m,    2, x + mx + rx , y + h, 0 - (rad - ry ));
-        evas_map_point_coord_set(m,    3, x + mx + prx, y + h, 0 - (rad - pry));
-
-        evas_map_point_image_uv_set(m, 0, px , 0);
-        evas_map_point_image_uv_set(m, 1, px + dst, 0);
-        evas_map_point_image_uv_set(m, 2, px + dst, h);
-        evas_map_point_image_uv_set(m, 3, px , h);
-
-        evas_map_point_color_set(m, 0, 255, 255, 255, 255);
-        evas_map_point_color_set(m, 1, 255, 255, 255, 255);
-        evas_map_point_color_set(m, 2, 255, 255, 255, 255);
-        evas_map_point_color_set(m, 3, 255, 255, 255, 255);
-
-        evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 512);
-
-        evas_object_map_enable_set(sl->obj, 1);
-        evas_object_map_set(sl->obj, m);
-        evas_map_free(m);
-
+        sl = _slice_new(st);
+
+        _slice_xyz(sl, 
+                   mx + prx, 0, -(rad - pry),
+                   mx + rx,  0, -(rad - ry),
+                   mx + rx,  h, -(rad - ry),
+                   mx + prx, h, -(rad - pry));
+        _slice_uv(sl,
+                  px,       0,
+                  px + dst, 0,
+                  px + dst, h,
+                  px,       h);
+        _slice_apply(sl, x, y, w, h);
+        st->slices = eina_list_append(st->slices, sl);
+        
         prx = rx;
         pry = ry;
         px += dst;
      }
    if (px < w)
      {
-        sl = calloc(1, sizeof(Slice));
+        sl = _slice_new(st);
+        
+        _slice_xyz(sl, 
+                   mx + prx,      0, -(rad - pry),
+                   mx + (px - w), 0, -(rad * 2),
+                   mx + (px - w), h, -(rad * 2),
+                   mx + prx,      h, -(rad - pry));
+        _slice_uv(sl,
+                  px, 0,
+                  w,  0,
+                  w,  h,
+                  px, h);
+        _slice_apply(sl, x, y, w, h);
         st->slices = eina_list_append(st->slices, sl);
-        sl->obj = evas_object_image_add(evas_object_evas_get(st->win));
-        evas_object_image_smooth_scale_set(sl->obj, 0);
-        evas_object_image_fill_set(sl->obj, 0, 0, w, h);
-        evas_object_pass_events_set(sl->obj, 1);
-        evas_object_image_source_set(sl->obj, st->orig);
-        evas_object_show(sl->obj);
-
-        m = evas_map_new(4);
-        evas_map_smooth_set(m, 0);
-
-        evas_map_point_coord_set(m,    0, x + mx + prx, y    , 0 - (rad - pry));
-        evas_map_point_coord_set(m,    1, x + mx + (px - w) , y    , 0 - (rad * 2  ));
-        evas_map_point_coord_set(m,    2, x + mx + (px - w) , y + h, 0 - (rad * 2  ));
-        evas_map_point_coord_set(m,    3, x + mx + prx, y + h, 0 - (rad - pry));
-
-        evas_map_point_image_uv_set(m, 0, px , 0);
-        evas_map_point_image_uv_set(m, 1, w, 0);
-        evas_map_point_image_uv_set(m, 2, w, h);
-        evas_map_point_image_uv_set(m, 3, px , h);
-
-        evas_map_point_color_set(m, 0, 255, 255, 255, 255);
-        evas_map_point_color_set(m, 1, 255, 255, 255, 255);
-        evas_map_point_color_set(m, 2, 255, 255, 255, 255);
-        evas_map_point_color_set(m, 3, 255, 255, 255, 255);
-
-        evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 512);
-
-        evas_object_map_enable_set(sl->obj, 1);
-        evas_object_map_set(sl->obj, m);
-        evas_map_free(m);
      }
 }
 
@@ -207,16 +357,10 @@ static void
 _slice_end(State *st)
 {
    Slice *sl;
-   EINA_LIST_FREE(st->slices, sl)
-     {
-        evas_object_del(sl->obj);
-        free(sl);
-     }
-   if (st->base)
-     {
-        evas_object_del(st->base);
-        st->base = NULL;
-     }
+   
+   if (st->base) _slice_free(st->base);
+   st->base = NULL;
+   EINA_LIST_FREE(st->slices, sl) _slice_free(sl);
 }
 
 static void
@@ -286,7 +430,7 @@ test_flip_page(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_i
    evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    evas_object_show(bg);
 
-#if 1
+#if 0
    im = elm_layout_add(win);
    snprintf(buf, sizeof(buf), "%s/objects/test.edj", PACKAGE_DATA_DIR);
    elm_layout_file_set(im, buf, "layout");
@@ -306,5 +450,48 @@ test_flip_page(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_i
 
    evas_object_resize(win, 480, 480);
    evas_object_show(win);
+   
+#ifdef PAGEMESH
+   Evas_Object *sl;
+
+   sl = elm_slider_add(win);
+   elm_slider_min_max_set(sl, -5, 5);
+   elm_slider_value_set(sl, 0);
+   sl_rho = sl;
+   evas_object_smart_callback_add(sl, "changed", _sl_ch, NULL);
+   elm_slider_label_set(sl, "rho");
+   elm_slider_unit_format_set(sl, "%1.2f");
+   elm_slider_span_size_set(sl, 320);
+   evas_object_move(sl, 10, 20);
+   evas_object_resize(sl, 460, 40);
+   evas_object_layer_set(sl, 100);
+   evas_object_show(sl);
+   
+   sl = elm_slider_add(win);
+   elm_slider_min_max_set(sl, 0, 10);
+   elm_slider_value_set(sl, 7.86);
+   sl_theta = sl;
+   evas_object_smart_callback_add(sl, "changed", _sl_ch, NULL);
+   elm_slider_label_set(sl, "theta");
+   elm_slider_unit_format_set(sl, "%1.2f");
+   elm_slider_span_size_set(sl, 320);
+   evas_object_move(sl, 10, 60);
+   evas_object_resize(sl, 460, 40);
+   evas_object_layer_set(sl, 100);
+   evas_object_show(sl);
+   
+   sl = elm_slider_add(win);
+   elm_slider_min_max_set(sl, -800, 800);
+   elm_slider_value_set(sl, -400);
+   sl_A = sl;
+   evas_object_smart_callback_add(sl, "changed", _sl_ch, NULL);
+   elm_slider_label_set(sl, "A");
+   elm_slider_unit_format_set(sl, "%1.2f");
+   elm_slider_span_size_set(sl, 320);
+   evas_object_move(sl, 10, 100);
+   evas_object_resize(sl, 460, 40);
+   evas_object_layer_set(sl, 100);
+   evas_object_show(sl);
+#endif   
 }
 #endif