diff options
author | David Walter Seikel | 2014-04-22 15:13:38 +1000 |
---|---|---|
committer | David Walter Seikel | 2014-04-22 15:13:38 +1000 |
commit | dd009ccdfd62f9153dbc72f5f5de5d5f72979690 (patch) | |
tree | 50d62438c6d47dccf82f440986919b1ed3edbbd9 /ClientHamr | |
parent | Move most of the README's and other docs into the new docs directory. (diff) | |
download | SledjHamr-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.c | 456 | ||||
-rw-r--r-- | ClientHamr/GuiLua/GuiLua.h | 35 | ||||
-rwxr-xr-x | ClientHamr/GuiLua/build.lua | 23 | ||||
-rw-r--r-- | ClientHamr/GuiLua/skang.c | 16 | ||||
-rw-r--r-- | ClientHamr/GuiLua/skang.lua | 1686 | ||||
-rw-r--r-- | ClientHamr/GuiLua/test.lua | 211 | ||||
-rw-r--r-- | ClientHamr/GuiLua/test.properties | 1 | ||||
-rwxr-xr-x | ClientHamr/GuiLua/test.sh | 3 | ||||
-rw-r--r-- | ClientHamr/GuiLua/test.skang | 14 | ||||
-rw-r--r-- | ClientHamr/GuiLua/test_c.c | 88 | ||||
-rw-r--r-- | ClientHamr/extantz/CDemo.cpp | 510 | ||||
-rw-r--r-- | ClientHamr/extantz/CDemo.h | 63 | ||||
-rwxr-xr-x | ClientHamr/extantz/build.lua | 26 | ||||
-rw-r--r-- | ClientHamr/extantz/crappisspuke.cpp | 294 | ||||
-rw-r--r-- | ClientHamr/extantz/extantz.c | 1588 | ||||
-rw-r--r-- | ClientHamr/extantz/extantz.edc | 30 | ||||
-rw-r--r-- | ClientHamr/extantz/extantz.h | 215 | ||||
-rw-r--r-- | ClientHamr/extantz/extantzCamera.cpp | 282 | ||||
-rw-r--r-- | ClientHamr/extantz/extantzCamera.h | 101 |
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 | |||
3 | Provides the skang and widget Lua packages. | ||
4 | |||
5 | In the initial intended use case, several applications will be using | ||
6 | this all at once, with one central app hosting all the GUIs. | ||
7 | |||
8 | Basically this should deal with "windows" and their contents. A | ||
9 | "window" in this case is hosted in the central app as some sort of | ||
10 | internal window, but the user can "tear off" those windows, then they | ||
11 | get their own OS hosted window. This could be done by the hosting app | ||
12 | sending the current window contents to the original app as a skang file. | ||
13 | |||
14 | Between the actual GUI and the app might be a socket, or a stdin/out | ||
15 | pipe. Just like matrix-RAD, this should be transparent to the app. | ||
16 | Also just like matrix-RAD, widgets can be connected to variable / | ||
17 | functions (C or Lua), and any twiddlings with those widgets runs the | ||
18 | function / changes the variable, again transparent to the app, except | ||
19 | for any registered get/set methods. | ||
20 | |||
21 | This interface between the GUI and the app is "skang" files, which are | ||
22 | basically Lua scripts. The GUI and the app can send skang files back | ||
23 | and forth, usually the app sends actual GUI stuff, and usually the GUI | ||
24 | sends variable twiddles or action calls. Usually. | ||
25 | |||
26 | To start with, this will be used to support multiple apps hosting their | ||
27 | windows in extantz, allowing the big viewer blob to be split up into | ||
28 | modules. At some point converting LL XML based UI shit into skang could | ||
29 | be done. Also, this should be an exntension to LuaSL, so in-world | ||
30 | scripts can have a poper GUI for a change. | ||
31 | |||
32 | |||
33 | NOTES and TODOs - | ||
34 | |||
35 | Lua 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 | |||
53 | Making these packages all a sub package of skang seems like a great | ||
54 | idea. On the other hand, looks like most things are just getting folded | ||
55 | into skang anyway. See | ||
56 | http://www.inf.puc-rio.br/~roberto/pil2/chapter15.pdf part 15.5 for | ||
57 | package details. | ||
58 | |||
59 | See if I can use LuaJIT FFI here. Since this will be a library, and | ||
60 | skang apps could be written in C or Lua, perhaps writing this library to | ||
61 | be FFI friendly instead of the usual Lua C binding might be the way to | ||
62 | go? LuaJIT is not ready yet, since it needs include files copied into | ||
63 | Lua files, and does not support macros, which EFL uses a lot of. | ||
64 | |||
65 | For the "GUI hosted in another app" case, we will need some sort of | ||
66 | internal window manager running in that other app. | ||
67 | |||
68 | This might end up running dozens of Lua scripts, and could use the LuaSL | ||
69 | Lua script running system. Moving that into this library might be a | ||
70 | sane idea I think? Or prehaps a separate library that both LuaSL and | ||
71 | GuiLua use? | ||
72 | |||
73 | Raster wants a method of sending Lua tables around as edje messages. | ||
74 | Between C, Edje, Edje Lua, and Lua. Sending between threads, and across | ||
75 | sockets. Using a new edje message type, or eet for sockets, was | ||
76 | suggested, but perhaps Lua skang is a better choice? | ||
77 | |||
78 | Somehow access to the edje_lua2.c bindings should be provided. And | ||
79 | bindings to the rest of EFL when they are done. Assuming the other EFL | ||
80 | developers do proper introspection stuff, or let me do it. | ||
81 | |||
82 | The generic Lua binding helper functions I wrote for edje_lua2.c could | ||
83 | be used here as well, and expanded as discussed on the E devs mailing | ||
84 | list. This would include the thread safe Lua function stuff copied | ||
85 | into the README. | ||
86 | |||
87 | There will eventually be a built in editor, like the zen editor from | ||
88 | matrix-RAD. It might be a separate app. | ||
89 | |||
90 | NAWS should probably live in here to. If I ever get around to writing | ||
91 | it. lol | ||
92 | |||
93 | The pre tokenized widget structure thingy I had planned in the | ||
94 | matrix-RAD TODO just wont work, as it uses symbols. On the other hand, | ||
95 | we will be using Lua tables anyway. B-) | ||
96 | |||
97 | The last half of http://passingcuriosity.com/2009/extending-lua-in-c/ | ||
98 | might be of use. | ||
99 | |||
100 | */ | ||
101 | |||
102 | |||
103 | /* thing package | ||
104 | |||
105 | Currently this is in skang.lua, but should bring this in here later. | ||
106 | |||
107 | */ | ||
108 | |||
109 | |||
110 | /* skang package | ||
111 | |||
112 | Currently this is in skang.lua, but should bring this in here later. | ||
113 | |||
114 | */ | ||
115 | |||
116 | |||
117 | /* stuff & squeal packages | ||
118 | |||
119 | Currently Stuff is in skang.lua, but should bring this in here later. | ||
120 | |||
121 | */ | ||
122 | |||
123 | |||
124 | /* widget package | ||
125 | |||
126 | Currently widget design is in skang.lua, but should bring this in here later. | ||
127 | |||
128 | */ | ||
129 | |||
130 | |||
131 | /* introspection | ||
132 | |||
133 | As detailed in README, EFL introspection doesn't seem to really be on | ||
134 | the radar, but I might get lucky, or I might have to write it myself. | ||
135 | For quick and dirty early testing, I'll probably write a widget package | ||
136 | that has hard coded mappings between some basic "label", "button", etc. | ||
137 | and ordinary elementary widgets. Proper introspection can come later. | ||
138 | |||
139 | */ | ||
140 | |||
141 | |||
142 | |||
143 | #include "GuiLua.h" | ||
144 | |||
145 | |||
146 | globals ourGlobals; | ||
147 | static 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. | ||
152 | static 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 - | ||
162 | widget has to be a light userdata | ||
163 | The rest can be Lua sub things? Each with a C function to update the widget. | ||
164 | |||
165 | win.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) | ||
166 | win.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 | |||
169 | struct _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 | |||
180 | static 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 | |||
199 | static 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 | |||
238 | static 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 | |||
257 | static int colour(lua_State *L) | ||
258 | { | ||
259 | // TODO - This is just a stub for now. | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static 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 | |||
292 | static int clear(lua_State *L) | ||
293 | { | ||
294 | // TODO - This is just a stub for now. | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static 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 | |||
313 | static 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 | |||
326 | static 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 | |||
352 | Lua's require() function will strip any stuff from the front of the name | ||
353 | separated by a hyphen, so 'ClientHamr-GuiLua-libGuiLua' -> 'libGuiLua'. Then | ||
354 | it will search through a path, and eventually find this libGuiLua.so (or | ||
355 | libGuiLua.dll or whatever), then call luaopen_libGuiLua(), which should return | ||
356 | a table. The argument (only thing on the stack) for this function will | ||
357 | be 'libGuiLua'. | ||
358 | |||
359 | Normally luaL_register() creates a table of functions, that is the table | ||
360 | returned, but we want to do something different with skang. | ||
361 | */ | ||
362 | int 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 | |||
417 | void 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 | |||
15 | typedef 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 | |||
27 | struct _globals | ||
28 | { | ||
29 | Evas_Object *win; // Our Elm window. | ||
30 | int logDom; // Our logging domain. | ||
31 | }; | ||
32 | |||
33 | |||
34 | int luaopen_widget(lua_State *L); | ||
35 | void 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 | |||
3 | local dir = ... | ||
4 | |||
5 | if '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 | ||
14 | end | ||
15 | |||
16 | LDFLAGS = '-L ' .. dir .. ' ' .. LDFLAGS | ||
17 | |||
18 | removeFiles(dir, {'test_c.so', 'GuiLua.o', '../../libraries/libGuiLua.so', 'skang'}) | ||
19 | |||
20 | runCommand('C modules', dir, 'gcc ' .. CFLAGS .. ' -fPIC -shared -o test_c.so test_c.c') | ||
21 | runCommand(nil, dir, 'gcc ' .. CFLAGS .. ' -fPIC -c GuiLua.c') | ||
22 | runCommand('C libraries', dir, 'gcc ' .. CFLAGS .. ' -shared -Wl,-soname,libGuiLua.so -o ../../libraries/libGuiLua.so GuiLua.o') | ||
23 | runCommand('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 | |||
4 | EAPI_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 | |||
16 | ELM_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 | |||
3 | C 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 | |||
17 | In here should live all the internals of matrix-RAD that don't | ||
18 | specifically relate to widgets. This would include the "window" though. | ||
19 | |||
20 | skang.module(Evas) | ||
21 | skang.module(Elementary) | ||
22 | skang.skang('some/skang/file.skang') | ||
23 | |||
24 | This package is also what "apps" that use the system should "inherit" | ||
25 | from, in the same way matrix-RAD apps did. Skang "apps" could be Lua | ||
26 | modules. They could also be C code, like the extantz modules are likely | ||
27 | to be. Skang "apps" would automatically be associated with skang files | ||
28 | of the same name. | ||
29 | |||
30 | For a .skang file, the skang command (written in C) would strip off the | ||
31 | first line, add the two implied lines, then run it as Lua. The | ||
32 | skang.load() command would do the same. So that skang C comand would | ||
33 | just pass the file name to skang.load() in this library. B-) | ||
34 | |||
35 | The 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". | ||
69 | do -- Only I'm not gonna indent this. | ||
70 | |||
71 | mainSkin = {} | ||
72 | |||
73 | -- TODO - This needs to be expanded a bit to cover things like 1.42 | ||
74 | local 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. | ||
88 | moduleBegin = 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 | ||
170 | end | ||
171 | |||
172 | |||
173 | --[[ Parse command line parameters. | ||
174 | |||
175 | This is done in two parts. Skang will do an initial scan and tokenise, | ||
176 | then each module gets a chance to pull it's own Things from the result. | ||
177 | |||
178 | Make the command line parameter getting MUCH more intelligent, try to support the common | ||
179 | command line interfaces - | ||
180 | |||
181 | arg value | ||
182 | a value | ||
183 | /arg value | ||
184 | /a value | ||
185 | --arg value | ||
186 | --a value | ||
187 | -a value | ||
188 | -ab ('a' and 'b' are both shortcuts.) | ||
189 | arg=value | ||
190 | a=value | ||
191 | arg1=value1&arg2=value2 | ||
192 | arg1=value1|arg2=value2 | ||
193 | a=value1&a=value2 | ||
194 | +arg/-arg (Can't support this generically.) | ||
195 | |||
196 | Ignore /,-,--,& except as arg introducers. Use = as value introducer. Expect | ||
197 | arg or a. If type is String, expect a value. If type is integer, and next token is | ||
198 | not an integer, increment current value, otherwise expect integer value. If type is | ||
199 | boolean, value beginning with T, t, F, f, etc is true, otherwise value is false, unless | ||
200 | next token starts with an introducer, then value is true. | ||
201 | |||
202 | TODO - 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 | |||
218 | ARGS = {} | ||
219 | lua = '' | ||
220 | command = '' | ||
221 | |||
222 | |||
223 | -- Do an initial scan and tokenise of the command line arguments. | ||
224 | scanArguments = 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 | ||
242 | end | ||
243 | |||
244 | parseType = 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 | ||
305 | end | ||
306 | |||
307 | pullArguments = 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 | ||
344 | end | ||
345 | |||
346 | -- Restore the environment, and grab paramateres from standard places. | ||
347 | moduleEnd = 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 | ||
372 | end | ||
373 | |||
374 | |||
375 | -- Call this now so that from now on, this is like any other module. | ||
376 | local _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. | ||
379 | if type(jit) == 'table' then | ||
380 | print('Skang is being run by ' .. jit.version .. ' under ' .. jit.os .. ' on a ' .. jit.arch) | ||
381 | else | ||
382 | print('Skang is being run by Lua version ' .. _VERSION) | ||
383 | end | ||
384 | |||
385 | scanArguments(arg) | ||
386 | |||
387 | |||
388 | function printTableStart(table, space, name) | ||
389 | print(space .. name .. ": ") | ||
390 | print(space .. "{") | ||
391 | printTable(table, space .. " ") | ||
392 | print(space .. "}") | ||
393 | if '' == space then print('') end | ||
394 | end | ||
395 | |||
396 | function 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 | ||
421 | end | ||
422 | |||
423 | |||
424 | csv2table = 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 | ||
433 | end | ||
434 | |||
435 | |||
436 | shiftLeft = function (tab) | ||
437 | local result = tab[1] | ||
438 | table.remove(tab, 1) | ||
439 | return result | ||
440 | end | ||
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' | ||
445 | local isTrue = 't1aopswy' | ||
446 | -- false 0 no nack nope zero negative nah 'no way' 'get real' 'uh uh' 'fuck off' 'bugger off' | ||
447 | local isFalse = 'f0bgnuz' | ||
448 | isBoolean = 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 | ||
467 | end | ||
468 | |||
469 | |||
470 | --[[ Thing Java package | ||
471 | |||
472 | matrix-RAD had Thing as the base class of everything. | ||
473 | |||
474 | Each "users session" (matrix-RAD term that came from Java | ||
475 | applets/servlets) has a ThingSpace, which is a tree that holds | ||
476 | everything else. It holds the class cache, commands, loaded modules, | ||
477 | variables and their values, widgets and their states. In matrix-RAD I | ||
478 | built BonsiaTree and LeafLike, for the old FDO system I built dumbtrees. | ||
479 | |||
480 | Other 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 | |||
496 | In matrix-RAD Stuff took care of multi value Things, like database rows. | ||
497 | |||
498 | Stuff is an abstract class that gets extended by other classes, like | ||
499 | SquealStuff, which was the only thing extending it. It dealt with the | ||
500 | basic "collection of things" stuff. Each individual thing was called a | ||
501 | stufflet. A final fooStuff would extend SquealStuff, and include an | ||
502 | array of strings called "stufflets" that at least named the stufflets, | ||
503 | but could also include metadata and links to other Stuffs. | ||
504 | |||
505 | There was various infrastructure for reading and writing Stuff, throwing | ||
506 | rows of Stuff into grids, having choices of Stuff, linking stufflets to | ||
507 | individual widgets, having default Stuffs for windows, validating | ||
508 | Stuffs, etc. | ||
509 | |||
510 | In Lua, setting up stuff has been folded into the general Thing stuff. | ||
511 | |||
512 | ]] | ||
513 | |||
514 | |||
515 | --[[ Thing structure - | ||
516 | |||
517 | In the following, meta(table) is short for getmetatable(table). | ||
518 | |||
519 | In Lua everything is supposed to be a first class value, and variables are just places to store values. | ||
520 | All variables are in fact stored in tables, even if it's just the local environment table. | ||
521 | Any variable that has a value of nil, doesn't actually exist. That's the definition. | ||
522 | While non table things can have metatables, Lua can only set metatables on tables, C has no such restriction. | ||
523 | meta(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. | ||
528 | Using both __index and __newindex, and keeping the actual values elsewhere, is called a proxy table. | ||
529 | meta(table).__call(table, ...) is called when trying to access table as a function - table(...). | ||
530 | |||
531 | It's worth repeating - | ||
532 | All variables in Lua are in some table somewhere, even if it's just the global environment table. | ||
533 | Metatables are only associated vith values, not variables. | ||
534 | Lua can only attach metatables to values that are tables, but C can attach metatables to any value. | ||
535 | |||
536 | |||
537 | A Thing is a managed variable stored in a parent proxy table, which is usually empty. | ||
538 | So 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 | |||
543 | Each 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. | ||
555 | All things that a description doesn't have should be inherited from the Thing table. | ||
556 | setmetatable(aStuff, {__index = Thing}) | ||
557 | Descriptions should be able to be easily shared by various Things. | ||
558 | |||
559 | |||
560 | A parent's metatable has __self, which is it's own description. | ||
561 | A parent is free to use it's own name space for anything it wants. | ||
562 | Only the variables it specifies as managed Things are dealt with here. | ||
563 | |||
564 | |||
565 | Things that are tables are treated differently, in two different ways even. | ||
566 | Ordinary table Things are basically treated recursively, the table is a parent, and it gets it's own Things. | ||
567 | There is also 'Keyed' type table Things, where the keys to this table are arbitrary, but we still want to store Things in it. | ||
568 | In 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 | |||
571 | TODO - | ||
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. | ||
584 | local 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 | |||
654 | getStuffed = 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 | ||
669 | end | ||
670 | |||
671 | local 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] | ||
686 | end, | ||
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. | ||
748 | end, | ||
749 | |||
750 | __call = function (func, ...) | ||
751 | return thingasm(func, ...) | ||
752 | end, | ||
753 | |||
754 | } | ||
755 | |||
756 | newMum = function () | ||
757 | local result = {} | ||
758 | --[[ From an email by Mike Pall - | ||
759 | "Important: create the metatable and its metamethods once and reuse | ||
760 | the _same_ metatable for _every_ instance." | ||
761 | |||
762 | This is for LuaJIT, he's the author, and concerns performance. | ||
763 | |||
764 | TODO - 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 | ||
772 | end | ||
773 | |||
774 | |||
775 | -- skang.thingasm() Creates a new Thing, or changes an existing one. | ||
776 | --[[ It can be called in many different ways - | ||
777 | |||
778 | It can be called with positional arguments - (names, help, default, types, widget, required, acl, boss) | ||
779 | Or it can be called with a table - {names, help, pattern='.*', acl='rwx'} | ||
780 | |||
781 | The first argument can be another Thing (the parent), or a string list of names (see below). | ||
782 | |||
783 | It can be called by itself, with no parent specified - | ||
784 | thingasm('foo', 'help text) | ||
785 | In 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. | ||
787 | All others include the parent as the first argument, which would be a table. | ||
788 | |||
789 | It 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'} | ||
799 | thingasm = 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()) | ||
884 | print('\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 | ||
919 | end | ||
920 | |||
921 | |||
922 | fixNames = 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 | ||
934 | end | ||
935 | |||
936 | |||
937 | copy = 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 | ||
957 | end | ||
958 | |||
959 | module = function (name) | ||
960 | _G[name] = require(name) | ||
961 | return _G[name] | ||
962 | end | ||
963 | |||
964 | stuff = function (aThingy, aStuff) | ||
965 | return getmetatable(aThingy).__self.stuff[aStuff] | ||
966 | end | ||
967 | |||
968 | |||
969 | get = 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 | ||
981 | end | ||
982 | |||
983 | |||
984 | reset = 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 | ||
994 | end | ||
995 | |||
996 | |||
997 | set = 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 | ||
1008 | end | ||
1009 | |||
1010 | |||
1011 | -- Get our C functions installed into skang. | ||
1012 | -- This has to be after thingasm is defined. | ||
1013 | package.cpath = package.cpath .. ';../../libraries/lib?.so' | ||
1014 | local GuiLua = require 'GuiLua' | ||
1015 | |||
1016 | |||
1017 | thingasm('module,l', 'Load a module.', module, 'file') | ||
1018 | thingasm('get', 'Get the current value of an existing Thing or metadata.', get, 'thing,key,name') | ||
1019 | thingasm('reset', 'Reset the current value of an existing Thing or metadata.', reset, 'thing,key,name') | ||
1020 | thingasm('set', 'Set the current value of an existing Thing or metadata.', set, 'thing,key,name,data') | ||
1021 | |||
1022 | thingasm('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 | ||
1028 | local widgets = {} | ||
1029 | --thingasm{widgets, 'window', 'The window.', types='userdata'} | ||
1030 | thingasm{widgets, 'W', 'Holds all the widgets', types='Keyed'} | ||
1031 | widgets.W{'Cwidget', 'The widget.', types='userdata'} | ||
1032 | widgets.W{'action,a', 'The action for the widget.', 'nada', types='string'} | ||
1033 | local aIsValid = function (self, parent) | ||
1034 | local result = Thing.isValid(self, parent) | ||
1035 | |||
1036 | if result then | ||
1037 | local value = parent[self.names[1] ] | ||
1038 | print('NEW ACTION - ' .. self.names[1] .. ' = ' .. value .. ' ' .. type(parent.Cwidget)) | ||
1039 | action(parent.Cwidget, value) | ||
1040 | end | ||
1041 | return result | ||
1042 | end | ||
1043 | |||
1044 | widgets.W{'look,l', 'The look of the widget.', types='string'} | ||
1045 | --[[ | ||
1046 | widgets.W{'colour,color,c', 'The colours of the widget.', types='table'} | ||
1047 | widgets.W.c{'red,r', 'The red colour of the widget.', 255, types='number'} | ||
1048 | widgets.W.c{'green,g', 'The green colour of the widget.', 255, types='number'} | ||
1049 | widgets.W.c{'blue,b', 'The blue colour of the widget.', 255, types='number'} | ||
1050 | widgets.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. | ||
1053 | local wMum = getmetatable(widgets.W.c) | ||
1054 | wMum.__call = function (func, ...) | ||
1055 | return Colour(func, ...) | ||
1056 | end | ||
1057 | ]] | ||
1058 | |||
1059 | window = 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 | ||
1067 | end | ||
1068 | |||
1069 | thingasm{'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. | ||
1073 | skang = function (name) | ||
1074 | end | ||
1075 | |||
1076 | thingasm('skang', 'Parse the contents of a skang file or URL.', skang, 'URL') | ||
1077 | |||
1078 | |||
1079 | moduleEnd(_M) | ||
1080 | |||
1081 | end | ||
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 | |||
1186 | Java skang could run as a stand alone applicion, as an applet in a web | ||
1187 | page, or as a servlet on a web server. This was pretty much all | ||
1188 | transparent to the user. The security system reflected that. Lua skang | ||
1189 | wont run in web pages, but can still have client / server behaviour. | ||
1190 | The general idea was, and still is, that the GUI is the client side (in | ||
1191 | web 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 | ||
1193 | server for in world scripts). Client side can request that server side | ||
1194 | runs commands. Serevr side can send values and commands back to the | ||
1195 | client. Mostly it all happenes automatically through the ACLs. | ||
1196 | |||
1197 | Bouncer is the Java skang security manager, it extended the Java | ||
1198 | SecurityManager. Lua has no such thing, though C code running stuff in | ||
1199 | a sandbox does a similar job. Fascist is the Java security supervisor, | ||
1200 | again should go into the C sandbox. | ||
1201 | |||
1202 | Human is used for authenticating a human, Puter for authenticating a | ||
1203 | computer, Suits for corporate style authentication, and they all | ||
1204 | extended Who, the base authentication module. | ||
1205 | |||
1206 | For now, I have no idea how this all translates into Lua, but putting | ||
1207 | this here for a reminder to think about security during the design | ||
1208 | stage. | ||
1209 | |||
1210 | |||
1211 | This is the old Java ACL definition - | ||
1212 | acl - access control list. | ||
1213 | Owner is usually the person running the Thingspace. | ||
1214 | RWX~,---,Rwxgroup1,r--group2,r-xgroup3,rw-group4,--X~user1 | ||
1215 | rwx~ is for the owner. The second one is the default. The rest are per group or per user. | ||
1216 | Capital letters mean that they get access from the network to. | ||
1217 | --- No access at all. | ||
1218 | RWX Full access. | ||
1219 | R-- Read only access. | ||
1220 | r-x Read and execute, but only locally. | ||
1221 | rw- 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. | ||
1225 | Ri- read, but only set from init (ei. skinURL not set from properties or skang files). | ||
1226 | RI- 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). | ||
1230 | s-- Read only, but not even visible to applets. | ||
1231 | sss Only visible to servlets and applications. | ||
1232 | --S Send to servlet to execute if applet, otherwise execute normally. | ||
1233 | S-- Read only, but ignore local version and get it from server. | ||
1234 | ggg GUI Thing, only visible to Applets and applications. | ||
1235 | GGG GUI Thing, but servlets can access them across the net. | ||
1236 | |||
1237 | For servlet only modules from an applet, the applet only loads the skanglet class, using it for all | ||
1238 | access to the module. | ||
1239 | |||
1240 | |||
1241 | Lua 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 | ||
1246 | to sandbox it at the process level. Everything else has far too many | ||
1247 | loopholes." | ||
1248 | |||
1249 | http://lua-users.org/lists/lua-l/2011-02/msg01595.html | ||
1250 | http://lua-users.org/lists/lua-l/2011-02/msg01609.html | ||
1251 | http://lua-users.org/lists/lua-l/2011-02/msg01097.html | ||
1252 | http://lua-users.org/lists/lua-l/2011-02/msg01106.html | ||
1253 | |||
1254 | So that's processes, not threads like LuaProc does. B-( | ||
1255 | |||
1256 | However, security in depth is good, so still worthwhile looking at it from other levels as well. | ||
1257 | |||
1258 | General solution is to create a new environment, which we are doing | ||
1259 | anyway, then whitelist the safe stuff into it, instead of blacklisting | ||
1260 | unsafe stuff. Coz you never know if new unsafe stuff might exist. | ||
1261 | |||
1262 | Different between 5.1 (setfenv) and 5.2 (_ENV) | ||
1263 | |||
1264 | http://lua-users.org/wiki/SandBoxes - | ||
1265 | |||
1266 | ------------------------------------------------------ | ||
1267 | -- make environment | ||
1268 | local 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] | ||
1300 | local 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) | ||
1306 | end | ||
1307 | |||
1308 | -- run code under environment [Lua 5.2] | ||
1309 | local 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) | ||
1313 | end | ||
1314 | ------------------------------------------------------ | ||
1315 | |||
1316 | Also includes a table of safe / unsafe stuff. | ||
1317 | |||
1318 | |||
1319 | While whitelisting stuff, could also wrap unsafe stuff to make them more safe. | ||
1320 | |||
1321 | print() -> should reroute to our output widgets. | ||
1322 | rawget/set() -> don't bypass the metatables, but gets tricky and recursive. | ||
1323 | require -> don't allow bypassing the sandbox to get access to restricted modules | ||
1324 | package.loaded -> ditto | ||
1325 | |||
1326 | |||
1327 | Other things to do - | ||
1328 | |||
1329 | debug.sethook() can be used to call a hook every X lines, which can help with endless loops and such. | ||
1330 | Have a custom memory allocater, like edje_lua2 does. | ||
1331 | |||
1332 | ------------------------------------------------------ | ||
1333 | ------------------------------------------------------ | ||
1334 | |||
1335 | The 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 | --[[ | ||
1418 | The 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 | |||
1458 | What 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 | |||
1482 | Alternate 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 | |||
1650 | public 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". | ||
3 | do -- Only I'm not gonna indent this. | ||
4 | |||
5 | local skang = require 'skang' | ||
6 | local _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 | |||
12 | print('code') | ||
13 | |||
14 | -- A variable that is private to this module. | ||
15 | local 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 | |||
19 | skang.thingasm{'fooble,f', 'Help text goes here', 1, widget='"edit", "The fooble:", 1, 1, 10, 50', required=true} | ||
20 | skang.thingasm('bar', 'Help text', "Default") | ||
21 | skang.thingasm('foo') | ||
22 | |||
23 | -- We can use inline functions if we don't need the function internally. | ||
24 | skang.thingasm('ffunc', 'Help Text', function (arg1, arg2) | ||
25 | print('Inside test.ffunc(' .. arg1 .. ', ' .. arg2 .. ')') | ||
26 | end, 'number,string') | ||
27 | |||
28 | print('Ending soon') | ||
29 | skang.moduleEnd(_M) | ||
30 | |||
31 | end | ||
32 | |||
33 | |||
34 | -- Test it. | ||
35 | local skang = require 'skang' | ||
36 | local test = require 'test' | ||
37 | local test_c = require 'test_c' | ||
38 | local copy = skang.copy(test, 'copy') | ||
39 | |||
40 | print('End ' .. test.bar .. ' ' .. test.VERSION .. ' ' .. skang.get(test, 'ffunc', 'help') .. ' ->> ' .. skang.get(test, 'f', 'action')) | ||
41 | |||
42 | print('') | ||
43 | |||
44 | print('foo = ' .. test.foo .. ' ->> ' .. skang.get(test, 'foo', 'help')) | ||
45 | print('fooble = ' .. test.fooble) | ||
46 | print('cfooble = ' .. test_c.cfooble .. ' ->> ' .. skang.get(test_c, 'cfooble', 'help') .. ' [' .. skang.get(test_c, 'cfooble', 'widget') .. ']') | ||
47 | print('cfunc ->> ' .. skang.get(test_c, 'cfunc', 'help')) | ||
48 | test.ffunc('one', 2) | ||
49 | test_c.cfunc(0, 'zero') | ||
50 | print('') | ||
51 | |||
52 | test.f = 42 | ||
53 | print('f is now ' .. test.fooble .. ' ' .. test.f) | ||
54 | print('copy_f is now ' .. copy.fooble .. ' ' .. copy.f) | ||
55 | copy.f = 24 | ||
56 | print('f is now ' .. test.fooble .. ' ' .. test.f) | ||
57 | print('copy_f is now ' .. copy.fooble .. ' ' .. copy.f) | ||
58 | test.f = nil | ||
59 | print('f is now ' .. test.fooble .. ' ' .. test.f) | ||
60 | test.fooble = 42 | ||
61 | print('f is now ' .. test.fooble .. ' ' .. test.f) | ||
62 | test.fooble = nil | ||
63 | print('f is now ' .. test.fooble .. ' ' .. test.f) | ||
64 | print('') | ||
65 | |||
66 | print(skang.isBoolean(true)) | ||
67 | print(skang.isBoolean(1)) | ||
68 | print(skang.isBoolean('1')) | ||
69 | print(skang.isBoolean('true')) | ||
70 | print(skang.isBoolean('Yep')) | ||
71 | print(skang.isBoolean('?')) | ||
72 | print(skang.isBoolean(test)) | ||
73 | print(skang.isBoolean(function (a) return true end)) | ||
74 | print('') | ||
75 | print(skang.isBoolean(false)) | ||
76 | print(skang.isBoolean(nil)) | ||
77 | print(skang.isBoolean(0)) | ||
78 | print(skang.isBoolean('')) | ||
79 | print(skang.isBoolean('0')) | ||
80 | print(skang.isBoolean('false')) | ||
81 | print(skang.isBoolean('Nope')) | ||
82 | print(skang.isBoolean(function (a) return false end)) | ||
83 | print('') | ||
84 | |||
85 | -- Make it required, even though it was anyway. | ||
86 | skang.set(test, 'f', 'required', true) | ||
87 | -- Disable the default value, so we see "is required" errors. | ||
88 | skang.reset(test, 'f', 'default') | ||
89 | test.fooble = 42 | ||
90 | test.fooble = 'Should fail.' | ||
91 | test.fooble = 42 | ||
92 | test.fooble = nil | ||
93 | test.fooble = 42 | ||
94 | test.fooble = true | ||
95 | test.f = 42 | ||
96 | test.f = nil | ||
97 | test.bar = 123 | ||
98 | print('') | ||
99 | |||
100 | skang.set(test, 'f', 'required', false) | ||
101 | test.f = 42 | ||
102 | test.f = nil | ||
103 | skang.set(test, 'f', 'default', 999) | ||
104 | test.f = 42 | ||
105 | test.f = nil | ||
106 | print(test.fooble .. ' ' .. test.f) | ||
107 | print(skang.get(test, 'f', 'default')) | ||
108 | print('') | ||
109 | |||
110 | local stuff = {} | ||
111 | stuff.t = {} | ||
112 | |||
113 | skang.thingasm{stuff, 'a', 'A test stufflet'} | ||
114 | skang.thingasm{stuff.t, 'b', 'A sub stufflet'} | ||
115 | skang.thingasm{stuff.t, 'c', 'Another sub stufflet'} | ||
116 | skang.thingasm{stuff, 's', 'A Stuff', types='table'} | ||
117 | stuff.s{'sa,a', 'A stufflet in a Stuff'} | ||
118 | stuff.s{'sb,b', 'Another stufflet in a Stuff'} | ||
119 | skang.thingasm{stuff, 'S', 'A database table of Stuff', types='Keyed'} | ||
120 | stuff.S{'field0', 'The first field of the db table.'} | ||
121 | stuff.S{'field1', 'The second field of the db table.'} | ||
122 | |||
123 | print('*********************************') | ||
124 | skang.fixNames(skang, 'skang') | ||
125 | skang.fixNames(test, 'test') | ||
126 | skang.fixNames(test_c, 'test_c') | ||
127 | skang.fixNames(stuff, 'stuff') | ||
128 | print('*********************************') | ||
129 | |||
130 | print(skang.get(stuff, 'a', 'help')) | ||
131 | print(skang.get(stuff.t, 'b', 'help')) | ||
132 | print(skang.get(stuff.t, 'c', 'help')) | ||
133 | print(skang.get(stuff, 's', 'help')) | ||
134 | print(skang.get(stuff.s, 'sa', 'help')) | ||
135 | print(skang.get(stuff.s, 'sb', 'help')) | ||
136 | print(skang.get(stuff.S, 'field0', 'help')) | ||
137 | print(skang.get(stuff.S, 'field1', 'help')) | ||
138 | skang.thingasm{test, 'baz,b', 'A test stufflet for test'} | ||
139 | print(skang.get(test, 'b', 'help')) | ||
140 | print(skang.get(test, 'f', 'help')) | ||
141 | -- Should fail isValid() | ||
142 | stuff.a = 1 | ||
143 | stuff.t.b = '2' | ||
144 | stuff.t.c = '3' | ||
145 | test.b = '422222' | ||
146 | test.f = 5 | ||
147 | test_c.cbar = '666' | ||
148 | -- This one doesn't actually exist. | ||
149 | test_c.bar = '7' | ||
150 | stuff.s.sa = true | ||
151 | stuff.s.sb = 22 | ||
152 | stuff.s.b = 33 | ||
153 | print('') | ||
154 | -- TODO - This triggers isValid() twice for each table element. | ||
155 | stuff.s = {a=8, sb='9'} | ||
156 | print('') | ||
157 | stuff.s.sb = 99 | ||
158 | -- NOTE - Yet this doesn't trigger isValid() twice. | ||
159 | stuff.S['record0'] = {field0=0, field1='zero'} | ||
160 | stuff.S['record1'] = {field0='1', field1='one'} | ||
161 | stuff.S['record2'] = {field0='2', field1='two'} | ||
162 | |||
163 | print('') | ||
164 | |||
165 | print(skang.get(stuff, 'a')) | ||
166 | print(skang.get(stuff.t, 'b')) | ||
167 | print(skang.get(stuff.t, 'c')) | ||
168 | print(skang.get(test, 'b')) | ||
169 | print(skang.get(test, 'baz')) | ||
170 | print(skang.get(test, 'f')) | ||
171 | print(skang.get(test, 'fooble')) | ||
172 | print(skang.get(test_c, 'cbar')) | ||
173 | print(skang.get(test_c, 'bar')) | ||
174 | print(type(skang.get(stuff, 's'))) | ||
175 | print(skang.get(stuff.s, 'sa')) | ||
176 | print(skang.get(stuff.s, 'sb')) | ||
177 | print('') | ||
178 | |||
179 | print(stuff.a) | ||
180 | print(stuff.t.b) | ||
181 | print(stuff.t.c) | ||
182 | print(test.b) | ||
183 | print(test.baz) | ||
184 | print(test.f) | ||
185 | print(test.fooble) | ||
186 | print(test_c.cbar) | ||
187 | print(test_c.bar) | ||
188 | print(test_c.c) | ||
189 | print(test_c.cfooble) | ||
190 | print(stuff.s.sa) | ||
191 | print(stuff.s.sb) | ||
192 | print('') | ||
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 | |||
198 | print(stuff.S['record0'].field1) | ||
199 | print(stuff.S['record1'].field0) | ||
200 | print(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 @@ | |||
1 | fooble = '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 | ||
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 translate 'quit' into the Lua 'skang.quit()'? | ||
10 | |||
11 | skang.thingasm{win, 'ffuncer', 'Calls ffunc', types = 'widget', widget='"button", "ffunc()", 10, 40, 100, 30', action='test.ffunc(3, 4)'} | ||
12 | |||
13 | test.bar = 'things' | ||
14 | test.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 | |||
3 | Seems to be several problems with linking in various OSes, here's some | ||
4 | possibly helpful links - | ||
5 | |||
6 | http://lua.2524044.n2.nabble.com/C-Lua-modules-not-compatible-with-every-Lua-interpreter-td7647522.html | ||
7 | http://lua-users.org/wiki/LuaProxyDllFour | ||
8 | http://stackoverflow.com/questions/11492194/how-do-you-create-a-lua-plugin-that-calls-the-c-lua-api?rq=1 | ||
9 | http://lua-users.org/lists/lua-l/2008-01/msg00671.html | ||
10 | */ | ||
11 | |||
12 | |||
13 | #include "GuiLua.h" | ||
14 | |||
15 | |||
16 | static const char *ourName = "test_c"; | ||
17 | int skang, _M; | ||
18 | |||
19 | static 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 | |||
30 | Lua's require() function will strip any stuff from the front of the name | ||
31 | separated by a hyphen, so 'ClientHamr-GuiLua-test_c' -> 'test_c'. Then | ||
32 | it will search through a path, and eventually find this test_c.so (or | ||
33 | test_c.dll or whatever), then call luaopen_test_c(), which should return | ||
34 | a table. The argument (only thing on the stack) for this function will | ||
35 | be 'test_c'. | ||
36 | |||
37 | Normally luaL_register() creates a table of functions, that is the table | ||
38 | returned, but we want to do something different with skang. | ||
39 | */ | ||
40 | int 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 | |||
10 | CDemo::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 | |||
21 | CDemo::~CDemo() | ||
22 | { | ||
23 | if (mapSelector) | ||
24 | mapSelector->drop(); | ||
25 | |||
26 | if (metaSelector) | ||
27 | metaSelector->drop(); | ||
28 | } | ||
29 | |||
30 | |||
31 | void 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 | |||
53 | void CDemo::preDraw(GLData *gld, u32 now) | ||
54 | { | ||
55 | if (((now - sceneStartTime) > timeForThisScene) && (timeForThisScene != -1)) | ||
56 | switchToNextScene(gld); | ||
57 | |||
58 | createParticleImpacts(); | ||
59 | } | ||
60 | |||
61 | |||
62 | bool 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 | |||
83 | void 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 | |||
212 | void 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 | |||
398 | void 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 | |||
474 | void 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 | |||
11 | const int CAMERA_COUNT = 7; | ||
12 | |||
13 | class CDemo : public IEventReceiver | ||
14 | { | ||
15 | public: | ||
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 | |||
26 | private: | ||
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 | |||
3 | local dir = ... | ||
4 | |||
5 | if '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 | ||
14 | end | ||
15 | |||
16 | CFLAGS = CFLAGS .. ' -I../../libraries/irrlicht-1.8.1/include -I/usr/X11R6/include' | ||
17 | LDFLAGS = LDFLAGS .. ' -L../../libraries/irrlicht-1.8.1/lib/Linux' | ||
18 | libs = libs .. ' -lIrrlicht -lGL -lbz2' | ||
19 | |||
20 | removeFiles(dir, {'../../extantz', 'crappisspuke.o', 'CDemo.o', 'extantzCamera.o', '../../media/extantz.edj'}) | ||
21 | |||
22 | runCommand('edje_cc', dir, 'edje_cc ' .. EDJE_FLAGS .. ' extantz.edc ../../media/extantz.edj') | ||
23 | runCommand('Irrlicht files', dir, 'g++ ' .. CFLAGS .. ' -O3 -ffast-math -c crappisspuke.cpp -o crappisspuke.o ' .. LDFLAGS) | ||
24 | runCommand(nil, dir, 'g++ ' .. CFLAGS .. ' -O3 -ffast-math -c CDemo.cpp -o CDemo.o ' .. LDFLAGS) | ||
25 | runCommand('extantz', dir, 'g++ ' .. CFLAGS .. ' -O3 -ffast-math -c extantzCamera.cpp -o extantzCamera.o ' .. LDFLAGS) | ||
26 | runCommand(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 | |||
7 | SExposedVideoData videoData; | ||
8 | |||
9 | IAnimatedMeshSceneNode *node; | ||
10 | CDemo *myDemo; | ||
11 | // This is the movement speed in units per second. | ||
12 | const 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 | ||
15 | u32 then; | ||
16 | |||
17 | #ifdef __cplusplus | ||
18 | extern "C" { | ||
19 | #endif | ||
20 | |||
21 | EAPI 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 - | ||
43 | 4. evas exposes an opengl-es2 api. any existing engine needs to be adapted to | ||
44 | use this. that's pretty much the end of that. if the engine doesn't have a | ||
45 | gles2 port.. it will need one. once it has one, then it is a simple matter of | ||
46 | replacing all the gl calls as follows: | ||
47 | |||
48 | glDrawArrays() -> api->glDrawArrays() | ||
49 | glBindBuffer() -> api->glBindBuffer() | ||
50 | |||
51 | you 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 | |||
59 | then fix up all the gl calls to be | ||
60 | |||
61 | EG()glDrawArrays() | ||
62 | EG()glBindBuffer() | ||
63 | |||
64 | etc. | ||
65 | |||
66 | doing the above allows evas to decide how to share context. it may allocate a | ||
67 | separate context or share its own. either way as far as the evasgl api user is | ||
68 | concerned.. they get their own private context to play with. if it does NOT do | ||
69 | the above (use the api exposed by evas gl) then wrapping can't context switches | ||
70 | can't work. all gl calls HAVE to go through the wrapped api to work right. this | ||
71 | is because we can't REPLACE the internals of the gl driver which otherwise | ||
72 | would be managing context and state all internally and we have zero access to | ||
73 | that - especially with closed drivers. we'd end up writing a proxy gl library | ||
74 | which conflicts with real gl symbol-wise (thus taking over and replacing | ||
75 | normal gl calls) and i know i have no interest in maintaining a separate | ||
76 | libGLwhatever.so that is an exact copy of gl and it's api's just to wrap it | ||
77 | when we expose that wrapper without symbol complications via evas gl. | ||
78 | |||
79 | 5. the engine will need to be adapted so the draw function is callable - eg by | ||
80 | elm_glview. then it's easy to switch where rendering happens. evas offers a fast | ||
81 | path to avoid buffer copies and make the gl view draw part of the evas | ||
82 | rendering path directly. this would offer almost zero overhead vs doing it | ||
83 | directly with egl/gles etc. to your backbuffer yourself, BUT gets you the bonus | ||
84 | of having your 3d view as part of a larger scenegraph. combine 2 or 3 of them | ||
85 | in a single window. overlay with evas objects or elm widgets for hud etc. all | ||
86 | for free. this also implies the engine has to integrate to the efl mainloop | ||
87 | etc. 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 | |||
228 | EAPI 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 | |||
266 | EAPI void drawIrr_end(GLData *gld) | ||
267 | { | ||
268 | IVideoDriver *driver = gld->driver; | ||
269 | |||
270 | if (gld->useIrr) | ||
271 | driver->endScene(); | ||
272 | } | ||
273 | |||
274 | EAPI 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 | |||
4 | int _log_domain = -1; | ||
5 | |||
6 | Eina_Hash *grids; | ||
7 | Eina_Hash *viewers; | ||
8 | |||
9 | static 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 | |||
17 | static 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 | |||
26 | static 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 | |||
36 | static Elm_Genlist_Item_Class *grid_gic = NULL; | ||
37 | static Elm_Genlist_Item_Class *account_gic = NULL; | ||
38 | static 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"; | ||
42 | static 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 | |||
52 | static 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 | */ | ||
73 | static 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 | |||
171 | static void free_gear(Gear *gear) | ||
172 | { | ||
173 | free(gear->vertices); | ||
174 | free(gear); | ||
175 | gear = NULL; | ||
176 | } | ||
177 | |||
178 | static 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 | |||
197 | static 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 | |||
214 | static 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 | |||
221 | static 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 | |||
244 | static 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 | ||
263 | static 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 | |||
294 | static 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 | |||
330 | static 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 | |||
393 | static 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 | |||
496 | static 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. | ||
536 | static 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. | ||
566 | static 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 | |||
575 | static 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. | ||
585 | static 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 | |||
614 | static 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 | |||
626 | static 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 | |||
715 | static 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. | ||
725 | static 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. | ||
772 | static 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. | ||
787 | static 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. | ||
797 | static 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 | |||
815 | static 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 | |||
932 | static 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 | |||
941 | static void _promote(void *data, Evas_Object *obj , void *event_info ) | ||
942 | { | ||
943 | elm_naviframe_item_promote(data); | ||
944 | } | ||
945 | |||
946 | static 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 | |||
967 | static 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 | |||
979 | static 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 | |||
991 | static 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 | |||
1003 | static 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 | |||
1015 | static 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 | |||
1028 | static 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 | |||
1041 | static 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 | |||
1079 | static 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 | |||
1106 | static 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 | |||
1122 | static 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 | |||
1146 | static 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 | |||
1158 | static 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 | |||
1203 | static 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 | |||
1238 | static 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 | |||
1385 | EAPI_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 | } | ||
1588 | ELM_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 @@ | |||
1 | externals { | ||
2 | external: "elm"; | ||
3 | } | ||
4 | |||
5 | collections { | ||
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 | |||
26 | ADD_CUBE(blue-cube, cube-blue); | ||
27 | ADD_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 | /* | ||
34 | In the Irrlicht Engine, everything can be found in the namespace 'irr'. So if | ||
35 | you want to use a class of the engine, you have to write irr:: before the name | ||
36 | of the class. For example to use the IrrlichtDevice write: irr::IrrlichtDevice. | ||
37 | To get rid of the irr:: in front of the name of every class, we tell the | ||
38 | compiler that we use that namespace from now on, and we will not have to write | ||
39 | irr:: anymore. | ||
40 | */ | ||
41 | using namespace irr; | ||
42 | |||
43 | /* | ||
44 | There are 5 sub namespaces in the Irrlicht Engine. Take a look at them, you can | ||
45 | read a detailed description of them in the documentation by clicking on the top | ||
46 | menu item 'Namespace List' or by using this link: | ||
47 | http://irrlicht.sourceforge.net/docu/namespaces.html | ||
48 | Like the irr namespace, we do not want these 5 sub namespaces now, to keep this | ||
49 | example simple. Hence, we tell the compiler again that we do not want always to | ||
50 | write their names. | ||
51 | */ | ||
52 | using namespace core; | ||
53 | using namespace scene; | ||
54 | using namespace video; | ||
55 | |||
56 | extern "C"{ | ||
57 | #else | ||
58 | |||
59 | // Irrlicht stuff. It's C++, so we gotta use incomplete types. | ||
60 | typedef struct IrrlichtDevice IrrlichtDevice; | ||
61 | typedef struct IVideoDriver IVideoDriver; | ||
62 | typedef struct ISceneManager ISceneManager; | ||
63 | typedef 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 | |||
74 | extern int _log_domain; | ||
75 | |||
76 | |||
77 | typedef struct _Gear Gear; | ||
78 | typedef struct _GLData GLData; | ||
79 | |||
80 | typedef enum | ||
81 | { | ||
82 | EZP_NONE, | ||
83 | EZP_AURORA, | ||
84 | EZP_OPENSIM, | ||
85 | EZP_SECOND_LIFE, | ||
86 | EZP_SLEDJHAMR, | ||
87 | EZP_TRITIUM | ||
88 | } ezPlatform; | ||
89 | |||
90 | typedef 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 | |||
101 | typedef 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; | ||
117 | GLData *gld; // Just a temporary evil hack to pass gld to _grid_sel_cb(). | ||
118 | } ezGrid; | ||
119 | |||
120 | typedef 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 | |||
129 | typedef 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 | |||
140 | struct _Gear | ||
141 | { | ||
142 | GLfloat *vertices; | ||
143 | GLuint vbo; | ||
144 | int count; | ||
145 | }; | ||
146 | |||
147 | // GL related data here. | ||
148 | struct _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 | |||
207 | EAPI int startIrr(GLData *gld); | ||
208 | EAPI void drawIrr_start(GLData *gld); | ||
209 | EAPI void drawIrr_end(GLData *gld); | ||
210 | EAPI 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 | |||
23 | namespace irr | ||
24 | { | ||
25 | namespace 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. | ||
30 | ICameraSceneNode *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), | ||
51 | extantzCamera::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 | ||
69 | extantzCamera::~extantzCamera() | ||
70 | { | ||
71 | // if (CursorControl) | ||
72 | // CursorControl->drop(); | ||
73 | } | ||
74 | |||
75 | |||
76 | void 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 | |||
240 | ISceneNodeAnimator* 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 | ||
248 | extern "C" { | ||
249 | #endif | ||
250 | |||
251 | cameraMove *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 | |||
17 | using namespace irr; | ||
18 | using namespace scene; | ||
19 | |||
20 | extern "C"{ | ||
21 | #else | ||
22 | typedef struct extantzCamera extantzCamera; | ||
23 | typedef struct ICameraSceneNode ICameraSceneNode; | ||
24 | #endif | ||
25 | |||
26 | typedef struct | ||
27 | { | ||
28 | float x, y, z; | ||
29 | float r, s, t; | ||
30 | float jump; | ||
31 | float JumpSpeed, RotateSpeed, MoveSpeed; | ||
32 | } cameraMove; | ||
33 | |||
34 | cameraMove *getCameraMove(ICameraSceneNode *camera); | ||
35 | |||
36 | #ifdef __cplusplus | ||
37 | } | ||
38 | |||
39 | |||
40 | //namespace irr::gui | ||
41 | //{ | ||
42 | // class ICursorControl; | ||
43 | //} | ||
44 | |||
45 | |||
46 | namespace irr | ||
47 | { | ||
48 | namespace 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 | |||