aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/extantz/extantz.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/extantz/extantz.c')
-rw-r--r--src/extantz/extantz.c1588
1 files changed, 1588 insertions, 0 deletions
diff --git a/src/extantz/extantz.c b/src/extantz/extantz.c
new file mode 100644
index 0000000..09b5196
--- /dev/null
+++ b/src/extantz/extantz.c
@@ -0,0 +1,1588 @@
1#include "extantz.h"
2
3
4int _log_domain = -1;
5
6Eina_Hash *grids;
7Eina_Hash *viewers;
8
9static char *gridTest[][3] =
10{
11 {"3rd Rock Grid", "http://grid.3rdrockgrid.com:8002/", "http://grid.3rdrockgrid.com/3rg_login"},
12 {"Infinite Grid", "http://grid.infinitegrid.org:8002/", "http://www.infinitegrid.org/loginscreen.php"},
13 {"Second Life Grid", "https://login.agni.lindenlab.com/cgi-bin/login.cgi", "http://secondlife.com/"},
14 {NULL, NULL, NULL}
15};
16
17static char *accountTest[][3] =
18{
19 {"3rd Rock Grid", "onefang rejected", "password"},
20 {"Infinite Grid", "infinite onefang", "MyB1GSecrit"},
21 {"Infinite Grid", "onefang rejected", "MySecrit"},
22 {NULL, NULL, NULL}
23};
24
25
26static char *viewerTest[][3] =
27{
28 {"Imprudence", "1.4.0 beta 3", ""},
29 {"Kokua", "3.4.4.25633", ""},
30 {"meta-impy", "1.4.0 beta 1.5", ""},
31 {"SL", "v3", ""},
32 {NULL, NULL, NULL}
33};
34
35
36static Elm_Genlist_Item_Class *grid_gic = NULL;
37static Elm_Genlist_Item_Class *account_gic = NULL;
38static Elm_Genlist_Item_Class *viewer_gic = NULL;
39
40//static const char *img1 = PACKAGE_DATA_DIR "/media/plant_01.jpg";
41//static const char *img2 = PACKAGE_DATA_DIR "/media/sky_01.jpg";
42static const char *img3 = PACKAGE_DATA_DIR "/media/rock_01.jpg";
43
44
45#define EPHYSICS_TEST_THEME "extantz"
46
47
48#if DO_GEARS
49//--------------------------------//
50// Gear Stuff.
51
52static GLfloat *vert(GLfloat *p, GLfloat x, GLfloat y, GLfloat z, GLfloat *n)
53{
54 p[0] = x;
55 p[1] = y;
56 p[2] = z;
57 p[3] = n[0];
58 p[4] = n[1];
59 p[5] = n[2];
60
61 return p + 6;
62}
63
64/* Draw a gear wheel. You'll probably want to call this function when
65 * building a display list since we do a lot of trig here.
66 *
67 * Input: inner_radius - radius of hole at center
68 * outer_radius - radius at center of teeth
69 * width - width of gear
70 * teeth - number of teeth
71 * tooth_depth - depth of tooth
72 */
73static Gear *make_gear(GLData *gld, GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth)
74{
75 GLint i;
76 GLfloat r0, r1, r2;
77 GLfloat da;
78 GLfloat *v;
79 Gear *gear;
80 double s[5], c[5];
81 GLfloat normal[3];
82 const int tris_per_tooth = 20;
83 Evas_GL_API *gl = gld->glApi;
84
85 gear = (Gear*)malloc(sizeof(Gear));
86 if (gear == NULL)
87 return NULL;
88
89 r0 = inner_radius;
90 r1 = outer_radius - tooth_depth / 2.0;
91 r2 = outer_radius + tooth_depth / 2.0;
92
93 da = 2.0 * M_PI / teeth / 4.0;
94
95 gear->vertices = calloc(teeth * tris_per_tooth * 3 * 6, sizeof *gear->vertices);
96 s[4] = 0;
97 c[4] = 1;
98 v = gear->vertices;
99 for (i = 0; i < teeth; i++)
100 {
101 s[0] = s[4];
102 c[0] = c[4];
103 s[1] = sin(i * 2.0 * M_PI / teeth + da);
104 c[1] = cos(i * 2.0 * M_PI / teeth + da);
105 s[2] = sin(i * 2.0 * M_PI / teeth + da * 2);
106 c[2] = cos(i * 2.0 * M_PI / teeth + da * 2);
107 s[3] = sin(i * 2.0 * M_PI / teeth + da * 3);
108 c[3] = cos(i * 2.0 * M_PI / teeth + da * 3);
109 s[4] = sin(i * 2.0 * M_PI / teeth + da * 4);
110 c[4] = cos(i * 2.0 * M_PI / teeth + da * 4);
111
112 normal[0] = 0.0;
113 normal[1] = 0.0;
114 normal[2] = 1.0;
115
116 v = vert(v, r2 * c[1], r2 * s[1], width * 0.5, normal);
117
118 v = vert(v, r2 * c[1], r2 * s[1], width * 0.5, normal);
119 v = vert(v, r2 * c[2], r2 * s[2], width * 0.5, normal);
120 v = vert(v, r1 * c[0], r1 * s[0], width * 0.5, normal);
121 v = vert(v, r1 * c[3], r1 * s[3], width * 0.5, normal);
122 v = vert(v, r0 * c[0], r0 * s[0], width * 0.5, normal);
123 v = vert(v, r1 * c[4], r1 * s[4], width * 0.5, normal);
124 v = vert(v, r0 * c[4], r0 * s[4], width * 0.5, normal);
125
126 v = vert(v, r0 * c[4], r0 * s[4], width * 0.5, normal);
127 v = vert(v, r0 * c[0], r0 * s[0], width * 0.5, normal);
128 v = vert(v, r0 * c[4], r0 * s[4], -width * 0.5, normal);
129 v = vert(v, r0 * c[0], r0 * s[0], -width * 0.5, normal);
130
131 normal[0] = 0.0;
132 normal[1] = 0.0;
133 normal[2] = -1.0;
134
135 v = vert(v, r0 * c[4], r0 * s[4], -width * 0.5, normal);
136
137 v = vert(v, r0 * c[4], r0 * s[4], -width * 0.5, normal);
138 v = vert(v, r1 * c[4], r1 * s[4], -width * 0.5, normal);
139 v = vert(v, r0 * c[0], r0 * s[0], -width * 0.5, normal);
140 v = vert(v, r1 * c[3], r1 * s[3], -width * 0.5, normal);
141 v = vert(v, r1 * c[0], r1 * s[0], -width * 0.5, normal);
142 v = vert(v, r2 * c[2], r2 * s[2], -width * 0.5, normal);
143 v = vert(v, r2 * c[1], r2 * s[1], -width * 0.5, normal);
144
145 v = vert(v, r1 * c[0], r1 * s[0], width * 0.5, normal);
146
147 v = vert(v, r1 * c[0], r1 * s[0], width * 0.5, normal);
148 v = vert(v, r1 * c[0], r1 * s[0], -width * 0.5, normal);
149 v = vert(v, r2 * c[1], r2 * s[1], width * 0.5, normal);
150 v = vert(v, r2 * c[1], r2 * s[1], -width * 0.5, normal);
151 v = vert(v, r2 * c[2], r2 * s[2], width * 0.5, normal);
152 v = vert(v, r2 * c[2], r2 * s[2], -width * 0.5, normal);
153 v = vert(v, r1 * c[3], r1 * s[3], width * 0.5, normal);
154 v = vert(v, r1 * c[3], r1 * s[3], -width * 0.5, normal);
155 v = vert(v, r1 * c[4], r1 * s[4], width * 0.5, normal);
156 v = vert(v, r1 * c[4], r1 * s[4], -width * 0.5, normal);
157
158 v = vert(v, r1 * c[4], r1 * s[4], -width * 0.5, normal);
159 }
160
161 gear->count = (v - gear->vertices) / 6;
162
163 gl->glGenBuffers(1, &gear->vbo);
164 gl->glBindBuffer(GL_ARRAY_BUFFER, gear->vbo);
165 gl->glBufferData(GL_ARRAY_BUFFER, gear->count * 6 * 4, gear->vertices, GL_STATIC_DRAW);
166
167
168 return gear;
169}
170
171static void free_gear(Gear *gear)
172{
173 free(gear->vertices);
174 free(gear);
175 gear = NULL;
176}
177
178static void multiply(GLfloat *m, const GLfloat *n)
179{
180 GLfloat tmp[16];
181 const GLfloat *row, *column;
182 div_t d;
183 int i, j;
184
185 for (i = 0; i < 16; i++)
186 {
187 tmp[i] = 0;
188 d = div(i, 4);
189 row = n + d.quot * 4;
190 column = m + d.rem;
191 for (j = 0; j < 4; j++)
192 tmp[i] += row[j] * column[j * 4];
193 }
194 memcpy(m, &tmp, sizeof tmp);
195}
196
197static void rotate(GLfloat *m, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
198{
199 double s, c;
200
201 s = sin(angle);
202 c = cos(angle);
203 GLfloat r[16] =
204 {
205 x * x * (1 - c) + c, y * x * (1 - c) + z * s, x * z * (1 - c) - y * s, 0,
206 x * y * (1 - c) - z * s, y * y * (1 - c) + c, y * z * (1 - c) + x * s, 0,
207 x * z * (1 - c) + y * s, y * z * (1 - c) - x * s, z * z * (1 - c) + c, 0,
208 0, 0, 0, 1
209 };
210
211 multiply(m, r);
212}
213
214static void translate(GLfloat *m, GLfloat x, GLfloat y, GLfloat z)
215{
216 GLfloat t[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 };
217
218 multiply(m, t);
219}
220
221static void draw_gear(GLData *gld, Gear *gear, GLfloat *m, GLfloat x, GLfloat y, GLfloat angle, const GLfloat *color)
222{
223 Evas_GL_API *gl = gld->glApi;
224 GLfloat tmp[16];
225
226 memcpy(tmp, m, sizeof tmp);
227 translate(tmp, x, y, 0);
228 rotate(tmp, 2 * M_PI * angle / 360.0, 0, 0, 1);
229 gl->glUniformMatrix4fv(gld->proj_location, 1, GL_FALSE, tmp);
230 gl->glUniform3fv(gld->light_location, 1, gld->light);
231 gl->glUniform4fv(gld->color_location, 1, color);
232
233 gl->glBindBuffer(GL_ARRAY_BUFFER, gear->vbo);
234
235 gl->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), NULL);
236 gl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLfloat *) 0 + 3);
237 gl->glEnableVertexAttribArray(0);
238 gl->glEnableVertexAttribArray(1);
239 gl->glDrawArrays(GL_TRIANGLE_STRIP, 0, gear->count);
240}
241#endif
242
243
244static void gldata_init(GLData *gld)
245{
246 gld->useEGL = USE_EGL;
247 gld->useIrr = USE_IRR;
248
249 gld->view_rotx = -20.0;
250 gld->view_roty = -30.0;
251 gld->view_rotz = 0.0;
252 gld->angle = 0.0;
253
254 gld->light[0] = 1.0;
255 gld->light[1] = 1.0;
256 gld->light[2] = -5.0;
257}
258
259//-------------------------//
260
261
262#if DO_GEARS
263static const char vertex_shader[] =
264 "uniform mat4 proj;\n"
265 "attribute vec4 position;\n"
266 "attribute vec4 normal;\n"
267 "varying vec3 rotated_normal;\n"
268 "varying vec3 rotated_position;\n"
269 "vec4 tmp;\n"
270 "void main()\n"
271 "{\n"
272 " gl_Position = proj * position;\n"
273 " rotated_position = gl_Position.xyz;\n"
274 " tmp = proj * normal;\n"
275 " rotated_normal = tmp.xyz;\n"
276 "}\n";
277
278 static const char fragment_shader[] =
279 "#ifdef GL_ES\n"
280 "precision mediump float;\n"
281 "#endif\n"
282 "uniform vec4 color;\n"
283 "uniform vec3 light;\n"
284 "varying vec3 rotated_normal;\n"
285 "varying vec3 rotated_position;\n"
286 "vec3 light_direction;\n"
287 "vec4 white = vec4(0.5, 0.5, 0.5, 1.0);\n"
288 "void main()\n"
289 "{\n"
290 " light_direction = normalize(light - rotated_position);\n"
291 " gl_FragColor = color + white * dot(light_direction, rotated_normal);\n"
292 "}\n";
293
294static GLuint load_shader(GLData *gld, GLenum type, const char *shader_src)
295{
296 Evas_GL_API *gl = gld->glApi;
297 GLuint shader;
298 GLint compiled = 0;
299
300 // Create the shader object
301 if (!(shader = gl->glCreateShader(type))) return 0;
302 gl->glShaderSource(shader, 1, &shader_src, NULL);
303 // Compile the shader
304 gl->glCompileShader(shader);
305 gl->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
306
307 if (!compiled)
308 {
309 GLint len = 0;
310
311 gl->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
312 if (len > 1)
313 {
314 char *info = malloc(sizeof(char) * len);
315
316 if (info)
317 {
318 gl->glGetShaderInfoLog(shader, len, NULL, info);
319 printf("Error compiling shader:\n"
320 "%s\n", info);
321 free(info);
322 }
323 }
324 gl->glDeleteShader(shader);
325 return 0;
326 }
327 return shader;
328}
329
330static void gears_init(GLData *gld)
331{
332 Evas_GL_API *gl = gld->glApi;
333 GLint linked = 0;
334
335// char msg[512];
336
337 gl->glEnable(GL_CULL_FACE);
338 gl->glEnable(GL_DEPTH_TEST);
339 gl->glEnable(GL_BLEND);
340
341 // Load the vertex/fragment shaders
342 gld->vtx_shader = load_shader(gld, GL_VERTEX_SHADER, vertex_shader);
343 gld->fgmt_shader = load_shader(gld, GL_FRAGMENT_SHADER, fragment_shader);
344
345 // Create the program object
346 if (!(gld->program = gl->glCreateProgram()))
347 return;
348
349 gl->glAttachShader(gld->program, gld->vtx_shader);
350 gl->glAttachShader(gld->program, gld->fgmt_shader);
351
352 // Bind shader attributes.
353 gl->glBindAttribLocation(gld->program, 0, "position");
354 gl->glBindAttribLocation(gld->program, 1, "normal");
355
356 // Link the program
357 gl->glLinkProgram(gld->program);
358 gld->glApi->glGetProgramiv(gld->program, GL_LINK_STATUS, &linked);
359
360 if (!linked)
361 {
362 GLint len = 0;
363
364 gld->glApi->glGetProgramiv(gld->program, GL_INFO_LOG_LENGTH, &len);
365 if (len > 1)
366 {
367 char *info = malloc(sizeof(char) * len);
368
369 if (info)
370 {
371 gld->glApi->glGetProgramInfoLog(gld->program, len, NULL, info);
372 printf("Error linking program:\n%s\n", info);
373 free(info);
374 }
375 }
376 gld->glApi->glDeleteProgram(gld->program);
377 }
378
379 gl->glUseProgram(gld->program);
380 gld->proj_location = gl->glGetUniformLocation(gld->program, "proj");
381 gld->light_location = gl->glGetUniformLocation(gld->program, "light");
382 gld->color_location = gl->glGetUniformLocation(gld->program, "color");
383
384 /* make the gears */
385 gld->gear1 = make_gear(gld, 1.0, 4.0, 1.0, 20, 0.7);
386 gld->gear2 = make_gear(gld, 0.5, 2.0, 2.0, 10, 0.7);
387 gld->gear3 = make_gear(gld, 1.3, 2.0, 0.5, 10, 0.7);
388
389 gld->gearsInited = EINA_TRUE;
390}
391#endif
392
393static void _on_camera_input_down(void *data, Evas *evas, Evas_Object *obj, void *event_info)
394{
395 GLData *gld = data;
396 Evas_Event_Key_Down *ev = event_info;
397
398 if (gld->move)
399 {
400 // TODO - Careful, gld->move MIGHT be read at the other end by another thread. MIGHT, coz I really don't know at what point the camera animate routine is actually called.
401
402 // Yes, we are dealing with the horrid Evas keyboard handling FUCKING STRING COMPARES! Soooo ...
403 // TODO - make this a hash lookup dammit.
404 if (0 == strcmp(ev->key, "Escape"))
405 {
406 }
407 else if (0 == strcmp(ev->key, "Left"))
408 gld->move->r = 2.0;
409 else if (0 == strcmp(ev->key, "Right"))
410 gld->move->r = -2.0;
411 else if (0 == strcmp(ev->key, "Up"))
412 gld->move->x = 2.0;
413 else if (0 == strcmp(ev->key, "Down"))
414 gld->move->x = -2.0;
415// else if (0 == strcmp(ev->key, "Prior"))
416// ;
417// else if (0 == strcmp(ev->key, "Next"))
418// ;
419// else if (0 == strcmp(ev->key, "Home"))
420// ;
421// else if (0 == strcmp(ev->key, "End"))
422// ;
423 else if (0 == strcmp(ev->key, "space"))
424 gld->move->jump = 1.0;
425 else
426 printf("Unexpected down keystroke - %s\n", ev->key);
427 }
428 else
429 printf("Camera input not ready\n");
430}
431
432/* SL / OS camera controls
433 up / down / w / s moves avatar forward / backward
434 shifted version does the same
435 double tap triggers run mode / or fast fly mode
436 Running backwards turns your avatar to suit, walking does not.
437 left / right / a / d rotates avatar left / right, strafes in mouselook
438 shifted version turns the avatar to walk sideways, so not really a strafe.
439 So not sure if the "strafe" in mouse look turns the avatar as well?
440 PgDn / c crouch while it is held down move up in flight mode
441 PgUp jump move down in flight mode
442 Home toggle flying
443 End Nothing?
444 Esc return to third person view
445 m toggle mouse look
446 mouse wheel move view closer / further away from current focused object or avatar
447 Alt left click focus on some other object
448 Ins ???
449 Del ???
450 BS ???
451 Tab ???
452
453 Mouse look is just first person view, moving mouse looks left / right / up / down.
454 Not sure if the avatar rotates with left / right, but that's likely.
455
456 mouse moves With the left mouse button held down -
457 left / right up / down
458 ---------------------------------
459 for avatar swings avatar around zoom in and out of avatar
460 for object nothing
461 alt orbit left / right zoom in and out
462 alt ctrl orbit left / right orbit up / down
463 alt shift orbit left / right zoom in and out
464 alt ctrl shift shift view left / right / up / down
465 ctrl Nothing?
466 shift Nothing?
467 ctrl shift Nothing?
468
469 Need to also consider when looking at a moving object / avatar.
470
471 I think there are other letter keys that duplicate arrow keys and such. I'll look for them later, but I don't use them.
472 No idea what the function keys are mapped to, but think it's various non camera stuff.
473 I'm damn well leaving the Win/Command and Menu keys for the OS / window manager. lol
474 Keypad keys? Not interested, I don't have them.
475 Print Screen / SysRq, Pause / Break, other oddball keys, also not interested.
476 NOTE - gonna have an easily programmable "bind key to command" thingy, like E17s, so that can deal with other keys.
477 Should even let them be saveable so people can swap them with other people easily.
478
479 TODO - implement things like space mouse, sixaxis, phone as controller, joysticks, data gloves, etc.
480*/
481
482/* A moveRotate array of floats.
483 * X, Y, Z, and whatever the usual letters are for rotations. lol
484 * Each one means "move or rotate this much in this direction".
485 * Where 1.0 means "what ever the standard move is if that key is held down".
486 * So a keyboard move would just change it's part to 1.0 or -1.0 on key down,
487 * and back to 0.0 on key up. Or 2.0 / -2.0 if in run mode.
488 * Which would even work in fly mode.
489 * A joystick could be set to range over -2.0 to 2.0, and just set it's part directly.
490 * A mouse look rotate, well will come to that when we need to. B-)
491 * Setting the x or y to be the DIFFERENCE in window position of the mouse (-1.0 to 1.0) since the last frame.
492 *
493 * TODO - In the Elm_glview version, 2.0 seems to be correct speed for walking, but I thought 1.0 was in Evas_GL.
494 */
495
496static void _on_camera_input_up(void *data, Evas *evas, Evas_Object *obj, void *event_info)
497{
498 GLData *gld = data;
499 Evas_Event_Key_Up *ev = event_info;
500
501 if (gld->move)
502 {
503 // TODO - Careful, gld->move MIGHT be read at the other end by another thread. MIGHT, coz I really don't know at what point the camera animate routine is actually called.
504
505 // Yes, we are dealing with the horrid Evas keyboard handling FUCKING STRING COMPARES! Soooo ...
506 // TODO - make this a hash lookup dammit.
507 if (0 == strcmp(ev->key, "Escape"))
508 {
509 }
510 else if (0 == strcmp(ev->key, "Left"))
511 gld->move->r = 0.0;
512 else if (0 == strcmp(ev->key, "Right"))
513 gld->move->r = 0.0;
514 else if (0 == strcmp(ev->key, "Up"))
515 gld->move->x = 0.0;
516 else if (0 == strcmp(ev->key, "Down"))
517 gld->move->x = 0.0;
518// else if (0 == strcmp(ev->key, "Prior"))
519// ;
520// else if (0 == strcmp(ev->key, "Next"))
521// ;
522// else if (0 == strcmp(ev->key, "Home"))
523// ;
524// else if (0 == strcmp(ev->key, "End"))
525// ;
526 else if (0 == strcmp(ev->key, "space"))
527 gld->move->jump = 0.0;
528 else
529 printf("Unexpected up keystroke - %s\n", ev->key);
530 }
531 else
532 printf("Camera input not ready\n");
533}
534
535// Elm style event callback.
536static Eina_Bool _cb_event_GL(void *data, Evas_Object *obj, Evas_Object *src, Evas_Callback_Type type, void *event_info)
537{
538 GLData *gld = data;
539 Eina_Bool processed = EINA_FALSE;
540
541 switch (type)
542 {
543 case EVAS_CALLBACK_KEY_DOWN :
544 {
545 _on_camera_input_down(gld, evas_object_evas_get(obj), obj, event_info);
546 processed = EINA_TRUE;
547 break;
548 }
549
550 case EVAS_CALLBACK_KEY_UP :
551 {
552 _on_camera_input_up(gld, evas_object_evas_get(obj), obj, event_info);
553 processed = EINA_TRUE;
554 break;
555 }
556
557 default :
558 printf("Unknown GL input event.\n");
559 }
560
561 return processed;
562}
563
564// Elm inlined image windows needs this to change focus on mouse click.
565// Evas style event callback.
566static void _cb_mouse_down_elm(void *data, Evas *evas, Evas_Object *obj, void *event_info)
567{
568// GLData *gld = data;
569 Evas_Event_Mouse_Down *ev = event_info;
570
571 if (1 == ev->button)
572 elm_object_focus_set(obj, EINA_TRUE);
573}
574
575static void _resize_winwin(GLData *gld)
576{
577 Evas_Coord x, y, w, h;
578
579 evas_object_geometry_get(gld->elmGl, &x, &y, &w, &h);
580 evas_object_move(elm_win_inlined_image_object_get (gld->winwin), x, y);
581 evas_object_resize(elm_win_inlined_image_object_get(gld->winwin), w, h);
582}
583
584// Called from on_pixels (), or the Elm_gliew resize callback.
585static void _resize(GLData *gld)
586{
587 Evas_GL_API *gl = gld->glApi;
588
589 _resize_winwin(gld);
590
591#if DO_GEARS
592 GLfloat ar, m[16] = {
593 1.0, 0.0, 0.0, 0.0,
594 0.0, 1.0, 0.0, 0.0,
595 0.0, 0.0, 0.1, 0.0,
596 0.0, 0.0, 0.0, 1.0
597 };
598
599 // GL Viewport stuff. you can avoid doing this if viewport is all the
600 // same as last frame if you want
601 if (gld->img_w < gld->img_h)
602 ar = gld->img_w;
603 else
604 ar = gld->img_h;
605
606 m[0] = 0.1 * ar / gld->img_w;
607 m[5] = 0.1 * ar / gld->img_h;
608 memcpy(gld->proj, m, sizeof gld->proj);
609#endif
610
611 gl->glViewport(0, 0, (GLint) gld->img_w, (GLint) gld->img_h);
612}
613
614static void _resize_gl(Evas_Object *obj)
615{
616 int w, h;
617 GLData *gld = evas_object_data_get(obj, "gld");
618
619 elm_glview_size_get(obj, &w, &h);
620
621 gld->img_w = w;
622 gld->img_h = h;
623 _resize(gld);
624}
625
626static void on_pixels(void *data, Evas_Object *obj)
627{
628 GLData *gld = data;
629 Evas_GL_API *gl = gld->glApi;
630
631 // get the image size in case it changed with evas_object_image_size_set()
632 if (gld->r1)
633 {
634 Evas_Coord w, h;
635
636 // Poor mans resize check. coz Elm wont do it easily.
637 evas_object_image_size_get(gld->r1, &w, &h);
638 if ((gld->img_w != w) || (gld->img_h != h))
639 {
640 // No idea where this crap came from.
641 //float new_w = ((float) gld->scr_w / ((float) gld->scr_w * (float) w));
642 //float new_h = ((float) gld->scr_h / ((float) gld->scr_h * (float) h));
643
644 //gld->sfc_w = new_w;
645 //gld->sfc_h = new_h;
646 //evas_object_image_fill_set(gld->r1, 0, 0, gld->sfc_w, gld->sfc_h);
647 gld->img_w = w;
648 gld->img_h = h;
649 gld->resized = 1;
650 }
651 }
652
653 if (gld->useEGL)
654 {
655 // Yes, we DO need to do our own make current, coz aparently the Irrlicht one is useless.
656 // Hopefully Elm_GL has done this for us by now.
657 // Evas_GL needs it to.
658 if (gld->ctx)
659 evas_gl_make_current(gld->evasGl, gld->sfc, gld->ctx);
660 }
661
662 if (!gld->doneIrr)
663 gld->doneIrr = startIrr(gld); // Needs to be after gld->win is shown, and needs to be done in the render thread.
664#if DO_GEARS
665 if (!gld->gearsInited)
666 gears_init(gld);
667#endif
668
669 if (gld->resized)
670 _resize(gld);
671
672 drawIrr_start(gld);
673
674#if DO_GEARS
675 if (gld->useEGL)
676 {
677 static const GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
678 static const GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
679 static const GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
680 GLfloat m[16];
681
682 // Draw the gears.
683 if (!gld->useIrr)
684 {
685 gl->glClearColor(0.7, 0.0, 1.0, 1.0);
686 gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
687 }
688
689 memcpy(m, gld->proj, sizeof m);
690 rotate(m, 2 * M_PI * gld->view_rotx / 360.0, 1, 0, 0);
691 rotate(m, 2 * M_PI * gld->view_roty / 360.0, 0, 1, 0);
692 rotate(m, 2 * M_PI * gld->view_rotz / 360.0, 0, 0, 1);
693
694 draw_gear(gld, gld->gear1, m, -3.0, -2.0, gld->angle, red);
695 draw_gear(gld, gld->gear2, m, 3.1, -2.0, -2 * gld->angle - 9.0, green);
696 draw_gear(gld, gld->gear3, m, -3.1, 4.2, -2 * gld->angle - 25.0, blue);
697 gld->angle += 2.0;
698 }
699#endif
700
701 drawIrr_end(gld);
702
703#if USE_IR
704#else
705 // This might get done deep within drawIrr_end, but only if we are using Irrlicht.
706
707 // Optional - Flush the GL pipeline
708 gl->glFlush();
709// gl->glFinish();
710#endif
711
712 gld->resized = 0;
713}
714
715static void _draw_gl(Evas_Object *obj)
716{
717// Evas_GL_API *gl = elm_glview_gl_api_get(obj);
718 GLData *gld = evas_object_data_get(obj, "gld");
719 if (!gld) return;
720
721 on_pixels(gld, obj);
722}
723
724// Callback from Evas, also used as the general callback for deleting the GL stuff.
725static void _clean_gl(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
726{
727 GLData *gld = data;
728 Evas_GL_API *gl = gld->glApi;
729
730 ecore_animator_del(gld->animator);
731
732 if (gld->useEGL)
733 {
734 // Do a make_current before deleting all the GL stuff.
735 evas_gl_make_current(gld->evasGl, gld->sfc, gld->ctx);
736
737 }
738
739 gl->glDeleteShader(gld->vtx_shader);
740 gl->glDeleteShader(gld->fgmt_shader);
741 gl->glDeleteProgram(gld->program);
742
743 if (gld->evasGl)
744 {
745 // Irrlicht wants to destroy the context and surface, so only do this if Irrlicht wont.
746 if (!gld->doneIrr)
747 {
748 evas_gl_surface_destroy(gld->evasGl, gld->sfc);
749 evas_gl_context_destroy(gld->evasGl, gld->ctx);
750 }
751 // TODO - hope this is OK, considering the context and surface might get dealt with by Irrlicht.
752 // Might be better to teach Irrlicht to not destroy shit it did not create.
753 evas_gl_config_free(gld->cfg);
754 evas_gl_free(gld->evasGl);
755 }
756
757 // TODO - Since this is created on the render thread, better hope this is being deleted on the render thread.
758 finishIrr(gld);
759
760#if DO_GEARS
761 gl->glDeleteBuffers(1, &gld->gear1->vbo);
762 gl->glDeleteBuffers(1, &gld->gear2->vbo);
763 gl->glDeleteBuffers(1, &gld->gear3->vbo);
764
765 free_gear(gld->gear1);
766 free_gear(gld->gear2);
767 free_gear(gld->gear3);
768#endif
769}
770
771// Callback from Elm, coz they do shit different.
772static void _del_gl(Evas_Object *obj)
773{
774 GLData *gld = evas_object_data_get(obj, "gld");
775 if (!gld)
776 {
777 printf("Unable to get GLData. \n");
778 return;
779 }
780
781 _clean_gl(gld, NULL, NULL, NULL);
782
783 evas_object_data_del((Evas_Object*)obj, "gld");
784}
785
786// Callback for when the app quits.
787static void _on_done(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
788{
789 GLData *gld = data;
790
791 evas_object_del(gld->win);
792 free(gld);
793 elm_exit();
794}
795
796// Callback from the animator.
797static Eina_Bool doFrame(void *data)
798{
799 GLData *gld = data;
800
801 // Mark the pixels as dirty, so they get rerendered each frame, then Irrlicht can draw it's stuff each frame.
802 // This causes on_pixel to be triggered by Evas_GL, and _draw_gl for Elm_glview.
803 if (gld->r1)
804 evas_object_image_pixels_dirty_set(gld->r1, EINA_TRUE);
805 if (gld->elmGl)
806 elm_glview_changed_set(gld->elmGl);
807
808 // If not using Evas_GL, we need to call on_pixel() manually.
809 if (!gld->useEGL)
810 on_pixels(gld, gld->r1);
811
812 return EINA_TRUE; // Keep calling us.
813}
814
815static void init_evas_gl(GLData *gld)
816{
817 if (!gld->useEGL)
818 return;
819
820 gld->sfc_w = gld->win_w;
821 gld->sfc_h = gld->win_h;
822
823 // Get the Evas / canvas from the elm window (that the Evas_Object "lives on"), which is itself an Evas_Object created by Elm, so not sure if it was created internally with Ecore_Evas.
824 gld->canvas = evas_object_evas_get(gld->win);
825 // An Ecore_Evas holds an Evas.
826 // Get the Ecore_Evas that wraps an Evas.
827 gld->ee = ecore_evas_ecore_evas_get(gld->canvas); // Only use this on Evas that was created with Ecore_Evas.
828
829#if USE_ELM_GL
830 // Add a GLView
831 gld->elmGl = elm_glview_add(gld->win);
832 evas_object_size_hint_align_set(gld->elmGl, EVAS_HINT_FILL, EVAS_HINT_FILL);
833 evas_object_size_hint_weight_set(gld->elmGl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
834 elm_glview_mode_set(gld->elmGl, 0 | ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH | ELM_GLVIEW_DIRECT);
835 elm_glview_resize_policy_set(gld->elmGl, ELM_GLVIEW_RESIZE_POLICY_RECREATE); // Destroy the current surface on a resize and create a new one.
836 elm_glview_render_policy_set(gld->elmGl, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND);
837// elm_glview_render_policy_set(gld->elmGl, ELM_GLVIEW_RENDER_POLICY_ALWAYS);
838 // These get called in the render thread I think.
839 // None let me pass data, so this is why we are adding "gld" data to the object below.
840 // Maybe we can use elm_object_signal_callback_add or elm_object_item_signal_callback_add (edje signals)?
841 //elm_glview_init_func_set(gld->elmGl, _init_gl); // Not actually needed, it gets done in on_pixels.
842 elm_glview_del_func_set(gld->elmGl, _del_gl);
843 elm_glview_resize_func_set(gld->elmGl, _resize_gl);
844 elm_glview_render_func_set(gld->elmGl, (Elm_GLView_Func_Cb) _draw_gl);
845
846 // Not needed, the resize callback above deals with that.
847 //elm_win_resize_object_add(gld->win, gld->elmGl);
848 gld->glApi = elm_glview_gl_api_get(gld->elmGl);
849 evas_object_data_set(gld->elmGl, "gld", gld);
850 evas_object_show(gld->elmGl);
851 elm_box_pack_end(gld->bx, gld->elmGl);
852#else
853 // get the evas gl handle for doing gl things
854 gld->evasGl = evas_gl_new(gld->canvas);
855 gld->glApi = evas_gl_api_get(gld->evasGl);
856
857 // Set a surface config
858 gld->cfg = evas_gl_config_new();
859 gld->cfg->color_format = EVAS_GL_RGBA_8888;
860 gld->cfg->depth_bits = EVAS_GL_DEPTH_BIT_32;
861 gld->cfg->stencil_bits = EVAS_GL_STENCIL_NONE;
862 gld->cfg->options_bits = EVAS_GL_OPTIONS_DIRECT;
863
864 // create a surface and context
865 gld->sfc = evas_gl_surface_create(gld->evasGl, gld->cfg, gld->sfc_w, gld->sfc_h);
866 gld->ctx = evas_gl_context_create(gld->evasGl, NULL); // The second NULL is for sharing contexts I think, which might be what we want to do with Irrlicht. It's not documented.
867
868 // Set up the image object, a filled one by default.
869 gld->r1 = evas_object_image_filled_add(gld->canvas);
870
871 // attach important data we need to the object using key names. This just
872 // avoids some global variables and means we can do nice cleanup. You can
873 // avoid this if you are lazy
874 // Not actually needed, with evas we can pass data pointers to stuff.
875 //evas_object_data_set(gld->r1, "gld", gld);
876
877 // when the object is deleted - call the on_del callback. like the above,
878 // this is just being clean
879 evas_object_event_callback_add(gld->r1, EVAS_CALLBACK_DEL, _clean_gl, gld);
880
881 // set up an actual pixel size for the buffer data. it may be different
882 // to the output size. any windowing system has something like this, just
883 // evas has 2 sizes, a pixel size and the output object size
884 evas_object_image_size_set(gld->r1, gld->sfc_w, gld->sfc_h);
885 // Not actualy needed, as we create the image already filled.
886 //evas_object_image_fill_set(gld->r1, 0, 0, gld->sfc_w, gld->sfc_h);
887
888 // These two are not in the original example, but I get black r1 when I leave them out.
889 evas_object_size_hint_align_set(gld->r1, EVAS_HINT_FILL, EVAS_HINT_FILL);
890 evas_object_size_hint_weight_set(gld->r1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
891
892 // set up the native surface info to use the context and surface created
893 // above
894 evas_gl_native_surface_get(gld->evasGl, gld->sfc, &(gld->ns));
895 evas_object_image_native_surface_set(gld->r1, &(gld->ns));
896 evas_object_image_pixels_get_callback_set(gld->r1, on_pixels, gld);
897
898 // move the image object somewhere, resize it and show it. any windowing
899 // system would need this kind of thing - place a child "window"
900 // Hmm, no need to resize it anyway, it's sized above.
901 evas_object_move(gld->r1, 0, 0);
902 //evas_object_resize(gld->r1, gld->sfc_w, gld->sfc_h);
903 elm_win_resize_object_add(gld->win, gld->r1);
904 evas_object_show(gld->r1);
905 elm_box_pack_end(gld->bx, gld->r1);
906
907 evas_object_event_callback_add(gld->r1, EVAS_CALLBACK_MOUSE_DOWN, _cb_mouse_down_GL, gld);
908// evas_object_event_callback_add(gld->r1, EVAS_CALLBACK_KEY_DOWN, _on_camera_input_down, gld);
909// evas_object_event_callback_add(gld->r1, EVAS_CALLBACK_KEY_UP, _on_camera_input_up, gld);
910#endif
911
912 // NOTE: if you delete r1, this animator will keep running trying to access
913 // r1 so you'd better delete this animator with ecore_animator_del() or
914 // structure how you do animation differently. you can also attach it like
915 // evasGl, sfc, etc. etc. if this animator is specific to this object
916 // only and delete it in the del handler for the obj.
917 //
918 // TODO - apparently the proper way to deal with the new async rendering is to have this animator do the dirty thing, and call the Irrlicht rendering stuff in the on_pixel call set above.
919 // That still leaves the problem of the Irrlicht setup being in the main thread. Which also should be done in on_pixel, as that's done in the correct thread.
920
921 // Jiggling this seems to produce a trade off between flickering and frame rate. Nothing else changed the flickering.
922 ecore_animator_frametime_set(0.04); // Default is 1/30, or 0.033333
923 gld->animator = ecore_animator_add(doFrame, gld); // This animator will be called every frame tick, which defaults to 1/30 seconds.
924
925 return;
926}
927
928
929//-------------------------//
930
931
932static Evas_Object *_content_image_new(Evas_Object *parent, const char *img)
933{
934 Evas_Object *ic;
935
936 ic = elm_icon_add(parent);
937 elm_image_file_set(ic, img, NULL);
938 return ic;
939}
940
941static void _promote(void *data, Evas_Object *obj , void *event_info )
942{
943 elm_naviframe_item_promote(data);
944}
945
946static char *_grid_label_get(void *data, Evas_Object *obj, const char *part)
947{
948 ezGrid *thisGrid = data;
949 char buf[256];
950
951 if (!strcmp(part, "elm.text"))
952 {
953 int count = eina_clist_count(&(thisGrid->accounts));
954
955 if (0 == count)
956 snprintf(buf, sizeof(buf), "%s (no accounts)", thisGrid->name);
957 else if (1 == count)
958 snprintf(buf, sizeof(buf), "%s (%d account)", thisGrid->name, count);
959 else
960 snprintf(buf, sizeof(buf), "%s (%d accounts)", thisGrid->name, count);
961 }
962 else
963 snprintf(buf, sizeof(buf), "%s", thisGrid->loginURI);
964 return strdup(buf);
965}
966
967static Evas_Object *_grid_content_get(void *data, Evas_Object *obj, const char *part)
968{
969 ezGrid *thisGrid = data;
970 Evas_Object *ic = elm_icon_add(obj);
971
972 if (!strcmp(part, "elm.swallow.icon"))
973 elm_icon_standard_set(ic, thisGrid->icon);
974
975 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
976 return ic;
977}
978
979static char * _account_label_get(void *data, Evas_Object *obj, const char *part)
980{
981 ezAccount *thisAccount = data;
982 char buf[256];
983
984 buf[0] = '\0';
985 if (!strcmp(part, "elm.text"))
986 snprintf(buf, sizeof(buf), "%s", thisAccount->name);
987
988 return strdup(buf);
989}
990
991static Evas_Object *_account_content_get(void *data, Evas_Object *obj, const char *part)
992{
993 ezAccount *thisAccount = data;
994 Evas_Object *ic = elm_icon_add(obj);
995
996 if (!strcmp(part, "elm.swallow.icon"))
997 elm_icon_standard_set(ic, thisAccount->icon);
998
999 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
1000 return ic;
1001}
1002
1003static char *_viewer_label_get(void *data, Evas_Object *obj, const char *part)
1004{
1005 ezViewer *thisViewer = data;
1006 char buf[256];
1007
1008 if (!strcmp(part, "elm.text"))
1009 snprintf(buf, sizeof(buf), "%s", thisViewer->name);
1010 else
1011 snprintf(buf, sizeof(buf), "%s", thisViewer->version);
1012 return strdup(buf);
1013}
1014
1015static Evas_Object *_viewer_content_get(void *data, Evas_Object *obj, const char *part)
1016{
1017 ezViewer *thisViewer = data;
1018 Evas_Object *ic = elm_icon_add(obj);
1019
1020 if (!strcmp(part, "elm.swallow.icon"))
1021 elm_icon_standard_set(ic, thisViewer->icon);
1022
1023 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
1024 return ic;
1025}
1026
1027
1028static void _grid_sel_cb(void *data, Evas_Object *obj, void *event_info)
1029{
1030 ezGrid *thisGrid = data;
1031 GLData *gld = thisGrid->gld;
1032 char buf[PATH_MAX];
1033
1034// sprintf(buf, "dillo -f -g '%dx%d+%d+%d' %s &", gld->win_w - (gld->win_w / 5), gld->win_h - 30, gld->win_w / 5, gld->win_y, thisGrid->splashPage);
1035 sprintf(buf, "uzbl -g '%dx%d+%d+%d' -u %s &", gld->win_w - (gld->win_w / 5), gld->win_h - 30, gld->win_w / 5, gld->win_y, thisGrid->splashPage);
1036 printf("%s ### genlist obj [%p], item pointer [%p]\n", buf, obj, event_info);
1037// comment this out for now, busy dealing with input stuff, don't want to trigger this multiple times.
1038// system(buf);
1039}
1040
1041static void cb_mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info)
1042{
1043 Evas_Event_Mouse_Move *ev = event_info;
1044 Evas_Object *orig = data;
1045 Evas_Coord x, y;
1046 Evas_Map *p;
1047 int i, w, h;
1048
1049 if (!ev->buttons) return;
1050 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1051 evas_object_move(obj,
1052 x + (ev->cur.canvas.x - ev->prev.output.x),
1053 y + (ev->cur.canvas.y - ev->prev.output.y));
1054 evas_object_image_size_get(orig, &w, &h);
1055 p = evas_map_new(4);
1056 evas_object_map_enable_set(orig, EINA_TRUE);
1057// evas_object_raise(orig);
1058 for (i = 0; i < 4; i++)
1059 {
1060 Evas_Object *hand;
1061 char key[32];
1062
1063 snprintf(key, sizeof(key), "h-%i\n", i);
1064 hand = evas_object_data_get(orig, key);
1065 evas_object_raise(hand);
1066 evas_object_geometry_get(hand, &x, &y, NULL, NULL);
1067 x += 15;
1068 y += 15;
1069 evas_map_point_coord_set(p, i, x, y, 0);
1070 if (i == 0) evas_map_point_image_uv_set(p, i, 0, 0);
1071 else if (i == 1) evas_map_point_image_uv_set(p, i, w, 0);
1072 else if (i == 2) evas_map_point_image_uv_set(p, i, w, h);
1073 else if (i == 3) evas_map_point_image_uv_set(p, i, 0, h);
1074 }
1075 evas_object_map_set(orig, p);
1076 evas_map_free(p);
1077}
1078
1079static void create_handles(Evas_Object *obj)
1080{
1081 int i;
1082 Evas_Coord x, y, w, h;
1083
1084 evas_object_geometry_get(obj, &x, &y, &w, &h);
1085 for (i = 0; i < 4; i++)
1086 {
1087 Evas_Object *hand;
1088 char buf[PATH_MAX];
1089 char key[32];
1090
1091 hand = evas_object_image_filled_add(evas_object_evas_get(obj));
1092 evas_object_resize(hand, 31, 31);
1093 snprintf(buf, sizeof(buf), "%s/media/pt.png", elm_app_data_dir_get());
1094 evas_object_image_file_set(hand, buf, NULL);
1095 if (i == 0) evas_object_move(hand, x - 15, y - 15);
1096 else if (i == 1) evas_object_move(hand, x + w - 15, y - 15);
1097 else if (i == 2) evas_object_move(hand, x + w - 15, y + h - 15);
1098 else if (i == 3) evas_object_move(hand, x - 15, y + h - 15);
1099 evas_object_event_callback_add(hand, EVAS_CALLBACK_MOUSE_MOVE, cb_mouse_move, obj);
1100 evas_object_show(hand);
1101 snprintf(key, sizeof(key), "h-%i\n", i);
1102 evas_object_data_set(obj, key, hand);
1103 }
1104}
1105
1106static Evas_Object *_toolbar_menu_add(Evas_Object *win, Evas_Object *tb, char *label)
1107{
1108 Evas_Object *menu= NULL;
1109 Elm_Object_Item *tb_it;
1110//, *menu_it;
1111
1112 tb_it = elm_toolbar_item_append(tb, NULL, label, NULL, NULL);
1113 elm_toolbar_item_menu_set(tb_it, EINA_TRUE);
1114 // Priority is for when toolbar items are set to hide or menu when there are too many of them. They get hidden or put on the menu based on priority.
1115 elm_toolbar_item_priority_set(tb_it, 9999);
1116 elm_toolbar_menu_parent_set(tb, win);
1117 menu = elm_toolbar_item_menu_get(tb_it);
1118
1119 return menu;
1120}
1121
1122static Evas_Object *fang_win_add(GLData *gld)
1123{
1124 Evas_Object *win, *bg;
1125
1126 // In theory this should create an EWS window, in practice, I'm not seeing any difference.
1127 // Guess I'll have to implement my own internal window manager. I don't think a basic one will be that hard. Famous last words.
1128// elm_config_engine_set("ews");
1129 win = elm_win_add(gld->win, "inlined", ELM_WIN_INLINED_IMAGE);
1130 // On mouse down we try to shift focus to the backing image, this seems to be the correct thing to force focus onto it's widgets.
1131 // According to the Elm inlined image window example, this is what's needed to.
1132 evas_object_event_callback_add(elm_win_inlined_image_object_get(win), EVAS_CALLBACK_MOUSE_DOWN, _cb_mouse_down_elm, gld);
1133 elm_win_alpha_set(win, EINA_TRUE);
1134
1135 // Apparently transparent is not good enough for ELM backgrounds, so make it a rectangle.
1136 // Apparently coz ELM prefers stuff to have edjes. A bit over the top if all I want is a transparent rectangle.
1137 bg = evas_object_rectangle_add(evas_object_evas_get(win));
1138 evas_object_color_set(bg, 50, 0, 100, 100);
1139 evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1140 elm_win_resize_object_add(win, bg);
1141 evas_object_show(bg);
1142
1143 return win;
1144}
1145
1146static void fang_win_complete(GLData *gld, Evas_Object *win, int x, int y, int w, int h)
1147{
1148 // image object for win is unlinked to its pos/size - so manual control
1149 // this allows also for using map and other things with it.
1150 evas_object_move(elm_win_inlined_image_object_get(win), x, y);
1151 // Odd, it needs to be resized twice. WTF?
1152 evas_object_resize(win, w, h);
1153 evas_object_resize(elm_win_inlined_image_object_get(win), w, h);
1154 evas_object_show(win);
1155 create_handles(elm_win_inlined_image_object_get(win));
1156}
1157
1158static void overlay_add(GLData *gld)
1159{
1160 Evas_Object *bg;
1161//, *bx, *tb, *menu;
1162// Elm_Object_Item *tb_it, *menu_it;
1163
1164 // There many are reasons for this window.
1165 // The first is to cover the GL and provide something to click on to change focus.
1166 // The second is to provide something to click on for all the GL type clicking stuff that needs to be done. In other words, no click through,we catch the clicks here.
1167 // So we can probably avoid the following issue -
1168 // How to do click through? evas_object_pass_events_set(rectangle, EINA_TRUE), and maybe need to do that to the underlaying window to?
1169 // Though if the rectangle is entirely transparent, or even hidden, events might pass through anyway.
1170 // Gotta have click through on the parts where there's no other window.
1171 // The third is to have the other windows live here.
1172 // This idea doesn't work, as it breaks the damn focus again.
1173 // Don't think it's needed anyway.
1174 // While on the subject of layers, need a HUD layer of some sort, but Irrlicht might support that itself.
1175
1176 gld->winwin = elm_win_add(gld->win, "inlined", ELM_WIN_INLINED_IMAGE);
1177 // On mouse down we try to shift focus to the backing image, this seems to be the correct thing to force focus onto it's widgets.
1178 // According to the Elm inlined image window example, this is what's needed to.
1179 evas_object_event_callback_add(elm_win_inlined_image_object_get(gld->winwin), EVAS_CALLBACK_MOUSE_DOWN, _cb_mouse_down_elm, gld);
1180 // In this code, we are making our own camera, so grab it's input when we are focused.
1181 evas_object_event_callback_add(gld->winwin, EVAS_CALLBACK_KEY_DOWN, _on_camera_input_down, gld);
1182 evas_object_event_callback_add(gld->winwin, EVAS_CALLBACK_KEY_UP, _on_camera_input_up, gld);
1183 elm_object_event_callback_add(gld->winwin, _cb_event_GL, gld);
1184
1185 elm_win_alpha_set(gld->winwin, EINA_TRUE);
1186 // Apparently transparent is not good enough for ELM backgrounds, so make it a rectangle.
1187 // Apparently coz ELM prefers stuff to have edjes. A bit over the top if all I want is a transparent rectangle.
1188 bg = evas_object_rectangle_add(evas_object_evas_get(gld->winwin));
1189 evas_object_color_set(bg, 0, 0, 0, 0);
1190 evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1191 elm_win_resize_object_add(gld->winwin, bg);
1192 evas_object_show(bg);
1193
1194 // image object for win is unlinked to its pos/size - so manual control
1195 // this allows also for using map and other things with it.
1196 evas_object_move(elm_win_inlined_image_object_get(gld->winwin), 0, 0);
1197 // Odd, it needs to be resized twice. WTF?
1198 evas_object_resize(gld->winwin, gld->win_w, gld->win_h);
1199 evas_object_resize(elm_win_inlined_image_object_get(gld->winwin), gld->win_w, gld->win_h);
1200 evas_object_show(gld->winwin);
1201}
1202
1203static void chat_add(GLData *gld)
1204{
1205 Evas_Object *win, *bx, *en;
1206
1207 win = fang_win_add(gld);
1208
1209 bx = elm_box_add(win);
1210 elm_win_resize_object_add(win, bx);
1211 evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1212 evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
1213
1214 en = elm_entry_add(win);
1215 elm_entry_scrollable_set(en, EINA_TRUE);
1216 evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1217 evas_object_size_hint_align_set(en, EVAS_HINT_FILL, EVAS_HINT_FILL);
1218 elm_object_text_set(en, "History is shown here");
1219 elm_entry_editable_set(en, EINA_FALSE);
1220 evas_object_show(en);
1221 elm_box_pack_end(bx, en);
1222
1223 en = elm_entry_add(win);
1224 elm_entry_scrollable_set(en, EINA_TRUE);
1225 evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1226 evas_object_size_hint_align_set(en, EVAS_HINT_FILL, EVAS_HINT_FILL);
1227 elm_object_text_set(en, "");
1228 elm_entry_editable_set(en, EINA_TRUE);
1229 evas_object_show(en);
1230 elm_box_pack_end(bx, en);
1231
1232 evas_object_show(bx);
1233
1234 fang_win_complete(gld, win, 30, 500, gld->win_w / 3, gld->win_h / 3);
1235}
1236
1237
1238static void woMan_add(GLData *gld)
1239{
1240// Evas_Object *win, *bg, *bx, *ic, *bb, *av, *en, *bt, *nf, *tab, *tb, *gridList, *viewerList, *menu;
1241 Evas_Object *win, *bx, *bt, *nf, *tab, *tb, *gridList, *viewerList, *menu;
1242 Elm_Object_Item *tb_it, *menu_it, *tab_it;
1243// char buf[PATH_MAX];
1244 int i;
1245
1246 win = fang_win_add(gld);
1247
1248 bx = elm_box_add(win);
1249 elm_win_resize_object_add(win, bx);
1250 evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1251 evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
1252
1253 // A tab thingy.
1254 tb = elm_toolbar_add(win);
1255 evas_object_size_hint_weight_set(tb, EVAS_HINT_EXPAND, 0.0);
1256 evas_object_size_hint_align_set(tb, EVAS_HINT_FILL, EVAS_HINT_FILL);
1257 elm_toolbar_shrink_mode_set(tb, ELM_TOOLBAR_SHRINK_SCROLL);
1258
1259 // Menu.
1260 tb_it = elm_toolbar_item_append(tb, NULL, "Menu", NULL, NULL);
1261 elm_toolbar_item_menu_set(tb_it, EINA_TRUE);
1262 // Priority is for when toolbar items are set to hide or menu when there are too many of them. They get hidden or put on the menu based on priority.
1263 elm_toolbar_item_priority_set(tb_it, 9999);
1264 elm_toolbar_menu_parent_set(tb, win);
1265 menu = elm_toolbar_item_menu_get(tb_it);
1266
1267 menu_it = elm_menu_item_add(menu, NULL, NULL, "edit", NULL, NULL);
1268 elm_menu_item_add(menu, menu_it, NULL, "preferences", NULL, NULL);
1269 menu_it = elm_menu_item_add(menu, NULL, NULL, "help", NULL, NULL);
1270 elm_menu_item_add(menu, menu_it, NULL, "about woMan", NULL, NULL);
1271 elm_menu_item_separator_add(menu, NULL);
1272 menu_it = elm_menu_item_add(menu, NULL, NULL, "advanced", NULL, NULL);
1273 elm_menu_item_add(menu, menu_it, NULL, "debug settings", NULL, NULL);
1274
1275 // The toolbar needs to be packed into the box AFTER the menus are added.
1276 elm_box_pack_end(bx, tb);
1277 evas_object_show(tb);
1278
1279 gridList = elm_genlist_add(win);
1280 grids = eina_hash_stringshared_new(free);
1281
1282 grid_gic = elm_genlist_item_class_new();
1283 grid_gic->item_style = "double_label";
1284 grid_gic->func.text_get = _grid_label_get;
1285 grid_gic->func.content_get = _grid_content_get;
1286 grid_gic->func.state_get = NULL;
1287 grid_gic->func.del = NULL;
1288 for (i = 0; NULL != gridTest[i][0]; i++)
1289 {
1290 ezGrid *thisGrid = calloc(1, sizeof(ezGrid));
1291
1292 if (thisGrid)
1293 {
1294 eina_clist_init(&(thisGrid->accounts));
1295 eina_clist_init(&(thisGrid->landmarks));
1296 thisGrid->name = gridTest[i][0];
1297 thisGrid->loginURI = gridTest[i][1];
1298 thisGrid->splashPage = gridTest[i][2];
1299 thisGrid->icon = "folder";
1300 thisGrid->gld = gld;
1301 thisGrid->item = elm_genlist_item_append(gridList, grid_gic, thisGrid, NULL, ELM_GENLIST_ITEM_TREE, _grid_sel_cb, thisGrid);
1302 eina_hash_add(grids, thisGrid->name, thisGrid);
1303 }
1304 }
1305
1306 account_gic = elm_genlist_item_class_new();
1307 account_gic->item_style = "default";
1308 account_gic->func.text_get = _account_label_get;
1309 account_gic->func.content_get = _account_content_get;
1310 account_gic->func.state_get = NULL;
1311 account_gic->func.del = NULL;
1312 for (i = 0; NULL != accountTest[i][0]; i++)
1313 {
1314 ezAccount *thisAccount = calloc(1, sizeof(ezAccount));
1315 ezGrid *grid = eina_hash_find(grids, accountTest[i][0]);
1316
1317 if (thisAccount && grid)
1318 {
1319 thisAccount->name = accountTest[i][1];
1320 thisAccount->password = accountTest[i][2];
1321 thisAccount->icon = "file";
1322 elm_genlist_item_append(gridList, account_gic, thisAccount, grid->item, ELM_GENLIST_ITEM_NONE, NULL, NULL);
1323 eina_clist_add_tail(&(grid->accounts), &(thisAccount->grid));
1324 }
1325 }
1326
1327 // Viewers stuff
1328 viewerList = elm_genlist_add(win);
1329 viewer_gic = elm_genlist_item_class_new();
1330 viewer_gic->item_style = "double_label";
1331 viewer_gic->func.text_get = _viewer_label_get;
1332 viewer_gic->func.content_get = _viewer_content_get;
1333 viewer_gic->func.state_get = NULL;
1334 viewer_gic->func.del = NULL;
1335 for (i = 0; NULL != viewerTest[i][0]; i++)
1336 {
1337 ezViewer *thisViewer = calloc(1, sizeof(ezViewer));
1338
1339 if (thisViewer)
1340 {
1341 thisViewer->name = viewerTest[i][0];
1342 thisViewer->version = viewerTest[i][1];
1343 thisViewer->path = viewerTest[i][2];
1344 thisViewer->icon = "file";
1345 thisViewer->item = elm_genlist_item_append(viewerList, viewer_gic, thisViewer, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
1346 }
1347 }
1348
1349 // Toolbar pages
1350 nf = elm_naviframe_add(win);
1351 evas_object_size_hint_weight_set(nf, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1352 evas_object_size_hint_align_set(nf, EVAS_HINT_FILL, EVAS_HINT_FILL);
1353 evas_object_show(nf);
1354
1355 tab = viewerList; tab_it = elm_naviframe_item_push(nf, NULL, NULL, NULL, tab, NULL); elm_naviframe_item_title_enabled_set(tab_it, EINA_FALSE, EINA_TRUE); elm_toolbar_item_append(tb, NULL, "Viewers", _promote, tab_it);
1356 tab = _content_image_new(win, img3); tab_it = elm_naviframe_item_push(nf, NULL, NULL, NULL, tab, NULL); elm_naviframe_item_title_enabled_set(tab_it, EINA_FALSE, EINA_TRUE); elm_toolbar_item_append(tb, NULL, "Landmarks", _promote, tab_it);
1357 tab = gridList; tab_it = elm_naviframe_item_push(nf, NULL, NULL, NULL, tab, NULL); elm_naviframe_item_title_enabled_set(tab_it, EINA_FALSE, EINA_TRUE); elm_toolbar_item_append(tb, NULL, "Grids", _promote, tab_it);
1358 elm_box_pack_end(bx, nf);
1359
1360#if USE_EO
1361 // Not ready for prime time yet, or I'm missing a step. Causes it to hang after closing the window.
1362 // Slightly better now, it bitches instead of hanging.
1363 bt = eo_add(ELM_OBJ_BUTTON_CLASS, win);
1364 elm_object_text_set(bt, "Login"); // No eo interface for this that I can find.
1365 eo_do(bt,
1366// evas_obj_text_set("Login"),
1367 evas_obj_size_hint_align_set(EVAS_HINT_FILL, EVAS_HINT_FILL),
1368 evas_obj_size_hint_weight_set(EVAS_HINT_EXPAND, 0.0),
1369 evas_obj_visibility_set(EINA_TRUE)
1370 );
1371#else
1372 bt = elm_button_add(win);
1373 elm_object_text_set(bt, "Login");
1374 evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
1375 evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
1376 evas_object_show(bt);
1377#endif
1378// evas_object_smart_callback_add(bt, "clicked", NULL, NULL);
1379 elm_box_pack_end(bx, bt);
1380 evas_object_show(bx);
1381
1382 fang_win_complete(gld, win, 30, 30, gld->win_w / 3, gld->win_h / 3);
1383}
1384
1385EAPI_MAIN int elm_main(int argc, char **argv)
1386{
1387// Evas_Object *bg, *menu, *bt, *tb;
1388 Evas_Object *menu, *tb;
1389 Elm_Object_Item *tb_it;
1390//, *menu_it;
1391 EPhysics_Body *boundary;
1392 EPhysics_World *world;
1393 EPhysics_Body *box_body1, *box_body2;
1394 Evas_Object *box1, *box2;
1395 GLData *gld = NULL;
1396// char buf[PATH_MAX];
1397// int i;
1398// Eina_Bool gotWebKit = elm_need_web(); // Initialise ewebkit if it exists, or return EINA_FALSE if it don't.
1399
1400 _log_domain = eina_log_domain_register("extantz", NULL);
1401 // Don't do this, we need to clean up other stuff to, so set a clean up function below.
1402 //elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
1403
1404 // If you want efl to handle finding your bin/lib/data dirs, you must do this below.
1405 elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR);
1406 elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
1407 elm_app_info_set(elm_main, "datadir", "media/sky_03.jpg");
1408 fprintf(stdout, "prefix was set to: %s\n", elm_app_prefix_dir_get());
1409 fprintf(stdout, "data directory is: %s\n", elm_app_data_dir_get());
1410 fprintf(stdout, "library directory is: %s\n", elm_app_lib_dir_get());
1411 fprintf(stdout, "locale directory is: %s\n", elm_app_locale_dir_get());
1412
1413 // These are set via the elementary_config tool, which is hard to find.
1414 elm_config_finger_size_set(0);
1415 elm_config_scale_set(1.0);
1416
1417 // alloc a data struct to hold our relevant gl info in
1418 if (!(gld = calloc(1, sizeof(GLData)))) return 1;
1419 gldata_init(gld);
1420
1421 // Set the engine to opengl_x11, then open our window.
1422 if (gld->useEGL)
1423 elm_config_preferred_engine_set("opengl_x11");
1424 gld->win = elm_win_add(NULL, "extantz", ELM_WIN_BASIC);
1425 // Set preferred engine back to default from config
1426 elm_config_preferred_engine_set(NULL);
1427
1428#if USE_PHYSICS
1429 if (!ephysics_init())
1430 return 1;
1431#endif
1432
1433 elm_win_title_set(gld->win, "extantz virtual world manager");
1434 evas_object_smart_callback_add(gld->win, "delete,request", _on_done, gld);
1435
1436 // Get the screen size.
1437 elm_win_screen_size_get(gld->win, &gld->win_x, &gld->win_y, &gld->scr_w, &gld->scr_h);
1438 gld->win_x = gld->win_x + (gld->scr_w / 3);
1439 gld->win_w = gld->scr_w / 2;
1440 gld->win_h = gld->scr_h - 30;
1441
1442 // Note, we don't need an Elm_bg, the entire thing gets covered with the GL rendering surface anyway.
1443#if 0
1444 bg = elm_bg_add(gld->win);
1445 elm_bg_load_size_set(bg, gld->win_w, gld->win_h);
1446 elm_bg_option_set(bg, ELM_BG_OPTION_CENTER);
1447 snprintf(buf, sizeof(buf), "%s/media/sky_03.jpg", elm_app_data_dir_get());
1448 elm_bg_file_set(bg, buf, NULL);
1449 evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1450 elm_win_resize_object_add(gld->win, bg);
1451 evas_object_show(bg);
1452#endif
1453
1454 gld->bx = elm_box_add(gld->win);
1455 evas_object_size_hint_weight_set(gld->bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1456 evas_object_size_hint_align_set(gld->bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
1457 elm_win_resize_object_add(gld->win, gld->bx);
1458 evas_object_show(gld->bx);
1459
1460 overlay_add(gld);
1461 woMan_add(gld);
1462 chat_add(gld);
1463
1464 // Gotta do this after adding the windows, otherwise the menu renders under the window.
1465 // This sucks, gotta redefine this menu each time we create a new window?
1466 // Also, GL focus gets lost when any menu is used. sigh
1467
1468 // A toolbar thingy.
1469 tb = elm_toolbar_add(gld->win);
1470 evas_object_size_hint_weight_set(tb, EVAS_HINT_EXPAND, 0.0);
1471 evas_object_size_hint_align_set(tb, EVAS_HINT_FILL, EVAS_HINT_FILL);
1472 elm_toolbar_shrink_mode_set(tb, ELM_TOOLBAR_SHRINK_SCROLL);
1473 elm_toolbar_align_set(tb, 0.0);
1474
1475 // Menus.
1476 menu = _toolbar_menu_add(gld->win, tb, "file");
1477 elm_menu_item_add(menu, NULL, NULL, "quit", _on_done, gld);
1478
1479 menu = _toolbar_menu_add(gld->win, tb, "edit");
1480 elm_menu_item_add(menu, NULL, NULL, "preferences", NULL, NULL);
1481
1482 menu = _toolbar_menu_add(gld->win, tb, "view");
1483 menu = _toolbar_menu_add(gld->win, tb, "world");
1484 menu = _toolbar_menu_add(gld->win, tb, "tools");
1485
1486 menu = _toolbar_menu_add(gld->win, tb, "help");
1487 elm_menu_item_add(menu, NULL, NULL, "grid help", NULL, NULL);
1488 elm_menu_item_separator_add(menu, NULL);
1489 elm_menu_item_add(menu, NULL, NULL, "extantz blogs", NULL, NULL);
1490 elm_menu_item_add(menu, NULL, NULL, "extantz forum", NULL, NULL);
1491 elm_menu_item_separator_add(menu, NULL);
1492 elm_menu_item_add(menu, NULL, NULL, "about extantz", NULL, NULL);
1493
1494 menu = _toolbar_menu_add(gld->win, tb, "advanced");
1495 elm_menu_item_add(menu, NULL, NULL, "debug settings", NULL, NULL);
1496
1497 menu = _toolbar_menu_add(gld->win, tb, "god");
1498
1499 // Other stuff in the toolbar.
1500 tb_it = elm_toolbar_item_append(tb, NULL, NULL, NULL, NULL);
1501 elm_toolbar_item_separator_set(tb_it, EINA_TRUE);
1502 tb_it = elm_toolbar_item_append(tb, NULL, "restriction icons", NULL, NULL);
1503 tb_it = elm_toolbar_item_append(tb, NULL, NULL, NULL, NULL);
1504 elm_toolbar_item_separator_set(tb_it, EINA_TRUE);
1505 tb_it = elm_toolbar_item_append(tb, NULL, "hop://localhost/Anarchadia 152, 155, 51 - Lost plot (Adult)", NULL, NULL);
1506 tb_it = elm_toolbar_item_append(tb, NULL, NULL, NULL, NULL);
1507 elm_toolbar_item_separator_set(tb_it, EINA_TRUE);
1508 tb_it = elm_toolbar_item_append(tb, NULL, "date time:o'clock", NULL, NULL);
1509
1510 // The toolbar needs to be packed into the box AFTER the menus are added.
1511 evas_object_show(tb);
1512 elm_box_pack_start(gld->bx, tb);
1513
1514 // This does elm_box_pack_end(), so needs to be after the others.
1515 init_evas_gl(gld);
1516
1517 evas_object_show(gld->bx);
1518
1519#if USE_PHYSICS
1520 // ePhysics stuff.
1521 world = ephysics_world_new();
1522 ephysics_world_render_geometry_set(world, 0, 0, -50, gld->win_w, gld->win_h, 100);
1523
1524 boundary = ephysics_body_bottom_boundary_add(world);
1525 ephysics_body_restitution_set(boundary, 1);
1526 ephysics_body_friction_set(boundary, 0);
1527
1528 boundary = ephysics_body_top_boundary_add(world);
1529 ephysics_body_restitution_set(boundary, 1);
1530 ephysics_body_friction_set(boundary, 0);
1531
1532 boundary = ephysics_body_left_boundary_add(world);
1533 ephysics_body_restitution_set(boundary, 1);
1534 ephysics_body_friction_set(boundary, 0);
1535
1536 boundary = ephysics_body_right_boundary_add(world);
1537 ephysics_body_restitution_set(boundary, 1);
1538 ephysics_body_friction_set(boundary, 0);
1539
1540 box1 = elm_image_add(gld->win);
1541 elm_image_file_set(box1, PACKAGE_DATA_DIR "/media/" EPHYSICS_TEST_THEME ".edj", "blue-cube");
1542 evas_object_move(box1, gld->win_w / 2 - 80, gld->win_h - 200);
1543 evas_object_resize(box1, 70, 70);
1544 evas_object_show(box1);
1545
1546 box_body1 = ephysics_body_box_add(world);
1547 ephysics_body_evas_object_set(box_body1, box1, EINA_TRUE);
1548 ephysics_body_restitution_set(box_body1, 0.7);
1549 ephysics_body_friction_set(box_body1, 0);
1550 ephysics_body_linear_velocity_set(box_body1, -150, 200, 0);
1551 ephysics_body_angular_velocity_set(box_body1, 0, 0, 36);
1552 ephysics_body_sleeping_threshold_set(box_body1, 0.1, 0.1);
1553
1554 box2 = elm_image_add(gld->win);
1555 elm_image_file_set(box2, PACKAGE_DATA_DIR "/media/" EPHYSICS_TEST_THEME ".edj", "purple-cube");
1556 evas_object_move(box2, gld->win_w / 2 + 10, gld->win_h - 200);
1557 evas_object_resize(box2, 70, 70);
1558 evas_object_show(box2);
1559
1560 box_body2 = ephysics_body_box_add(world);
1561 ephysics_body_evas_object_set(box_body2, box2, EINA_TRUE);
1562 ephysics_body_restitution_set(box_body2, 0.7);
1563 ephysics_body_friction_set(box_body2, 0);
1564 ephysics_body_linear_velocity_set(box_body2, 80, -60, 0);
1565 ephysics_body_angular_velocity_set(box_body2, 0, 0, 360);
1566 ephysics_body_sleeping_threshold_set(box_body2, 0.1, 0.1);
1567
1568 ephysics_world_gravity_set(world, 0, 0, 0);
1569#endif
1570
1571 evas_object_move(gld->win, gld->win_x, gld->win_y);
1572 evas_object_resize(gld->win, gld->win_w, gld->win_h);
1573 evas_object_show(gld->win);
1574
1575 _resize_winwin(gld);
1576
1577 elm_run();
1578
1579#if USE_PHYSICS
1580 ephysics_world_del(world);
1581 ephysics_shutdown();
1582#endif
1583
1584 elm_shutdown();
1585
1586 return 0;
1587}
1588ELM_MAIN()