aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ClientHamr
diff options
context:
space:
mode:
authorDavid Walter Seikel2014-04-22 15:13:38 +1000
committerDavid Walter Seikel2014-04-22 15:13:38 +1000
commitdd009ccdfd62f9153dbc72f5f5de5d5f72979690 (patch)
tree50d62438c6d47dccf82f440986919b1ed3edbbd9 /ClientHamr
parentMove most of the README's and other docs into the new docs directory. (diff)
downloadSledjHamr-dd009ccdfd62f9153dbc72f5f5de5d5f72979690.zip
SledjHamr-dd009ccdfd62f9153dbc72f5f5de5d5f72979690.tar.gz
SledjHamr-dd009ccdfd62f9153dbc72f5f5de5d5f72979690.tar.bz2
SledjHamr-dd009ccdfd62f9153dbc72f5f5de5d5f72979690.tar.xz
Move all source into the new src directory, and shuffle a few other things around.
Diffstat (limited to 'ClientHamr')
-rw-r--r--ClientHamr/GuiLua/GuiLua.c456
-rw-r--r--ClientHamr/GuiLua/GuiLua.h35
-rwxr-xr-xClientHamr/GuiLua/build.lua23
-rw-r--r--ClientHamr/GuiLua/skang.c16
-rw-r--r--ClientHamr/GuiLua/skang.lua1686
-rw-r--r--ClientHamr/GuiLua/test.lua211
-rw-r--r--ClientHamr/GuiLua/test.properties1
-rwxr-xr-xClientHamr/GuiLua/test.sh3
-rw-r--r--ClientHamr/GuiLua/test.skang14
-rw-r--r--ClientHamr/GuiLua/test_c.c88
-rw-r--r--ClientHamr/extantz/CDemo.cpp510
-rw-r--r--ClientHamr/extantz/CDemo.h63
-rwxr-xr-xClientHamr/extantz/build.lua26
-rw-r--r--ClientHamr/extantz/crappisspuke.cpp294
-rw-r--r--ClientHamr/extantz/extantz.c1588
-rw-r--r--ClientHamr/extantz/extantz.edc30
-rw-r--r--ClientHamr/extantz/extantz.h215
-rw-r--r--ClientHamr/extantz/extantzCamera.cpp282
-rw-r--r--ClientHamr/extantz/extantzCamera.h101
19 files changed, 0 insertions, 5642 deletions
diff --git a/ClientHamr/GuiLua/GuiLua.c b/ClientHamr/GuiLua/GuiLua.c
deleted file mode 100644
index c7a368c..0000000
--- a/ClientHamr/GuiLua/GuiLua.c
+++ /dev/null
@@ -1,456 +0,0 @@
1/* GuiLua - a GUI library that implements matrix-RAD style stuff.
2
3Provides the skang and widget Lua packages.
4
5In the initial intended use case, several applications will be using
6this all at once, with one central app hosting all the GUIs.
7
8Basically this should deal with "windows" and their contents. A
9"window" in this case is hosted in the central app as some sort of
10internal window, but the user can "tear off" those windows, then they
11get their own OS hosted window. This could be done by the hosting app
12sending the current window contents to the original app as a skang file.
13
14Between the actual GUI and the app might be a socket, or a stdin/out
15pipe. Just like matrix-RAD, this should be transparent to the app.
16Also just like matrix-RAD, widgets can be connected to variable /
17functions (C or Lua), and any twiddlings with those widgets runs the
18function / changes the variable, again transparent to the app, except
19for any registered get/set methods.
20
21This interface between the GUI and the app is "skang" files, which are
22basically Lua scripts. The GUI and the app can send skang files back
23and forth, usually the app sends actual GUI stuff, and usually the GUI
24sends variable twiddles or action calls. Usually.
25
26To start with, this will be used to support multiple apps hosting their
27windows in extantz, allowing the big viewer blob to be split up into
28modules. At some point converting LL XML based UI shit into skang could
29be done. Also, this should be an exntension to LuaSL, so in-world
30scripts can have a poper GUI for a change.
31
32
33NOTES and TODOs -
34
35Lua scripts do -
36 require 'widget' -> loads widget.c
37 Widget.c is a library like test_c.
38 It starts up GuiLua.c app, with stdin/stdout pipe.
39 Widget.c then acts as a proxy for all the widget stuff.
40 So Lua modules via C libraries can work with Elm code that has a special main and has to be an app.
41 Seems simplest.
42
43 Also -
44 Some of this gets shared with LuaSL, since it came from there anyway.
45
46 Finally -
47 Add a --gui command line option, that runs foo.skang.
48 Than change the hash bang to use it.
49 And if there's a matching module, load the module first, call gimmeSkin() on it.
50 So that any with an internal default skin get that instead.
51 Same if there's a module, but no skang file.
52
53Making these packages all a sub package of skang seems like a great
54idea. On the other hand, looks like most things are just getting folded
55into skang anyway. See
56http://www.inf.puc-rio.br/~roberto/pil2/chapter15.pdf part 15.5 for
57package details.
58
59See if I can use LuaJIT FFI here. Since this will be a library, and
60skang apps could be written in C or Lua, perhaps writing this library to
61be FFI friendly instead of the usual Lua C binding might be the way to
62go? LuaJIT is not ready yet, since it needs include files copied into
63Lua files, and does not support macros, which EFL uses a lot of.
64
65For the "GUI hosted in another app" case, we will need some sort of
66internal window manager running in that other app.
67
68This might end up running dozens of Lua scripts, and could use the LuaSL
69Lua script running system. Moving that into this library might be a
70sane idea I think? Or prehaps a separate library that both LuaSL and
71GuiLua use?
72
73Raster wants a method of sending Lua tables around as edje messages.
74Between C, Edje, Edje Lua, and Lua. Sending between threads, and across
75sockets. Using a new edje message type, or eet for sockets, was
76suggested, but perhaps Lua skang is a better choice?
77
78Somehow access to the edje_lua2.c bindings should be provided. And
79bindings to the rest of EFL when they are done. Assuming the other EFL
80developers do proper introspection stuff, or let me do it.
81
82The generic Lua binding helper functions I wrote for edje_lua2.c could
83be used here as well, and expanded as discussed on the E devs mailing
84list. This would include the thread safe Lua function stuff copied
85into the README.
86
87There will eventually be a built in editor, like the zen editor from
88matrix-RAD. It might be a separate app.
89
90NAWS should probably live in here to. If I ever get around to writing
91it. lol
92
93The pre tokenized widget structure thingy I had planned in the
94matrix-RAD TODO just wont work, as it uses symbols. On the other hand,
95we will be using Lua tables anyway. B-)
96
97The last half of http://passingcuriosity.com/2009/extending-lua-in-c/
98might be of use.
99
100*/
101
102
103/* thing package
104
105Currently this is in skang.lua, but should bring this in here later.
106
107*/
108
109
110/* skang package
111
112Currently this is in skang.lua, but should bring this in here later.
113
114*/
115
116
117/* stuff & squeal packages
118
119Currently Stuff is in skang.lua, but should bring this in here later.
120
121*/
122
123
124/* widget package
125
126Currently widget design is in skang.lua, but should bring this in here later.
127
128*/
129
130
131/* introspection
132
133As detailed in README, EFL introspection doesn't seem to really be on
134the radar, but I might get lucky, or I might have to write it myself.
135For quick and dirty early testing, I'll probably write a widget package
136that has hard coded mappings between some basic "label", "button", etc.
137and ordinary elementary widgets. Proper introspection can come later.
138
139*/
140
141
142
143#include "GuiLua.h"
144
145
146globals ourGlobals;
147static const char *globName = "ourGlobals";
148
149
150// TODO - These functions should be able to deal with multiple windows.
151// TODO - Should be able to open external and internal windows, and even switch between them on the fly.
152static void _on_done(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
153{
154// globals *ourGlobals = data;
155
156 // Tell the main loop to stop, which it will, eventually.
157 elm_exit();
158}
159
160
161/* Sooo, how to do this -
162widget has to be a light userdata
163The rest can be Lua sub things? Each with a C function to update the widget.
164
165win.quitter:colour(1,2,3,4) -> win.quitter.colour(win.quitter, 1,2,3,4) -> __call(win.quitter.colour, win.quitter, 1,2,3,4) -> skang.colour(win.quitter.colour, win.quitter, 1,2,3,4)
166win.quitter.colour.r = 5 -> direct access to the table, well "direct" via Thing and Mum. We eventually want to call skang.colour() though.
167*/
168
169struct _Widget
170{
171 char magic[8];
172 Evas_Object *obj;
173 char *label, *look, *action, *help;
174 // foreground / background colour
175 // thing
176 // types {}
177 // skangCoord x, y, w, h
178};
179
180static void _on_click(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
181{
182 globals *ourGlobals;
183 lua_State *L = data;
184 struct _Widget *wid;
185
186 lua_getfield(L, LUA_REGISTRYINDEX, globName);
187 ourGlobals = lua_touserdata(L, -1);
188 lua_pop(L, 1);
189
190 wid = evas_object_data_get(obj, "Widget");
191 if (wid)
192 {
193 PD("Doing action %s", wid->action);
194 if (0 != luaL_dostring(L, wid->action))
195 PE("Error running - %s", wid->action);
196 }
197}
198
199static int widget(lua_State *L)
200{
201 globals *ourGlobals;
202 char *type = "label";
203 char *title = ":";
204 int x = 1, y = 1, w = WIDTH/3, h = HEIGHT/3;
205
206 lua_getfield(L, LUA_REGISTRYINDEX, globName);
207 ourGlobals = lua_touserdata(L, -1);
208 lua_pop(L, 1);
209
210 pull_lua(L, 1, "$type $title %x %y %w %h", &type, &title, &x, &y, &w, &h);
211
212 // Poor mans introspection, until I write real introspection into EFL.
213 if (strcmp(type, "button") == 0)
214 {
215 struct _Widget *wid;
216
217 wid = calloc(1, sizeof(struct _Widget));
218 strcpy(wid->magic, "Widget");
219 wid->label = strdup(title);
220 wid->obj = elm_button_add(ourGlobals->win);
221 elm_object_text_set(wid->obj, title);
222 evas_object_smart_callback_add(wid->obj, "clicked", _on_click, L);
223 evas_object_resize(wid->obj, w, h);
224 evas_object_move(wid->obj, x, y);
225 evas_object_show(wid->obj);
226 evas_object_data_set(wid->obj, "Widget", wid);
227 /* Evas_Object *bt isn't a real pointer it seems. At least Lua bitches about it -
228 PANIC: unprotected error in call to Lua API (bad light userdata pointer)
229 So we wrap it.
230 */
231 lua_pushlightuserdata(L, (void *) wid);
232 return 1;
233 }
234
235 return 0;
236}
237
238static int action(lua_State *L)
239{
240 globals *ourGlobals;
241 struct _Widget *wid = lua_touserdata(L, 1);
242 char *action = "nada";
243
244 lua_getfield(L, LUA_REGISTRYINDEX, globName);
245 ourGlobals = lua_touserdata(L, -1);
246 lua_pop(L, 1);
247
248 pull_lua(L, 2, "$", &action);
249 if (wid && strcmp(wid->magic, "Widget") == 0)
250 {
251 PD("Setting action %s", action);
252 wid->action = strdup(action);
253 }
254 return 0;
255}
256
257static int colour(lua_State *L)
258{
259// TODO - This is just a stub for now.
260
261 return 0;
262}
263
264static int window(lua_State *L)
265{
266 globals *ourGlobals;
267 char *name = "GuiLua";
268 char *title = "GuiLua test harness";
269 int w = WIDTH, h = HEIGHT;
270
271 lua_getfield(L, LUA_REGISTRYINDEX, globName);
272 ourGlobals = lua_touserdata(L, -1);
273 lua_pop(L, 1);
274
275 pull_lua(L, 1, "%w %h $title $name", &w, &h, &title, &name);
276 PI("Setting window to %d %d %s", w, h, title);
277
278 if ((ourGlobals->win = elm_win_util_standard_add(name, title)))
279 {
280 evas_object_smart_callback_add(ourGlobals->win, "delete,request", _on_done, ourGlobals);
281 evas_object_resize(ourGlobals->win, w, h);
282 evas_object_move(ourGlobals->win, 0, 0);
283 evas_object_show(ourGlobals->win);
284
285 lua_pushlightuserdata(L, &ourGlobals->win);
286 return 1;
287 }
288
289 return 0;
290}
291
292static int clear(lua_State *L)
293{
294// TODO - This is just a stub for now.
295
296 return 0;
297}
298
299static int loopWindow(lua_State *L)
300{
301 globals *ourGlobals;
302
303 lua_getfield(L, LUA_REGISTRYINDEX, globName);
304 ourGlobals = lua_touserdata(L, -1);
305 lua_pop(L, 1);
306
307 if (ourGlobals->win)
308 elm_run();
309
310 return 0;
311}
312
313static int quit(lua_State *L)
314{
315 globals *ourGlobals;
316
317 lua_getfield(L, LUA_REGISTRYINDEX, globName);
318 ourGlobals = lua_touserdata(L, -1);
319 lua_pop(L, 1);
320
321 _on_done(ourGlobals, NULL, NULL);
322
323 return 0;
324}
325
326static int closeWindow(lua_State *L)
327{
328 globals *ourGlobals;
329
330 lua_getfield(L, LUA_REGISTRYINDEX, globName);
331 ourGlobals = lua_touserdata(L, -1);
332 lua_pop(L, 1);
333
334 // Elm will delete our buttons to, and EO will bitch four times for each.
335 if (ourGlobals->win)
336 evas_object_del(ourGlobals->win);
337
338 if (ourGlobals->logDom >= 0)
339 {
340 eina_log_domain_unregister(ourGlobals->logDom);
341 ourGlobals->logDom = -1;
342 }
343
344 // This shuts down Elementary, but keeps the main loop running until all ecore_evas are freed.
345 elm_shutdown();
346
347 return 0;
348}
349
350/* local widget = require 'libGuiLua'
351
352Lua's require() function will strip any stuff from the front of the name
353separated by a hyphen, so 'ClientHamr-GuiLua-libGuiLua' -> 'libGuiLua'. Then
354it will search through a path, and eventually find this libGuiLua.so (or
355libGuiLua.dll or whatever), then call luaopen_libGuiLua(), which should return
356a table. The argument (only thing on the stack) for this function will
357be 'libGuiLua'.
358
359Normally luaL_register() creates a table of functions, that is the table
360returned, but we want to do something different with skang.
361*/
362int luaopen_GuiLua(lua_State *L)
363{
364 int skang;
365
366 // In theory this function only ever gets called once.
367 memset(&ourGlobals, 0, sizeof(globals));
368 ourGlobals.logDom = loggingStartup("GuiLua", ourGlobals.logDom);
369
370 elm_policy_set(ELM_POLICY_EXIT, ELM_POLICY_EXIT_NONE);
371 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_NONE);
372 elm_policy_set(ELM_POLICY_THROTTLE, ELM_POLICY_THROTTLE_HIDDEN_ALWAYS);
373
374 // These are set via the elementary_config tool, which is hard to find.
375 elm_config_finger_size_set(0);
376 elm_config_scale_set(1.0);
377
378// pseudo-indices, special tables that can be accessed like the stack -
379// LUA_GLOBALSINDEX - thread environment, where globals are
380// LUA_ENVIRONINDEX - C function environment, in this case luaopen_widget() is the C function
381// LUA_REGISTRYINDEX - C registry, global, for unique keys use the module name as a string, or a lightuserdata address to a C object in our module.
382// lua_upvalueindex(n) - C function upvalues
383
384 // Shove ourGlobals into the registry.
385 lua_pushlightuserdata(L, &ourGlobals);
386 lua_setfield(L, LUA_REGISTRYINDEX, globName);
387
388 // The skang module should have been loaded by now, so we can just grab it out of package.loaded[].
389 lua_getglobal(L, "package");
390 lua_getfield(L, lua_gettop(L), "loaded");
391 lua_remove(L, -2); // Removes "package"
392 lua_getfield(L, lua_gettop(L), SKANG);
393 lua_remove(L, -2); // Removes "loaded"
394 lua_setfield(L, LUA_REGISTRYINDEX, SKANG);
395 lua_getfield(L, LUA_REGISTRYINDEX, SKANG); // Puts the skang table back on the stack.
396 skang = lua_gettop(L);
397
398 // Define our functions.
399//thingasm{'window', 'The size and title of the application Frame.', window, 'x,y,name', acl='GGG'}
400 push_lua(L, "@ ( { = $ $ & $ $acl } )", skang, THINGASM, skang, "Cwindow", "Opens our window.", window, "number,number,string", "GGG", 0);
401 push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "clear", "The current skin is cleared of all widgets.", clear, 0);
402 push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "widget", "Create a widget.", widget, 0);
403 push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "action", "Add an action to a widget.", action, 0);
404 push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "Colour", "Change widget colours.", colour, 0);
405 push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "loopWindow", "Run our windows main loop.", loopWindow, 0);
406 push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "quit", "Quit, exit, remove thyself.", quit, 0);
407 push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "closeWindow", "Closes our window.", closeWindow, 0);
408
409 // A test of the array building stuff.
410 push_lua(L, "@ ( { = $ $ % $widget !required } )", skang, THINGASM, skang, "wibble", "It's wibbly!", 1, "'edit', 'The wibblinator:', 1, 1, 10, 50", 1, 0);
411
412 // Makes no difference what we return, but it's expecting something.
413 return 1;
414}
415
416
417void GuiLuaDo(int argc, char **argv)
418{
419 lua_State *L;
420 lua_Number i;
421
422 L = luaL_newstate();
423 if (L)
424 {
425 luaL_openlibs(L);
426
427 // Pass all our command line arguments to Lua.
428 i = 1;
429 lua_newtable(L);
430 while (--argc > 0 && *++argv != '\0')
431 {
432 lua_pushnumber(L, i++);
433 lua_pushstring(L, *argv);
434 lua_settable(L, -3);
435 }
436 lua_setfield(L, LUA_GLOBALSINDEX, "arg");
437
438
439 // When we do this, skang will process all the arguments passed to GuiLuaDo().
440 // This likely includes a module load, which likely opens a window.
441 lua_getglobal(L, "require");
442 lua_pushstring(L, SKANG);
443 lua_call(L, 1, 1);
444 lua_setfield(L, LUA_GLOBALSINDEX, SKANG);
445
446
447 // Run the main loop via a Lua call.
448 // This does nothing if no module opened a window.
449 if (0 != luaL_dostring(L, "skang.loopWindow()"))
450 PEm("Error running - skang.loopWindow()");
451 lua_pop(L, closeWindow(L));
452 lua_close(L);
453 }
454 else
455 fprintf(stderr, "Failed to start Lua!\n");
456}
diff --git a/ClientHamr/GuiLua/GuiLua.h b/ClientHamr/GuiLua/GuiLua.h
deleted file mode 100644
index 156fa1a..0000000
--- a/ClientHamr/GuiLua/GuiLua.h
+++ /dev/null
@@ -1,35 +0,0 @@
1
2#include <stdio.h>
3#include <ctype.h>
4
5#include <Elementary.h>
6
7#include <lua.h>
8#include <luajit.h>
9#include <lualib.h>
10#include <lauxlib.h>
11
12#include "LumbrJack.h"
13#include "Runnr.h"
14
15typedef struct _globals globals;
16
17
18#define WIDTH (300)
19#define HEIGHT (300)
20
21#define SKANG "skang"
22#define MODULEBEGIN "moduleBegin"
23#define MODULEEND "moduleEnd"
24#define THINGASM "thingasm"
25
26
27struct _globals
28{
29 Evas_Object *win; // Our Elm window.
30 int logDom; // Our logging domain.
31};
32
33
34int luaopen_widget(lua_State *L);
35void GuiLuaDo(int argc, char **argv);
diff --git a/ClientHamr/GuiLua/build.lua b/ClientHamr/GuiLua/build.lua
deleted file mode 100755
index 7e1da15..0000000
--- a/ClientHamr/GuiLua/build.lua
+++ /dev/null
@@ -1,23 +0,0 @@
1#!/usr/bin/env lua
2
3local dir = ...
4
5if 'nil' == type(dir) then
6 local build, err = loadfile('../../build.lua')
7 if build then
8 setfenv(build, getfenv(2))
9 build(2)
10 else
11 print("ERROR - " .. err)
12 end
13 dir = workingDir
14end
15
16LDFLAGS = '-L ' .. dir .. ' ' .. LDFLAGS
17
18removeFiles(dir, {'test_c.so', 'GuiLua.o', '../../libraries/libGuiLua.so', 'skang'})
19
20runCommand('C modules', dir, 'gcc ' .. CFLAGS .. ' -fPIC -shared -o test_c.so test_c.c')
21runCommand(nil, dir, 'gcc ' .. CFLAGS .. ' -fPIC -c GuiLua.c')
22runCommand('C libraries', dir, 'gcc ' .. CFLAGS .. ' -shared -Wl,-soname,libGuiLua.so -o ../../libraries/libGuiLua.so GuiLua.o')
23runCommand('C apps', dir, 'gcc ' .. CFLAGS .. ' -Wl,-export-dynamic -o skang skang.c ' .. LDFLAGS .. ' -lGuiLua ' .. libs)
diff --git a/ClientHamr/GuiLua/skang.c b/ClientHamr/GuiLua/skang.c
deleted file mode 100644
index facc239..0000000
--- a/ClientHamr/GuiLua/skang.c
+++ /dev/null
@@ -1,16 +0,0 @@
1#include "GuiLua.h"
2
3
4EAPI_MAIN int elm_main(int argc, char **argv)
5{
6 elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR);
7 elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
8 elm_app_compile_lib_dir_set(PACKAGE_LIB_DIR);
9 elm_app_info_set(elm_main, "GuiLua", "skang.lua");
10
11 GuiLuaDo(argc, argv);
12
13 return 0;
14}
15
16ELM_MAIN()
diff --git a/ClientHamr/GuiLua/skang.lua b/ClientHamr/GuiLua/skang.lua
deleted file mode 100644
index 23549c3..0000000
--- a/ClientHamr/GuiLua/skang.lua
+++ /dev/null
@@ -1,1686 +0,0 @@
1--[[ TODO - This should be in C, but so far development has been quite rapid doing it in Lua.
2
3C will let us -
4 Actually do the widget stuff.
5 Slap meta tables on all value types.
6 Which lets us put the meta table on the variable, instead of on the table, which I think is cleaner.
7 Figure out the directory separator.
8 Network stuff. No need to look at Lua socket stuff, we have Ecore_Con.
9 Database stuff. No need to look at Lua SQL stuff, we have esskyuehl. Maybe.
10
11 Actually, we could have the best of both worlds, since it is currently a C / Lua hybrid. B-)
12]]
13
14
15--[[ Skang package
16
17In here should live all the internals of matrix-RAD that don't
18specifically relate to widgets. This would include the "window" though.
19
20skang.module(Evas)
21skang.module(Elementary)
22skang.skang('some/skang/file.skang')
23
24This package is also what "apps" that use the system should "inherit"
25from, in the same way matrix-RAD apps did. Skang "apps" could be Lua
26modules. They could also be C code, like the extantz modules are likely
27to be. Skang "apps" would automatically be associated with skang files
28of the same name.
29
30For a .skang file, the skang command (written in C) would strip off the
31first line, add the two implied lines, then run it as Lua. The
32skang.load() command would do the same. So that skang C comand would
33just pass the file name to skang.load() in this library. B-)
34
35The old skang argument types are -
36
37{"name", "java.lang.String"},
38{"action", "java.lang.String"},
39{"type", "java.lang.String"},
40{"data", "java.lang.String"},
41{"URL", "java.lang.String"},
42{"file", "java.lang.String"},
43{"method", "java.lang.String"},
44{"lx", "java.lang.String"},
45{"ly", "java.lang.String"},
46{"lw", "java.lang.String"},
47{"lh", "java.lang.String"},
48{"normal", "java.lang.String"},
49{"ghost", "java.lang.String"},
50{"active", "java.lang.String"},
51{"toggle", "java.lang.String"},
52{"boolean","java.lang.Boolean"},
53{"number", "java.lang.Integer"},
54{"int", "java.lang.Integer"},
55{"x", "java.lang.Integer"},
56{"y", "java.lang.Integer"},
57{"w", "java.lang.Integer"},
58{"h", "java.lang.Integer"},
59{"r", "java.lang.Integer"},
60{"g", "java.lang.Integer"},
61{"b", "java.lang.Integer"},
62{"alpha", "java.lang.Integer"},
63{"acl", "net.matrix_rad.security.ACL"},
64]]
65
66
67-- Wrapping the entire module in do .. end helps if people just join a bunch of modules together, which apparently is popular.
68-- By virtue of the fact we are stuffing our result into package.loaded[], just plain running this works as "loading the module".
69do -- Only I'm not gonna indent this.
70
71mainSkin = {}
72
73-- TODO - This needs to be expanded a bit to cover things like 1.42
74local versions = {
75 '0%.0', 'unwritten', 'Just a stub, no code at all, or completely non-existant.',
76 '0%.1', 'prototype', 'Stuff that has only been prototyped, or partly written. There is some code, and it may even work, but it is not even close to the finished product.',
77 '%d%.3', 'written', 'Stuff that has already been written. It may not be perfect, but it is considered an aproximation of the finished product.',
78 '%d%.5', 'alpha', 'Version being tested by official alpha testers.',
79 '%d%.9', 'beta', 'Version passed alpha testing, but not ready for final release.',
80 '1%.0', 'final', 'Version ready for final release, fully tested.',
81 '3%.0', 'poetry', 'Near perfection has been acheived.',
82 '5%.0', 'nirvana', 'Perfection has been acheived.',
83 '9%.0', 'bible', 'This is the Whord of Ghod.',
84}
85
86-- Trying to capture best practices here for creating modules, especially since module() is broken and deprecated.
87-- TODO - Should parse in license type to.
88moduleBegin = function (name, author, copyright, version, timestamp, skin, isLua)
89 local _M = {} -- This is what we return to require().
90 local level = 2
91
92 if 'nil' == type(isLua) then isLua = true end
93
94 package.loaded[name] = _M -- Stuff the result into where require() can find it, instead of returning it at the end.
95 -- Returning it at the end does the same thing.
96 -- This is so that we can have all the module stuff at the top, in this function.
97 -- Should do this before any further require(), so that circular references don't blow out.
98
99 -- Save the callers environment.
100 local savedEnvironment
101 if isLua then
102 savedEnvironment = getfenv(level)
103 else
104 -- While the above works fine for test_c, it doesn't for GuiLua. Odd.
105 savedEnvironment = getfenv(1)
106 end
107
108 -- Clone the environment into _M, so the module can access everything as usual after the setfenv() below.
109 --[[ TODO - Check if this also clones _G or _ENV. And see if it leaks stuff in either direction.
110 local _G = _G -- Only sets a local _G for this function.
111 _M._G = _G -- This clone loop might do this, but we don't want to be able to access the old _G from outside via this leak.
112 In Lua 5.1 at least, _G was special. In 5.2, _ENV sorta replaces setfenv(), but no idea if this clone loop stomps on that.
113 ]]
114 for k, v in pairs(savedEnvironment) do
115 _M[k] = v
116 end
117
118 _M._M = _M -- So that references to _M below the setfenv() actually go to the real _M.
119 _M._NAME = name
120 _M._PACKAGE = string.gsub(_M._NAME, "[^.]*$", "") -- Strip the name down to the package name.
121 _M.isLua = isLua
122
123 -- Parse in an entire copyright message, and strip that down into bits, to put back together.
124 local date, owner = string.match(copyright, '[Cc]opyright (%d%d%d%d) (.*)')
125 _M.AUTHOR = author or owner
126 _M.COPYRIGHT = 'Copyright ' .. date .. ' ' .. _M.AUTHOR
127 -- Translate the version number into a version string.
128 local versionName, versionDesc = ' ', ''
129 for i = 1, #versions / 3 do
130 if 1 == string.find(version, versions[i]) then
131 versionName = ' ' .. versions[i + 1] .. ' '
132 versionDesc = versions[i + 2]
133 break
134 end
135 end
136 _M.VERSION = version .. versionName .. timestamp
137 _M.VERSION_DESC = versionDesc
138 -- If there is a .skang file, read that in and override the passed in skin.
139 local f = io.open(name .. '.skang')
140 if f then
141 skin = f:read('*l')
142 if '#' == string.sub(skin, 1, 1) then skin = '' end
143 skin = skin .. f:read('*a')
144 f:close()
145 end
146 if skin then
147 skin = "local skang = require 'skang'\nlocal " .. name .. " = require '" .. name .. "'\n" .. skin
148 if nil == mainSkin._NAME then mainSkin = _M end
149 end
150 _M.DEFAULT_SKANG = skin
151
152 --_G[_M._NAME] = _M -- Stuff it into a global of the same name.
153 -- Not such a good idea to stomp on global name space.
154 -- It's also redundant coz we get stored in package.loaded[_M._NAME] anyway.
155 -- This is why module() is broken.
156 _M.savedEnvironment = savedEnvironment
157 -- NOTE - setfenv() wont work if the environment it refers to is a C function. Worse, getfenv() returns the global environment, so we can't tell.
158 if isLua then
159 -- setfenv() sets the environment for the FUNCTION, stack level deep.
160 -- The number is the stack level -
161 -- 0 running thread, 1 current function, 2 function that called this function, etc
162 setfenv(level, _M) -- Use the result for the modules internal global environment, so they don't need to qualify internal names.
163 -- Dunno if this causes problems with the do ... end style of joining modules. It does. So we need to restore in moduleEnd().
164 -- Next question, does this screw with the environment of the skang module? No it doesn't, coz that's set up at require 'skang' time.
165 end
166
167 print('Loaded module ' .. _M._NAME .. ' version ' .. _M.VERSION .. ', ' .. _M.COPYRIGHT .. '.\n ' .. _M.VERSION_DESC)
168
169 return _M
170end
171
172
173--[[ Parse command line parameters.
174
175This is done in two parts. Skang will do an initial scan and tokenise,
176then each module gets a chance to pull it's own Things from the result.
177
178Make the command line parameter getting MUCH more intelligent, try to support the common
179command line interfaces -
180
181arg value
182a value
183/arg value
184/a value
185--arg value
186--a value
187-a value
188-ab ('a' and 'b' are both shortcuts.)
189arg=value
190a=value
191arg1=value1&arg2=value2
192arg1=value1|arg2=value2
193a=value1&a=value2
194+arg/-arg (Can't support this generically.)
195
196Ignore /,-,--,& except as arg introducers. Use = as value introducer. Expect
197arg or a. If type is String, expect a value. If type is integer, and next token is
198not an integer, increment current value, otherwise expect integer value. If type is
199boolean, value beginning with T, t, F, f, etc is true, otherwise value is false, unless
200next token starts with an introducer, then value is true.
201
202TODO - Finish supporting all of the above.
203 These all need deeper parsing, but we dunno if they might have been inside quoted strings from the shell.
204 arg=value Shell.
205 arg1=value1&arg2=value2 For URLs.
206 arg1=value1|arg2=value2 Can't remember why, probably the old skang multivalue syntax.
207 Test it all.
208 Skang command line should have standardish stuff, like --version, --help, --help module.thing.
209 Lua does these already, might be no need to do them ourselves -
210 -e 'some code'.
211 -i go interactive after running the script.
212 -v version.
213 - read from stdin non interactively.
214 LuaJIT also has this -
215 -- stop processing options.
216]]
217
218ARGS = {}
219lua = ''
220command = ''
221
222
223-- Do an initial scan and tokenise of the command line arguments.
224scanArguments = function (args)
225 if args then
226 lua = args[-1]
227 command = args[0]
228 for i, v in ipairs(args) do
229 local pre = ''
230 if '--' == string.sub(v, 1, 2) then pre = '--'; v = string.sub(v, 3, -1) end
231 if '-' == string.sub(v, 1, 1) then pre = '-'; v = string.sub(v, 2, -1) end
232 if '+' == string.sub(v, 1, 1) then pre = '+'; v = string.sub(v, 2, -1) end
233 -- TODO - Make this the opposite of the directory separator for what ever platform we are running on.
234 -- Which Lua can't figure out I think.
235 if '/' == string.sub(v, 1, 1) then pre = '/'; v = string.sub(v, 2, -1) end
236 if '=' == string.sub(v, 1, 1) then pre = '='; v = string.sub(v, 2, -1) end
237 if '&' == string.sub(v, 1, 1) then pre = '&'; v = string.sub(v, 2, -1) end
238 if '|' == string.sub(v, 1, 1) then pre = '|'; v = string.sub(v, 2, -1) end
239 if '' ~= v then ARGS[i] = {pre, v} end
240 end
241 end
242end
243
244parseType = function (module, thingy, v, value)
245 if 'string' == thingy.types[1] then
246 if value then
247 module[v[2] ] = value[2]
248 value[2] = nil -- Mark it as used.
249 else
250 print('ERROR - Expected a string value for ' .. thingy.names[1])
251 end
252 end
253
254 if 'number' == thingy.types[1] then
255 if value then
256 -- If the introducer is '-', then this should be a negative number.
257 if '-' == value[1] then value[1] = ''; value[2] = '-' .. value[2] end
258 -- Only parse the next value as a number if it doesn't have an introducer.
259 if ('' == value[1]) or ('=' == value[1]) then
260 value[2] = tonumber(value[2])
261 if value[2] then
262 module[v[2] ] = value[2]
263 value[2] = nil -- Mark it as used.
264 else
265 print('ERROR - Expected a number value for ' .. thingy.names[1])
266 end
267 else
268 module[v[2] ] = module[v[2] ] + 1
269 end
270 else
271 print('ERROR - Expected a number value for ' .. thingy.names[1])
272 end
273 end
274
275 if 'function' == thingy.types[1] then
276 local args = {}
277 -- TODO - Should allow more than one argument, but would need to pass in ARGS and i.
278 if 2 == #thingy.types then
279 if value then
280 -- TODO - Should check the type of the arguments.
281 args[#args + 1] = value[2]
282 module[v[2] ](args[1])
283 value[2] = nil -- Mark it as used.
284 else
285 print('ERROR - Expected an argument for ' .. thingy.names[1])
286 end
287 else
288 module[v[2] ]()
289 end
290 end
291
292 if 'boolean' == thingy.types[1] then
293 if value then
294 -- Only parse the next value as a boolean if it doesn't have an introducer.
295 if ('' == value[1]) or ('=' == value[1]) then
296 module[v[2] ] = isBoolean(value[2])
297 value[2] = nil -- Mark it as used.
298 else
299 module[v[2] ] = true
300 end
301 else
302 print('ERROR - Expected a boolean value for ' .. thingy.names[1])
303 end
304 end
305end
306
307pullArguments = function (module)
308 -- Look for our command line arguments.
309 local metaMum = getmetatable(module)
310 if metaMum and metaMum.__self then
311 for i, v in ipairs(ARGS) do
312 if v[2] then
313 local thingy = metaMum.__self.stuff[v[2] ]
314 -- Did we find one of ours?
315 if thingy then
316 parseType(module, thingy, v, ARGS[i + 1])
317 v[2] = nil -- Mark it as used.
318 else
319 -- Didn't find one directly, check for single letter matches in '-abc'.
320 for k, w in pairs(metaMum.__self.stuff) do
321 if 1 == #w.names[1] then
322 for j = 1, #v[2] do
323 if string.sub(v[2], j, 1) == w.names[1] then
324 if 1 == j then
325 v[2] = string.sub(v[2], 2, -1)
326 if 'boolean' == w.types[1] then module[v[2] ] = true end
327 elseif #v[2] == j then
328 v[2] = string.sub(v[2], 1, j - 1)
329 -- The one at the end is the only one that could have a following value.
330 parseType(module, w, v, ARGS[i + 1])
331 else
332 v[2] = string.sub(v[2], 1, j - 1) .. string.sub(v[2], j + 1, -1)
333 if 'boolean' == w.types[1] then module[v[2] ] = true end
334 end
335 if '' == v[2] then v[2] = nil end -- Mark it as used.
336 end
337 end
338 end
339 end
340 end
341 end
342 end
343 end
344end
345
346-- Restore the environment, and grab paramateres from standard places.
347moduleEnd = function (module)
348 -- See if there is a properties file, and run it in the modules environment.
349 local properties, err = loadfile(module._NAME .. '.properties')
350 if properties then
351 setfenv(properties, getfenv(2))
352 properties()
353 elseif 'cannot open ' ~= string.sub(err, 1, 12) then
354 print("ERROR - " .. err)
355 end
356
357 pullArguments(module)
358
359 -- Run the main skin, which is the first skin that is defined. In theory, the skin from the main module.
360 if mainSkin == module then
361 print("RUNNING SKIN FOR " .. module._NAME)
362 local skin, err = loadstring(module.DEFAULT_SKANG)
363 if skin then
364 setfenv(skin, getfenv(2))
365 skin()
366 else
367 print("ERROR - " .. err)
368 end
369 end
370
371 if module.isLua then setfenv(2, module.savedEnvironment) end
372end
373
374
375-- Call this now so that from now on, this is like any other module.
376local _M = moduleBegin('skang', 'David Seikel', 'Copyright 2014 David Seikel', '0.1', '2014-03-27 02:57:00')
377
378-- This works coz LuaJIT automatically loads the jit module.
379if type(jit) == 'table' then
380 print('Skang is being run by ' .. jit.version .. ' under ' .. jit.os .. ' on a ' .. jit.arch)
381else
382 print('Skang is being run by Lua version ' .. _VERSION)
383end
384
385scanArguments(arg)
386
387
388function printTableStart(table, space, name)
389 print(space .. name .. ": ")
390 print(space .. "{")
391 printTable(table, space .. " ")
392 print(space .. "}")
393 if '' == space then print('') end
394end
395
396function printTable(table, space)
397 if nil == table then return end
398 for k, v in pairs(table) do
399 if type(v) == "table" then
400 if v._NAME then
401 print(space .. "SKANG module " .. v._NAME .. ";")
402 else
403 printTableStart(v, space, k)
404 end
405 elseif type(v) == "string" then
406 print(space .. k .. ': "' .. v .. '";')
407 elseif type(v) == "function" then
408 print(space .. "function " .. k .. "();")
409 elseif type(v) == "userdata" then
410 print(space .. "userdata " .. k .. ";")
411 elseif type(v) == "boolean" then
412 if (v) then
413 print(space .. "boolean " .. k .. " TRUE ;")
414 else
415 print(space .. "boolean " .. k .. " FALSE ;")
416 end
417 else
418 print(space .. k .. ": " .. v .. ";")
419 end
420 end
421end
422
423
424csv2table = function (csv)
425 local result = {}
426 local i = 1
427
428 for v in string.gmatch(csv, ' *([^,]+)') do
429 result[i] = v
430 i = i + 1
431 end
432 return result
433end
434
435
436shiftLeft = function (tab)
437 local result = tab[1]
438 table.remove(tab, 1)
439 return result
440end
441
442
443-- My clever boolean check, this is the third language I've written this in. B-)
444-- true 1 yes ack ok one positive absolutely affirmative 'ah ha' 'shit yeah' 'why not'
445local isTrue = 't1aopswy'
446-- false 0 no nack nope zero negative nah 'no way' 'get real' 'uh uh' 'fuck off' 'bugger off'
447local isFalse = 'f0bgnuz'
448isBoolean = function (aBoolean)
449 local result = false
450
451 if type(aBoolean) ~= 'nil' then
452 -- The default case, presence of a value means it's true.
453 result = true
454 if type(aBoolean) == 'boolean' then result = aBoolean
455 elseif type(aBoolean) == 'function' then result = aBoolean()
456 elseif type(aBoolean) == 'number' then result = (aBoolean ~= 0)
457 elseif type(aBoolean) == 'string' then
458 if '' == aBoolean then
459 result = false
460 else
461 if 1 == string.find(string.lower(aBoolean), '^[' .. isTrue .. ']') then result = true end
462 if 1 == string.find(string.lower(aBoolean), '^[' .. isFalse .. ']') then result = false end
463 end
464 end
465 end
466 return result
467end
468
469
470--[[ Thing Java package
471
472matrix-RAD had Thing as the base class of everything.
473
474Each "users session" (matrix-RAD term that came from Java
475applets/servlets) has a ThingSpace, which is a tree that holds
476everything else. It holds the class cache, commands, loaded modules,
477variables and their values, widgets and their states. In matrix-RAD I
478built BonsiaTree and LeafLike, for the old FDO system I built dumbtrees.
479
480Other Thing things are -
481 get/set The getter and setter.
482 number No idea how this was useful.
483 skang The owning object, a Skang (actually got this, called module for now).
484 owner The owning object, a String (module._NAME).
485 clas Class of the Thing, a Class. (pointless)
486 type Class of the Thing, a String. (pointless)
487 realType Real Class of the Thing, a String. (pointless)
488 myRoot ThingSpace we are in, a ThingSpace.
489
490 Also various functions to wrap checking the security, like canDo, canRead, etc.
491]]
492
493
494--[[ Stuff Java package
495
496In matrix-RAD Stuff took care of multi value Things, like database rows.
497
498Stuff is an abstract class that gets extended by other classes, like
499SquealStuff, which was the only thing extending it. It dealt with the
500basic "collection of things" stuff. Each individual thing was called a
501stufflet. A final fooStuff would extend SquealStuff, and include an
502array of strings called "stufflets" that at least named the stufflets,
503but could also include metadata and links to other Stuffs.
504
505There was various infrastructure for reading and writing Stuff, throwing
506rows of Stuff into grids, having choices of Stuff, linking stufflets to
507individual widgets, having default Stuffs for windows, validating
508Stuffs, etc.
509
510In Lua, setting up stuff has been folded into the general Thing stuff.
511
512]]
513
514
515--[[ Thing structure -
516
517In the following, meta(table) is short for getmetatable(table).
518
519In Lua everything is supposed to be a first class value, and variables are just places to store values.
520All variables are in fact stored in tables, even if it's just the local environment table.
521Any variable that has a value of nil, doesn't actually exist. That's the definition.
522While non table things can have metatables, Lua can only set metatables on tables, C has no such restriction.
523meta(table).__index and __newindex only work on table entries that don't exist.
524 __index(table, key) is called if table.key is nil.
525 Though if __index is a table, then try __index[key].
526 __newindex(table, key, value) is called if table.key is nil.
527 Though if __newindex is a table, then try __newindex[key] = value.
528Using both __index and __newindex, and keeping the actual values elsewhere, is called a proxy table.
529meta(table).__call(table, ...) is called when trying to access table as a function - table(...).
530
531It's worth repeating -
532All variables in Lua are in some table somewhere, even if it's just the global environment table.
533Metatables are only associated vith values, not variables.
534Lua can only attach metatables to values that are tables, but C can attach metatables to any value.
535
536
537A Thing is a managed variable stored in a parent proxy table, which is usually empty.
538So the values stored in this Thing are actually stored in meta(parent)__values[thing].
539 parent[thing] -> __index (parent, thing) -> meta(parent).__values[thing]
540 parent[thing] = value -> __newindex(parent, thing, value) -> meta(parent).__values[thing] = value
541
542
543Each Thing has a description table that includes -
544 names - An array of names, the first one is the "official" name.
545 types - An array of types, the first one is the "official" type.
546 help - A descriptive text for humans to read.
547 default - The default value.
548 widget - A default widget definition.
549 required - If the Thing is required.
550 isValid - A function that tests if the Thing is valid.
551 errors - Any errors related to the Thing.
552 isKeyed - Is this a parent for Things that are stored under an arbitrary key.
553 stuff - An array of descriptions for sub Things, so Things that are tables can have their own Things.
554 and other things that aren't actually used yet.
555All things that a description doesn't have should be inherited from the Thing table.
556 setmetatable(aStuff, {__index = Thing})
557Descriptions should be able to be easily shared by various Things.
558
559
560A parent's metatable has __self, which is it's own description.
561A parent is free to use it's own name space for anything it wants.
562Only the variables it specifies as managed Things are dealt with here.
563
564
565Things that are tables are treated differently, in two different ways even.
566Ordinary table Things are basically treated recursively, the table is a parent, and it gets it's own Things.
567There is also 'Keyed' type table Things, where the keys to this table are arbitrary, but we still want to store Things in it.
568In this case, when a table is assigned to this Keyed Thing, via a new key, a new table Thing is created by copying the parent Thing description.
569
570
571TODO -
572 test.foo -> test.__index(test, 'foo') -> test.__values[foo]; if that's nil, and test.stuff[foo], then return an empty table instead?
573 Do we still need a parent pointer?
574 Should be in __values I guess.
575 __values[key].value
576 __values[key].parent
577 Weak references might help in here somewhere.
578 Maybe try looking in the skang table for Things that are not found?
579 Maybe put Things in the skang table that are unique from modules?
580 I think this is what matrix-RAD Collisions was all about.
581]]
582
583-- There is no ThingSpace, or Stuff, now it's all just in this meta table.
584local Thing =
585{
586-- Default Thing values.
587 names = {'unknown'},
588 help = 'No description supplied.', -- help text describing this Thing.
589 default = '', -- The default value. This could be a funcion, making this a command.
590 types = {}, -- A list of types. The first is the type of the Thing itself, the rest are for multi value Things. Or argument types for commands.
591 required = false, -- Is this thing is required. TODO - Maybe fold this into types somehow, or acl?
592 widget = '', -- Default widget command arguments for creating this Thing as a widget.
593-- acl = '', -- Access Control List defining security restrains.
594-- boss = '', -- The Thing or person that owns this Thing, otherwise it is self owned.
595
596 action = 'nada', -- An optional action to perform.
597 tell = '', -- The skang command that created this Thing.
598 pattern = '.*', -- A pattern to restrict values.
599
600 isKeyed = false, -- Is this thing an arbitrarily Keyed table?
601 isReadOnly = false, -- Is this Thing read only?
602 isServer = false, -- Is this Thing server side?
603 isStub = false, -- Is this Thing a stub?
604 isStubbed = false, -- Is this Thing stubbed elsewhere?
605
606 hasCrashed = 0, -- How many times this Thing has crashed.
607
608 append = function (self,data) -- Append to the value of this Thing.
609 end,
610
611 stuff = {}, -- The sub things this Thing has, for modules, tables, and Keyed tables.
612 errors = {}, -- A list of errors returned by isValid().
613
614 isValid = function (self, parent) -- Check if this Thing is valid, return resulting error messages in errors.
615 -- Anything that overrides this method, should call this super method first.
616 local name = self.names[1]
617 local metaMum = getmetatable(parent)
618 local value = metaMum.__values[name]
619 local mum = metaMum.__self.names[1]
620
621 local t = type(value) or 'nil'
622 self.errors = {}
623 -- TODO - Naturally there should be formatting functions for stuffing Thing stuff into strings, and overridable output functions.
624 if 'nil' == t then
625 if self.required then table.insert(self.errors, mum .. '.' .. name .. ' is required!') end
626 else
627 if 'widget' == self.types[1] then
628 -- TODO - Should validate any attached Thing.
629 elseif self.types[1] ~= t then table.insert(self.errors, mum .. '.' .. name .. ' should be a ' .. self.types[1] .. ', but it is a ' .. t .. '!')
630 else
631 if 'number' == t then value = '' .. value end
632 if ('number' == t) or ('string' == t) then
633 if 1 ~= string.find(value, '^' .. self.pattern .. '$') then table.insert(self.errors, mum .. '.' .. name .. ' does not match pattern "' .. self.pattern .. '"!') end
634 end
635 end
636 end
637
638 for k, v in pairs(self.stuff) do
639 if not v:isValid(value) then
640 for i, w in ipairs(v.errors) do
641 table.insert(self.errors, w)
642 end
643 end
644 end
645
646 return #(self.errors) == 0
647 end,
648
649 remove = function (self) -- Delete this Thing.
650 end,
651}
652
653
654getStuffed = function (parent, key)
655 local metaMum = getmetatable(parent)
656 local thingy
657
658 if metaMum and metaMum.__self then
659 thingy = metaMum.__self.stuff[key]
660
661 if not thingy then
662 -- Deal with getting a table entry.
663 if metaMum.__values[key] then
664 thingy = getmetatable(metaMum.__values[key]).__self
665 end
666 end
667 end
668 return metaMum, thingy
669end
670
671local Mum =
672{
673
674__index = function (parent, key)
675 -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist.
676
677 -- First see if this is a Thing.
678 local metaMum, thingy = getStuffed(parent, key)
679
680 if thingy then
681 return metaMum.__values[thingy.names[1] ] or thingy.default
682 end
683
684 -- Then see if we can inherit it from Thing.
685 return Thing[key]
686end,
687
688__newindex = function (parent, key, value)
689 -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist.
690
691 -- First see if this is a Thing.
692 local metaMum, thingy = getStuffed(parent, key)
693
694 if not thingy then
695 if metaMum.__self.isKeyed then
696 -- Deal with setting a new Keyed table entry.
697 local newThing = copy(parent, key)
698 local newSelf = getmetatable(newThing).__self
699 rawset(metaMum.__values, key, newThing)
700 thingy = {}
701 for k, v in pairs(newSelf) do
702 thingy[k] = v
703 end
704 thingy.names={key}
705 thingy.types={'table'}
706 setmetatable(thingy, {__index = Thing}) -- To pick up isValid, pattern, and the other stuff by default.
707 end
708 end
709
710 if thingy then
711 local name = thingy.names[1]
712 local oldMum
713
714 if 'table' == type(value) then
715 -- Coz setting it via metaMum screws with the __index stuff somehow.
716 local oldValue = metaMum.__values[name]
717 if 'table' == type(oldValue) then
718 oldMum = getmetatable(oldValue)
719 if oldMum then
720 -- TODO - This SHOULD work, but doesn't -
721 --setmetatable(value, oldMum)
722 -- Instead we do this -
723 -- Clear out any values in the old table.
724 for k, v in pairs(oldMum.__values) do
725 oldMum.__values[k] = nil
726 end
727 for k, v in pairs(value) do
728 local newK = oldMum.__self.stuff[k]
729 if newK then newK = newK.names[1] else newK = k end
730 oldMum.__values[newK] = v
731 end
732 end
733 end
734 end
735 if nil == oldMum then metaMum.__values[name] = value end
736 -- NOTE - invalid values are still stored, this is by design.
737 if not thingy:isValid(parent) then
738 for i, v in ipairs(thingy.errors) do
739 print('ERROR - ' .. v)
740 end
741 end
742 -- TODO - Go through it's linked things and set them to.
743 -- Done, don't fall through to the rawset()
744 return
745 end
746
747 rawset(parent, key, value) -- Stuff it normally.
748end,
749
750__call = function (func, ...)
751 return thingasm(func, ...)
752end,
753
754}
755
756newMum = function ()
757 local result = {}
758--[[ From an email by Mike Pall -
759"Important: create the metatable and its metamethods once and reuse
760the _same_ metatable for _every_ instance."
761
762This is for LuaJIT, he's the author, and concerns performance.
763
764TODO - Which is the exact opposite of what we are doing. Perhaps we can fix that?
765]]
766 for k, v in pairs(Mum) do
767 result[k] = v
768 end
769 result.__self = {stuff={}}
770 result.__values = {}
771 return result
772end
773
774
775-- skang.thingasm() Creates a new Thing, or changes an existing one.
776--[[ It can be called in many different ways -
777
778It can be called with positional arguments - (names, help, default, types, widget, required, acl, boss)
779Or it can be called with a table - {names, help, pattern='.*', acl='rwx'}
780
781The first argument can be another Thing (the parent), or a string list of names (see below).
782
783It can be called by itself, with no parent specified -
784 thingasm('foo', 'help text)
785In this case the surrounding Lua environment becomes the parent of foo.
786 If the first argument (or first in the table) is a string, then it's this form.
787All others include the parent as the first argument, which would be a table.
788
789It can be called by calling the parent as a function -
790 foo('bar', 'some help', types='table') -- ___call(foo, 'bar', ...) And now foo is the parent.
791 foo.bar{'baz', types='Keyed'} -- thingasm({foo.bar, 'baz', ...})
792 foo.bar.baz{'field0'} -- thingasm({foo.bar.baz, 'field0'})
793 foo.bar.baz{'field1'}
794]]
795
796-- names - a comma seperated list of names, aliases, and shortcuts. The first one is the official name.
797-- If this is not a new thing, then only the first one is used to look it up.
798-- So to change names, use skang.thingasm{'oldName', names='newName,otherNewName'}
799thingasm = function (names, ...)
800 local params = {...}
801 local new = false
802 local parent
803 local set = true
804
805 -- Check how we were called, and re arrange stuff to match.
806 if 0 == #params then
807 if ('table' == type(names)) then -- thingasm{...}
808 params = names
809 names = shiftLeft(params)
810 if 'table' == type(names) then -- thingasm{parent, 'foo', ...}
811 parent = names
812 names = shiftLeft(params)
813 end
814 end -- thingasm("foo") otherwise
815 else
816 if 'table' == type(names) then
817 parent = names
818 if 'string' == type(...) then params = {...} -- C or __call(table, string, ..)
819 elseif 'table' == type(...) then params = ... -- __call(table, table)
820 end
821 names = shiftLeft(params)
822 end -- thingasm('foo', ...) otherwise
823 end
824
825 -- Break out the names.
826 names = csv2table(names)
827 local name = names[1]
828 local oldNames = {}
829
830 -- TODO - Double check this comment - No need to bitch and return if no names, this will crash for us.
831
832 -- Grab the environment of the calling function if no parent was passed in.
833 parent = parent or getfenv(2)
834 local metaMum = getmetatable(parent)
835 -- Coz at module creation time, Thing is an empty table, or in case this is for a new parent.
836 if nil == metaMum then
837 metaMum = newMum()
838 metaMum.__self.names = {parent._NAME or 'NoName'}
839 if parent._NAME then metaMum.__self.types = {'Module'} end
840 setmetatable(parent, metaMum)
841 end
842
843 local thingy = metaMum.__self.stuff[name]
844 if not thingy then -- This is a new Thing.
845 new = true
846 thingy = {}
847 thingy.names = names
848 thingy.stuff = {}
849 setmetatable(thingy, {__index = Thing}) -- To pick up isValid, pattern, and the other stuff by default.
850 end
851
852 -- Pull out positional arguments.
853 thingy.help = params[1] or thingy.help
854 thingy.default = params[2] or thingy.default
855 local types = params[3] or table.concat(thingy.types or {}, ',')
856
857 -- Pull out named arguments.
858 for k, v in pairs(params) do
859 if 'string' == type(k) then
860 if 'types' == k then types = v
861 elseif 'names' == k then
862 oldNames = thingy.names
863 thingy.names = cvs2table(v)
864 elseif 'required' == k then
865 if isBoolean(v) then thingy.required = true end
866 else thingy[k] = v
867 end
868 end
869 end
870
871 -- Find type, default to string, then break out the other types.
872 local typ = type(thingy.default)
873 if 'nil' == typ then typ = 'string' end
874 if 'function' == typ then types = typ .. ',' .. types end
875 if '' == types then types = typ end
876 thingy.types = csv2table(types)
877
878 if 'widget' == thingy.types[1] then
879 set = false
880 local args, err = loadstring('return ' .. thingy.widget)
881 if args then
882 setfenv(args, parent)
883 thingy.Cwidget = widget(args())
884print('\nNO IDEA WHY this does isValid() three times on the action, and the first one being a string.')
885 parent.W[name] = thingy
886 else
887 print("ERROR - " .. err)
888 end
889 end
890
891 -- Deal with Keyed and tables.
892 if 'Keyed' == thingy.types[1] then
893 set = false
894 thingy.types[1] = 'table'
895 thingy.isKeyed = true
896 end
897 if 'table' == thingy.types[1] then
898 -- Default in this case becomes a parent.
899 if '' == thingy.default then thingy.default = {} end
900 local thisMum = newMum()
901 thisMum.__self = thingy
902 setmetatable(thingy.default, thisMum)
903 end
904
905 if 'userdata' == thingy.types[1] then
906 set = false
907 end
908
909 -- Remove old names, then stash the Thing under all of it's new names.
910 for i, v in ipairs(oldNames) do
911 metaMum.__self.stuff[v] = nil
912 end
913 for i, v in ipairs(thingy.names) do
914 metaMum.__self.stuff[v] = thingy
915 end
916
917 -- This triggers the Mum.__newindex metamethod above. If nothing else, it triggers thingy.isValid()
918 if new and set then parent[name] = thingy.default end
919end
920
921
922fixNames = function (module, name)
923 local stuff = getmetatable(module)
924 if stuff then
925 stuff.__self.names[1] = name
926 for k, v in pairs(stuff.__self.stuff) do
927 if 'table' == v.types[1] then
928 local name = v.names[1]
929 print(name .. ' -> ' .. name)
930 fixNames(stuff.__values[name], name)
931 end
932 end
933 end
934end
935
936
937copy = function (parent, name)
938 local result = {}
939 local stuff = getmetatable(parent).__self.stuff
940
941 for k, v in pairs(stuff) do
942 local temp = {}
943 for l, w in pairs(v) do
944 temp[l] = w
945 end
946 temp[1] = table.concat(temp.names, ',')
947 temp.names = nil
948 temp.types = table.concat(temp.types, ',')
949 temp.errors = nil
950 thingasm(result, temp)
951 end
952 getmetatable(result).__self.names = {name}
953
954-- TODO - Should we copy values to?
955
956 return result
957end
958
959module = function (name)
960 _G[name] = require(name)
961 return _G[name]
962end
963
964stuff = function (aThingy, aStuff)
965 return getmetatable(aThingy).__self.stuff[aStuff]
966end
967
968
969get = function (stuff, key, name)
970 local result
971 if name then
972 local thingy = getmetatable(stuff)
973 if thingy then
974 local this = thingy.__self.stuff[key]
975 if this then result = this[name] end
976 end
977 else
978 result = stuff[key]
979 end
980 return result
981end
982
983
984reset = function (stuff, key, name)
985 if name then
986 local thingy = getmetatable(stuff)
987 if thingy then
988 local this = thingy.__self.stuff[key]
989 if this then this[name] = nil end
990 end
991 else
992 stuff[key] = nil
993 end
994end
995
996
997set = function (stuff, key, name, value)
998 if 'nil' ~= type(value) then
999 local thingy = getmetatable(stuff)
1000 if thingy then
1001 local this = thingy.__self.stuff[key]
1002 if this then this[name] = value end
1003 end
1004 else
1005 -- In this case, value isn't there, so we are reusing the third argument as the value.
1006 stuff[key] = name
1007 end
1008end
1009
1010
1011-- Get our C functions installed into skang.
1012-- This has to be after thingasm is defined.
1013package.cpath = package.cpath .. ';../../libraries/lib?.so'
1014local GuiLua = require 'GuiLua'
1015
1016
1017thingasm('module,l', 'Load a module.', module, 'file')
1018thingasm('get', 'Get the current value of an existing Thing or metadata.', get, 'thing,key,name')
1019thingasm('reset', 'Reset the current value of an existing Thing or metadata.', reset, 'thing,key,name')
1020thingasm('set', 'Set the current value of an existing Thing or metadata.', set, 'thing,key,name,data')
1021
1022thingasm('nada', 'Do nothing.', function () --[[ This function intentionally left blank. ]] end)
1023
1024
1025
1026-- Widget wrappers.
1027-- TODO - Fix this up so we don't need .W
1028local widgets = {}
1029--thingasm{widgets, 'window', 'The window.', types='userdata'}
1030thingasm{widgets, 'W', 'Holds all the widgets', types='Keyed'}
1031widgets.W{'Cwidget', 'The widget.', types='userdata'}
1032widgets.W{'action,a', 'The action for the widget.', 'nada', types='string'}
1033local aIsValid = function (self, parent)
1034 local result = Thing.isValid(self, parent)
1035
1036 if result then
1037 local value = parent[self.names[1] ]
1038print('NEW ACTION - ' .. self.names[1] .. ' = ' .. value .. ' ' .. type(parent.Cwidget))
1039 action(parent.Cwidget, value)
1040 end
1041 return result
1042end
1043
1044widgets.W{'look,l', 'The look of the widget.', types='string'}
1045--[[
1046widgets.W{'colour,color,c', 'The colours of the widget.', types='table'}
1047widgets.W.c{'red,r', 'The red colour of the widget.', 255, types='number'}
1048widgets.W.c{'green,g', 'The green colour of the widget.', 255, types='number'}
1049widgets.W.c{'blue,b', 'The blue colour of the widget.', 255, types='number'}
1050widgets.W.c{'alpha,a', 'The alpha colour of the widget.', 255, types='number'}
1051-- At this point we want to change widgets.W.c() to go to a different __call, coz right now it's going to the Mum.__call, which wraps thingasm.
1052-- TODO - Keep an eye on this if we change to a single Mum, instead of the shallow copy we use now.
1053local wMum = getmetatable(widgets.W.c)
1054wMum.__call = function (func, ...)
1055 return Colour(func, ...)
1056end
1057]]
1058
1059window = function(w, h, title, name)
1060 name = name or 'myWindow'
1061 local win = {}
1062 win = copy(widgets, name)
1063 local wMum, wThingy = getStuffed(win.W, 'a')
1064 wThingy.isValid = aIsValid
1065 win.window = Cwindow(w, h, title, name)
1066 return win
1067end
1068
1069thingasm{'window', 'Specifies the size and title of the application Frame.', window, 'number,number,string', acl="GGG"}
1070
1071
1072-- TODO - Some function stubs, for now. Fill them up later.
1073skang = function (name)
1074end
1075
1076thingasm('skang', 'Parse the contents of a skang file or URL.', skang, 'URL')
1077
1078
1079moduleEnd(_M)
1080
1081end
1082
1083-- Boss is the person that owns a Thing.
1084
1085--[[ The original Skang parameters and commands.
1086 public final static String MY_USAGE[][] =
1087 {
1088 {"skinURL", "skinURL", "Y", "s", null, "URL of skin file.", "", "RI-"},
1089 {"debug", "debug", "N", "", "0", "Set debugging level to :\n\t-1 - errors and warnings only (-q)\n\t0 - basic information\n\t1 - advanced information (-v)\n\t2 - trace functions\n\t3 - trace protocol\n\t4 - dump packets + stuff\n\t5 - detail", "", ""},
1090 {"browser", "browser", "N", "", "mozilla %f", "Browser to run.", "", ""},
1091 {"downloaddir", "downloadDir", "N", "", "download", "Download directory.", "", ""},
1092 {"sessionID", "sessionID", "N", "", null, "SessionID from servlet.", "", ""},
1093 {"JSESSIONID", "JSESSIONID", "N", "", null, "JSESSIONID from servlet engine.", "", ""},
1094 {"servletpath", "servletPath", "N", "", "matrix_rad", "Servlet path.", "", ""},
1095 {"servletport", "servletPort", "N", "", null, "Servlet port.", "", ""},
1096 {"servletsslport", "servletSSLPort", "N", "", null, "Servlet SSL port.", "", ""},
1097 {"HTML", "HTML", "N", "", "false", "Output to HTML?", "", ""},
1098 {"PHP", "PHP", "N", "", "false", "Output though the PHP wrapper", "", ""},
1099 {"inbrowser", "inBrowser", "N", "", "true", "Run in browser window?", "", ""},
1100 {"SSL", "SSL", "N", "", null, "Dummy to avoid a web server bug.", "", ""},
1101 {"NOSSL", "NOSSL", "N", "", null, "Dummy to avoid a web server bug.", "", ""},
1102 {"corporate", "corporate", "N", "", null, "Are we doing corporate shit?", "", ""},
1103 {"", "", "", "", "", "", "", ""}
1104 };
1105 public final static String MY_SKANG[][] =
1106 {
1107-- {"module", "addModule", "file,data", "Load a module.", "", ""},
1108 {"append", "appendThing", "name,data", "Append to the current value of a Thing.", "", ""},
1109 {"#!java", "bash", "name,name,name,name,name,name,name", "A not so clever unix script compatability hack.", "", ""},
1110 {"pending", "pendingDoThing", "action", "Do an action when you are ready.", "", ""},
1111 {"applet", "doIfApplet", "action", "Only do this if we are an applet.", "", ""},
1112 {"application", "doIfApplication", "action", "Only do this if we are an application.", "", ""},
1113 {"corporateshit", "doIfCorporateShit", "action", "Only do this if we are doing corporate shit.", "", ""},
1114 {"realworld", "doIfRealWorld", "action", "Only do this if we are in the real world.", "", ""},
1115 {"servlet", "doIfServlet", "action", "Only do this if we are a servlet.", "", ""},
1116 {"do", "doThing", "action", "Do this action.", "", ""},
1117 {"grab", "getFile", "URL", "Grab a file from a URL.", "", ""},
1118-- {"get", "getThing", "name", "Get the current value of an existing thing.", "", ""},
1119 {"gimmeskin", "gimmeSkin", "", "Returns the modules default skin.", "", ""},
1120 {"help", "helpThing", "file", "Show help page.", "", ""},
1121-- {"nada", "nothing", "data", "Does nothing B-).", "", ""},
1122 {"postshow", "postShowThings", "URL,name", "POST the values of all Things to the URL, show the returned content.", "", ""},
1123 {"post", "postThings", "URL", "POST the values of all Things to the URL, return the content.", "", ""},
1124 {"postparse", "postParseThings", "URL", "POST the values of all Things to the URL, parse the returned content.", "", ""},
1125 {"quiet", "quiet", "", "Output errors and warnings only.", "", ""},
1126 {"remove", "removeThing", "name", "Remove an existing thing.", "", ""},
1127 {"sethelp", "setHelp", "name,data", "Change the help for something.", "", ""},
1128-- {"set", "setThing", "name,data", "Set the current value of an existing Thing.", "", ""},
1129-- {"skang", "skangRead", "URL", "Parse the contents of a skang file or URL.", "", ""},
1130-- {"quit", "startQuit", "", "Quit, exit, remove thyself.", "", ""},
1131 {"stopwhinging", "stopWhinging", "", "Clear all messages.", "", ""},
1132 {"tell", "tellThing", "name", "Returns details of an existing Thing.", "", ""},
1133 {"togglebug", "toggleIgnoreBrowserBug", "", "Toggle ignorance of a certain browser bug.", "", ""},
1134 {"verbose", "verbose", "", "Output advanced information.", "", ""},
1135 {"", "", "", "", "", ""}
1136]]
1137
1138--[[ The original SkangAWT parameters and commands.
1139 public final static String MY_USAGE[][] =
1140 {
1141 {"", "", "", "", "", "", "", ""}
1142 };
1143 public final static String MY_SKANG[][] =
1144 {
1145 {"taction", "tactionWidget", "name,action", "Set the alternative action for a widget.", "", ""},
1146 {"action", "actionWidget", "name,action", "Set the action for a widget.", "", ""},
1147 {"pane", "addPane", "name,x,y,w,h,data", "Add a pane to the current module.", "", ""},
1148 {"widget", "addWidget", "name,type,lx,ly,lw,lh,data,data", "Add a widget to the current skin.", "", ""},
1149 {"checkboxgroup", "checkBoxGroup", "number", "Make the next 'number' Checkboxes part of a check box group.", "", ""},
1150-- {"clear", "clearWidgets", "", "The current skin is cleared of all widgets.", "", ""},
1151 {"colour", "colourWidget", "name,r,g,b,alpha,r,g,b,alpha", "Set widget's background and foreground colour.", "", "GGG"},
1152 {"doaction", "doWidget", "name", "Do a widgets action.", "", "GGG"},
1153 {"disable", "disableWidget", "name", "Disable a widget.", "", "GGG"},
1154 {"enable", "enableWidget", "name", "Enable a widget.", "", "GGG"},
1155 {"hide", "hideWidget", "name", "Hide a widget.", "", "GGG"},
1156 {"hideall", "hideAllWidgets", "name,lx,ly,lw,lh", "Hide all widgets.", "", "GGG"},
1157 {"look", "lookWidget", "name,normal,ghost,active,toggle", "Set the current look of an existing widget.", "", "GGG"},
1158 {"mask", "maskWidget", "name,data", "Set the mask for a widget.", "", ""},
1159 {"onmouse", "onMouse", "name,data", "Do something on mouse hover.", "", ""},
1160 {"offmouse", "offMouse", "name,data", "Do something off mouse hover.", "", ""},
1161 {"popup", "popupWidget", "name,data,data,data,data", "Create a popup.", "", "GGG"},
1162 {"readonly", "readOnlyWidget", "name", "Make a widget read only.", "", "GGG"},
1163 {"writeonly", "writeOnlyWidget", "name", "Make a widget write only.", "", "GGG"},
1164 {"satori", "satori", "x,y", "Give me the developers menu.", "", "GGG"},
1165 {"showloginwindow", "showLoginWindow", "", "Show user login window.", "", "GGG"},
1166 {"show", "showWidget", "name", "Show a widget.", "", "GGG"},
1167-- {"window", "setSkangFrame", "x,y,name", "Specifies the size and title of the application Frame.", "", "GGG"},
1168 {"stuff", "stuffWidget", "name,data", "Set the stuff for a widget's pane.", "", ""},
1169 {"stufflet", "stuffWidget", "name,data,data", "Set the stufflet for a widget.", "", ""},
1170 {"stufflist", "stuffListWidget", "name,data", "List the stuff in this widget.", "", ""},
1171 {"stuffload", "stuffLoadWidget", "name,data,data", "Load the stuff for a widget.", "", ""},
1172 {"stuffsave", "stuffSaveWidget", "name,data,data", "Save the stuff for a widget.", "", ""},
1173 {"stuffdelete", "stuffDeleteWidget", "name,data,data", "Delete the stuff for a widget.", "", "SSS"},
1174 {"stuffclear", "stuffClearWidget", "name,data", "Clear the stuff for a widget.", "", "SSS"},
1175 {"rowtowidgets", "rowToWidgets", "name", "Copy Grid row to matching widgets.", "", ""},
1176 {"widgetstorow", "widgetsToRow", "name,data", "Copy matching widgets to Grid row.", "", ""},
1177 {"clearrow", "clearRow", "name", "Clear Grid row and matching widgets.", "", ""},
1178 {"clearrowwidgets", "clearRowWidgets", "name", "Clear only the Grid row matching widgets.", "", ""},
1179 {"", "", "", "", "", ""}
1180 };
1181]]
1182
1183
1184--[[ security package
1185
1186Java skang could run as a stand alone applicion, as an applet in a web
1187page, or as a servlet on a web server. This was pretty much all
1188transparent to the user. The security system reflected that. Lua skang
1189wont run in web pages, but can still have client / server behaviour.
1190The general idea was, and still is, that the GUI is the client side (in
1191web page, in extantz GUI) that sends values back to the server side
1192(servlet, actual Lua package running as a separate process, or the world
1193server for in world scripts). Client side can request that server side
1194runs commands. Serevr side can send values and commands back to the
1195client. Mostly it all happenes automatically through the ACLs.
1196
1197Bouncer is the Java skang security manager, it extended the Java
1198SecurityManager. Lua has no such thing, though C code running stuff in
1199a sandbox does a similar job. Fascist is the Java security supervisor,
1200again should go into the C sandbox.
1201
1202Human is used for authenticating a human, Puter for authenticating a
1203computer, Suits for corporate style authentication, and they all
1204extended Who, the base authentication module.
1205
1206For now, I have no idea how this all translates into Lua, but putting
1207this here for a reminder to think about security during the design
1208stage.
1209
1210
1211This is the old Java ACL definition -
1212 acl - access control list.
1213Owner is usually the person running the Thingspace.
1214RWX~,---,Rwxgroup1,r--group2,r-xgroup3,rw-group4,--X~user1
1215rwx~ is for the owner. The second one is the default. The rest are per group or per user.
1216Capital letters mean that they get access from the network to.
1217--- No access at all.
1218RWX Full access.
1219R-- Read only access.
1220r-x Read and execute, but only locally.
1221rw- Read and write a field, but don't execute a method.
1222-w- A password.
1223-a- An append only log file.
1224-A- An append only log file on the server.
1225Ri- read, but only set from init (ei. skinURL not set from properties or skang files).
1226RI- As above, but applet.init() can set it too.
1227--x Thing is both method and field, only execution of the method is allowed.
1228--p Run as owner (Pretend).
1229--P Run across the network as owner (can run in applet triggered by server).
1230s-- Read only, but not even visible to applets.
1231sss Only visible to servlets and applications.
1232--S Send to servlet to execute if applet, otherwise execute normally.
1233S-- Read only, but ignore local version and get it from server.
1234ggg GUI Thing, only visible to Applets and applications.
1235GGG GUI Thing, but servlets can access them across the net.
1236
1237For servlet only modules from an applet, the applet only loads the skanglet class, using it for all
1238access to the module.
1239
1240
1241Lua Security best practices -
1242
1243 From an email by Mike Pall -
1244
1245"The only reasonably safe way to run untrusted/malicious Lua scripts is
1246to sandbox it at the process level. Everything else has far too many
1247loopholes."
1248
1249http://lua-users.org/lists/lua-l/2011-02/msg01595.html
1250http://lua-users.org/lists/lua-l/2011-02/msg01609.html
1251http://lua-users.org/lists/lua-l/2011-02/msg01097.html
1252http://lua-users.org/lists/lua-l/2011-02/msg01106.html
1253
1254So that's processes, not threads like LuaProc does. B-(
1255
1256However, security in depth is good, so still worthwhile looking at it from other levels as well.
1257
1258General solution is to create a new environment, which we are doing
1259anyway, then whitelist the safe stuff into it, instead of blacklisting
1260unsafe stuff. Coz you never know if new unsafe stuff might exist.
1261
1262Different between 5.1 (setfenv) and 5.2 (_ENV)
1263
1264http://lua-users.org/wiki/SandBoxes -
1265
1266------------------------------------------------------
1267-- make environment
1268local env = -- add functions you know are safe here
1269{
1270 ipairs = ipairs,
1271 next = next,
1272 pairs = pairs,
1273 pcall = pcall,
1274 tonumber = tonumber,
1275 tostring = tostring,
1276 type = type,
1277 unpack = unpack,
1278 coroutine = { create = coroutine.create, resume = coroutine.resume,
1279 running = coroutine.running, status = coroutine.status,
1280 wrap = coroutine.wrap },
1281 string = { byte = string.byte, char = string.char, find = string.find,
1282 format = string.format, gmatch = string.gmatch, gsub = string.gsub,
1283 len = string.len, lower = string.lower, match = string.match,
1284 rep = string.rep, reverse = string.reverse, sub = string.sub,
1285 upper = string.upper },
1286 table = { insert = table.insert, maxn = table.maxn, remove = table.remove,
1287 sort = table.sort },
1288 math = { abs = math.abs, acos = math.acos, asin = math.asin,
1289 atan = math.atan, atan2 = math.atan2, ceil = math.ceil, cos = math.cos,
1290 cosh = math.cosh, deg = math.deg, exp = math.exp, floor = math.floor,
1291 fmod = math.fmod, frexp = math.frexp, huge = math.huge,
1292 ldexp = math.ldexp, log = math.log, log10 = math.log10, max = math.max,
1293 min = math.min, modf = math.modf, pi = math.pi, pow = math.pow,
1294 rad = math.rad, random = math.random, sin = math.sin, sinh = math.sinh,
1295 sqrt = math.sqrt, tan = math.tan, tanh = math.tanh },
1296 os = { clock = os.clock, difftime = os.difftime, time = os.time },
1297}
1298
1299-- run code under environment [Lua 5.1]
1300local function run(untrusted_code)
1301 if untrusted_code:byte(1) == 27 then return nil, "binary bytecode prohibited" end
1302 local untrusted_function, message = loadstring(untrusted_code)
1303 if not untrusted_function then return nil, message end
1304 setfenv(untrusted_function, env)
1305 return pcall(untrusted_function)
1306end
1307
1308-- run code under environment [Lua 5.2]
1309local function run(untrusted_code)
1310 local untrusted_function, message = load(untrusted_code, nil, 't', env)
1311 if not untrusted_function then return nil, message end
1312 return pcall(untrusted_function)
1313end
1314------------------------------------------------------
1315
1316Also includes a table of safe / unsafe stuff.
1317
1318
1319While whitelisting stuff, could also wrap unsafe stuff to make them more safe.
1320
1321print() -> should reroute to our output widgets.
1322rawget/set() -> don't bypass the metatables, but gets tricky and recursive.
1323require -> don't allow bypassing the sandbox to get access to restricted modules
1324package.loaded -> ditto
1325
1326
1327Other things to do -
1328
1329debug.sethook() can be used to call a hook every X lines, which can help with endless loops and such.
1330Have a custom memory allocater, like edje_lua2 does.
1331
1332------------------------------------------------------
1333------------------------------------------------------
1334
1335The plan -
1336
1337 Process level -
1338 Have a Lua script runner C program / library.
1339 It does the LuaProc thing, and the edje_lua2 memory allocater thing.
1340 Other code feeds scripts to it via a pipe.
1341 Unless they are using this as a library.
1342 It can be chrooted, ulimited, LXC containered, etc.
1343 It has an internal watchdog thread.
1344 The truly paranoid can have a watchdog timer process watch it.
1345 Watches for a "new Lua state pulled off the queue" signal.
1346 This could be done from the App that spawned it.
1347
1348 It runs a bunch of worker threads, with a queue of ready Lua states.
1349 Each Lua state being run has lua_sethook() set to run each X lines, AND a watchdog timer set.
1350 If either is hit, then the Lua state is put back on the queue.
1351 (Currently LuaProc states go back an the queue when waiting for a "channel message", which does a lua_yeild().)
1352 NOTE - apparently "compiled code" bypasses hooks, though there's an undocumented LuaJIT compile switch for that. http://lua-users.org/lists/lua-l/2011-02/msg01106.html
1353 EFL is event based.
1354 LSL is event based.
1355 LuaSL is event based.
1356 Java skang is event based, with anything that has long running stuff overriding runBit().
1357 Coz Java AWT is event based, the "events" are over ridden methods in each widget class.
1358 Should all work if we keep this as event based.
1359 An "event" is a bit of Lua script in a string, at Input trust level usually.
1360 Configurable for this script runner is -
1361 IP address & port, or pipe name.
1362 Security level to run at, defaults to Network.
1363 Number of worker threads, defaults to number of CPUs.
1364 Memory limit per Lua state.
1365 Lines & time per tick for Lua states.
1366
1367 Different levels of script trust -
1368 System - the local skang and similar stuff.
1369 -> No security at all.
1370 App - Lua scripts and C from the running application.
1371 -> Current module level security.
1372 Each has it's own environment, with no cross environment leakage.
1373 Runs in the Apps process, though that might be the script runner as a library.
1374 Or could be skang's main loop.
1375 Local - Lua scripts and skang files sent from the client apps running on the same system.
1376 -> As per App.
1377 Runs in a script runner, maybe? Or just the Apps script runner.
1378 Limit OS and file stuff, the client app can do those itself.
1379 Network - Lua scripts and skang files sent from the network.
1380 -> Runs in a script runner.
1381 Option to chroot it, ulimit it, etc.
1382 Heavily Lua sandboxed via environment.
1383 It can access nails, but via network derived credentials.
1384 Can have very limited local storage, not direct file access though, but via some sort of security layer.
1385 Can have network access.
1386 Can have GUI access, but only to it's own window.
1387 Config - Lua scripts run as configuration files.
1388 -> Almost empty local environment, can really only do math and set Things.
1389 Input - Lua scripts run as a result of hitting skang widgets on the other end of a socket.
1390 -> As per Config, but can include function calls.
1391 Also would need sanitizing, as this can come from the network.
1392 Microsoft - Not to be trusted at all.
1393 Apple - Don't expect them to trust us.
1394
1395 NOTE - edje_lua2 would be roughly Local trust level.
1396
1397 So we need to be able to pass Lua between processes -
1398 Have to be able to do it from C, from Lua, and from Lua embedded in C.
1399 edje_lua2 - uses Edje messages / signals.
1400 LuaSL - uses Ecore_Con, in this case a TCP port, even though it's only local.
1401 LuaSL mainloop for it's scripts is to basically wait for these messages from LuaProc.
1402 Which yield's until we get one.
1403 Eventually gets Lua code as a string -> loadstring() -> setfenv() -> pcall()
1404 The pcall returns a string that we send back as a LuaProc message.
1405 Extantz - we want to use stdin/stdout for the pipe, but otherwise LuaSL style semantics.
1406
1407 Hmm, Extantz could run external skang modules in two ways -
1408 Run the module as a separate app, with stdin/stdout.
1409 Require the module, and run it internally.
1410 Stuff like the in world editor and radar would be better as module, since they are useless outside Extantz?
1411 Radar is useless outside Extantz, editor could be used to edit a local file.
1412 Stuff like woMan would be better off as a separate application, so it can start and stop extantz.
1413
1414]]
1415
1416
1417--[[
1418The main loop.
1419 A Lua skang module is basically a table, with skang managed fields.
1420 Once it calls moduleEnd(), it's expected to have finished.
1421 test.lua is currently an exception, it runs test stuff afterwards.
1422 So their code just registers Things and local variables.
1423 Some of those Things might be functions for manipulating internal module state.
1424 A C module has it's variables managed outside of it by Lua.
1425 So would have to go via LUA_GLOBALSINDEX to get to them.
1426 Unless they are userdata, which are C things anyway.
1427 Though it's functions are obviously inside the C module.
1428 Normal Lua module semantics expect them to return to the require call after setting themselves up.
1429 So test.lua is really an aberation.
1430
1431 Soooo, where does the main loop go?
1432 The skang module itself could define the main loop.
1433 Should not actually call it though, coz skang is itself a module.
1434
1435 In Java we had different entry points depending on how it was called.
1436 If it was called as an applet or application, it got it's own thread with a mainloop.
1437 That main loop just slept and called runBit() on all registered modules.
1438 If it was loaded as a module, it bypassed that stuff.
1439 I don't think Lua provides any such mechanism.
1440 In theory, the first call to moduleBegin would be the one that was started as an application.
1441 So we could capture that, and test against it in moduleEnd to find when THAT module finally got to the end.
1442 THEN we can start the main loop (test.lua being the exception that fucks this up).
1443 Though test.lua could include a runBits() that quits the main loop, then starts the main loop at the very end once more?
1444 The problem with this is applications that require skang type modules.
1445 The first one they require() isn't going to return.
1446 Eventually skang itself will get loaded. It looks at the "arg" global, which SHOULD be the command line.
1447 Including the name of the application, which we could use to double check.
1448 Extantz / script runner would set this arg global itself.
1449
1450 Skang applications have one main loop per app.
1451 Skang modules use the main loop of what ever app called them.
1452 Non skang apps have the option of calling skangs main loop.
1453 Extantz starts many external skang apps, which each get their own main loop.
1454 Extantz has it's own Ecore main loop.
1455 LuaSL still has one main loop per script.
1456 LSL scripts get their own main loop, but LSL is stupid and doesn't have any real "module" type stuff.
1457
1458What does skang main loop actually do?
1459 In Java it just slept for a bit, then called runBit() from each module, and the only module that had one was watch.
1460 Actually better off using Ecore timers for that sort of thing.
1461 Skang main loop has nothing to do? lol
1462 Well, except for the "wait for LuaProc channel messages" thing.
1463 Widget main loop would be Ecore's main loop.
1464
1465 Extantz loads a skang module.
1466 Module runs in extantz script runner.
1467 Module runs luaproc message main loop from skang.
1468 Evas / Elm widgets send signals, call C callbacks.
1469 Extantz sends Lua input scripts via luaproc messages to module.
1470 Extantz runs separate skang module.
1471 Module runs in it's own process.
1472 Module runs it's own message loop on the end of stdin.
1473 Evas / Elm widgets send signals, call C callbacks.
1474 Extantz sends Lua Input scripts to module via stdout.
1475 Module runs stand alone.
1476 Module runs in it's own process.
1477 Module has to have widget start Ecore's main loop.
1478 Module runs it's own message loop, waiting for widget to send it messages.
1479 Evas / Elm widgets send signals, call C callbacks.
1480 Widget sends Lua Input scripts to module.
1481
1482Alternate plan -
1483 Skang has no main loop, modules are just tables.
1484 OK, so sometimes skang has to start up an Ecore main loop.
1485 With either Ecore_Con, or Evas and Elm.
1486 skang.message(string)
1487 Call it to pass a bit of Lua to skang, which is likely Input.
1488 Widget twiddles happen in Ecore's main loop, via signals and call backs.
1489 Eventually these call backs hit the widgets action string.
1490 Send that action string to skang.message().
1491
1492 Extantz loads a skang module.
1493 Extantz has a skang Lua state.
1494 Module is just another table in skang.
1495 Widget -> callback -> action string -> skang.message()
1496 Extantz runs separate skang module.
1497 Skang module C code runs an Ecore main loop.
1498 Module is just another table in skang.
1499 Skang C uses Ecore_Con to get messages from Extantz' Ecore_Con.
1500 Widget -> callback -> action string -> Ecore_Con -> skang.message()
1501 OOORRRR ....
1502 Skang runs a main loop reading stdin.
1503 Widget -> callback -> action string -> stdout -> skang.message()
1504 Module runs stand alone.
1505 Skang module C code runs an Ecore main loop.
1506 Module is just another table in skang.
1507 Widget -> callback -> action string -> skang.message()
1508 Extantz loads a skang module from the network.
1509 Skang module runs on the server with it's own Ecore main loop somehow.
1510 Module is just another table in skang.
1511 Extantz uses Ecore_Con to get messages from Extantz' Ecore_Con, via TCP.
1512 Widget -> callback -> action string -> Ecore_Con -> skang.message()
1513 OOORRRR ....
1514 Remember, these are untrusted, so that's what the script runner is for.
1515 Skang module runs in the script runner, with some sort of luaproc interface.
1516 Widget -> callback -> action string -> Ecore_Con -> luaproc -> skang.message()
1517
1518 Skang running as a web server.
1519 Skang runs an Ecore main loop.
1520 Skang has an Ecore_Con server attached to port 80.
1521 Skang loads modules as usual.
1522 Skang responds to specific URLs with HTML forms generated from Skang files.
1523 Skang gets post data back, which kinda looks like Input. B-)
1524
1525 Extantz runs a LuaSL / LSL script from the network.
1526 Send this one to the LuaSL script runner.
1527 Coz LSL scripts tend to have lots of copies with the same name in different objects.
1528 Could get too huge to deal with via "just another table".
1529 In this case, compiling the LSL might be needed to.
1530
1531]]
1532
1533
1534--[[ TODO
1535 NOTE that skang.thingasm{} doesn't care what other names you pass in, they all get assigned to the Thing.
1536
1537
1538 Widget -
1539 Should include functions for actually dealing with widgets, plus a way
1540 of creating widgets via introspection. Should also allow access to
1541 widget internals via table access. Lua code could look like this -
1542
1543 foo = widget('label', 0, "0.1", 0.5, 0, 'Text goes here :")
1544 -- Method style.
1545 foo:colour(255, 255, 255, 0, 0, 100, 255, 0)
1546 foo:hide()
1547 foo:action("skang.load(some/skang/file.skang)")
1548 -- Table style.
1549 foo.action = "skang.load('some/skang/file.skang')"
1550 foo.colour.r = 123
1551 foo.look('some/edje/file/somewhere.edj')
1552 foo.help = 'This is a widget for labelling some foo.'
1553
1554 Widgets get a type as well, which would be label, button, edit, grid, etc.
1555 A grid could even have sub types - grid,number,string,button,date.
1556 A required widget might mean that the window HAS to have one.
1557 Default for a widget could be the default creation arguments - '"Press me", 1, 1, 10, 50'.
1558
1559 skang.thingasm{'myButton', types='Button', rectangle={1, 1, 10, 50}, title='Press me', ...}
1560
1561 skang.thingasm('foo,s,fooAlias', 'Foo is a bar, not the drinking type.', function () print('foo') end, '', '"button", "The foo :"' 1, 1, 10, 50')
1562 myButton = skang.widget('foo') -- Gets the default widget creation arguments.
1563 myButton:colour(1, 2, 3, 4)
1564 -- Use generic positional / named arguments for widget to, then we can do -
1565 myEditor = skang.widget{'foo', "edit", "Edit foo :", 5, 15, 10, 100, look='edit.edj', colour={blue=20}, action='...'}
1566 -- Using the Thing alias stuff, maybe we can do the "first stage tokenise" step after all -
1567 myEditor = skang.widget{'foo', "edit", "Edit foo :", 5, 15, 10, 100, l='edit.edj', c={b=20}, a='...'}
1568 myEditor:colour(1, 2, 3, 4, 5, 6, 7, 8)
1569 myButton = 'Not default' -- myEditor and foo change to. Though now foo is a command, not a parameter, so maybe don't change that.
1570 -- Though the 'quit' Thing could have a function that does quitting, this is just an example of NOT linking to a Thing.
1571 -- If we had linked to this theoretical 'quit' Thing, then pushing that Quit button would invoke it's Thing function.
1572 quitter = skang.widget(nil, 'button', 'Quit', 0.5, 0.5, 0.5, 0.5)
1573 quitter:action('quit')
1574
1575 For widgets with "rows", which was handled by Stuff in skang, we could
1576 maybe use the Lua concat operator via metatable. I think that works by
1577 having the widget (a table) on one side of the concat or the other, and
1578 the metatable function gets passed left and right sides, then must
1579 return the result. Needs some experimentation, but it might look like
1580 this -
1581
1582 this.bar = this.bar .. 'new choice'
1583 this.bar = 'new first choice' .. this.bar
1584
1585
1586 coordinates and sizes -
1587
1588 Originally skang differentiated between pixels and character cells,
1589 using plain integers to represent pixels, and _123 to represent
1590 character cells. The skang TODO wanted to expand that to percentages
1591 and relative numbers. We can't use _123 in Lua, so some other method
1592 needs to be used. Should include those TODO items in this new design.
1593
1594 Specifying character cells should be done as strings - "123"
1595
1596 Percentages can be done as small floating point numbers between 0 and 1,
1597 which is similar to Edje. Since Lua only has a floating point number
1598 type, both 0 and 1 should still represent pixels / character cells -
1599
1600 0.1, 0.5, "0.2", "0.9"
1601
1602 Relative numbers could be done as strings, with the widget to be
1603 relative to, a + or -, then the number. This still leaves the problem
1604 of telling if the number is pixels or character cells. Also, relative
1605 to what part of the other widget? Some more thought needs to be put
1606 into this.
1607
1608 Another idea for relative numbers could be to have a coord object with
1609 various methods, so we could have something like -
1610
1611 button:bottom(-10):right(5) -- 10 pixels below the bottom of button, 5 pixels to the right of the right edge of button.
1612 button:width("12") -- 12 characters longer than the width of button.
1613
1614 But then how do we store that so that things move when the thing they are
1615 relative to moves?
1616
1617
1618 Squeal -
1619 Squeal was the database driver interface for SquealStuff, the database
1620 version of Stuff. Maybe we could wrap esskyuehl? Not really in need of
1621 database stuff for now, but should keep it in mind.
1622 For SquealStuff, the metadata would be read from the SQL database automatically.
1623
1624 squeal.database('db', 'host', 'someDb', 'user', 'password') -> Should return a Squeal Thing.
1625 local db = require 'someDbThing' -> Same as above, only the database details are encodode in the someDbThing source, OR come from someDbThing.properties.
1626 db:getTable('stuff', 'someTable') -> Grabs the metadata, but not the rows.
1627 db:read('stuff', 'select * from someTable'} -> Fills stuff up with several rows, including setting up the metadata for the columns.
1628 stuff[1].field1 -> Is a Thing, with a proper metatable, that was created automatically from the database meta data.
1629 stuff:read('someIndex') -> Grabs a single row that has the key 'someIndex', or perhaps multiple rows since this might have SQL under it.
1630 stuff = db:read('stuff', 'select * from someTable where key='someIndex')
1631
1632 stuff:write() -> Write all rows to the database table.
1633 stuff:write(1) -> Write one row to the database table.
1634 stuff:stuff('field1').isValid = someFunction -- Should work, all stuff[key] share the same Thing description.
1635 stuff:isValid(db) -> Validate the entire Thing against it's metadata at least.
1636 window.stuff = stuff -> Window gets stuff as it's default 'Keyed' table, any widgets with same names as the table fields get linked.
1637 grid.stuff = stuff -> Replace contents of this grid widget with data from all the rows in stuff.
1638 choice.stuff = stuff -> As in grid, but only using the keys.
1639 widget.stuff = stuff:stuff('field1') -> This widget gets a particular stufflet.
1640 widget would have to look up getmetatable(window.stuff).parent. Or maybe this should work some other way?
1641
1642 In all these cases above, stuff is a 'Keyed' table that has a Thing metatable, so it has sub Things.
1643 Should include some way of specifyings details like key name, where string, etc.
1644 getmetatable(stuff).__keyName
1645 getmetatable(stuff).__squeal.where
1646 And a way to link this database table to others, via the key of the other, as a field in this Stuff.
1647 stuff:stuff('field0').__link = {parent, key, index}
1648 In Java we had this -
1649
1650public class PersonStuff extends SquealStuff
1651{
1652
1653...
1654
1655 public final static String FULLNAME = "fullname";
1656
1657 public static final String keyField = "ID"; // Name of key field/s.
1658 public static final String where = keyField + "='%k'";
1659 public static final String listName = "last";
1660 public static final String tables = "PEOPLE";
1661 public static final String select = null;
1662 public static final String stufflets[] =
1663 {
1664 keyField,
1665 "PASSWD_ID|net.matrix_rad.squeal.PasswdStuff|,OTHER",
1666 "QUALIFICATION_IDS|net.matrix_rad.people.QualificationStuff|,OTHER",
1667 "INTERESTING_IDS|net.matrix_rad.people.InterestingStuff|,OTHER",
1668 "title",
1669 "first",
1670 "middle",
1671 "last",
1672 "suffix",
1673
1674...
1675
1676 FULLNAME + "||,VARCHAR,512"
1677 };
1678}
1679
1680]]
1681
1682
1683-- Gotta check out this _ENV thing, 5.2 only. Seems to replace the need for setfenv(). Seems like setfenv should do what we want, and is more backward compatible.
1684-- "_ENV is not supported directly in 5.1, so its use can prevent a module from remaining compatible with 5.1.
1685-- Maybe you can simulate _ENV with setfenv and trapping gets/sets to it via __index/__newindex metamethods, or just avoid _ENV."
1686-- LuaJIT doesn't support _ENV anyway.
diff --git a/ClientHamr/GuiLua/test.lua b/ClientHamr/GuiLua/test.lua
deleted file mode 100644
index 705f7ad..0000000
--- a/ClientHamr/GuiLua/test.lua
+++ /dev/null
@@ -1,211 +0,0 @@
1-- Wrapping the entire module in do .. end helps if people just join a bunch of modules together, which apparently is popular.
2-- By virtue of the fact we are stuffing our result into package.loaded[], just plain running this works as "loading the module".
3do -- Only I'm not gonna indent this.
4
5local skang = require 'skang'
6local _M = skang.moduleBegin('test', nil, 'Copyright 2014 David Seikel', '0.1', '2014-03-27 03:57:00', [[
7 local win = skang.window(500, 500, "G'day planet.", 'testWindow')
8 skang.thingasm{win, 'quitter', 'Quits the skang window', types = 'widget', widget='"button", "Quit", 10, 10, 100, 30'}
9 win.W.quitter.action = 'skang.quit()' -- TODO Should look it up in ThingSpace.commands, and translat 'quit' into the Lua 'skang.quit()'?
10]])
11
12print('code')
13
14-- A variable that is private to this module.
15local fool = 22
16
17-- TODO - Could have a table of tables, and ipair through the top level, passing the inner ones to skang.thingasm{}.
18
19skang.thingasm{'fooble,f', 'Help text goes here', 1, widget='"edit", "The fooble:", 1, 1, 10, 50', required=true}
20skang.thingasm('bar', 'Help text', "Default")
21skang.thingasm('foo')
22
23-- We can use inline functions if we don't need the function internally.
24skang.thingasm('ffunc', 'Help Text', function (arg1, arg2)
25 print('Inside test.ffunc(' .. arg1 .. ', ' .. arg2 .. ')')
26end, 'number,string')
27
28print('Ending soon')
29skang.moduleEnd(_M)
30
31end
32
33
34-- Test it.
35local skang = require 'skang'
36local test = require 'test'
37local test_c = require 'test_c'
38local copy = skang.copy(test, 'copy')
39
40print('End ' .. test.bar .. ' ' .. test.VERSION .. ' ' .. skang.get(test, 'ffunc', 'help') .. ' ->> ' .. skang.get(test, 'f', 'action'))
41
42print('')
43
44print('foo = ' .. test.foo .. ' ->> ' .. skang.get(test, 'foo', 'help'))
45print('fooble = ' .. test.fooble)
46print('cfooble = ' .. test_c.cfooble .. ' ->> ' .. skang.get(test_c, 'cfooble', 'help') .. ' [' .. skang.get(test_c, 'cfooble', 'widget') .. ']')
47print('cfunc ->> ' .. skang.get(test_c, 'cfunc', 'help'))
48test.ffunc('one', 2)
49test_c.cfunc(0, 'zero')
50print('')
51
52test.f = 42
53print('f is now ' .. test.fooble .. ' ' .. test.f)
54print('copy_f is now ' .. copy.fooble .. ' ' .. copy.f)
55copy.f = 24
56print('f is now ' .. test.fooble .. ' ' .. test.f)
57print('copy_f is now ' .. copy.fooble .. ' ' .. copy.f)
58test.f = nil
59print('f is now ' .. test.fooble .. ' ' .. test.f)
60test.fooble = 42
61print('f is now ' .. test.fooble .. ' ' .. test.f)
62test.fooble = nil
63print('f is now ' .. test.fooble .. ' ' .. test.f)
64print('')
65
66print(skang.isBoolean(true))
67print(skang.isBoolean(1))
68print(skang.isBoolean('1'))
69print(skang.isBoolean('true'))
70print(skang.isBoolean('Yep'))
71print(skang.isBoolean('?'))
72print(skang.isBoolean(test))
73print(skang.isBoolean(function (a) return true end))
74print('')
75print(skang.isBoolean(false))
76print(skang.isBoolean(nil))
77print(skang.isBoolean(0))
78print(skang.isBoolean(''))
79print(skang.isBoolean('0'))
80print(skang.isBoolean('false'))
81print(skang.isBoolean('Nope'))
82print(skang.isBoolean(function (a) return false end))
83print('')
84
85-- Make it required, even though it was anyway.
86skang.set(test, 'f', 'required', true)
87-- Disable the default value, so we see "is required" errors.
88skang.reset(test, 'f', 'default')
89test.fooble = 42
90test.fooble = 'Should fail.'
91test.fooble = 42
92test.fooble = nil
93test.fooble = 42
94test.fooble = true
95test.f = 42
96test.f = nil
97test.bar = 123
98print('')
99
100skang.set(test, 'f', 'required', false)
101test.f = 42
102test.f = nil
103skang.set(test, 'f', 'default', 999)
104test.f = 42
105test.f = nil
106print(test.fooble .. ' ' .. test.f)
107print(skang.get(test, 'f', 'default'))
108print('')
109
110local stuff = {}
111stuff.t = {}
112
113skang.thingasm{stuff, 'a', 'A test stufflet'}
114skang.thingasm{stuff.t, 'b', 'A sub stufflet'}
115skang.thingasm{stuff.t, 'c', 'Another sub stufflet'}
116skang.thingasm{stuff, 's', 'A Stuff', types='table'}
117stuff.s{'sa,a', 'A stufflet in a Stuff'}
118stuff.s{'sb,b', 'Another stufflet in a Stuff'}
119skang.thingasm{stuff, 'S', 'A database table of Stuff', types='Keyed'}
120stuff.S{'field0', 'The first field of the db table.'}
121stuff.S{'field1', 'The second field of the db table.'}
122
123print('*********************************')
124skang.fixNames(skang, 'skang')
125skang.fixNames(test, 'test')
126skang.fixNames(test_c, 'test_c')
127skang.fixNames(stuff, 'stuff')
128print('*********************************')
129
130print(skang.get(stuff, 'a', 'help'))
131print(skang.get(stuff.t, 'b', 'help'))
132print(skang.get(stuff.t, 'c', 'help'))
133print(skang.get(stuff, 's', 'help'))
134print(skang.get(stuff.s, 'sa', 'help'))
135print(skang.get(stuff.s, 'sb', 'help'))
136print(skang.get(stuff.S, 'field0', 'help'))
137print(skang.get(stuff.S, 'field1', 'help'))
138skang.thingasm{test, 'baz,b', 'A test stufflet for test'}
139print(skang.get(test, 'b', 'help'))
140print(skang.get(test, 'f', 'help'))
141-- Should fail isValid()
142stuff.a = 1
143stuff.t.b = '2'
144stuff.t.c = '3'
145test.b = '422222'
146test.f = 5
147test_c.cbar = '666'
148-- This one doesn't actually exist.
149test_c.bar = '7'
150stuff.s.sa = true
151stuff.s.sb = 22
152stuff.s.b = 33
153print('')
154-- TODO - This triggers isValid() twice for each table element.
155stuff.s = {a=8, sb='9'}
156print('')
157stuff.s.sb = 99
158-- NOTE - Yet this doesn't trigger isValid() twice.
159stuff.S['record0'] = {field0=0, field1='zero'}
160stuff.S['record1'] = {field0='1', field1='one'}
161stuff.S['record2'] = {field0='2', field1='two'}
162
163print('')
164
165print(skang.get(stuff, 'a'))
166print(skang.get(stuff.t, 'b'))
167print(skang.get(stuff.t, 'c'))
168print(skang.get(test, 'b'))
169print(skang.get(test, 'baz'))
170print(skang.get(test, 'f'))
171print(skang.get(test, 'fooble'))
172print(skang.get(test_c, 'cbar'))
173print(skang.get(test_c, 'bar'))
174print(type(skang.get(stuff, 's')))
175print(skang.get(stuff.s, 'sa'))
176print(skang.get(stuff.s, 'sb'))
177print('')
178
179print(stuff.a)
180print(stuff.t.b)
181print(stuff.t.c)
182print(test.b)
183print(test.baz)
184print(test.f)
185print(test.fooble)
186print(test_c.cbar)
187print(test_c.bar)
188print(test_c.c)
189print(test_c.cfooble)
190print(stuff.s.sa)
191print(stuff.s.sb)
192print('')
193
194--skang.printTableStart(stuff.s, '', 'stuff.s')
195--skang.printTableStart(stuff.S, '', 'stuff.S')
196--skang.printTableStart(getmetatable(stuff.S), '', 'stuff.S metatable')
197
198print(stuff.S['record0'].field1)
199print(stuff.S['record1'].field0)
200print(stuff.S['record2'].field1)
201
202--skang.printTableStart(stuff.S['record0'], '', 'stuff.S[record0]')
203--skang.printTableStart(getmetatable(stuff.S['record0']), '', 'metatable stuff.S[record0]')
204--skang.printTableStart(getmetatable(stuff.S['record1']), '', 'metatable stuff.S[record1]')
205--skang.printTableStart(getmetatable(stuff.S['record2']), '', 'metatable stuff.S[record2]')
206
207--skang.printTableStart(getmetatable(stuff.s), '', 'stuff.s metatable')
208--skang.printTableStart(getmetatable(stuff), '', 'stuff metatable')
209--skang.printTableStart(getmetatable(stuff.S), '', 'stuff.S metatable')
210
211--skang.printTableStart(getmetatable(test), '', 'test metatable')
diff --git a/ClientHamr/GuiLua/test.properties b/ClientHamr/GuiLua/test.properties
deleted file mode 100644
index 71a371d..0000000
--- a/ClientHamr/GuiLua/test.properties
+++ /dev/null
@@ -1 +0,0 @@
1fooble = 'forty two'
diff --git a/ClientHamr/GuiLua/test.sh b/ClientHamr/GuiLua/test.sh
deleted file mode 100755
index 1effdb3..0000000
--- a/ClientHamr/GuiLua/test.sh
+++ /dev/null
@@ -1,3 +0,0 @@
1#! /bin/bash
2
3./skang -l test -foo "argy bargy"
diff --git a/ClientHamr/GuiLua/test.skang b/ClientHamr/GuiLua/test.skang
deleted file mode 100644
index 10382b5..0000000
--- a/ClientHamr/GuiLua/test.skang
+++ /dev/null
@@ -1,14 +0,0 @@
1#!/usr/bin/env skang -l test -- Lua allows this shell hack.
2
3-- There's an implied local skang = require 'skang'
4-- There's an implied local test = require 'test'
5
6-- This is a bit more verbose than I wanted. lol
7local win = skang.window(500, 500, "G'day planet.", 'testWindow')
8skang.thingasm{win, 'quitter', 'Quits the skang window', types = 'widget', widget='"button", "Quit", 10, 10, 100, 30'}
9win.W.quitter.action = 'skang.quit()' -- TODO Should look it up in ThingSpace.commands, and translate 'quit' into the Lua 'skang.quit()'?
10
11skang.thingasm{win, 'ffuncer', 'Calls ffunc', types = 'widget', widget='"button", "ffunc()", 10, 40, 100, 30', action='test.ffunc(3, 4)'}
12
13test.bar = 'things'
14test.ffunc(1, 'two')
diff --git a/ClientHamr/GuiLua/test_c.c b/ClientHamr/GuiLua/test_c.c
deleted file mode 100644
index 5328bda..0000000
--- a/ClientHamr/GuiLua/test_c.c
+++ /dev/null
@@ -1,88 +0,0 @@
1/* Should be a Lua skang module, roughly the same as test.lua
2
3Seems to be several problems with linking in various OSes, here's some
4possibly helpful links -
5
6http://lua.2524044.n2.nabble.com/C-Lua-modules-not-compatible-with-every-Lua-interpreter-td7647522.html
7http://lua-users.org/wiki/LuaProxyDllFour
8http://stackoverflow.com/questions/11492194/how-do-you-create-a-lua-plugin-that-calls-the-c-lua-api?rq=1
9http://lua-users.org/lists/lua-l/2008-01/msg00671.html
10*/
11
12
13#include "GuiLua.h"
14
15
16static const char *ourName = "test_c";
17int skang, _M;
18
19static int cfunc (lua_State *L)
20{
21 double arg1 = luaL_checknumber(L, 1);
22 const char *arg2 = luaL_checkstring(L, 2);
23
24 printf("Inside %s.cfunc(%f, %s)\n", ourName, arg1, arg2);
25 return 0;
26}
27
28/* local test_c = require 'test_c'
29
30Lua's require() function will strip any stuff from the front of the name
31separated by a hyphen, so 'ClientHamr-GuiLua-test_c' -> 'test_c'. Then
32it will search through a path, and eventually find this test_c.so (or
33test_c.dll or whatever), then call luaopen_test_c(), which should return
34a table. The argument (only thing on the stack) for this function will
35be 'test_c'.
36
37Normally luaL_register() creates a table of functions, that is the table
38returned, but we want to do something different with skang.
39*/
40int luaopen_test_c(lua_State *L)
41{
42 // In theory, the only thing on the stack now is 'test_c' from the require() call.
43
44// pseudo-indices, special tables that can be accessed like the stack -
45// LUA_GLOBALSINDEX - thread environment, where globals are
46// LUA_ENVIRONINDEX - C function environment, in this case luaopen_test_c() is the C function
47// LUA_REGISTRYINDEX - C registry, global, for unique keys use the module name as a string, or a lightuserdata address to a C object in our module.
48// lua_upvalueindex(n) - C function upvalues
49
50// The only locals we care about are skang and _M.
51// All modules go into package.loaded[name] as well.
52// skang is essentially a global anyway.
53// _M we pass back as the result, and our functions get added to it by skang.thingasm()
54// Not entirely true, _M is a proxy table, getmetatable(_M).__values[cfunc] would be our function.
55
56// local skang = require 'skang'
57 lua_getglobal(L, "require");
58 lua_pushstring(L, SKANG);
59 lua_call(L, 1, 1);
60 lua_setfield(L, LUA_REGISTRYINDEX, SKANG);
61 lua_getfield(L, LUA_REGISTRYINDEX, SKANG);
62 skang = lua_gettop(L);
63
64// local _M = skang.moduleBegin('test_c', nil, 'Copyright 2014 David Seikel', '0.1', '2014-03-27 03:57:00', nil, false)
65 push_lua(L, "@ ( $ ~ $ $ $ ~ ! )", skang, MODULEBEGIN, ourName, "Copyright 2014 David Seikel", "0.1", "2014-03-27 03:57:00", 0, 1);
66 lua_setfield(L, LUA_REGISTRYINDEX, ourName);
67 lua_getfield(L, LUA_REGISTRYINDEX, ourName);
68 _M = lua_gettop(L);
69
70// This uses function{} style.
71// skang.thingasm{_M, 'cfooble,c', 'cfooble help text', 1, widget=\"'edit', 'The cfooble:', 1, 1, 10, 50\", required=true}
72 push_lua(L, "@ ( { = $ $ % $widget !required } )", skang, THINGASM, _M, "cfooble,c", "cfooble help text", 1, "'edit', 'The cfooble:', 1, 1, 10, 50", 1, 0);
73
74// skang.thing(_M, 'cbar', 'Help text', 'Default')
75 push_lua(L, "@ ( = $ $ $ )", skang, THINGASM, _M, "cbar", "Help text", "Default", 0);
76
77// skang.thingasm(_M, 'cfoo')
78 push_lua(L, "@ ( = $ )", skang, THINGASM, _M, "cfoo", 0);
79
80// skang.thingasm(_M, 'cfunc', 'cfunc does nothing really', cfunc, 'number,string')
81 push_lua(L, "@ ( = $ $ & $ )", skang, THINGASM, _M, "cfunc", "cfunc does nothing really", cfunc, "number,string", 0);
82
83// skang.moduleEnd(_M)
84 push_lua(L, "@ ( = )", skang, MODULEEND, _M, 0);
85
86 // Return _M, the table itself, not the index.
87 return 1;
88}
diff --git a/ClientHamr/extantz/CDemo.cpp b/ClientHamr/extantz/CDemo.cpp
deleted file mode 100644
index 0ca40f1..0000000
--- a/ClientHamr/extantz/CDemo.cpp
+++ /dev/null
@@ -1,510 +0,0 @@
1// This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt.
2// This file is not documented.
3
4#include <irrlicht.h>
5#include "extantz.h"
6#include "extantzCamera.h"
7#include "CDemo.h"
8
9
10CDemo::CDemo(GLData *gld, bool a)
11: additive(a),
12 device(gld->device),
13 currentScene(0),
14 quakeLevelMesh(0), quakeLevelNode(0), skyboxNode(0), model1(0), model2(0),
15 campFire(0), metaSelector(0), mapSelector(0), sceneStartTime(0),
16 timeForThisScene(0)
17{
18}
19
20
21CDemo::~CDemo()
22{
23 if (mapSelector)
24 mapSelector->drop();
25
26 if (metaSelector)
27 metaSelector->drop();
28}
29
30
31void CDemo::setup(GLData *gld)
32{
33 device = gld->device;
34 IrrlichtDevice *device = gld->device;
35// IVideoDriver *driver = gld->driver;
36// ISceneManager *smgr = gld->smgr;
37
38 if (device->getFileSystem()->existFile("irrlicht.dat"))
39 device->getFileSystem()->addFileArchive("irrlicht.dat");
40 else
41 device->getFileSystem()->addFileArchive("media/Irrlicht/irrlicht.dat");
42 if (device->getFileSystem()->existFile("map-20kdm2.pk3"))
43 device->getFileSystem()->addFileArchive("map-20kdm2.pk3");
44 else
45 device->getFileSystem()->addFileArchive("media/Irrlicht/map-20kdm2.pk3");
46
47 sceneStartTime = device->getTimer()->getTime();
48 timeForThisScene = 0;
49 loadSceneData();
50}
51
52
53void CDemo::preDraw(GLData *gld, u32 now)
54{
55 if (((now - sceneStartTime) > timeForThisScene) && (timeForThisScene != -1))
56 switchToNextScene(gld);
57
58 createParticleImpacts();
59}
60
61
62bool CDemo::OnEvent(const SEvent& event)
63{
64 if (!device)
65 return false;
66
67 if (( ((event.EventType == EET_KEY_INPUT_EVENT) && (event.KeyInput.Key == KEY_SPACE) && (event.KeyInput.PressedDown == false)) ||
68 ((event.EventType == EET_MOUSE_INPUT_EVENT) && (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)) ) && (currentScene == 3))
69 {
70 shoot();
71 }
72 else
73 if (device->getSceneManager()->getActiveCamera())
74 {
75 device->getSceneManager()->getActiveCamera()->OnEvent(event);
76 return true;
77 }
78
79 return false;
80}
81
82
83void CDemo::switchToNextScene(GLData *gld)
84{
85 currentScene++;
86 if (currentScene > 3)
87 currentScene = 1;
88
89 scene::ISceneManager* sm = device->getSceneManager();
90 scene::ISceneNodeAnimator* sa = 0;
91 scene::ICameraSceneNode* camera = 0;
92
93 camera = sm->getActiveCamera();
94
95 switch(currentScene)
96 {
97 case 1: // panorama camera
98 {
99 core::array<core::vector3df> points, points2;
100
101 points.push_back(core::vector3df(-931.473755f, 900.0f, 2000.0f)); // -49873
102 points.push_back(core::vector3df(-931.473755f, 900.0f, 2000.0f)); // -49873
103 points.push_back(core::vector3df(-931.473755f, 700.0f, 1750.0f)); // -49873
104 points.push_back(core::vector3df(-931.473755f, 500.0f, 1500.0f)); // -49873
105 points.push_back(core::vector3df(-931.473755f, 300.0f, 1250.0f)); // -49873
106 points.push_back(core::vector3df(-931.473755f, 200.0f, 1000.0f)); // -49873
107 points.push_back(core::vector3df(-931.473755f, 138.300003f, 987.279114f)); // -49873
108 points.push_back(core::vector3df(-847.902222f, 136.757553f, 915.792725f)); // -50559
109 points.push_back(core::vector3df(-748.680420f, 152.254501f, 826.418945f)); // -51964
110 points.push_back(core::vector3df(-708.428406f, 213.569580f, 784.466675f)); // -53251
111 points.push_back(core::vector3df(-686.217651f, 288.141174f, 762.965576f)); // -54015
112 points.push_back(core::vector3df(-679.685059f, 365.095612f, 756.551453f)); // -54733
113 points.push_back(core::vector3df(-671.317871f, 447.360107f, 749.394592f)); // -55588
114 points.push_back(core::vector3df(-669.468445f, 583.335632f, 747.711853f)); // -56178
115 points.push_back(core::vector3df(-667.611267f, 727.313232f, 746.018250f)); // -56757
116 points.push_back(core::vector3df(-665.853210f, 862.791931f, 744.436096f)); // -57859
117 points.push_back(core::vector3df(-642.649597f, 1026.047607f, 724.259827f)); // -59705
118 points.push_back(core::vector3df(-517.793884f, 838.396790f, 490.326050f)); // -60983
119 points.push_back(core::vector3df(-474.387299f, 715.691467f, 344.639984f)); // -61629
120 points.push_back(core::vector3df(-444.600250f, 601.155701f, 180.938095f)); // -62319
121 points.push_back(core::vector3df(-414.808899f, 479.691406f, 4.866660f)); // -63048
122 points.push_back(core::vector3df(-410.418945f, 429.642242f, -134.332687f)); // -63757
123 points.push_back(core::vector3df(-399.837585f, 411.498383f, -349.350983f)); // -64418
124 points.push_back(core::vector3df(-390.756653f, 403.970093f, -524.454407f)); // -65005
125 points.push_back(core::vector3df(-334.864227f, 350.065491f, -732.397400f)); // -65701
126 points.push_back(core::vector3df(-195.253387f, 349.577209f, -812.475891f)); // -66335
127 points.push_back(core::vector3df(16.255573f, 363.743134f, -833.800415f)); // -67170
128 points.push_back(core::vector3df(234.940964f, 352.957825f, -820.150696f)); // -67939
129 points.push_back(core::vector3df(436.797668f, 349.236450f, -816.914185f)); // -68596
130 points.push_back(core::vector3df(575.236206f, 356.244812f, -719.788513f)); // -69166
131 points.push_back(core::vector3df(594.131042f, 387.173828f, -609.675598f)); // -69744
132 points.push_back(core::vector3df(617.615234f, 412.002899f, -326.174072f)); // -70640
133 points.push_back(core::vector3df(606.456848f, 403.221954f, -104.179291f)); // -71390
134 points.push_back(core::vector3df(610.958252f, 407.037750f, 117.209778f)); // -72085
135 points.push_back(core::vector3df(597.956909f, 395.167877f, 345.942200f)); // -72817
136 points.push_back(core::vector3df(587.383118f, 391.444519f, 566.098633f)); // -73477
137 points.push_back(core::vector3df(559.572449f, 371.991333f, 777.689453f)); // -74124
138 points.push_back(core::vector3df(423.753204f, 329.990051f, 925.859741f)); // -74941
139 points.push_back(core::vector3df(247.520050f, 252.818954f, 935.311829f)); // -75651
140 points.push_back(core::vector3df(114.756012f, 199.799759f, 805.014160f));
141 points.push_back(core::vector3df(96.783348f, 181.639481f, 648.188110f));
142 points.push_back(core::vector3df(97.865623f, 138.905975f, 484.812561f));
143 points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
144 points.push_back(core::vector3df(99.0f, 95.0f, 347.0f));
145 points.push_back(core::vector3df(99.0f, 90.0f, 347.0f));
146 points.push_back(core::vector3df(99.0f, 85.0f, 347.0f));
147 points.push_back(core::vector3df(99.0f, 80.0f, 347.0f));
148 points.push_back(core::vector3df(99.0f, 75.0f, 347.0f));
149 points.push_back(core::vector3df(99.0f, 75.0f, 347.0f));
150 points.push_back(core::vector3df(99.0f, 75.0f, 347.0f));
151 timeForThisScene = (points.size() - 2) * 1000;
152 camera = sm->addCameraSceneNode(0, points[0], core::vector3df(0, 400, 0));
153 sa = sm->createFollowSplineAnimator(device->getTimer()->getTime(), points, 1.0f, 0.6f, false, false);
154 camera->addAnimator(sa);
155 sa->drop();
156 }
157 break;
158
159 case 2: // panorama camera
160 {
161 core::array<core::vector3df> points;
162
163 camera->setTarget(core::vector3df(100, 145, -80));
164
165 points.push_back(core::vector3df(99.0f, 75.0f, 347.0f));
166 points.push_back(core::vector3df(100.0f, 75.0f, 347.0f));
167 points.push_back(core::vector3df(105.0f, 75.0f, 347.0f));
168 points.push_back(core::vector3df(110.0f, 70.0f, 347.0f));
169 points.push_back(core::vector3df(115.0f, 70.0f, -160.0f));
170 points.push_back(core::vector3df(120.0f, 70.0f, -160.0f));
171 points.push_back(core::vector3df(125.0f, 65.0f, -160.0f));
172 points.push_back(core::vector3df(130.0f, 65.0f, -160.0f));
173 points.push_back(core::vector3df(135.0f, 65.0f, -160.0f));
174 points.push_back(core::vector3df(150.0f, 170.0f, -160.0f));
175 points.push_back(core::vector3df(150.0f, 170.0f, -160.0f));
176 points.push_back(core::vector3df(150.0f, 170.0f, -160.0f));
177 timeForThisScene = (points.size() - 2) * 1000;
178 sa = sm->createFollowSplineAnimator(device->getTimer()->getTime(), points, 1.0f, 0.6f, false, false);
179 camera->addAnimator(sa);
180 sa->drop();
181 }
182 break;
183
184 case 3: // interactive, go around
185 {
186 if (camera)
187 {
188 sm->setActiveCamera(0);
189 camera->remove();
190 camera = 0;
191 }
192 timeForThisScene = -1;
193
194 gld->camera = addExtantzCamera(sm, NULL, -1);
195 camera = gld->camera;
196 camera->setPosition(core::vector3df(108, 140, -140));
197 camera->setFarValue(5000.0f);
198 gld->move = getCameraMove(gld->camera);
199
200 scene::ISceneNodeAnimatorCollisionResponse* collider =
201 sm->createCollisionResponseAnimator(metaSelector, camera, core::vector3df(25, 50, 25), core::vector3df(0, quakeLevelMesh ? -10.f : 0.0f, 0), core::vector3df(0, 45, 0), 0.005f);
202 camera->addAnimator(collider);
203 collider->drop();
204 }
205 break;
206 }
207
208 sceneStartTime = device->getTimer()->getTime();
209}
210
211
212void CDemo::loadSceneData()
213{
214 // load quake level
215
216 video::IVideoDriver* driver = device->getVideoDriver();
217 scene::ISceneManager* sm = device->getSceneManager();
218
219 // Quake3 Shader controls Z-Writing
220 sm->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
221
222 quakeLevelMesh = (scene::IQ3LevelMesh*) sm->getMesh("maps/20kdm2.bsp");
223
224 if (quakeLevelMesh)
225 {
226 u32 i;
227
228 //move all quake level meshes (non-realtime)
229 core::matrix4 m;
230 m.setTranslation(core::vector3df(-1300,-70,-1249));
231
232 for (i = 0; i != scene::quake3::E_Q3_MESH_SIZE; ++i)
233 sm->getMeshManipulator()->transform(quakeLevelMesh->getMesh(i), m);
234
235 quakeLevelNode = sm->addOctreeSceneNode(quakeLevelMesh->getMesh( scene::quake3::E_Q3_MESH_GEOMETRY));
236 if (quakeLevelNode)
237 {
238 //quakeLevelNode->setPosition(core::vector3df(-1300, -70, -1249));
239 quakeLevelNode->setVisible(true);
240
241 // create map triangle selector
242 mapSelector = sm->createOctreeTriangleSelector(quakeLevelMesh->getMesh(0), quakeLevelNode, 128);
243
244 // if not using shader and no gamma it's better to use more lighting, because
245 // quake3 level are usually dark
246 quakeLevelNode->setMaterialType(video::EMT_LIGHTMAP_M4);
247
248 // set additive blending if wanted
249 if (additive)
250 quakeLevelNode->setMaterialType(video::EMT_LIGHTMAP_ADD);
251 }
252
253 // the additional mesh can be quite huge and is unoptimized
254 scene::IMesh *additional_mesh = quakeLevelMesh->getMesh(scene::quake3::E_Q3_MESH_ITEMS);
255
256 for (i = 0; i != additional_mesh->getMeshBufferCount(); ++i)
257 {
258 scene::IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer(i);
259 const video::SMaterial &material = meshBuffer->getMaterial();
260
261 //! The ShaderIndex is stored in the material parameter
262 s32 shaderIndex = (s32) material.MaterialTypeParam2;
263
264 // the meshbuffer can be rendered without additional support, or it has no shader
265 const scene::quake3::IShader *shader = quakeLevelMesh->getShader(shaderIndex);
266 if (0 == shader)
267 {
268 continue;
269 }
270 // Now add the MeshBuffer(s) with the current Shader to the Manager
271 sm->addQuake3SceneNode(meshBuffer, shader);
272 }
273 }
274
275 // load sydney model and create 2 instances
276
277 scene::IAnimatedMesh *mesh = 0;
278 mesh = sm->getMesh("media/Irrlicht/sydney.md2");
279 if (mesh)
280 {
281 model1 = sm->addAnimatedMeshSceneNode(mesh);
282 if (model1)
283 {
284 model1->setMaterialTexture(0, driver->getTexture("media/Irrlicht/sydney.bmp"));
285 model1->setPosition(core::vector3df(100, 40, -80));
286 model1->setScale(core::vector3df(2, 2, 2));
287 model1->setMD2Animation(scene::EMAT_STAND);
288 model1->setMaterialFlag(video::EMF_LIGHTING, true);
289 model1->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
290 model1->addShadowVolumeSceneNode();
291 }
292
293 model2 = sm->addAnimatedMeshSceneNode(mesh);
294 if (model2)
295 {
296 model2->setMaterialTexture(0, driver->getTexture("media/Irrlicht/spheremap.jpg"));
297 model2->setPosition(core::vector3df(180, 15, -60));
298 model2->setScale(core::vector3df(2, 2, 2));
299 model2->setMD2Animation(scene::EMAT_RUN);
300 model2->setMaterialFlag(video::EMF_LIGHTING, false);
301 model2->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
302 model2->setMaterialType(video::EMT_SPHERE_MAP);
303 model2->addShadowVolumeSceneNode();
304 }
305 }
306
307 scene::ISceneNodeAnimator *anim = 0;
308
309 // create sky box
310 driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
311 skyboxNode = sm->addSkyBoxSceneNode(
312 driver->getTexture("media/Irrlicht/irrlicht2_up.jpg"),
313 driver->getTexture("media/Irrlicht/irrlicht2_dn.jpg"),
314 driver->getTexture("media/Irrlicht/irrlicht2_lf.jpg"),
315 driver->getTexture("media/Irrlicht/irrlicht2_rt.jpg"),
316 driver->getTexture("media/Irrlicht/irrlicht2_ft.jpg"),
317 driver->getTexture("media/Irrlicht/irrlicht2_bk.jpg"));
318 driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
319
320 // create walk-between-portals animation
321 core::vector3df waypoint[2];
322 waypoint[0].set(-150, 40, 100);
323 waypoint[1].set(350, 40, 100);
324
325 if (model2)
326 {
327 anim = device->getSceneManager()->createFlyStraightAnimator(waypoint[0], waypoint[1], 2000, true);
328 model2->addAnimator(anim);
329 anim->drop();
330 }
331
332 // create animation for portals;
333 core::array<video::ITexture*> textures;
334 for (s32 g=1; g<8; ++g)
335 {
336 core::stringc tmp("media/Irrlicht/portal");
337 tmp += g;
338 tmp += ".bmp";
339 video::ITexture* t = driver->getTexture(tmp);
340 textures.push_back(t);
341 }
342
343 anim = sm->createTextureAnimator(textures, 100);
344
345 // create portals
346 scene::IBillboardSceneNode* bill = 0;
347 for (int r = 0; r < 2; ++r)
348 {
349 bill = sm->addBillboardSceneNode(0, core::dimension2d<f32>(100, 100), waypoint[r]+ core::vector3df(0, 20, 0));
350 bill->setMaterialFlag(video::EMF_LIGHTING, false);
351 bill->setMaterialTexture(0, driver->getTexture("media/Irrlicht/portal1.bmp"));
352 bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
353 bill->addAnimator(anim);
354 }
355
356 anim->drop();
357
358 // create circle flying dynamic light with transparent billboard attached
359 scene::ILightSceneNode *light = 0;
360
361 light = sm->addLightSceneNode(0, core::vector3df(0, 0, 0), video::SColorf(1.0f, 1.0f, 1.f, 1.0f), 500.f);
362 anim = sm->createFlyCircleAnimator(core::vector3df(100, 150, 80), 80.0f, 0.0005f);
363
364 light->addAnimator(anim);
365 anim->drop();
366
367 bill = device->getSceneManager()->addBillboardSceneNode(light, core::dimension2d<f32>(40, 40));
368 bill->setMaterialFlag(video::EMF_LIGHTING, false);
369 bill->setMaterialTexture(0, driver->getTexture("media/Irrlicht/particlewhite.bmp"));
370 bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
371
372 // create meta triangle selector with all triangles selectors in it.
373 metaSelector = sm->createMetaTriangleSelector();
374 metaSelector->addTriangleSelector(mapSelector);
375
376 // create camp fire
377 campFire = sm->addParticleSystemSceneNode(false);
378 campFire->setPosition(core::vector3df(100, 120, 600));
379 campFire->setScale(core::vector3df(2, 2, 2));
380
381 scene::IParticleEmitter *em = campFire->createBoxEmitter(core::aabbox3d<f32>(-7, 0, -7, 7, 1, 7), core::vector3df(0.0f, 0.06f, 0.0f), 80, 100, video::SColor(1, 255, 255, 255), video::SColor(1, 255, 255, 255), 800, 2000);
382 em->setMinStartSize(core::dimension2d<f32>(20.0f, 10.0f));
383 em->setMaxStartSize(core::dimension2d<f32>(20.0f, 10.0f));
384 campFire->setEmitter(em);
385 em->drop();
386
387 scene::IParticleAffector *paf = campFire->createFadeOutParticleAffector();
388 campFire->addAffector(paf);
389 paf->drop();
390
391 campFire->setMaterialFlag(video::EMF_LIGHTING, false);
392 campFire->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
393 campFire->setMaterialTexture(0, driver->getTexture("media/Irrlicht/fireball.bmp"));
394 campFire->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
395}
396
397
398void CDemo::shoot()
399{
400 scene::ISceneManager *sm = device->getSceneManager();
401 scene::ICameraSceneNode *camera = sm->getActiveCamera();
402
403 if ((!camera) || (!mapSelector))
404 return;
405
406 SParticleImpact imp;
407 imp.when = 0;
408
409 // get line of camera
410 core::vector3df start = camera->getPosition();
411 core::vector3df end = (camera->getTarget() - start);
412 end.normalize();
413 start += end * 8.0f;
414 end = start + (end * camera->getFarValue());
415
416 core::triangle3df triangle;
417
418 core::line3d<f32> line(start, end);
419
420 // get intersection point with map
421 scene::ISceneNode* hitNode;
422 if (sm->getSceneCollisionManager()->getCollisionPoint(line, mapSelector, end, triangle, hitNode))
423 {
424 // collides with wall
425 core::vector3df out = triangle.getNormal();
426 out.setLength(0.03f);
427
428 imp.when = 1;
429 imp.outVector = out;
430 imp.pos = end;
431 }
432 else
433 {
434 // doesnt collide with wall
435 core::vector3df start = camera->getPosition();
436 core::vector3df end = (camera->getTarget() - start);
437 end.normalize();
438 start += end * 8.0f;
439 end = start + (end * camera->getFarValue());
440 }
441
442 // create fire ball
443 scene::ISceneNode *node = 0;
444 node = sm->addBillboardSceneNode(0, core::dimension2d<f32>(25, 25), start);
445
446 node->setMaterialFlag(video::EMF_LIGHTING, false);
447 node->setMaterialTexture(0, device->getVideoDriver()->getTexture("media/Irrlicht/fireball.bmp"));
448 node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
449
450 f32 length = (f32)(end - start).getLength();
451 const f32 speed = 0.6f;
452 u32 time = (u32) (length / speed);
453
454 scene::ISceneNodeAnimator *anim = 0;
455
456 // set flight line
457 anim = sm->createFlyStraightAnimator(start, end, time);
458 node->addAnimator(anim);
459 anim->drop();
460
461 anim = sm->createDeleteAnimator(time);
462 node->addAnimator(anim);
463 anim->drop();
464
465 if (imp.when)
466 {
467 // create impact note
468 imp.when = device->getTimer()->getTime() + (time - 100);
469 Impacts.push_back(imp);
470 }
471}
472
473
474void CDemo::createParticleImpacts()
475{
476 u32 now = device->getTimer()->getTime();
477 scene::ISceneManager *sm = device->getSceneManager();
478
479 for (s32 i = 0; i < (s32) Impacts.size(); ++i)
480 if (now > Impacts[i].when)
481 {
482 // create smoke particle system
483 scene::IParticleSystemSceneNode *pas = 0;
484
485 pas = sm->addParticleSystemSceneNode(false, 0, -1, Impacts[i].pos);
486
487 pas->setParticleSize(core::dimension2d<f32>(10.0f, 10.0f));
488
489 scene::IParticleEmitter* em = pas->createBoxEmitter(core::aabbox3d<f32>(-5, -5, -5, 5, 5, 5), Impacts[i].outVector, 20, 40, video::SColor(50, 255, 255, 255), video::SColor(50, 255, 255, 255), 1200, 1600, 20);
490 pas->setEmitter(em);
491 em->drop();
492
493 scene::IParticleAffector *paf = campFire->createFadeOutParticleAffector();
494 pas->addAffector(paf);
495 paf->drop();
496
497 pas->setMaterialFlag(video::EMF_LIGHTING, false);
498 pas->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
499 pas->setMaterialTexture(0, device->getVideoDriver()->getTexture("media/Irrlicht/smoke.bmp"));
500 pas->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
501
502 scene::ISceneNodeAnimator *anim = sm->createDeleteAnimator(2000);
503 pas->addAnimator(anim);
504 anim->drop();
505
506 // delete entry
507 Impacts.erase(i);
508 i--;
509 }
510}
diff --git a/ClientHamr/extantz/CDemo.h b/ClientHamr/extantz/CDemo.h
deleted file mode 100644
index 035c01f..0000000
--- a/ClientHamr/extantz/CDemo.h
+++ /dev/null
@@ -1,63 +0,0 @@
1// This is a Demo of the Irrlicht Engine (c) 2006 by N.Gebhardt.
2// This file is not documented.
3
4#ifndef __C_DEMO_H_INCLUDED__
5#define __C_DEMO_H_INCLUDED__
6
7#ifdef _IRR_WINDOWS_
8#include <windows.h>
9#endif
10
11const int CAMERA_COUNT = 7;
12
13class CDemo : public IEventReceiver
14{
15public:
16
17 CDemo(GLData *gld, bool additive);
18
19 ~CDemo();
20
21 void setup(GLData *gld);
22 void preDraw(GLData *gld, u32 now);
23
24 virtual bool OnEvent(const SEvent& event);
25
26private:
27
28 void createLoadingScreen();
29 void loadSceneData();
30 void switchToNextScene(GLData *gld);
31 void shoot();
32 void createParticleImpacts();
33
34 bool additive;
35 IrrlichtDevice *device;
36
37 struct SParticleImpact
38 {
39 u32 when;
40 core::vector3df pos;
41 core::vector3df outVector;
42 };
43
44 int currentScene;
45
46 scene::IQ3LevelMesh* quakeLevelMesh;
47 scene::ISceneNode* quakeLevelNode;
48 scene::ISceneNode* skyboxNode;
49 scene::IAnimatedMeshSceneNode* model1;
50 scene::IAnimatedMeshSceneNode* model2;
51 scene::IParticleSystemSceneNode* campFire;
52
53 scene::IMetaTriangleSelector* metaSelector;
54 scene::ITriangleSelector* mapSelector;
55
56 s32 sceneStartTime;
57 s32 timeForThisScene;
58
59 core::array<SParticleImpact> Impacts;
60};
61
62#endif
63
diff --git a/ClientHamr/extantz/build.lua b/ClientHamr/extantz/build.lua
deleted file mode 100755
index 0bb2a0b..0000000
--- a/ClientHamr/extantz/build.lua
+++ /dev/null
@@ -1,26 +0,0 @@
1#!/usr/bin/env lua
2
3local dir = ...
4
5if 'nil' == type(dir) then
6 local build, err = loadfile('../../build.lua')
7 if build then
8 setfenv(build, getfenv(2))
9 build(2)
10 else
11 print("ERROR - " .. err)
12 end
13 dir = workingDir
14end
15
16CFLAGS = CFLAGS .. ' -I../../libraries/irrlicht-1.8.1/include -I/usr/X11R6/include'
17LDFLAGS = LDFLAGS .. ' -L../../libraries/irrlicht-1.8.1/lib/Linux'
18libs = libs .. ' -lIrrlicht -lGL -lbz2'
19
20removeFiles(dir, {'../../extantz', 'crappisspuke.o', 'CDemo.o', 'extantzCamera.o', '../../media/extantz.edj'})
21
22runCommand('edje_cc', dir, 'edje_cc ' .. EDJE_FLAGS .. ' extantz.edc ../../media/extantz.edj')
23runCommand('Irrlicht files', dir, 'g++ ' .. CFLAGS .. ' -O3 -ffast-math -c crappisspuke.cpp -o crappisspuke.o ' .. LDFLAGS)
24runCommand(nil, dir, 'g++ ' .. CFLAGS .. ' -O3 -ffast-math -c CDemo.cpp -o CDemo.o ' .. LDFLAGS)
25runCommand('extantz', dir, 'g++ ' .. CFLAGS .. ' -O3 -ffast-math -c extantzCamera.cpp -o extantzCamera.o ' .. LDFLAGS)
26runCommand(nil, dir, 'gcc ' .. CFLAGS .. ' extantz.c crappisspuke.o CDemo.o extantzCamera.o -o ../../extantz ' .. LDFLAGS .. ' ' .. libs)
diff --git a/ClientHamr/extantz/crappisspuke.cpp b/ClientHamr/extantz/crappisspuke.cpp
deleted file mode 100644
index 2af9dde..0000000
--- a/ClientHamr/extantz/crappisspuke.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
1
2#include <irrlicht.h>
3#include "extantz.h"
4#include "CDemo.h"
5
6
7SExposedVideoData videoData;
8
9IAnimatedMeshSceneNode *node;
10CDemo *myDemo;
11// This is the movement speed in units per second.
12const f32 MOVEMENT_SPEED = 5.f;
13// In order to do framerate independent movement, we have to know
14// how long it was since the last frame
15u32 then;
16
17#ifdef __cplusplus
18extern "C" {
19#endif
20
21EAPI int startIrr(GLData *gld)
22{
23 SIrrlichtCreationParameters params;
24 IrrlichtDevice *device;
25 IVideoDriver *driver;
26 ISceneManager *smgr;
27 bool additive = true;
28
29 if (!gld->useIrr)
30 return 1; // Return 1 so that the caller stops asking on each frame.
31
32#if USE_IRR
33 void *display = NULL;
34 unsigned long sfc = 0;
35 void *ctx = NULL;
36// Evas_GL_API *gl = gld->glApi;
37
38#if USE_DEMO
39 myDemo = new CDemo(gld, additive);
40#endif
41
42/* Raster says -
434. evas exposes an opengl-es2 api. any existing engine needs to be adapted to
44use this. that's pretty much the end of that. if the engine doesn't have a
45gles2 port.. it will need one. once it has one, then it is a simple matter of
46replacing all the gl calls as follows:
47
48glDrawArrays() -> api->glDrawArrays()
49glBindBuffer() -> api->glBindBuffer()
50
51you could make the port switchable with a macro:
52
53#ifdef EVASGL
54#define EG() my_evas_gl_api->
55#else
56#define EG()
57#endif
58
59then fix up all the gl calls to be
60
61EG()glDrawArrays()
62EG()glBindBuffer()
63
64etc.
65
66doing the above allows evas to decide how to share context. it may allocate a
67separate context or share its own. either way as far as the evasgl api user is
68concerned.. they get their own private context to play with. if it does NOT do
69the above (use the api exposed by evas gl) then wrapping can't context switches
70can't work. all gl calls HAVE to go through the wrapped api to work right. this
71is because we can't REPLACE the internals of the gl driver which otherwise
72would be managing context and state all internally and we have zero access to
73that - especially with closed drivers. we'd end up writing a proxy gl library
74which conflicts with real gl symbol-wise (thus taking over and replacing
75normal gl calls) and i know i have no interest in maintaining a separate
76libGLwhatever.so that is an exact copy of gl and it's api's just to wrap it
77when we expose that wrapper without symbol complications via evas gl.
78
795. the engine will need to be adapted so the draw function is callable - eg by
80elm_glview. then it's easy to switch where rendering happens. evas offers a fast
81path to avoid buffer copies and make the gl view draw part of the evas
82rendering path directly. this would offer almost zero overhead vs doing it
83directly with egl/gles etc. to your backbuffer yourself, BUT gets you the bonus
84of having your 3d view as part of a larger scenegraph. combine 2 or 3 of them
85in a single window. overlay with evas objects or elm widgets for hud etc. all
86for free. this also implies the engine has to integrate to the efl mainloop
87etc. of course.
88*/
89
90
91 sfc = ecore_evas_window_get(gld->ee);
92 // This is the way Raster wants me to do things, but these functions are not actually available. Pffft
93// ctx = gl->glGetCurrentContext();
94// display = gl->glGetCurrentDisplay();
95 ctx = glXGetCurrentContext();
96 display = glXGetCurrentDisplay();
97 /* For using a pre existing X11 window (with optional OpenGL). */
98 videoData = SExposedVideoData();
99 videoData.OpenGLLinux.X11Display = display; // void * - Connection to the X server.
100 videoData.OpenGLLinux.X11Window = sfc; // unsigned long - Specifies a GLX drawable. Must be either an X window ID or a GLX pixmap ID.
101 videoData.OpenGLLinux.X11Context = ctx; // void * - Specifies a GLX rendering context that is to be attached to drawable.
102
103 /*
104 The most important function of the engine is the createDevice()
105 function. The IrrlichtDevice is created by it, which is the root
106 object for doing anything with the engine. createDevice() has 7
107 parameters:
108
109 - deviceType: Type of the device. This can currently be the Null-device,
110 one of the two software renderers, D3D8, D3D9, or OpenGL. In this
111 example we use EDT_SOFTWARE, but to try out, you might want to
112 change it to EDT_BURNINGSVIDEO, EDT_NULL, EDT_DIRECT3D8,
113 EDT_DIRECT3D9, or EDT_OPENGL.
114
115 - windowSize: Size of the Window or screen in FullScreenMode to be
116 created. In this example we use 640x480.
117
118 - bits: Amount of color bits per pixel. This should be 16 or 32. The
119 parameter is often ignored when running in windowed mode.
120
121 - fullscreen: Specifies if we want the device to run in fullscreen mode
122 or not.
123
124 - stencilbuffer: Specifies if we want to use the stencil buffer (for
125 drawing shadows).
126
127 - vsync: Specifies if we want to have vsync enabled, this is only useful
128 in fullscreen mode.
129
130 - eventReceiver: An object to receive events. We do not want to use this
131 parameter here, and set it to 0.
132
133 Always check the return value to cope with unsupported drivers,
134 dimensions, etc.
135 */
136
137 params.DeviceType = EIDT_X11; // EIDT_BEST might be preferable.
138 if (ctx)
139 params.DriverType = video::EDT_OPENGL;
140 else
141 params.DriverType = video::EDT_BURNINGSVIDEO;
142 params.WindowSize = dimension2d<u32>(gld->sfc_w, gld->sfc_h);
143 params.Bits = 32; // Ignored in windowed mode?
144 params.ZBufferBits = 16; // Default 16.
145 params.Fullscreen = false; // The default anyway.
146 params.Stencilbuffer = false; // For shadows.
147 params.Vsync = false;
148 params.AntiAlias=true;
149 params.WithAlphaChannel = true;
150 params.IgnoreInput = true;
151 params.EventReceiver = myDemo; // Probably useless, EFL might not let Irrlicht grab the input.
152 params.WindowId = (void *) videoData.OpenGLLinux.X11Window;
153 params.VideoData = &videoData;
154
155 device = createDeviceEx(params);
156
157 if (!device)
158 return 0;
159 gld->device = device;
160
161 /*
162 Get a pointer to the VideoDriver and the SceneManager so that we do not always have to write
163 device->getVideoDriver() or device->getSceneManager().
164 */
165 driver = device->getVideoDriver(); gld->driver = driver;
166 smgr = device->getSceneManager(); gld->smgr = smgr;
167
168 // FIXME - this is what makes the window vanish in EFL 1.8, but worked fine in 1.7 I think.
169// device->setResizable(true);
170 driver->OnResize(dimension2d<u32>(gld->img_w, gld->img_h));
171 // Just gives me a blank screen. grrrr
172// driver->setViewPort(rect<s32>(0, 0, gld->img_w, gld->img_h));
173
174 // set ambient light
175 smgr->setAmbientLight (video::SColorf(0x00c0c0c0));
176
177#if USE_DEMO
178 myDemo->setup(gld);
179#else
180 /*
181 To show something interesting, we load a Quake 2 model and display it.
182 We only have to get the Mesh from the Scene Manager with getMesh() and add
183 a SceneNode to display the mesh with addAnimatedMeshSceneNode(). We
184 check the return value of getMesh() to become aware of loading problems
185 and other errors.
186
187 Instead of writing the filename sydney.md2, it would also be possible
188 to load a Maya object file (.obj), a complete Quake3 map (.bsp) or any
189 other supported file format. By the way, that cool Quake 2 model
190 called sydney was modelled by Brian Collins.
191 */
192 IAnimatedMesh* mesh = smgr->getMesh("media/Irrlicht/sydney.md2");
193 if (!mesh)
194 {
195 device->drop();
196 return 0;
197 }
198 node = smgr->addAnimatedMeshSceneNode(mesh);
199
200 /*
201 To let the mesh look a little bit nicer, we change its material. We
202 disable lighting because we do not have a dynamic light in here, and
203 the mesh would be totally black otherwise. Then we set the frame loop,
204 such that the predefined STAND animation is used. And last, we apply a
205 texture to the mesh. Without it the mesh would be drawn using only a
206 color.
207 */
208 if (node)
209 {
210// node->setMaterialFlag(EMF_LIGHTING, false);
211 node->setMD2Animation(scene::EMAT_STAND);
212 node->setMaterialTexture(0, driver->getTexture("media/Irrlicht/sydney.bmp"));
213 }
214
215 /*
216 To look at the mesh, we place a camera into 3d space at the position
217 (0, 30, -40). The camera looks from there to (0,5,0), which is
218 approximately the place where our md2 model is.
219 */
220 smgr->addCameraSceneNode(0, vector3df(50, 70, -65), vector3df(0, 50, 0));
221#endif
222
223 then = device->getTimer()->getTime();
224#endif
225 return 1;
226}
227
228EAPI void drawIrr_start(GLData *gld)
229{
230 if (gld->useIrr)
231 {
232 IrrlichtDevice *device = gld->device;
233 IVideoDriver *driver = gld->driver;
234 ISceneManager *smgr = gld->smgr;
235
236 // Increase virtual timer time, instead of device->run() if doing our own input processing.
237 device->getTimer()->tick();
238
239 // Work out a frame delta time.
240 const u32 now = device->getTimer()->getTime();
241// const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
242 then = now;
243
244
245#if USE_DEMO
246 myDemo->preDraw(gld, now);
247#else
248 core::vector3df nodePosition = node->getPosition();
249// nodePosition.Y -= MOVEMENT_SPEED * frameDeltaTime;
250 node->setPosition(nodePosition);
251#endif
252
253 /*
254 Anything can be drawn between a beginScene() and an endScene()
255 call. The beginScene() call clears the screen with a color and
256 the depth buffer, if desired. Then we let the Scene Manager and
257 the GUI Environment draw their content. With the endScene()
258 call everything is presented on the screen.
259 */
260 driver->beginScene(true, true, SColor(255, 255, 255, 255), videoData, NULL); // This does the context change, then clearBuffers()
261
262 smgr->drawAll();
263 }
264}
265
266EAPI void drawIrr_end(GLData *gld)
267{
268 IVideoDriver *driver = gld->driver;
269
270 if (gld->useIrr)
271 driver->endScene();
272}
273
274EAPI void finishIrr(GLData *gld)
275{
276 IrrlichtDevice *device = gld->device;
277
278 /*
279 After we are done with the render loop, we have to delete the Irrlicht
280 Device created before with createDevice(). In the Irrlicht Engine, you
281 have to delete all objects you created with a method or function which
282 starts with 'create'. The object is simply deleted by calling ->drop().
283 See the documentation at irr::IReferenceCounted::drop() for more
284 information.
285 */
286 if (gld->useIrr)
287 device->drop();
288}
289
290
291#ifdef __cplusplus
292}
293#endif
294
diff --git a/ClientHamr/extantz/extantz.c b/ClientHamr/extantz/extantz.c
deleted file mode 100644
index 09b5196..0000000
--- a/ClientHamr/extantz/extantz.c
+++ /dev/null
@@ -1,1588 +0,0 @@
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()
diff --git a/ClientHamr/extantz/extantz.edc b/ClientHamr/extantz/extantz.edc
deleted file mode 100644
index b4ed0b3..0000000
--- a/ClientHamr/extantz/extantz.edc
+++ /dev/null
@@ -1,30 +0,0 @@
1externals {
2 external: "elm";
3}
4
5collections {
6#define ADD_CUBE(_group, _file) \
7 images { \
8 image: #_file##".png" COMP; \
9 } \
10 group { \
11 name: #_group; \
12 parts { \
13 part { \
14 name: "cube"; \
15 type: IMAGE; \
16 mouse_events: 1; \
17 repeat_events: 0; \
18 description { \
19 state: "default" 0.0; \
20 image.normal: #_file##".png"; \
21 } \
22 } \
23 } \
24 }
25
26ADD_CUBE(blue-cube, cube-blue);
27ADD_CUBE(purple-cube, cube-purple);
28
29#undef ADD_CUBE
30}
diff --git a/ClientHamr/extantz/extantz.h b/ClientHamr/extantz/extantz.h
deleted file mode 100644
index afb94af..0000000
--- a/ClientHamr/extantz/extantz.h
+++ /dev/null
@@ -1,215 +0,0 @@
1#define USE_EO 0
2#define USE_PHYSICS 1
3#define USE_EGL 1 // If using Evas_GL, though it might be via Elm.
4#define USE_ELM_GL 1
5#define USE_IRR 1
6#define USE_DEMO 1
7#define DO_GEARS 0
8
9#if USE_EO
10 /* Enable access to unstable EFL API that are still in beta */
11 #define EFL_BETA_API_SUPPORT 1
12 /* Enable access to unstable EFL EO API. */
13 #define EFL_EO_API_SUPPORT 1
14#endif
15
16#include <Elementary.h>
17#include <elm_widget_glview.h>
18#include <Evas_GL.h>
19#include <EPhysics.h>
20#include "extantzCamera.h"
21
22
23#ifdef GL_GLES
24#include <EGL/egl.h>
25#include <EGL/eglext.h>
26#else
27# include <GL/glext.h>
28# include <GL/glx.h>
29#endif
30
31
32#ifdef __cplusplus
33/*
34In the Irrlicht Engine, everything can be found in the namespace 'irr'. So if
35you want to use a class of the engine, you have to write irr:: before the name
36of the class. For example to use the IrrlichtDevice write: irr::IrrlichtDevice.
37To get rid of the irr:: in front of the name of every class, we tell the
38compiler that we use that namespace from now on, and we will not have to write
39irr:: anymore.
40*/
41using namespace irr;
42
43/*
44There are 5 sub namespaces in the Irrlicht Engine. Take a look at them, you can
45read a detailed description of them in the documentation by clicking on the top
46menu item 'Namespace List' or by using this link:
47http://irrlicht.sourceforge.net/docu/namespaces.html
48Like the irr namespace, we do not want these 5 sub namespaces now, to keep this
49example simple. Hence, we tell the compiler again that we do not want always to
50write their names.
51*/
52using namespace core;
53using namespace scene;
54using namespace video;
55
56extern "C"{
57#else
58
59// Irrlicht stuff. It's C++, so we gotta use incomplete types.
60typedef struct IrrlichtDevice IrrlichtDevice;
61typedef struct IVideoDriver IVideoDriver;
62typedef struct ISceneManager ISceneManager;
63typedef struct ICameraSceneNode ICameraSceneNode;
64
65#endif
66
67
68#define CRI(...) EINA_LOG_DOM_CRIT(_log_domain, _VA_ARGS__)
69#define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
70#define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
71#define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
72#define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
73
74extern int _log_domain;
75
76
77typedef struct _Gear Gear;
78typedef struct _GLData GLData;
79
80typedef enum
81{
82 EZP_NONE,
83 EZP_AURORA,
84 EZP_OPENSIM,
85 EZP_SECOND_LIFE,
86 EZP_SLEDJHAMR,
87 EZP_TRITIUM
88} ezPlatform;
89
90typedef struct
91{
92 char *name;
93 char *version; // Version string.
94 char *path; // OS filesystem path to the viewer install.
95 char *icon;
96 uint16_t tag; // The UUID of the texture used in the avatar bake hack.
97 uint8_t r, g, b; // Colour used for the in world tag.
98 Elm_Object_Item *item;
99} ezViewer;
100
101typedef struct
102{
103 Eina_Clist accounts;
104 Eina_Clist landmarks;
105 char *name;
106 char *loginURI;
107 char *splashPage;
108 char *helperURI;
109 char *website;
110 char *supportPage;
111 char *registerPage;
112 char *passwordPage;
113 char *icon;
114 ezPlatform platform;
115 ezViewer *viewer;
116 Elm_Object_Item *item;
117GLData *gld; // Just a temporary evil hack to pass gld to _grid_sel_cb().
118} ezGrid;
119
120typedef struct
121{
122 Eina_Clist grid;
123 char *name;
124 char *password; // Think we need to pass unencrypted passwords to the viewer. B-(
125 char *icon;
126 ezViewer *viewer;
127} ezAccount;
128
129typedef struct
130{
131 Eina_Clist grid;
132 char *name;
133 char *sim;
134 char *screenshot;
135 short x, y, z;
136} ezLandmark;
137
138
139
140struct _Gear
141{
142 GLfloat *vertices;
143 GLuint vbo;
144 int count;
145};
146
147// GL related data here.
148struct _GLData
149{
150 Evas_Object *win, *winwin;
151
152 Ecore_Evas *ee;
153 Evas *canvas;
154 Evas_Native_Surface ns;
155
156 Evas_GL_Context *ctx;
157 Evas_GL_Surface *sfc;
158 Evas_GL_Config *cfg;
159 Evas_GL *evasGl; // The Evas way.
160 Evas_Object *elmGl; // The Elm way.
161 Evas_GL_API *glApi;
162
163 GLuint program;
164 GLuint vtx_shader;
165 GLuint fgmt_shader;
166 int scr_w, scr_h; // The size of the screen.
167 int win_w, win_h; // The size of the window.
168 int win_x, win_y; // The position of the window.
169 int sfc_w, sfc_h; // This is what Irrlicht is using, size of the GL image surface / glview.
170 int img_w, img_h; // Size of the viewport. DON'T reuse sfc_* here. Despite the fach that sfc_* is only used in the init when Irricht is disabled? WTF?
171 int useEGL : 1;
172 int useIrr : 1;
173 int doneIrr : 1;
174 int gearsInited : 1;
175 int resized : 1;
176
177 Evas_Object *bx, *r1;
178 Ecore_Animator *animator;
179
180 IrrlichtDevice *device;
181 IVideoDriver *driver;
182 ISceneManager *smgr;
183 ICameraSceneNode *camera;
184
185 cameraMove *move;
186
187 // Gear Stuff
188 GLfloat view_rotx;
189 GLfloat view_roty;
190 GLfloat view_rotz;
191
192 Gear *gear1;
193 Gear *gear2;
194 Gear *gear3;
195
196 GLfloat angle;
197
198 GLuint proj_location;
199 GLuint light_location;
200 GLuint color_location;
201
202 GLfloat proj[16];
203 GLfloat light[3];
204};
205
206
207EAPI int startIrr(GLData *gld);
208EAPI void drawIrr_start(GLData *gld);
209EAPI void drawIrr_end(GLData *gld);
210EAPI void finishIrr(GLData *gld);
211
212#ifdef __cplusplus
213}
214#endif
215
diff --git a/ClientHamr/extantz/extantzCamera.cpp b/ClientHamr/extantz/extantzCamera.cpp
deleted file mode 100644
index 6a7d36a..0000000
--- a/ClientHamr/extantz/extantzCamera.cpp
+++ /dev/null
@@ -1,282 +0,0 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5// The above is the copyright notice for CSceneNodeAnimatorCameraFPS.cpp,
6// According to the Irrlicht docs, that's just a demo and you are supposed to use it as an example for writing your own FPS style camera.
7// I'll be writing my own camera code, that includes first person, third person, and free camera styles.
8// I'll start with CSceneNodeAnimatorCameraFPS.cpp and morph it until it suits me.
9// As such, I expect lots of Nikolaus Gebhardt's code to go away.
10// To be replaced by my code, which will be copyright and licensed under the same license as the rest of extantz.
11
12// Initally I'll make it SecondLife like, coz that's what my muscle memory is used to.
13// It will get extended and made generic though.
14
15#include "extantzCamera.h"
16#include "IVideoDriver.h"
17#include "ISceneManager.h"
18#include "Keycodes.h"
19#include "ICursorControl.h"
20#include "ICameraSceneNode.h"
21#include "ISceneNodeAnimatorCollisionResponse.h"
22
23namespace irr
24{
25namespace scene
26{
27
28// Irrlicht hard codes a reference to the original FPS camera code inside it's scene manager. This is that code extracted so we can be more flexible.
29// TODO - Hmmm, Where's CursorControl come from? Ah, passed to the scene manager constructor, it's a GUI thing that we need to replace with an EFL thing. But only for mouselook mode.
30ICameraSceneNode *addExtantzCamera(ISceneManager* sm, ISceneNode* parent, s32 id)
31{
32 ICameraSceneNode* node = sm->addCameraSceneNode(parent, core::vector3df(), core::vector3df(0, 0, 100), id, true);
33 if (node)
34 {
35// ISceneNodeAnimator* anm = new extantzCamera(CursorControl);
36 ISceneNodeAnimator* anm = new extantzCamera();
37
38 // Bind the node's rotation to its target. This is consistent with 1.4.2 and below.
39 node->bindTargetAndRotation(true);
40 node->addAnimator(anm);
41 anm->drop();
42 }
43
44 return node;
45}
46
47
48//! constructor
49//extantzCamera::extantzCamera(gui::ICursorControl* cursorControl)
50// : CursorControl(cursorControl), MaxVerticalAngle(88.0f), MoveSpeed(0.4f), RotateSpeed(100.0f), JumpSpeed(3.0f),
51extantzCamera::extantzCamera()
52 : MaxVerticalAngle(88.0f), MouseYDirection(1.0f), LastAnimationTime(0), NoVerticalMovement(false)
53{
54 #ifdef _DEBUG
55 setDebugName("extantzCamera");
56 #endif
57
58 move.jump = 0.0; // Coz otherwise we start in jumping mode.
59 move.MoveSpeed = 0.1f;
60 move.RotateSpeed = 1.0f;
61 move.JumpSpeed = 3.0f;
62
63// if (CursorControl)
64// CursorControl->grab();
65}
66
67
68//! destructor
69extantzCamera::~extantzCamera()
70{
71// if (CursorControl)
72// CursorControl->drop();
73}
74
75
76void extantzCamera::animateNode(ISceneNode* node, u32 timeMs)
77{
78 if (!node || node->getType() != ESNT_CAMERA)
79 return;
80
81 ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);
82
83 if (0 == LastAnimationTime)
84 {
85 camera->updateAbsolutePosition();
86// if (CursorControl )
87// {
88// CursorControl->setPosition(0.5f, 0.5f);
89// CursorPos = CenterCursor = CursorControl->getRelativePosition();
90// }
91
92 LastAnimationTime = timeMs;
93 }
94
95 // If the camera isn't the active camera, and receiving input, then don't process it.
96 // TODO - it never is, coz we are bypassing that, but can we replace this with something else?
97 if(!camera->isInputReceiverEnabled())
98 {
99// return;
100 }
101
102 scene::ISceneManager * smgr = camera->getSceneManager();
103 if(smgr && smgr->getActiveCamera() != camera)
104 return;
105
106 // get time
107 f32 timeDiff = (f32) (timeMs - LastAnimationTime);
108 LastAnimationTime = timeMs;
109
110 // update position
111 core::vector3df pos = camera->getPosition();
112
113 // Update rotation
114 core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition());
115 core::vector3df relativeRotation = target.getHorizontalAngle();
116
117#if 0
118 if (CursorControl)
119 {
120 if (CursorPos != CenterCursor)
121 {
122 relativeRotation.Y -= (0.5f - CursorPos.X) * move.RotateSpeed;
123 relativeRotation.X -= (0.5f - CursorPos.Y) * move.RotateSpeed * MouseYDirection;
124
125 // X < MaxVerticalAngle or X > 360-MaxVerticalAngle
126
127 if (relativeRotation.X > MaxVerticalAngle*2 &&
128 relativeRotation.X < 360.0f-MaxVerticalAngle)
129 {
130 relativeRotation.X = 360.0f-MaxVerticalAngle;
131 }
132 else
133 if (relativeRotation.X > MaxVerticalAngle &&
134 relativeRotation.X < 360.0f-MaxVerticalAngle)
135 {
136 relativeRotation.X = MaxVerticalAngle;
137 }
138
139 // Do the fix as normal, special case below
140 // reset cursor position to the centre of the window.
141 CursorControl->setPosition(0.5f, 0.5f);
142 CenterCursor = CursorControl->getRelativePosition();
143
144 // needed to avoid problems when the event receiver is disabled
145 CursorPos = CenterCursor;
146 }
147
148 // Special case, mouse is whipped outside of window before it can update.
149 video::IVideoDriver* driver = smgr->getVideoDriver();
150 core::vector2d<u32> mousepos(u32(CursorControl->getPosition().X), u32(CursorControl->getPosition().Y));
151 core::rect<u32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);
152
153 // Only if we are moving outside quickly.
154 bool reset = !screenRect.isPointInside(mousepos);
155
156 if(reset)
157 {
158 // Force a reset.
159 CursorControl->setPosition(0.5f, 0.5f);
160 CenterCursor = CursorControl->getRelativePosition();
161 CursorPos = CenterCursor;
162 }
163 }
164#else
165 relativeRotation.Y -= move.r * move.RotateSpeed;
166 relativeRotation.X -= move.s * move.RotateSpeed * MouseYDirection;
167
168 // X < MaxVerticalAngle or X > 360-MaxVerticalAngle
169
170 if ((relativeRotation.X > (MaxVerticalAngle * 2)) && (relativeRotation.X < (360.0f - MaxVerticalAngle)))
171 relativeRotation.X = 360.0f - MaxVerticalAngle;
172 else if ((relativeRotation.X > MaxVerticalAngle) && (relativeRotation.X < (360.0f - MaxVerticalAngle)))
173 relativeRotation.X = MaxVerticalAngle;
174#endif
175
176 // set target
177
178 target.set(0,0, core::max_(1.f, pos.getLength()));
179 core::vector3df movedir = target;
180
181 core::matrix4 mat;
182 mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0));
183 mat.transformVect(target);
184
185 if (NoVerticalMovement)
186 {
187 mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0));
188 mat.transformVect(movedir);
189 }
190 else
191 {
192 movedir = target;
193 }
194
195 movedir.normalize();
196
197 pos += movedir * timeDiff * move.MoveSpeed * move.x;
198
199 // strafing
200 core::vector3df strafevect = target;
201 strafevect = strafevect.crossProduct(camera->getUpVector());
202
203 if (NoVerticalMovement)
204 strafevect.Y = 0.0f;
205
206 strafevect.normalize();
207
208 pos += strafevect * timeDiff * move.MoveSpeed * move.y;
209
210 // For jumping, we find the collision response animator attached to our camera
211 // and if it's not falling, we tell it to jump.
212 if (0.0 < move.jump)
213 {
214 const ISceneNodeAnimatorList& animators = camera->getAnimators();
215 ISceneNodeAnimatorList::ConstIterator it = animators.begin();
216 while(it != animators.end())
217 {
218 if(ESNAT_COLLISION_RESPONSE == (*it)->getType())
219 {
220 ISceneNodeAnimatorCollisionResponse * collisionResponse =
221 static_cast<ISceneNodeAnimatorCollisionResponse *>(*it);
222
223 if(!collisionResponse->isFalling())
224 collisionResponse->jump(move.JumpSpeed);
225 }
226
227 it++;
228 }
229 }
230
231 // write translation
232 camera->setPosition(pos);
233
234 // write right target
235 target += pos;
236 camera->setTarget(target);
237}
238
239
240ISceneNodeAnimator* extantzCamera::createClone(ISceneNode* node, ISceneManager* newManager)
241{
242// extantzCamera *newAnimator = new extantzCamera(CursorControl);
243 extantzCamera *newAnimator = new extantzCamera();
244 return newAnimator;
245}
246
247#ifdef __cplusplus
248extern "C" {
249#endif
250
251cameraMove *getCameraMove(ICameraSceneNode *camera)
252{
253 cameraMove *cm = NULL;
254
255 if (camera)
256 {
257 const ISceneNodeAnimatorList &animators = camera->getAnimators();
258 ISceneNodeAnimatorList::ConstIterator it = animators.begin();
259 while(it != animators.end())
260 {
261 // TODO - We assume FPS == extantzCamera, coz Irrlicht hard codes the camera types in an enum, which is a pain to add to from outside.
262 if(ESNAT_CAMERA_FPS == (*it)->getType())
263 {
264 extantzCamera *ec = static_cast<extantzCamera *>(*it);
265
266 cm = &(ec->move);
267 }
268
269 it++;
270 }
271 }
272 return cm;
273}
274
275#ifdef __cplusplus
276}
277#endif
278
279
280} // namespace scene
281} // namespace irr
282
diff --git a/ClientHamr/extantz/extantzCamera.h b/ClientHamr/extantz/extantzCamera.h
deleted file mode 100644
index 9d74236..0000000
--- a/ClientHamr/extantz/extantzCamera.h
+++ /dev/null
@@ -1,101 +0,0 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#ifndef __EXTANTZ_CAMERA_H_INCLUDED__
6#define __EXTANTZ_CAMERA_H_INCLUDED__
7
8
9#ifdef __cplusplus
10#include <ISceneNodeAnimator.h>
11#include <vector2d.h>
12#include <position2d.h>
13#include <SKeyMap.h>
14#include <irrArray.h>
15#include <ICameraSceneNode.h>
16
17using namespace irr;
18using namespace scene;
19
20extern "C"{
21#else
22typedef struct extantzCamera extantzCamera;
23typedef struct ICameraSceneNode ICameraSceneNode;
24#endif
25
26typedef struct
27{
28 float x, y, z;
29 float r, s, t;
30 float jump;
31 float JumpSpeed, RotateSpeed, MoveSpeed;
32} cameraMove;
33
34cameraMove *getCameraMove(ICameraSceneNode *camera);
35
36#ifdef __cplusplus
37}
38
39
40//namespace irr::gui
41//{
42// class ICursorControl;
43//}
44
45
46namespace irr
47{
48namespace scene
49{
50 ICameraSceneNode *addExtantzCamera(ISceneManager* sm, ISceneNode* parent, s32 id);
51
52 class extantzCamera : public ISceneNodeAnimator
53 {
54 public:
55
56 //! Constructor
57// extantzCamera(gui::ICursorControl* cursorControl);
58 extantzCamera();
59
60 //! Destructor
61 virtual ~extantzCamera();
62
63 //! Animates the scene node, currently only works on cameras
64 virtual void animateNode(ISceneNode* node, u32 timeMs);
65
66 //! This animator will receive events when attached to the active camera
67 virtual bool isEventReceiverEnabled() const
68 {
69 return false;
70 }
71
72 //! Returns the type of this animator
73 virtual ESCENE_NODE_ANIMATOR_TYPE getType() const
74 {
75 return ESNAT_CAMERA_FPS;
76 }
77
78 //! Creates a clone of this animator.
79 /** Please note that you will have to drop
80 (IReferenceCounted::drop()) the returned pointer once you're
81 done with it. */
82 virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0);
83
84 bool NoVerticalMovement;
85 // -1.0f for inverted mouse, defaults to 1.0f
86 f32 MouseYDirection;
87
88 cameraMove move;
89
90 private:
91 f32 MaxVerticalAngle;
92 s32 LastAnimationTime;
93// core::position2d<f32> CenterCursor, CursorPos;
94 };
95};
96};
97#endif
98
99
100#endif // __EXTANTZ_CAMERA_H_INCLUDED__
101