clean up flip code a bit. working on an eventual clean bit of code +
[framework/uifw/elementary.git] / src / bin / test_flip_page.c
1 #include <Elementary.h>
2 #ifdef HAVE_CONFIG_H
3 # include "elementary_config.h"
4 #endif
5 #ifndef ELM_LIB_QUICKLAUNCH
6
7 //#define PAGEMESH 1
8
9 typedef struct _State State;
10 typedef struct _Slice Slice;
11
12 typedef struct _Vertex2 Vertex2;
13 typedef struct _Vertex3 Vertex3;
14
15 struct _State
16 {
17    Evas_Object *orig, *win;
18    Evas_Coord down_x, down_y;
19    Eina_Bool  down : 1;
20    Evas_Coord x, y;
21    Slice *base;
22    Eina_List *slices;
23 };
24
25 struct _Slice
26 {
27    Evas_Object *obj;
28    // (0)---(1)
29    //  |     |
30    //  |     |
31    // (3)---(2)
32    double u[4], v[4];
33    double x[4], y[4], z[4];
34 };
35
36 struct _Vertex2
37 {
38    double x, y;
39 };
40
41 struct _Vertex3
42 {
43    double x, y, z;
44 };
45
46 static State state =
47 {
48    NULL, NULL,
49    0, 0,
50    0,
51    0, 0,
52    NULL,
53    NULL
54 };
55
56 #define RES 32
57
58 static Slice *
59 _slice_new(State *st)
60 {
61    Slice *sl;
62    
63    sl = calloc(1, sizeof(Slice));
64    if (!sl) return NULL;
65    sl->obj = evas_object_image_add(evas_object_evas_get(st->win));
66    evas_object_image_smooth_scale_set(sl->obj, 0);
67    evas_object_pass_events_set(sl->obj, 1);
68    evas_object_image_source_set(sl->obj, st->orig);
69    evas_object_show(sl->obj);
70    return sl;
71 }
72
73 static void
74 _slice_free(Slice *sl)
75 {
76    evas_object_del(sl->obj);
77    free(sl);
78 }
79
80 static void
81 _slice_apply(Slice *sl, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
82 {
83    Evas_Map *m;
84    int i;
85    
86    m = evas_map_new(4);
87    evas_map_smooth_set(m, 0);
88
89    for (i = 0; i < 4; i++)
90      {
91         evas_map_point_coord_set(m, i, x + sl->x[i], y + sl->y[i], sl->z[i]);
92         evas_map_point_image_uv_set(m, i, sl->u[i] , sl->v[i]);
93         evas_map_point_color_set(m, i, 255, 255, 255, 255);
94      }
95    
96    evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 512);
97
98 /*
99    // FIXME: lighting should be manual with pt 0 and 3 being white and
100    // 2 and 3 matching the
101    evas_map_util_3d_lighting(m,
102                              0  , 0  , -1000,
103                              255, 255, 255,
104                              20 , 20 , 20);
105  */
106    
107    evas_object_map_enable_set(sl->obj, EINA_TRUE);
108    evas_object_image_fill_set(sl->obj, 0, 0, w, h);
109    evas_object_map_set(sl->obj, m);
110    evas_map_free(m);
111 }
112
113 static void
114 _slice_xyz(Slice *sl, 
115            double x1, double y1, double z1,
116            double x2, double y2, double z2,
117            double x3, double y3, double z3,
118            double x4, double y4, double z4)
119 {
120    sl->x[0] = x1; sl->y[0] = y1; sl->z[0] = z1;
121    sl->x[1] = x2; sl->y[1] = y2; sl->z[1] = z2;
122    sl->x[2] = x3; sl->y[2] = y3; sl->z[2] = z3;
123    sl->x[3] = x4; sl->y[3] = y4; sl->z[3] = z4;
124 }
125
126 static void
127 _slice_uv(Slice *sl, 
128            double u1, double v1,
129            double u2, double v2,
130            double u3, double v3,
131            double u4, double v4)
132 {
133    sl->u[0] = u1; sl->v[0] = v1;
134    sl->u[1] = u2; sl->v[1] = v2;
135    sl->u[2] = u3; sl->v[2] = v3;
136    sl->u[3] = u4; sl->v[3] = v4;
137 }
138
139 #ifdef PAGEMESH
140 static Evas_Object *sl_rho, *sl_theta, *sl_A;
141
142 static void 
143 _deform_point(Vertex2 *vi, Vertex3 *vo, double rho, double theta, double A)
144 {
145    // ^Y
146    // |
147    // |    X
148    // +---->
149    // theta == cone angle (0 -> PI/2)
150    // A     == distance of cone apex from origin
151    // rho   == angle of cone from vertical axis (...-PI/2 to PI/2...)
152    Vertex3  v1;   // First stage of the deformation
153    double R, r, beta;
154    
155    // Radius of the circle circumscribed by vertex (vi->x, vi->y) around A
156    // on the x-y plane
157    R = sqrt(vi->x * vi->x + pow(vi->y - A, 2)); 
158    // Now get the radius of the cone cross section intersected by our vertex
159    // in 3D space.
160    r = R * sin(theta);                       
161    // Angle subtended by arc |ST| on the cone cross section.
162    beta = asin(vi->x / R) / sin(theta);       
163    
164    // *** MAGIC!!! ***
165    v1.x = r * sin(beta);
166    v1.y = R + A - r * (1 - cos(beta)) * sin(theta); 
167    v1.z = r * (1 - cos(beta)) * cos(theta);
168    
169    // Apply a basic rotation transform around the y axis to rotate the curled
170    // page. These two steps could be combined through simple substitution,
171    // but are left separate to keep the math simple for debugging and
172    // illustrative purposes.
173    vo->x = (v1.x * cos(rho)) - (v1.z * sin(rho));
174    vo->y = v1.y;
175    vo->z = (v1.x * sin(rho)) + (v1.z * cos(rho));
176 }
177
178 static void
179 _test(void)
180 {
181    static Eina_List *pts = NULL;
182    Evas_Object *o;
183    Evas_Map *m;
184    int i, j, k;
185    Evas_Coord x, y, w, h;
186    State *st = &state;
187    
188    EINA_LIST_FREE(pts, o) evas_object_del(o);
189    
190    evas_object_geometry_get(st->orig, &x, &y, &w, &h); 
191   for (j = 0; j < h; j += 20)
192      {
193         for (i = 0; i < w; i += 20)
194           {
195              Vertex2 vi;
196              Vertex3 vo;
197              double rho, theta, A, n;
198              
199              vi.x = i;
200              vi.y = j;
201              rho = elm_slider_value_get(sl_rho);
202              A = elm_slider_value_get(sl_A);
203              theta = elm_slider_value_get(sl_theta);
204              
205              _deform_point(&vi, &vo, rho, theta, A);
206              
207              o = evas_object_image_add(evas_object_evas_get(st->win));
208              evas_object_image_smooth_scale_set(o, 0);
209              evas_object_pass_events_set(o, 1);
210              evas_object_image_source_set(o, st->orig);
211              evas_object_show(o);
212              
213              m = evas_map_new(4);
214              evas_map_smooth_set(m, 0);
215              
216              k = 0;
217              evas_map_point_coord_set(m, k, x + vo.x, y + vo.y, -vo.z);
218              evas_map_point_image_uv_set(m, k, 0 , 0);
219              evas_map_point_color_set(m, k, 255, 255, 255, 255);
220              k++;
221              evas_map_point_coord_set(m, k, x + vo.x + 10, y + vo.y, -vo.z);
222              evas_map_point_image_uv_set(m, k, w , 0);
223              evas_map_point_color_set(m, k, 255, 255, 255, 255);
224              k++;
225              evas_map_point_coord_set(m, k, x + vo.x + 10, y + vo.y + 10, -vo.z);
226              evas_map_point_image_uv_set(m, k, w , h);
227              evas_map_point_color_set(m, k, 255, 255, 255, 255);
228              k++;
229              evas_map_point_coord_set(m, k, x + vo.x, y + vo.y + 10, -vo.z);
230              evas_map_point_image_uv_set(m, k, 0 , h);
231              evas_map_point_color_set(m, k, 255, 255, 255, 255);
232              k++;
233              
234              evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 512);
235              
236              evas_object_map_enable_set(o, EINA_TRUE);
237              evas_object_image_fill_set(o, 0, 0, w, h);
238              evas_object_map_set(o, m);
239              evas_map_free(m);
240              
241              pts = eina_list_append(pts, o);
242           }
243      }
244 }
245
246 static void
247 _sl_ch(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
248 {
249    _test();
250 }
251 #endif   
252
253 static void
254 _slice_update(State *st)
255 {
256    Evas_Coord x1, y1, x2, y2, mx, my, px, rx, ry, prx, pry, dst, dx, dy, pdst;
257    Evas_Coord x, y, w, h;
258    int i;
259    Slice *sl;
260    int rad;
261
262    evas_object_geometry_get(st->orig, &x, &y, &w, &h);
263    x1 = st->down_x;
264    y1 = st->down_y;
265    x2 = st->x;
266    y2 = st->y;
267    mx = (x1 + x2) / 2;
268    my = (y1 + y2) / 2;
269
270    if (mx < 0) mx = 0;
271    else if (mx >= w) mx = w - 1;
272    if (my < 0) my = 0;
273    else if (my >= h) my = h - 1;
274
275    if (!st->base) st->base = _slice_new(st);
276    sl = st->base;
277    
278    _slice_xyz(sl,
279               0,  0,  0,
280               mx, 0,  0,
281               mx, h,  0,
282               0,  h,  0);
283    _slice_uv(sl,
284              0,  0,
285              mx, 0,
286              mx, h,
287              0,  h);
288    _slice_apply(sl, x, y, w, h);
289    
290    EINA_LIST_FREE(st->slices, sl) _slice_free(sl);
291
292    // cylinder radius is width / 8
293    rad = (w - mx) / 4;
294    if (rad < (w / 16)) rad = (w / 16);
295    if (rad > (w / 8)) rad = w / 8;
296
297    rad = w / 10;
298
299    px = mx;
300    prx = 0;
301    pry = rad;
302    for (i = 1; i < RES; i++)
303      {
304         rx = (double)rad * sin((i * M_PI) / RES);
305         ry = (double)rad * cos((i * M_PI) / RES);
306         dx = rx - prx;
307         dy = ry - pry;
308         dst = sqrt((dx * dx) + (dy * dy));
309         if ((px + dst) > w)
310           {
311              pdst = dst;
312              dst = w - px;
313              rx = prx + (((rx - prx) * dst) / pdst);
314              ry = pry + (((ry - pry) * dst) / pdst);
315           }
316         if (dst <= 0) break;
317
318         sl = _slice_new(st);
319
320         _slice_xyz(sl, 
321                    mx + prx, 0, -(rad - pry),
322                    mx + rx,  0, -(rad - ry),
323                    mx + rx,  h, -(rad - ry),
324                    mx + prx, h, -(rad - pry));
325         _slice_uv(sl,
326                   px,       0,
327                   px + dst, 0,
328                   px + dst, h,
329                   px,       h);
330         _slice_apply(sl, x, y, w, h);
331         st->slices = eina_list_append(st->slices, sl);
332         
333         prx = rx;
334         pry = ry;
335         px += dst;
336      }
337    if (px < w)
338      {
339         sl = _slice_new(st);
340         
341         _slice_xyz(sl, 
342                    mx + prx,      0, -(rad - pry),
343                    mx + (px - w), 0, -(rad * 2),
344                    mx + (px - w), h, -(rad * 2),
345                    mx + prx,      h, -(rad - pry));
346         _slice_uv(sl,
347                   px, 0,
348                   w,  0,
349                   w,  h,
350                   px, h);
351         _slice_apply(sl, x, y, w, h);
352         st->slices = eina_list_append(st->slices, sl);
353      }
354 }
355
356 static void
357 _slice_end(State *st)
358 {
359    Slice *sl;
360    
361    if (st->base) _slice_free(st->base);
362    st->base = NULL;
363    EINA_LIST_FREE(st->slices, sl) _slice_free(sl);
364 }
365
366 static void
367 im_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info)
368 {
369    Evas_Event_Mouse_Down *ev = event_info;
370    Evas_Object *win = data;
371    Evas_Coord x, y;
372
373    if (ev->button != 1) return;
374    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
375    state.orig = obj;
376    state.win = win;
377    state.down = 1;
378    state.x = ev->canvas.x - x;
379    state.y = ev->canvas.y - y;
380    state.down_x = state.x;
381    state.down_y = state.y;
382    evas_object_lower(obj);
383    printf("v %i %i\n", state.x, state.y);
384    _slice_update(&state);
385 }
386
387 static void
388 im_up_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info)
389 {
390    Evas_Event_Mouse_Up *ev = event_info;
391    Evas_Coord x, y;
392
393    if (ev->button != 1) return;
394    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
395    state.down = 0;
396    state.x = ev->canvas.x - x;
397    state.y = ev->canvas.y - y;
398    evas_object_raise(obj);
399    printf("^ %i %i\n", state.x, state.y);
400    _slice_end(&state);
401 }
402
403 static void
404 im_move_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info)
405 {
406    Evas_Event_Mouse_Move *ev = event_info;
407    Evas_Coord x, y;
408
409    if (!state.down) return;
410    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
411    state.x = ev->cur.canvas.x - x;
412    state.y = ev->cur.canvas.y - y;
413    printf("@ %i %i\n", state.x, state.y);
414    _slice_update(&state);
415 }
416
417 void
418 test_flip_page(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
419 {
420    Evas_Object *win, *bg, *im;
421    char buf[PATH_MAX];
422
423    win = elm_win_add(NULL, "flip_page", ELM_WIN_BASIC);
424    elm_win_title_set(win, "Flip Page");
425    elm_win_focus_highlight_enabled_set(win, EINA_TRUE);
426    elm_win_autodel_set(win, 1);
427
428    bg = elm_bg_add(win);
429    elm_win_resize_object_add(win, bg);
430    evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
431    evas_object_show(bg);
432
433 #if 0
434    im = elm_layout_add(win);
435    snprintf(buf, sizeof(buf), "%s/objects/test.edj", PACKAGE_DATA_DIR);
436    elm_layout_file_set(im, buf, "layout");
437 #else
438    im = evas_object_image_filled_add(evas_object_evas_get(win));
439    snprintf(buf, sizeof(buf), "%s/images/%s",
440             PACKAGE_DATA_DIR, "twofish.jpg");
441    evas_object_image_file_set(im, buf, NULL);
442 #endif
443    evas_object_move(im, 40, 40);
444    evas_object_resize(im, 400, 400);
445    evas_object_show(im);
446
447    evas_object_event_callback_add(im, EVAS_CALLBACK_MOUSE_DOWN, im_down_cb, win);
448    evas_object_event_callback_add(im, EVAS_CALLBACK_MOUSE_UP,   im_up_cb,   win);
449    evas_object_event_callback_add(im, EVAS_CALLBACK_MOUSE_MOVE, im_move_cb, win);
450
451    evas_object_resize(win, 480, 480);
452    evas_object_show(win);
453    
454 #ifdef PAGEMESH
455    Evas_Object *sl;
456
457    sl = elm_slider_add(win);
458    elm_slider_min_max_set(sl, -5, 5);
459    elm_slider_value_set(sl, 0);
460    sl_rho = sl;
461    evas_object_smart_callback_add(sl, "changed", _sl_ch, NULL);
462    elm_slider_label_set(sl, "rho");
463    elm_slider_unit_format_set(sl, "%1.2f");
464    elm_slider_span_size_set(sl, 320);
465    evas_object_move(sl, 10, 20);
466    evas_object_resize(sl, 460, 40);
467    evas_object_layer_set(sl, 100);
468    evas_object_show(sl);
469    
470    sl = elm_slider_add(win);
471    elm_slider_min_max_set(sl, 0, 10);
472    elm_slider_value_set(sl, 7.86);
473    sl_theta = sl;
474    evas_object_smart_callback_add(sl, "changed", _sl_ch, NULL);
475    elm_slider_label_set(sl, "theta");
476    elm_slider_unit_format_set(sl, "%1.2f");
477    elm_slider_span_size_set(sl, 320);
478    evas_object_move(sl, 10, 60);
479    evas_object_resize(sl, 460, 40);
480    evas_object_layer_set(sl, 100);
481    evas_object_show(sl);
482    
483    sl = elm_slider_add(win);
484    elm_slider_min_max_set(sl, -800, 800);
485    elm_slider_value_set(sl, -400);
486    sl_A = sl;
487    evas_object_smart_callback_add(sl, "changed", _sl_ch, NULL);
488    elm_slider_label_set(sl, "A");
489    elm_slider_unit_format_set(sl, "%1.2f");
490    elm_slider_span_size_set(sl, 320);
491    evas_object_move(sl, 10, 100);
492    evas_object_resize(sl, 460, 40);
493    evas_object_layer_set(sl, 100);
494    evas_object_show(sl);
495 #endif   
496 }
497 #endif