aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/extantz
diff options
context:
space:
mode:
Diffstat (limited to 'src/extantz')
-rw-r--r--src/extantz/CDemo.cpp510
-rw-r--r--src/extantz/CDemo.h63
-rwxr-xr-xsrc/extantz/build.lua26
-rw-r--r--src/extantz/crappisspuke.cpp294
-rw-r--r--src/extantz/extantz.c1588
-rw-r--r--src/extantz/extantz.edc30
-rw-r--r--src/extantz/extantz.h215
-rw-r--r--src/extantz/extantzCamera.cpp282
-rw-r--r--src/extantz/extantzCamera.h101
9 files changed, 3109 insertions, 0 deletions
diff --git a/src/extantz/CDemo.cpp b/src/extantz/CDemo.cpp
new file mode 100644
index 0000000..0ca40f1
--- /dev/null
+++ b/src/extantz/CDemo.cpp
@@ -0,0 +1,510 @@
1// This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt.
2// This file is not documented.
3
4#include <irrlicht.h>
5#include "extantz.h"
6#include "extantzCamera.h"
7#include "CDemo.h"
8
9
10CDemo::CDemo(GLData *gld, bool a)
11: additive(a),
12 device(gld->device),
13 currentScene(0),
14 quakeLevelMesh(0), quakeLevelNode(0), skyboxNode(0), model1(0), model2(0),
15 campFire(0), metaSelector(0), mapSelector(0), sceneStartTime(0),
16 timeForThisScene(0)
17{
18}
19
20
21CDemo::~CDemo()
22{
23 if (mapSelector)
24 mapSelector->drop();
25
26 if (metaSelector)
27 metaSelector->drop();
28}
29
30
31void CDemo::setup(GLData *gld)
32{
33 device = gld->device;
34 IrrlichtDevice *device = gld->device;
35// IVideoDriver *driver = gld->driver;
36// ISceneManager *smgr = gld->smgr;
37
38 if (device->getFileSystem()->existFile("irrlicht.dat"))
39 device->getFileSystem()->addFileArchive("irrlicht.dat");
40 else
41 device->getFileSystem()->addFileArchive("media/Irrlicht/irrlicht.dat");
42 if (device->getFileSystem()->existFile("map-20kdm2.pk3"))
43 device->getFileSystem()->addFileArchive("map-20kdm2.pk3");
44 else
45 device->getFileSystem()->addFileArchive("media/Irrlicht/map-20kdm2.pk3");
46
47 sceneStartTime = device->getTimer()->getTime();
48 timeForThisScene = 0;
49 loadSceneData();
50}
51
52
53void CDemo::preDraw(GLData *gld, u32 now)
54{
55 if (((now - sceneStartTime) > timeForThisScene) && (timeForThisScene != -1))
56 switchToNextScene(gld);
57
58 createParticleImpacts();
59}
60
61
62bool CDemo::OnEvent(const SEvent& event)
63{
64 if (!device)
65 return false;
66
67 if (( ((event.EventType == EET_KEY_INPUT_EVENT) && (event.KeyInput.Key == KEY_SPACE) && (event.KeyInput.PressedDown == false)) ||
68 ((event.EventType == EET_MOUSE_INPUT_EVENT) && (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)) ) && (currentScene == 3))
69 {
70 shoot();
71 }
72 else
73 if (device->getSceneManager()->getActiveCamera())
74 {
75 device->getSceneManager()->getActiveCamera()->OnEvent(event);
76 return true;
77 }
78
79 return false;
80}
81
82
83void CDemo::switchToNextScene(GLData *gld)
84{
85 currentScene++;
86 if (currentScene > 3)
87 currentScene = 1;
88
89 scene::ISceneManager* sm = device->getSceneManager();
90 scene::ISceneNodeAnimator* sa = 0;
91 scene::ICameraSceneNode* camera = 0;
92
93 camera = sm->getActiveCamera();
94
95 switch(currentScene)
96 {
97 case 1: // panorama camera
98 {
99 core::array<core::vector3df> points, points2;
100
101 points.push_back(core::vector3df(-931.473755f, 900.0f, 2000.0f)); // -49873
102 points.push_back(core::vector3df(-931.473755f, 900.0f, 2000.0f)); // -49873
103 points.push_back(core::vector3df(-931.473755f, 700.0f, 1750.0f)); // -49873
104 points.push_back(core::vector3df(-931.473755f, 500.0f, 1500.0f)); // -49873
105 points.push_back(core::vector3df(-931.473755f, 300.0f, 1250.0f)); // -49873
106 points.push_back(core::vector3df(-931.473755f, 200.0f, 1000.0f)); // -49873
107 points.push_back(core::vector3df(-931.473755f, 138.300003f, 987.279114f)); // -49873
108 points.push_back(core::vector3df(-847.902222f, 136.757553f, 915.792725f)); // -50559
109 points.push_back(core::vector3df(-748.680420f, 152.254501f, 826.418945f)); // -51964
110 points.push_back(core::vector3df(-708.428406f, 213.569580f, 784.466675f)); // -53251
111 points.push_back(core::vector3df(-686.217651f, 288.141174f, 762.965576f)); // -54015
112 points.push_back(core::vector3df(-679.685059f, 365.095612f, 756.551453f)); // -54733
113 points.push_back(core::vector3df(-671.317871f, 447.360107f, 749.394592f)); // -55588
114 points.push_back(core::vector3df(-669.468445f, 583.335632f, 747.711853f)); // -56178
115 points.push_back(core::vector3df(-667.611267f, 727.313232f, 746.018250f)); // -56757
116 points.push_back(core::vector3df(-665.853210f, 862.791931f, 744.436096f)); // -57859
117 points.push_back(core::vector3df(-642.649597f, 1026.047607f, 724.259827f)); // -59705
118 points.push_back(core::vector3df(-517.793884f, 838.396790f, 490.326050f)); // -60983
119 points.push_back(core::vector3df(-474.387299f, 715.691467f, 344.639984f)); // -61629
120 points.push_back(core::vector3df(-444.600250f, 601.155701f, 180.938095f)); // -62319
121 points.push_back(core::vector3df(-414.808899f, 479.691406f, 4.866660f)); // -63048
122 points.push_back(core::vector3df(-410.418945f, 429.642242f, -134.332687f)); // -63757
123 points.push_back(core::vector3df(-399.837585f, 411.498383f, -349.350983f)); // -64418
124 points.push_back(core::vector3df(-390.756653f, 403.970093f, -524.454407f)); // -65005
125 points.push_back(core::vector3df(-334.864227f, 350.065491f, -732.397400f)); // -65701
126 points.push_back(core::vector3df(-195.253387f, 349.577209f, -812.475891f)); // -66335
127 points.push_back(core::vector3df(16.255573f, 363.743134f, -833.800415f)); // -67170
128 points.push_back(core::vector3df(234.940964f, 352.957825f, -820.150696f)); // -67939
129 points.push_back(core::vector3df(436.797668f, 349.236450f, -816.914185f)); // -68596
130 points.push_back(core::vector3df(575.236206f, 356.244812f, -719.788513f)); // -69166
131 points.push_back(core::vector3df(594.131042f, 387.173828f, -609.675598f)); // -69744
132 points.push_back(core::vector3df(617.615234f, 412.002899f, -326.174072f)); // -70640
133 points.push_back(core::vector3df(606.456848f, 403.221954f, -104.179291f)); // -71390
134 points.push_back(core::vector3df(610.958252f, 407.037750f, 117.209778f)); // -72085
135 points.push_back(core::vector3df(597.956909f, 395.167877f, 345.942200f)); // -72817
136 points.push_back(core::vector3df(587.383118f, 391.444519f, 566.098633f)); // -73477
137 points.push_back(core::vector3df(559.572449f, 371.991333f, 777.689453f)); // -74124
138 points.push_back(core::vector3df(423.753204f, 329.990051f, 925.859741f)); // -74941
139 points.push_back(core::vector3df(247.520050f, 252.818954f, 935.311829f)); // -75651
140 points.push_back(core::vector3df(114.756012f, 199.799759f, 805.014160f));
141 points.push_back(core::vector3df(96.783348f, 181.639481f, 648.188110f));
142 points.push_back(core::vector3df(97.865623f, 138.905975f, 484.812561f));
143 points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
144 points.push_back(core::vector3df(99.0f, 95.0f, 347.0f));
145 points.push_back(core::vector3df(99.0f, 90.0f, 347.0f));
146 points.push_back(core::vector3df(99.0f, 85.0f, 347.0f));
147 points.push_back(core::vector3df(99.0f, 80.0f, 347.0f));
148 points.push_back(core::vector3df(99.0f, 75.0f, 347.0f));
149 points.push_back(core::vector3df(99.0f, 75.0f, 347.0f));
150 points.push_back(core::vector3df(99.0f, 75.0f, 347.0f));
151 timeForThisScene = (points.size() - 2) * 1000;
152 camera = sm->addCameraSceneNode(0, points[0], core::vector3df(0, 400, 0));
153 sa = sm->createFollowSplineAnimator(device->getTimer()->getTime(), points, 1.0f, 0.6f, false, false);
154 camera->addAnimator(sa);
155 sa->drop();
156 }
157 break;
158
159 case 2: // panorama camera
160 {
161 core::array<core::vector3df> points;
162
163 camera->setTarget(core::vector3df(100, 145, -80));
164
165 points.push_back(core::vector3df(99.0f, 75.0f, 347.0f));
166 points.push_back(core::vector3df(100.0f, 75.0f, 347.0f));
167 points.push_back(core::vector3df(105.0f, 75.0f, 347.0f));
168 points.push_back(core::vector3df(110.0f, 70.0f, 347.0f));
169 points.push_back(core::vector3df(115.0f, 70.0f, -160.0f));
170 points.push_back(core::vector3df(120.0f, 70.0f, -160.0f));
171 points.push_back(core::vector3df(125.0f, 65.0f, -160.0f));
172 points.push_back(core::vector3df(130.0f, 65.0f, -160.0f));
173 points.push_back(core::vector3df(135.0f, 65.0f, -160.0f));
174 points.push_back(core::vector3df(150.0f, 170.0f, -160.0f));
175 points.push_back(core::vector3df(150.0f, 170.0f, -160.0f));
176 points.push_back(core::vector3df(150.0f, 170.0f, -160.0f));
177 timeForThisScene = (points.size() - 2) * 1000;
178 sa = sm->createFollowSplineAnimator(device->getTimer()->getTime(), points, 1.0f, 0.6f, false, false);
179 camera->addAnimator(sa);
180 sa->drop();
181 }
182 break;
183
184 case 3: // interactive, go around
185 {
186 if (camera)
187 {
188 sm->setActiveCamera(0);
189 camera->remove();
190 camera = 0;
191 }
192 timeForThisScene = -1;
193
194 gld->camera = addExtantzCamera(sm, NULL, -1);
195 camera = gld->camera;
196 camera->setPosition(core::vector3df(108, 140, -140));
197 camera->setFarValue(5000.0f);
198 gld->move = getCameraMove(gld->camera);
199
200 scene::ISceneNodeAnimatorCollisionResponse* collider =
201 sm->createCollisionResponseAnimator(metaSelector, camera, core::vector3df(25, 50, 25), core::vector3df(0, quakeLevelMesh ? -10.f : 0.0f, 0), core::vector3df(0, 45, 0), 0.005f);
202 camera->addAnimator(collider);
203 collider->drop();
204 }
205 break;
206 }
207
208 sceneStartTime = device->getTimer()->getTime();
209}
210
211
212void CDemo::loadSceneData()
213{
214 // load quake level
215
216 video::IVideoDriver* driver = device->getVideoDriver();
217 scene::ISceneManager* sm = device->getSceneManager();
218
219 // Quake3 Shader controls Z-Writing
220 sm->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
221
222 quakeLevelMesh = (scene::IQ3LevelMesh*) sm->getMesh("maps/20kdm2.bsp");
223
224 if (quakeLevelMesh)
225 {
226 u32 i;
227
228 //move all quake level meshes (non-realtime)
229 core::matrix4 m;
230 m.setTranslation(core::vector3df(-1300,-70,-1249));
231
232 for (i = 0; i != scene::quake3::E_Q3_MESH_SIZE; ++i)
233 sm->getMeshManipulator()->transform(quakeLevelMesh->getMesh(i), m);
234
235 quakeLevelNode = sm->addOctreeSceneNode(quakeLevelMesh->getMesh( scene::quake3::E_Q3_MESH_GEOMETRY));
236 if (quakeLevelNode)
237 {
238 //quakeLevelNode->setPosition(core::vector3df(-1300, -70, -1249));
239 quakeLevelNode->setVisible(true);
240
241 // create map triangle selector
242 mapSelector = sm->createOctreeTriangleSelector(quakeLevelMesh->getMesh(0), quakeLevelNode, 128);
243
244 // if not using shader and no gamma it's better to use more lighting, because
245 // quake3 level are usually dark
246 quakeLevelNode->setMaterialType(video::EMT_LIGHTMAP_M4);
247
248 // set additive blending if wanted
249 if (additive)
250 quakeLevelNode->setMaterialType(video::EMT_LIGHTMAP_ADD);
251 }
252
253 // the additional mesh can be quite huge and is unoptimized
254 scene::IMesh *additional_mesh = quakeLevelMesh->getMesh(scene::quake3::E_Q3_MESH_ITEMS);
255
256 for (i = 0; i != additional_mesh->getMeshBufferCount(); ++i)
257 {
258 scene::IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer(i);
259 const video::SMaterial &material = meshBuffer->getMaterial();
260
261 //! The ShaderIndex is stored in the material parameter
262 s32 shaderIndex = (s32) material.MaterialTypeParam2;
263
264 // the meshbuffer can be rendered without additional support, or it has no shader
265 const scene::quake3::IShader *shader = quakeLevelMesh->getShader(shaderIndex);
266 if (0 == shader)
267 {
268 continue;
269 }
270 // Now add the MeshBuffer(s) with the current Shader to the Manager
271 sm->addQuake3SceneNode(meshBuffer, shader);
272 }
273 }
274
275 // load sydney model and create 2 instances
276
277 scene::IAnimatedMesh *mesh = 0;
278 mesh = sm->getMesh("media/Irrlicht/sydney.md2");
279 if (mesh)
280 {
281 model1 = sm->addAnimatedMeshSceneNode(mesh);
282 if (model1)
283 {
284 model1->setMaterialTexture(0, driver->getTexture("media/Irrlicht/sydney.bmp"));
285 model1->setPosition(core::vector3df(100, 40, -80));
286 model1->setScale(core::vector3df(2, 2, 2));
287 model1->setMD2Animation(scene::EMAT_STAND);
288 model1->setMaterialFlag(video::EMF_LIGHTING, true);
289 model1->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
290 model1->addShadowVolumeSceneNode();
291 }
292
293 model2 = sm->addAnimatedMeshSceneNode(mesh);
294 if (model2)
295 {
296 model2->setMaterialTexture(0, driver->getTexture("media/Irrlicht/spheremap.jpg"));
297 model2->setPosition(core::vector3df(180, 15, -60));
298 model2->setScale(core::vector3df(2, 2, 2));
299 model2->setMD2Animation(scene::EMAT_RUN);
300 model2->setMaterialFlag(video::EMF_LIGHTING, false);
301 model2->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
302 model2->setMaterialType(video::EMT_SPHERE_MAP);
303 model2->addShadowVolumeSceneNode();
304 }
305 }
306
307 scene::ISceneNodeAnimator *anim = 0;
308
309 // create sky box
310 driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
311 skyboxNode = sm->addSkyBoxSceneNode(
312 driver->getTexture("media/Irrlicht/irrlicht2_up.jpg"),
313 driver->getTexture("media/Irrlicht/irrlicht2_dn.jpg"),
314 driver->getTexture("media/Irrlicht/irrlicht2_lf.jpg"),
315 driver->getTexture("media/Irrlicht/irrlicht2_rt.jpg"),
316 driver->getTexture("media/Irrlicht/irrlicht2_ft.jpg"),
317 driver->getTexture("media/Irrlicht/irrlicht2_bk.jpg"));
318 driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
319
320 // create walk-between-portals animation
321 core::vector3df waypoint[2];
322 waypoint[0].set(-150, 40, 100);
323 waypoint[1].set(350, 40, 100);
324
325 if (model2)
326 {
327 anim = device->getSceneManager()->createFlyStraightAnimator(waypoint[0], waypoint[1], 2000, true);
328 model2->addAnimator(anim);
329 anim->drop();
330 }
331
332 // create animation for portals;
333 core::array<video::ITexture*> textures;
334 for (s32 g=1; g<8; ++g)
335 {
336 core::stringc tmp("media/Irrlicht/portal");
337 tmp += g;
338 tmp += ".bmp";
339 video::ITexture* t = driver->getTexture(tmp);
340 textures.push_back(t);
341 }
342
343 anim = sm->createTextureAnimator(textures, 100);
344
345 // create portals
346 scene::IBillboardSceneNode* bill = 0;
347 for (int r = 0; r < 2; ++r)
348 {
349 bill = sm->addBillboardSceneNode(0, core::dimension2d<f32>(100, 100), waypoint[r]+ core::vector3df(0, 20, 0));
350 bill->setMaterialFlag(video::EMF_LIGHTING, false);
351 bill->setMaterialTexture(0, driver->getTexture("media/Irrlicht/portal1.bmp"));
352 bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
353 bill->addAnimator(anim);
354 }
355
356 anim->drop();
357
358 // create circle flying dynamic light with transparent billboard attached
359 scene::ILightSceneNode *light = 0;
360
361 light = sm->addLightSceneNode(0, core::vector3df(0, 0, 0), video::SColorf(1.0f, 1.0f, 1.f, 1.0f), 500.f);
362 anim = sm->createFlyCircleAnimator(core::vector3df(100, 150, 80), 80.0f, 0.0005f);
363
364 light->addAnimator(anim);
365 anim->drop();
366
367 bill = device->getSceneManager()->addBillboardSceneNode(light, core::dimension2d<f32>(40, 40));
368 bill->setMaterialFlag(video::EMF_LIGHTING, false);
369 bill->setMaterialTexture(0, driver->getTexture("media/Irrlicht/particlewhite.bmp"));
370 bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
371
372 // create meta triangle selector with all triangles selectors in it.
373 metaSelector = sm->createMetaTriangleSelector();
374 metaSelector->addTriangleSelector(mapSelector);
375
376 // create camp fire
377 campFire = sm->addParticleSystemSceneNode(false);
378 campFire->setPosition(core::vector3df(100, 120, 600));
379 campFire->setScale(core::vector3df(2, 2, 2));
380
381 scene::IParticleEmitter *em = campFire->createBoxEmitter(core::aabbox3d<f32>(-7, 0, -7, 7, 1, 7), core::vector3df(0.0f, 0.06f, 0.0f), 80, 100, video::SColor(1, 255, 255, 255), video::SColor(1, 255, 255, 255), 800, 2000);
382 em->setMinStartSize(core::dimension2d<f32>(20.0f, 10.0f));
383 em->setMaxStartSize(core::dimension2d<f32>(20.0f, 10.0f));
384 campFire->setEmitter(em);
385 em->drop();
386
387 scene::IParticleAffector *paf = campFire->createFadeOutParticleAffector();
388 campFire->addAffector(paf);
389 paf->drop();
390
391 campFire->setMaterialFlag(video::EMF_LIGHTING, false);
392 campFire->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
393 campFire->setMaterialTexture(0, driver->getTexture("media/Irrlicht/fireball.bmp"));
394 campFire->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
395}
396
397
398void CDemo::shoot()
399{
400 scene::ISceneManager *sm = device->getSceneManager();
401 scene::ICameraSceneNode *camera = sm->getActiveCamera();
402
403 if ((!camera) || (!mapSelector))
404 return;
405
406 SParticleImpact imp;
407 imp.when = 0;
408
409 // get line of camera
410 core::vector3df start = camera->getPosition();
411 core::vector3df end = (camera->getTarget() - start);
412 end.normalize();
413 start += end * 8.0f;
414 end = start + (end * camera->getFarValue());
415
416 core::triangle3df triangle;
417
418 core::line3d<f32> line(start, end);
419
420 // get intersection point with map
421 scene::ISceneNode* hitNode;
422 if (sm->getSceneCollisionManager()->getCollisionPoint(line, mapSelector, end, triangle, hitNode))
423 {
424 // collides with wall
425 core::vector3df out = triangle.getNormal();
426 out.setLength(0.03f);
427
428 imp.when = 1;
429 imp.outVector = out;
430 imp.pos = end;
431 }
432 else
433 {
434 // doesnt collide with wall
435 core::vector3df start = camera->getPosition();
436 core::vector3df end = (camera->getTarget() - start);
437 end.normalize();
438 start += end * 8.0f;
439 end = start + (end * camera->getFarValue());
440 }
441
442 // create fire ball
443 scene::ISceneNode *node = 0;
444 node = sm->addBillboardSceneNode(0, core::dimension2d<f32>(25, 25), start);
445
446 node->setMaterialFlag(video::EMF_LIGHTING, false);
447 node->setMaterialTexture(0, device->getVideoDriver()->getTexture("media/Irrlicht/fireball.bmp"));
448 node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
449
450 f32 length = (f32)(end - start).getLength();
451 const f32 speed = 0.6f;
452 u32 time = (u32) (length / speed);
453
454 scene::ISceneNodeAnimator *anim = 0;
455
456 // set flight line
457 anim = sm->createFlyStraightAnimator(start, end, time);
458 node->addAnimator(anim);
459 anim->drop();
460
461 anim = sm->createDeleteAnimator(time);
462 node->addAnimator(anim);
463 anim->drop();
464
465 if (imp.when)
466 {
467 // create impact note
468 imp.when = device->getTimer()->getTime() + (time - 100);
469 Impacts.push_back(imp);
470 }
471}
472
473
474void CDemo::createParticleImpacts()
475{
476 u32 now = device->getTimer()->getTime();
477 scene::ISceneManager *sm = device->getSceneManager();
478
479 for (s32 i = 0; i < (s32) Impacts.size(); ++i)
480 if (now > Impacts[i].when)
481 {
482 // create smoke particle system
483 scene::IParticleSystemSceneNode *pas = 0;
484
485 pas = sm->addParticleSystemSceneNode(false, 0, -1, Impacts[i].pos);
486
487 pas->setParticleSize(core::dimension2d<f32>(10.0f, 10.0f));
488
489 scene::IParticleEmitter* em = pas->createBoxEmitter(core::aabbox3d<f32>(-5, -5, -5, 5, 5, 5), Impacts[i].outVector, 20, 40, video::SColor(50, 255, 255, 255), video::SColor(50, 255, 255, 255), 1200, 1600, 20);
490 pas->setEmitter(em);
491 em->drop();
492
493 scene::IParticleAffector *paf = campFire->createFadeOutParticleAffector();
494 pas->addAffector(paf);
495 paf->drop();
496
497 pas->setMaterialFlag(video::EMF_LIGHTING, false);
498 pas->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
499 pas->setMaterialTexture(0, device->getVideoDriver()->getTexture("media/Irrlicht/smoke.bmp"));
500 pas->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
501
502 scene::ISceneNodeAnimator *anim = sm->createDeleteAnimator(2000);
503 pas->addAnimator(anim);
504 anim->drop();
505
506 // delete entry
507 Impacts.erase(i);
508 i--;
509 }
510}
diff --git a/src/extantz/CDemo.h b/src/extantz/CDemo.h
new file mode 100644
index 0000000..035c01f
--- /dev/null
+++ b/src/extantz/CDemo.h
@@ -0,0 +1,63 @@
1// This is a Demo of the Irrlicht Engine (c) 2006 by N.Gebhardt.
2// This file is not documented.
3
4#ifndef __C_DEMO_H_INCLUDED__
5#define __C_DEMO_H_INCLUDED__
6
7#ifdef _IRR_WINDOWS_
8#include <windows.h>
9#endif
10
11const int CAMERA_COUNT = 7;
12
13class CDemo : public IEventReceiver
14{
15public:
16
17 CDemo(GLData *gld, bool additive);
18
19 ~CDemo();
20
21 void setup(GLData *gld);
22 void preDraw(GLData *gld, u32 now);
23
24 virtual bool OnEvent(const SEvent& event);
25
26private:
27
28 void createLoadingScreen();
29 void loadSceneData();
30 void switchToNextScene(GLData *gld);
31 void shoot();
32 void createParticleImpacts();
33
34 bool additive;
35 IrrlichtDevice *device;
36
37 struct SParticleImpact
38 {
39 u32 when;
40 core::vector3df pos;
41 core::vector3df outVector;
42 };
43
44 int currentScene;
45
46 scene::IQ3LevelMesh* quakeLevelMesh;
47 scene::ISceneNode* quakeLevelNode;
48 scene::ISceneNode* skyboxNode;
49 scene::IAnimatedMeshSceneNode* model1;
50 scene::IAnimatedMeshSceneNode* model2;
51 scene::IParticleSystemSceneNode* campFire;
52
53 scene::IMetaTriangleSelector* metaSelector;
54 scene::ITriangleSelector* mapSelector;
55
56 s32 sceneStartTime;
57 s32 timeForThisScene;
58
59 core::array<SParticleImpact> Impacts;
60};
61
62#endif
63
diff --git a/src/extantz/build.lua b/src/extantz/build.lua
new file mode 100755
index 0000000..0bb2a0b
--- /dev/null
+++ b/src/extantz/build.lua
@@ -0,0 +1,26 @@
1#!/usr/bin/env lua
2
3local dir = ...
4
5if 'nil' == type(dir) then
6 local build, err = loadfile('../../build.lua')
7 if build then
8 setfenv(build, getfenv(2))
9 build(2)
10 else
11 print("ERROR - " .. err)
12 end
13 dir = workingDir
14end
15
16CFLAGS = CFLAGS .. ' -I../../libraries/irrlicht-1.8.1/include -I/usr/X11R6/include'
17LDFLAGS = LDFLAGS .. ' -L../../libraries/irrlicht-1.8.1/lib/Linux'
18libs = libs .. ' -lIrrlicht -lGL -lbz2'
19
20removeFiles(dir, {'../../extantz', 'crappisspuke.o', 'CDemo.o', 'extantzCamera.o', '../../media/extantz.edj'})
21
22runCommand('edje_cc', dir, 'edje_cc ' .. EDJE_FLAGS .. ' extantz.edc ../../media/extantz.edj')
23runCommand('Irrlicht files', dir, 'g++ ' .. CFLAGS .. ' -O3 -ffast-math -c crappisspuke.cpp -o crappisspuke.o ' .. LDFLAGS)
24runCommand(nil, dir, 'g++ ' .. CFLAGS .. ' -O3 -ffast-math -c CDemo.cpp -o CDemo.o ' .. LDFLAGS)
25runCommand('extantz', dir, 'g++ ' .. CFLAGS .. ' -O3 -ffast-math -c extantzCamera.cpp -o extantzCamera.o ' .. LDFLAGS)
26runCommand(nil, dir, 'gcc ' .. CFLAGS .. ' extantz.c crappisspuke.o CDemo.o extantzCamera.o -o ../../extantz ' .. LDFLAGS .. ' ' .. libs)
diff --git a/src/extantz/crappisspuke.cpp b/src/extantz/crappisspuke.cpp
new file mode 100644
index 0000000..2af9dde
--- /dev/null
+++ b/src/extantz/crappisspuke.cpp
@@ -0,0 +1,294 @@
1
2#include <irrlicht.h>
3#include "extantz.h"
4#include "CDemo.h"
5
6
7SExposedVideoData videoData;
8
9IAnimatedMeshSceneNode *node;
10CDemo *myDemo;
11// This is the movement speed in units per second.
12const f32 MOVEMENT_SPEED = 5.f;
13// In order to do framerate independent movement, we have to know
14// how long it was since the last frame
15u32 then;
16
17#ifdef __cplusplus
18extern "C" {
19#endif
20
21EAPI int startIrr(GLData *gld)
22{
23 SIrrlichtCreationParameters params;
24 IrrlichtDevice *device;
25 IVideoDriver *driver;
26 ISceneManager *smgr;
27 bool additive = true;
28
29 if (!gld->useIrr)
30 return 1; // Return 1 so that the caller stops asking on each frame.
31
32#if USE_IRR
33 void *display = NULL;
34 unsigned long sfc = 0;
35 void *ctx = NULL;
36// Evas_GL_API *gl = gld->glApi;
37
38#if USE_DEMO
39 myDemo = new CDemo(gld, additive);
40#endif
41
42/* Raster says -
434. evas exposes an opengl-es2 api. any existing engine needs to be adapted to
44use this. that's pretty much the end of that. if the engine doesn't have a
45gles2 port.. it will need one. once it has one, then it is a simple matter of
46replacing all the gl calls as follows:
47
48glDrawArrays() -> api->glDrawArrays()
49glBindBuffer() -> api->glBindBuffer()
50
51you could make the port switchable with a macro:
52
53#ifdef EVASGL
54#define EG() my_evas_gl_api->
55#else
56#define EG()
57#endif
58
59then fix up all the gl calls to be
60
61EG()glDrawArrays()
62EG()glBindBuffer()
63
64etc.
65
66doing the above allows evas to decide how to share context. it may allocate a
67separate context or share its own. either way as far as the evasgl api user is
68concerned.. they get their own private context to play with. if it does NOT do
69the above (use the api exposed by evas gl) then wrapping can't context switches
70can't work. all gl calls HAVE to go through the wrapped api to work right. this
71is because we can't REPLACE the internals of the gl driver which otherwise
72would be managing context and state all internally and we have zero access to
73that - especially with closed drivers. we'd end up writing a proxy gl library
74which conflicts with real gl symbol-wise (thus taking over and replacing
75normal gl calls) and i know i have no interest in maintaining a separate
76libGLwhatever.so that is an exact copy of gl and it's api's just to wrap it
77when we expose that wrapper without symbol complications via evas gl.
78
795. the engine will need to be adapted so the draw function is callable - eg by
80elm_glview. then it's easy to switch where rendering happens. evas offers a fast
81path to avoid buffer copies and make the gl view draw part of the evas
82rendering path directly. this would offer almost zero overhead vs doing it
83directly with egl/gles etc. to your backbuffer yourself, BUT gets you the bonus
84of having your 3d view as part of a larger scenegraph. combine 2 or 3 of them
85in a single window. overlay with evas objects or elm widgets for hud etc. all
86for free. this also implies the engine has to integrate to the efl mainloop
87etc. of course.
88*/
89
90
91 sfc = ecore_evas_window_get(gld->ee);
92 // This is the way Raster wants me to do things, but these functions are not actually available. Pffft
93// ctx = gl->glGetCurrentContext();
94// display = gl->glGetCurrentDisplay();
95 ctx = glXGetCurrentContext();
96 display = glXGetCurrentDisplay();
97 /* For using a pre existing X11 window (with optional OpenGL). */
98 videoData = SExposedVideoData();
99 videoData.OpenGLLinux.X11Display = display; // void * - Connection to the X server.
100 videoData.OpenGLLinux.X11Window = sfc; // unsigned long - Specifies a GLX drawable. Must be either an X window ID or a GLX pixmap ID.
101 videoData.OpenGLLinux.X11Context = ctx; // void * - Specifies a GLX rendering context that is to be attached to drawable.
102
103 /*
104 The most important function of the engine is the createDevice()
105 function. The IrrlichtDevice is created by it, which is the root
106 object for doing anything with the engine. createDevice() has 7
107 parameters:
108
109 - deviceType: Type of the device. This can currently be the Null-device,
110 one of the two software renderers, D3D8, D3D9, or OpenGL. In this
111 example we use EDT_SOFTWARE, but to try out, you might want to
112 change it to EDT_BURNINGSVIDEO, EDT_NULL, EDT_DIRECT3D8,
113 EDT_DIRECT3D9, or EDT_OPENGL.
114
115 - windowSize: Size of the Window or screen in FullScreenMode to be
116 created. In this example we use 640x480.
117
118 - bits: Amount of color bits per pixel. This should be 16 or 32. The
119 parameter is often ignored when running in windowed mode.
120
121 - fullscreen: Specifies if we want the device to run in fullscreen mode
122 or not.
123
124 - stencilbuffer: Specifies if we want to use the stencil buffer (for
125 drawing shadows).
126
127 - vsync: Specifies if we want to have vsync enabled, this is only useful
128 in fullscreen mode.
129
130 - eventReceiver: An object to receive events. We do not want to use this
131 parameter here, and set it to 0.
132
133 Always check the return value to cope with unsupported drivers,
134 dimensions, etc.
135 */
136
137 params.DeviceType = EIDT_X11; // EIDT_BEST might be preferable.
138 if (ctx)
139 params.DriverType = video::EDT_OPENGL;
140 else
141 params.DriverType = video::EDT_BURNINGSVIDEO;
142 params.WindowSize = dimension2d<u32>(gld->sfc_w, gld->sfc_h);
143 params.Bits = 32; // Ignored in windowed mode?
144 params.ZBufferBits = 16; // Default 16.
145 params.Fullscreen = false; // The default anyway.
146 params.Stencilbuffer = false; // For shadows.
147 params.Vsync = false;
148 params.AntiAlias=true;
149 params.WithAlphaChannel = true;
150 params.IgnoreInput = true;
151 params.EventReceiver = myDemo; // Probably useless, EFL might not let Irrlicht grab the input.
152 params.WindowId = (void *) videoData.OpenGLLinux.X11Window;
153 params.VideoData = &videoData;
154
155 device = createDeviceEx(params);
156
157 if (!device)
158 return 0;
159 gld->device = device;
160
161 /*
162 Get a pointer to the VideoDriver and the SceneManager so that we do not always have to write
163 device->getVideoDriver() or device->getSceneManager().
164 */
165 driver = device->getVideoDriver(); gld->driver = driver;
166 smgr = device->getSceneManager(); gld->smgr = smgr;
167
168 // FIXME - this is what makes the window vanish in EFL 1.8, but worked fine in 1.7 I think.
169// device->setResizable(true);
170 driver->OnResize(dimension2d<u32>(gld->img_w, gld->img_h));
171 // Just gives me a blank screen. grrrr
172// driver->setViewPort(rect<s32>(0, 0, gld->img_w, gld->img_h));
173
174 // set ambient light
175 smgr->setAmbientLight (video::SColorf(0x00c0c0c0));
176
177#if USE_DEMO
178 myDemo->setup(gld);
179#else
180 /*
181 To show something interesting, we load a Quake 2 model and display it.
182 We only have to get the Mesh from the Scene Manager with getMesh() and add
183 a SceneNode to display the mesh with addAnimatedMeshSceneNode(). We
184 check the return value of getMesh() to become aware of loading problems
185 and other errors.
186
187 Instead of writing the filename sydney.md2, it would also be possible
188 to load a Maya object file (.obj), a complete Quake3 map (.bsp) or any
189 other supported file format. By the way, that cool Quake 2 model
190 called sydney was modelled by Brian Collins.
191 */
192 IAnimatedMesh* mesh = smgr->getMesh("media/Irrlicht/sydney.md2");
193 if (!mesh)
194 {
195 device->drop();
196 return 0;
197 }
198 node = smgr->addAnimatedMeshSceneNode(mesh);
199
200 /*
201 To let the mesh look a little bit nicer, we change its material. We
202 disable lighting because we do not have a dynamic light in here, and
203 the mesh would be totally black otherwise. Then we set the frame loop,
204 such that the predefined STAND animation is used. And last, we apply a
205 texture to the mesh. Without it the mesh would be drawn using only a
206 color.
207 */
208 if (node)
209 {
210// node->setMaterialFlag(EMF_LIGHTING, false);
211 node->setMD2Animation(scene::EMAT_STAND);
212 node->setMaterialTexture(0, driver->getTexture("media/Irrlicht/sydney.bmp"));
213 }
214
215 /*
216 To look at the mesh, we place a camera into 3d space at the position
217 (0, 30, -40). The camera looks from there to (0,5,0), which is
218 approximately the place where our md2 model is.
219 */
220 smgr->addCameraSceneNode(0, vector3df(50, 70, -65), vector3df(0, 50, 0));
221#endif
222
223 then = device->getTimer()->getTime();
224#endif
225 return 1;
226}
227
228EAPI void drawIrr_start(GLData *gld)
229{
230 if (gld->useIrr)
231 {
232 IrrlichtDevice *device = gld->device;
233 IVideoDriver *driver = gld->driver;
234 ISceneManager *smgr = gld->smgr;
235
236 // Increase virtual timer time, instead of device->run() if doing our own input processing.
237 device->getTimer()->tick();
238
239 // Work out a frame delta time.
240 const u32 now = device->getTimer()->getTime();
241// const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
242 then = now;
243
244
245#if USE_DEMO
246 myDemo->preDraw(gld, now);
247#else
248 core::vector3df nodePosition = node->getPosition();
249// nodePosition.Y -= MOVEMENT_SPEED * frameDeltaTime;
250 node->setPosition(nodePosition);
251#endif
252
253 /*
254 Anything can be drawn between a beginScene() and an endScene()
255 call. The beginScene() call clears the screen with a color and
256 the depth buffer, if desired. Then we let the Scene Manager and
257 the GUI Environment draw their content. With the endScene()
258 call everything is presented on the screen.
259 */
260 driver->beginScene(true, true, SColor(255, 255, 255, 255), videoData, NULL); // This does the context change, then clearBuffers()
261
262 smgr->drawAll();
263 }
264}
265
266EAPI void drawIrr_end(GLData *gld)
267{
268 IVideoDriver *driver = gld->driver;
269
270 if (gld->useIrr)
271 driver->endScene();
272}
273
274EAPI void finishIrr(GLData *gld)
275{
276 IrrlichtDevice *device = gld->device;
277
278 /*
279 After we are done with the render loop, we have to delete the Irrlicht
280 Device created before with createDevice(). In the Irrlicht Engine, you
281 have to delete all objects you created with a method or function which
282 starts with 'create'. The object is simply deleted by calling ->drop().
283 See the documentation at irr::IReferenceCounted::drop() for more
284 information.
285 */
286 if (gld->useIrr)
287 device->drop();
288}
289
290
291#ifdef __cplusplus
292}
293#endif
294
diff --git a/src/extantz/extantz.c b/src/extantz/extantz.c
new file mode 100644
index 0000000..09b5196
--- /dev/null
+++ b/src/extantz/extantz.c
@@ -0,0 +1,1588 @@
1#include "extantz.h"
2
3
4int _log_domain = -1;
5
6Eina_Hash *grids;
7Eina_Hash *viewers;
8
9static char *gridTest[][3] =
10{
11 {"3rd Rock Grid", "http://grid.3rdrockgrid.com:8002/", "http://grid.3rdrockgrid.com/3rg_login"},
12 {"Infinite Grid", "http://grid.infinitegrid.org:8002/", "http://www.infinitegrid.org/loginscreen.php"},
13 {"Second Life Grid", "https://login.agni.lindenlab.com/cgi-bin/login.cgi", "http://secondlife.com/"},
14 {NULL, NULL, NULL}
15};
16
17static char *accountTest[][3] =
18{
19 {"3rd Rock Grid", "onefang rejected", "password"},
20 {"Infinite Grid", "infinite onefang", "MyB1GSecrit"},
21 {"Infinite Grid", "onefang rejected", "MySecrit"},
22 {NULL, NULL, NULL}
23};
24
25
26static char *viewerTest[][3] =
27{
28 {"Imprudence", "1.4.0 beta 3", ""},
29 {"Kokua", "3.4.4.25633", ""},
30 {"meta-impy", "1.4.0 beta 1.5", ""},
31 {"SL", "v3", ""},
32 {NULL, NULL, NULL}
33};
34
35
36static Elm_Genlist_Item_Class *grid_gic = NULL;
37static Elm_Genlist_Item_Class *account_gic = NULL;
38static Elm_Genlist_Item_Class *viewer_gic = NULL;
39
40//static const char *img1 = PACKAGE_DATA_DIR "/media/plant_01.jpg";
41//static const char *img2 = PACKAGE_DATA_DIR "/media/sky_01.jpg";
42static const char *img3 = PACKAGE_DATA_DIR "/media/rock_01.jpg";
43
44
45#define EPHYSICS_TEST_THEME "extantz"
46
47
48#if DO_GEARS
49//--------------------------------//
50// Gear Stuff.
51
52static GLfloat *vert(GLfloat *p, GLfloat x, GLfloat y, GLfloat z, GLfloat *n)
53{
54 p[0] = x;
55 p[1] = y;
56 p[2] = z;
57 p[3] = n[0];
58 p[4] = n[1];
59 p[5] = n[2];
60
61 return p + 6;
62}
63
64/* Draw a gear wheel. You'll probably want to call this function when
65 * building a display list since we do a lot of trig here.
66 *
67 * Input: inner_radius - radius of hole at center
68 * outer_radius - radius at center of teeth
69 * width - width of gear
70 * teeth - number of teeth
71 * tooth_depth - depth of tooth
72 */
73static Gear *make_gear(GLData *gld, GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth)
74{
75 GLint i;
76 GLfloat r0, r1, r2;
77 GLfloat da;
78 GLfloat *v;
79 Gear *gear;
80 double s[5], c[5];
81 GLfloat normal[3];
82 const int tris_per_tooth = 20;
83 Evas_GL_API *gl = gld->glApi;
84
85 gear = (Gear*)malloc(sizeof(Gear));
86 if (gear == NULL)
87 return NULL;
88
89 r0 = inner_radius;
90 r1 = outer_radius - tooth_depth / 2.0;
91 r2 = outer_radius + tooth_depth / 2.0;
92
93 da = 2.0 * M_PI / teeth / 4.0;
94
95 gear->vertices = calloc(teeth * tris_per_tooth * 3 * 6, sizeof *gear->vertices);
96 s[4] = 0;
97 c[4] = 1;
98 v = gear->vertices;
99 for (i = 0; i < teeth; i++)
100 {
101 s[0] = s[4];
102 c[0] = c[4];
103 s[1] = sin(i * 2.0 * M_PI / teeth + da);
104 c[1] = cos(i * 2.0 * M_PI / teeth + da);
105 s[2] = sin(i * 2.0 * M_PI / teeth + da * 2);
106 c[2] = cos(i * 2.0 * M_PI / teeth + da * 2);
107 s[3] = sin(i * 2.0 * M_PI / teeth + da * 3);
108 c[3] = cos(i * 2.0 * M_PI / teeth + da * 3);
109 s[4] = sin(i * 2.0 * M_PI / teeth + da * 4);
110 c[4] = cos(i * 2.0 * M_PI / teeth + da * 4);
111
112 normal[0] = 0.0;
113 normal[1] = 0.0;
114 normal[2] = 1.0;
115
116 v = vert(v, r2 * c[1], r2 * s[1], width * 0.5, normal);
117
118 v = vert(v, r2 * c[1], r2 * s[1], width * 0.5, normal);
119 v = vert(v, r2 * c[2], r2 * s[2], width * 0.5, normal);
120 v = vert(v, r1 * c[0], r1 * s[0], width * 0.5, normal);
121 v = vert(v, r1 * c[3], r1 * s[3], width * 0.5, normal);
122 v = vert(v, r0 * c[0], r0 * s[0], width * 0.5, normal);
123 v = vert(v, r1 * c[4], r1 * s[4], width * 0.5, normal);
124 v = vert(v, r0 * c[4], r0 * s[4], width * 0.5, normal);
125
126 v = vert(v, r0 * c[4], r0 * s[4], width * 0.5, normal);
127 v = vert(v, r0 * c[0], r0 * s[0], width * 0.5, normal);
128 v = vert(v, r0 * c[4], r0 * s[4], -width * 0.5, normal);
129 v = vert(v, r0 * c[0], r0 * s[0], -width * 0.5, normal);
130
131 normal[0] = 0.0;
132 normal[1] = 0.0;
133 normal[2] = -1.0;
134
135 v = vert(v, r0 * c[4], r0 * s[4], -width * 0.5, normal);
136
137 v = vert(v, r0 * c[4], r0 * s[4], -width * 0.5, normal);
138 v = vert(v, r1 * c[4], r1 * s[4], -width * 0.5, normal);
139 v = vert(v, r0 * c[0], r0 * s[0], -width * 0.5, normal);
140 v = vert(v, r1 * c[3], r1 * s[3], -width * 0.5, normal);
141 v = vert(v, r1 * c[0], r1 * s[0], -width * 0.5, normal);
142 v = vert(v, r2 * c[2], r2 * s[2], -width * 0.5, normal);
143 v = vert(v, r2 * c[1], r2 * s[1], -width * 0.5, normal);
144
145 v = vert(v, r1 * c[0], r1 * s[0], width * 0.5, normal);
146
147 v = vert(v, r1 * c[0], r1 * s[0], width * 0.5, normal);
148 v = vert(v, r1 * c[0], r1 * s[0], -width * 0.5, normal);
149 v = vert(v, r2 * c[1], r2 * s[1], width * 0.5, normal);
150 v = vert(v, r2 * c[1], r2 * s[1], -width * 0.5, normal);
151 v = vert(v, r2 * c[2], r2 * s[2], width * 0.5, normal);
152 v = vert(v, r2 * c[2], r2 * s[2], -width * 0.5, normal);
153 v = vert(v, r1 * c[3], r1 * s[3], width * 0.5, normal);
154 v = vert(v, r1 * c[3], r1 * s[3], -width * 0.5, normal);
155 v = vert(v, r1 * c[4], r1 * s[4], width * 0.5, normal);
156 v = vert(v, r1 * c[4], r1 * s[4], -width * 0.5, normal);
157
158 v = vert(v, r1 * c[4], r1 * s[4], -width * 0.5, normal);
159 }
160
161 gear->count = (v - gear->vertices) / 6;
162
163 gl->glGenBuffers(1, &gear->vbo);
164 gl->glBindBuffer(GL_ARRAY_BUFFER, gear->vbo);
165 gl->glBufferData(GL_ARRAY_BUFFER, gear->count * 6 * 4, gear->vertices, GL_STATIC_DRAW);
166
167
168 return gear;
169}
170
171static void free_gear(Gear *gear)
172{
173 free(gear->vertices);
174 free(gear);
175 gear = NULL;
176}
177
178static void multiply(GLfloat *m, const GLfloat *n)
179{
180 GLfloat tmp[16];
181 const GLfloat *row, *column;
182 div_t d;
183 int i, j;
184
185 for (i = 0; i < 16; i++)
186 {
187 tmp[i] = 0;
188 d = div(i, 4);
189 row = n + d.quot * 4;
190 column = m + d.rem;
191 for (j = 0; j < 4; j++)
192 tmp[i] += row[j] * column[j * 4];
193 }
194 memcpy(m, &tmp, sizeof tmp);
195}
196
197static void rotate(GLfloat *m, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
198{
199 double s, c;
200
201 s = sin(angle);
202 c = cos(angle);
203 GLfloat r[16] =
204 {
205 x * x * (1 - c) + c, y * x * (1 - c) + z * s, x * z * (1 - c) - y * s, 0,
206 x * y * (1 - c) - z * s, y * y * (1 - c) + c, y * z * (1 - c) + x * s, 0,
207 x * z * (1 - c) + y * s, y * z * (1 - c) - x * s, z * z * (1 - c) + c, 0,
208 0, 0, 0, 1
209 };
210
211 multiply(m, r);
212}
213
214static void translate(GLfloat *m, GLfloat x, GLfloat y, GLfloat z)
215{
216 GLfloat t[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 };
217
218 multiply(m, t);
219}
220
221static void draw_gear(GLData *gld, Gear *gear, GLfloat *m, GLfloat x, GLfloat y, GLfloat angle, const GLfloat *color)
222{
223 Evas_GL_API *gl = gld->glApi;
224 GLfloat tmp[16];
225
226 memcpy(tmp, m, sizeof tmp);
227 translate(tmp, x, y, 0);
228 rotate(tmp, 2 * M_PI * angle / 360.0, 0, 0, 1);
229 gl->glUniformMatrix4fv(gld->proj_location, 1, GL_FALSE, tmp);
230 gl->glUniform3fv(gld->light_location, 1, gld->light);
231 gl->glUniform4fv(gld->color_location, 1, color);
232
233 gl->glBindBuffer(GL_ARRAY_BUFFER, gear->vbo);
234
235 gl->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), NULL);
236 gl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLfloat *) 0 + 3);
237 gl->glEnableVertexAttribArray(0);
238 gl->glEnableVertexAttribArray(1);
239 gl->glDrawArrays(GL_TRIANGLE_STRIP, 0, gear->count);
240}
241#endif
242
243
244static void gldata_init(GLData *gld)
245{
246 gld->useEGL = USE_EGL;
247 gld->useIrr = USE_IRR;
248
249 gld->view_rotx = -20.0;
250 gld->view_roty = -30.0;
251 gld->view_rotz = 0.0;
252 gld->angle = 0.0;
253
254 gld->light[0] = 1.0;
255 gld->light[1] = 1.0;
256 gld->light[2] = -5.0;
257}
258
259//-------------------------//
260
261
262#if DO_GEARS
263static const char vertex_shader[] =
264 "uniform mat4 proj;\n"
265 "attribute vec4 position;\n"
266 "attribute vec4 normal;\n"
267 "varying vec3 rotated_normal;\n"
268 "varying vec3 rotated_position;\n"
269 "vec4 tmp;\n"
270 "void main()\n"
271 "{\n"
272 " gl_Position = proj * position;\n"
273 " rotated_position = gl_Position.xyz;\n"
274 " tmp = proj * normal;\n"
275 " rotated_normal = tmp.xyz;\n"
276 "}\n";
277
278 static const char fragment_shader[] =
279 "#ifdef GL_ES\n"
280 "precision mediump float;\n"
281 "#endif\n"
282 "uniform vec4 color;\n"
283 "uniform vec3 light;\n"
284 "varying vec3 rotated_normal;\n"
285 "varying vec3 rotated_position;\n"
286 "vec3 light_direction;\n"
287 "vec4 white = vec4(0.5, 0.5, 0.5, 1.0);\n"
288 "void main()\n"
289 "{\n"
290 " light_direction = normalize(light - rotated_position);\n"
291 " gl_FragColor = color + white * dot(light_direction, rotated_normal);\n"
292 "}\n";
293
294static GLuint load_shader(GLData *gld, GLenum type, const char *shader_src)
295{
296 Evas_GL_API *gl = gld->glApi;
297 GLuint shader;
298 GLint compiled = 0;
299
300 // Create the shader object
301 if (!(shader = gl->glCreateShader(type))) return 0;
302 gl->glShaderSource(shader, 1, &shader_src, NULL);
303 // Compile the shader
304 gl->glCompileShader(shader);
305 gl->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
306
307 if (!compiled)
308 {
309 GLint len = 0;
310
311 gl->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
312 if (len > 1)
313 {
314 char *info = malloc(sizeof(char) * len);
315
316 if (info)
317 {
318 gl->glGetShaderInfoLog(shader, len, NULL, info);
319 printf("Error compiling shader:\n"
320 "%s\n", info);
321 free(info);
322 }
323 }
324 gl->glDeleteShader(shader);
325 return 0;
326 }
327 return shader;
328}
329
330static void gears_init(GLData *gld)
331{
332 Evas_GL_API *gl = gld->glApi;
333 GLint linked = 0;
334
335// char msg[512];
336
337 gl->glEnable(GL_CULL_FACE);
338 gl->glEnable(GL_DEPTH_TEST);
339 gl->glEnable(GL_BLEND);
340
341 // Load the vertex/fragment shaders
342 gld->vtx_shader = load_shader(gld, GL_VERTEX_SHADER, vertex_shader);
343 gld->fgmt_shader = load_shader(gld, GL_FRAGMENT_SHADER, fragment_shader);
344
345 // Create the program object
346 if (!(gld->program = gl->glCreateProgram()))
347 return;
348
349 gl->glAttachShader(gld->program, gld->vtx_shader);
350 gl->glAttachShader(gld->program, gld->fgmt_shader);
351
352 // Bind shader attributes.
353 gl->glBindAttribLocation(gld->program, 0, "position");
354 gl->glBindAttribLocation(gld->program, 1, "normal");
355
356 // Link the program
357 gl->glLinkProgram(gld->program);
358 gld->glApi->glGetProgramiv(gld->program, GL_LINK_STATUS, &linked);
359
360 if (!linked)
361 {
362 GLint len = 0;
363
364 gld->glApi->glGetProgramiv(gld->program, GL_INFO_LOG_LENGTH, &len);
365 if (len > 1)
366 {
367 char *info = malloc(sizeof(char) * len);
368
369 if (info)
370 {
371 gld->glApi->glGetProgramInfoLog(gld->program, len, NULL, info);
372 printf("Error linking program:\n%s\n", info);
373 free(info);
374 }
375 }
376 gld->glApi->glDeleteProgram(gld->program);
377 }
378
379 gl->glUseProgram(gld->program);
380 gld->proj_location = gl->glGetUniformLocation(gld->program, "proj");
381 gld->light_location = gl->glGetUniformLocation(gld->program, "light");
382 gld->color_location = gl->glGetUniformLocation(gld->program, "color");
383
384 /* make the gears */
385 gld->gear1 = make_gear(gld, 1.0, 4.0, 1.0, 20, 0.7);
386 gld->gear2 = make_gear(gld, 0.5, 2.0, 2.0, 10, 0.7);
387 gld->gear3 = make_gear(gld, 1.3, 2.0, 0.5, 10, 0.7);
388
389 gld->gearsInited = EINA_TRUE;
390}
391#endif
392
393static void _on_camera_input_down(void *data, Evas *evas, Evas_Object *obj, void *event_info)
394{
395 GLData *gld = data;
396 Evas_Event_Key_Down *ev = event_info;
397
398 if (gld->move)
399 {
400 // TODO - Careful, gld->move MIGHT be read at the other end by another thread. MIGHT, coz I really don't know at what point the camera animate routine is actually called.
401
402 // Yes, we are dealing with the horrid Evas keyboard handling FUCKING STRING COMPARES! Soooo ...
403 // TODO - make this a hash lookup dammit.
404 if (0 == strcmp(ev->key, "Escape"))
405 {
406 }
407 else if (0 == strcmp(ev->key, "Left"))
408 gld->move->r = 2.0;
409 else if (0 == strcmp(ev->key, "Right"))
410 gld->move->r = -2.0;
411 else if (0 == strcmp(ev->key, "Up"))
412 gld->move->x = 2.0;
413 else if (0 == strcmp(ev->key, "Down"))
414 gld->move->x = -2.0;
415// else if (0 == strcmp(ev->key, "Prior"))
416// ;
417// else if (0 == strcmp(ev->key, "Next"))
418// ;
419// else if (0 == strcmp(ev->key, "Home"))
420// ;
421// else if (0 == strcmp(ev->key, "End"))
422// ;
423 else if (0 == strcmp(ev->key, "space"))
424 gld->move->jump = 1.0;
425 else
426 printf("Unexpected down keystroke - %s\n", ev->key);
427 }
428 else
429 printf("Camera input not ready\n");
430}
431
432/* SL / OS camera controls
433 up / down / w / s moves avatar forward / backward
434 shifted version does the same
435 double tap triggers run mode / or fast fly mode
436 Running backwards turns your avatar to suit, walking does not.
437 left / right / a / d rotates avatar left / right, strafes in mouselook
438 shifted version turns the avatar to walk sideways, so not really a strafe.
439 So not sure if the "strafe" in mouse look turns the avatar as well?
440 PgDn / c crouch while it is held down move up in flight mode
441 PgUp jump move down in flight mode
442 Home toggle flying
443 End Nothing?
444 Esc return to third person view
445 m toggle mouse look
446 mouse wheel move view closer / further away from current focused object or avatar
447 Alt left click focus on some other object
448 Ins ???
449 Del ???
450 BS ???
451 Tab ???
452
453 Mouse look is just first person view, moving mouse looks left / right / up / down.
454 Not sure if the avatar rotates with left / right, but that's likely.
455
456 mouse moves With the left mouse button held down -
457 left / right up / down
458 ---------------------------------
459 for avatar swings avatar around zoom in and out of avatar
460 for object nothing
461 alt orbit left / right zoom in and out
462 alt ctrl orbit left / right orbit up / down
463 alt shift orbit left / right zoom in and out
464 alt ctrl shift shift view left / right / up / down
465 ctrl Nothing?
466 shift Nothing?
467 ctrl shift Nothing?
468
469 Need to also consider when looking at a moving object / avatar.
470
471 I think there are other letter keys that duplicate arrow keys and such. I'll look for them later, but I don't use them.
472 No idea what the function keys are mapped to, but think it's various non camera stuff.
473 I'm damn well leaving the Win/Command and Menu keys for the OS / window manager. lol
474 Keypad keys? Not interested, I don't have them.
475 Print Screen / SysRq, Pause / Break, other oddball keys, also not interested.
476 NOTE - gonna have an easily programmable "bind key to command" thingy, like E17s, so that can deal with other keys.
477 Should even let them be saveable so people can swap them with other people easily.
478
479 TODO - implement things like space mouse, sixaxis, phone as controller, joysticks, data gloves, etc.
480*/
481
482/* A moveRotate array of floats.
483 * X, Y, Z, and whatever the usual letters are for rotations. lol
484 * Each one means "move or rotate this much in this direction".
485 * Where 1.0 means "what ever the standard move is if that key is held down".
486 * So a keyboard move would just change it's part to 1.0 or -1.0 on key down,
487 * and back to 0.0 on key up. Or 2.0 / -2.0 if in run mode.
488 * Which would even work in fly mode.
489 * A joystick could be set to range over -2.0 to 2.0, and just set it's part directly.
490 * A mouse look rotate, well will come to that when we need to. B-)
491 * Setting the x or y to be the DIFFERENCE in window position of the mouse (-1.0 to 1.0) since the last frame.
492 *
493 * TODO - In the Elm_glview version, 2.0 seems to be correct speed for walking, but I thought 1.0 was in Evas_GL.
494 */
495
496static void _on_camera_input_up(void *data, Evas *evas, Evas_Object *obj, void *event_info)
497{
498 GLData *gld = data;
499 Evas_Event_Key_Up *ev = event_info;
500
501 if (gld->move)
502 {
503 // TODO - Careful, gld->move MIGHT be read at the other end by another thread. MIGHT, coz I really don't know at what point the camera animate routine is actually called.
504
505 // Yes, we are dealing with the horrid Evas keyboard handling FUCKING STRING COMPARES! Soooo ...
506 // TODO - make this a hash lookup dammit.
507 if (0 == strcmp(ev->key, "Escape"))
508 {
509 }
510 else if (0 == strcmp(ev->key, "Left"))
511 gld->move->r = 0.0;
512 else if (0 == strcmp(ev->key, "Right"))
513 gld->move->r = 0.0;
514 else if (0 == strcmp(ev->key, "Up"))
515 gld->move->x = 0.0;
516 else if (0 == strcmp(ev->key, "Down"))
517 gld->move->x = 0.0;
518// else if (0 == strcmp(ev->key, "Prior"))
519// ;
520// else if (0 == strcmp(ev->key, "Next"))
521// ;
522// else if (0 == strcmp(ev->key, "Home"))
523// ;
524// else if (0 == strcmp(ev->key, "End"))
525// ;
526 else if (0 == strcmp(ev->key, "space"))
527 gld->move->jump = 0.0;
528 else
529 printf("Unexpected up keystroke - %s\n", ev->key);
530 }
531 else
532 printf("Camera input not ready\n");
533}
534
535// Elm style event callback.
536static Eina_Bool _cb_event_GL(void *data, Evas_Object *obj, Evas_Object *src, Evas_Callback_Type type, void *event_info)
537{
538 GLData *gld = data;
539 Eina_Bool processed = EINA_FALSE;
540
541 switch (type)
542 {
543 case EVAS_CALLBACK_KEY_DOWN :
544 {
545 _on_camera_input_down(gld, evas_object_evas_get(obj), obj, event_info);
546 processed = EINA_TRUE;
547 break;
548 }
549
550 case EVAS_CALLBACK_KEY_UP :
551 {
552 _on_camera_input_up(gld, evas_object_evas_get(obj), obj, event_info);
553 processed = EINA_TRUE;
554 break;
555 }
556
557 default :
558 printf("Unknown GL input event.\n");
559 }
560
561 return processed;
562}
563
564// Elm inlined image windows needs this to change focus on mouse click.
565// Evas style event callback.
566static void _cb_mouse_down_elm(void *data, Evas *evas, Evas_Object *obj, void *event_info)
567{
568// GLData *gld = data;
569 Evas_Event_Mouse_Down *ev = event_info;
570
571 if (1 == ev->button)
572 elm_object_focus_set(obj, EINA_TRUE);
573}
574
575static void _resize_winwin(GLData *gld)
576{
577 Evas_Coord x, y, w, h;
578
579 evas_object_geometry_get(gld->elmGl, &x, &y, &w, &h);
580 evas_object_move(elm_win_inlined_image_object_get (gld->winwin), x, y);
581 evas_object_resize(elm_win_inlined_image_object_get(gld->winwin), w, h);
582}
583
584// Called from on_pixels (), or the Elm_gliew resize callback.
585static void _resize(GLData *gld)
586{
587 Evas_GL_API *gl = gld->glApi;
588
589 _resize_winwin(gld);
590
591#if DO_GEARS
592 GLfloat ar, m[16] = {
593 1.0, 0.0, 0.0, 0.0,
594 0.0, 1.0, 0.0, 0.0,
595 0.0, 0.0, 0.1, 0.0,
596 0.0, 0.0, 0.0, 1.0
597 };
598
599 // GL Viewport stuff. you can avoid doing this if viewport is all the
600 // same as last frame if you want
601 if (gld->img_w < gld->img_h)
602 ar = gld->img_w;
603 else
604 ar = gld->img_h;
605
606 m[0] = 0.1 * ar / gld->img_w;
607 m[5] = 0.1 * ar / gld->img_h;
608 memcpy(gld->proj, m, sizeof gld->proj);
609#endif
610
611 gl->glViewport(0, 0, (GLint) gld->img_w, (GLint) gld->img_h);
612}
613
614static void _resize_gl(Evas_Object *obj)
615{
616 int w, h;
617 GLData *gld = evas_object_data_get(obj, "gld");
618
619 elm_glview_size_get(obj, &w, &h);
620
621 gld->img_w = w;
622 gld->img_h = h;
623 _resize(gld);
624}
625
626static void on_pixels(void *data, Evas_Object *obj)
627{
628 GLData *gld = data;
629 Evas_GL_API *gl = gld->glApi;
630
631 // get the image size in case it changed with evas_object_image_size_set()
632 if (gld->r1)
633 {
634 Evas_Coord w, h;
635
636 // Poor mans resize check. coz Elm wont do it easily.
637 evas_object_image_size_get(gld->r1, &w, &h);
638 if ((gld->img_w != w) || (gld->img_h != h))
639 {
640 // No idea where this crap came from.
641 //float new_w = ((float) gld->scr_w / ((float) gld->scr_w * (float) w));
642 //float new_h = ((float) gld->scr_h / ((float) gld->scr_h * (float) h));
643
644 //gld->sfc_w = new_w;
645 //gld->sfc_h = new_h;
646 //evas_object_image_fill_set(gld->r1, 0, 0, gld->sfc_w, gld->sfc_h);
647 gld->img_w = w;
648 gld->img_h = h;
649 gld->resized = 1;
650 }
651 }
652
653 if (gld->useEGL)
654 {
655 // Yes, we DO need to do our own make current, coz aparently the Irrlicht one is useless.
656 // Hopefully Elm_GL has done this for us by now.
657 // Evas_GL needs it to.
658 if (gld->ctx)
659 evas_gl_make_current(gld->evasGl, gld->sfc, gld->ctx);
660 }
661
662 if (!gld->doneIrr)
663 gld->doneIrr = startIrr(gld); // Needs to be after gld->win is shown, and needs to be done in the render thread.
664#if DO_GEARS
665 if (!gld->gearsInited)
666 gears_init(gld);
667#endif
668
669 if (gld->resized)
670 _resize(gld);
671
672 drawIrr_start(gld);
673
674#if DO_GEARS
675 if (gld->useEGL)
676 {
677 static const GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
678 static const GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
679 static const GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
680 GLfloat m[16];
681
682 // Draw the gears.
683 if (!gld->useIrr)
684 {
685 gl->glClearColor(0.7, 0.0, 1.0, 1.0);
686 gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
687 }
688
689 memcpy(m, gld->proj, sizeof m);
690 rotate(m, 2 * M_PI * gld->view_rotx / 360.0, 1, 0, 0);
691 rotate(m, 2 * M_PI * gld->view_roty / 360.0, 0, 1, 0);
692 rotate(m, 2 * M_PI * gld->view_rotz / 360.0, 0, 0, 1);
693
694 draw_gear(gld, gld->gear1, m, -3.0, -2.0, gld->angle, red);
695 draw_gear(gld, gld->gear2, m, 3.1, -2.0, -2 * gld->angle - 9.0, green);
696 draw_gear(gld, gld->gear3, m, -3.1, 4.2, -2 * gld->angle - 25.0, blue);
697 gld->angle += 2.0;
698 }
699#endif
700
701 drawIrr_end(gld);
702
703#if USE_IR
704#else
705 // This might get done deep within drawIrr_end, but only if we are using Irrlicht.
706
707 // Optional - Flush the GL pipeline
708 gl->glFlush();
709// gl->glFinish();
710#endif
711
712 gld->resized = 0;
713}
714
715static void _draw_gl(Evas_Object *obj)
716{
717// Evas_GL_API *gl = elm_glview_gl_api_get(obj);
718 GLData *gld = evas_object_data_get(obj, "gld");
719 if (!gld) return;
720
721 on_pixels(gld, obj);
722}
723
724// Callback from Evas, also used as the general callback for deleting the GL stuff.
725static void _clean_gl(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
726{
727 GLData *gld = data;
728 Evas_GL_API *gl = gld->glApi;
729
730 ecore_animator_del(gld->animator);
731
732 if (gld->useEGL)
733 {
734 // Do a make_current before deleting all the GL stuff.
735 evas_gl_make_current(gld->evasGl, gld->sfc, gld->ctx);
736
737 }
738
739 gl->glDeleteShader(gld->vtx_shader);
740 gl->glDeleteShader(gld->fgmt_shader);
741 gl->glDeleteProgram(gld->program);
742
743 if (gld->evasGl)
744 {
745 // Irrlicht wants to destroy the context and surface, so only do this if Irrlicht wont.
746 if (!gld->doneIrr)
747 {
748 evas_gl_surface_destroy(gld->evasGl, gld->sfc);
749 evas_gl_context_destroy(gld->evasGl, gld->ctx);
750 }
751 // TODO - hope this is OK, considering the context and surface might get dealt with by Irrlicht.
752 // Might be better to teach Irrlicht to not destroy shit it did not create.
753 evas_gl_config_free(gld->cfg);
754 evas_gl_free(gld->evasGl);
755 }
756
757 // TODO - Since this is created on the render thread, better hope this is being deleted on the render thread.
758 finishIrr(gld);
759
760#if DO_GEARS
761 gl->glDeleteBuffers(1, &gld->gear1->vbo);
762 gl->glDeleteBuffers(1, &gld->gear2->vbo);
763 gl->glDeleteBuffers(1, &gld->gear3->vbo);
764
765 free_gear(gld->gear1);
766 free_gear(gld->gear2);
767 free_gear(gld->gear3);
768#endif
769}
770
771// Callback from Elm, coz they do shit different.
772static void _del_gl(Evas_Object *obj)
773{
774 GLData *gld = evas_object_data_get(obj, "gld");
775 if (!gld)
776 {
777 printf("Unable to get GLData. \n");
778 return;
779 }
780
781 _clean_gl(gld, NULL, NULL, NULL);
782
783 evas_object_data_del((Evas_Object*)obj, "gld");
784}
785
786// Callback for when the app quits.
787static void _on_done(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
788{
789 GLData *gld = data;
790
791 evas_object_del(gld->win);
792 free(gld);
793 elm_exit();
794}
795
796// Callback from the animator.
797static Eina_Bool doFrame(void *data)
798{
799 GLData *gld = data;
800
801 // Mark the pixels as dirty, so they get rerendered each frame, then Irrlicht can draw it's stuff each frame.
802 // This causes on_pixel to be triggered by Evas_GL, and _draw_gl for Elm_glview.
803 if (gld->r1)
804 evas_object_image_pixels_dirty_set(gld->r1, EINA_TRUE);
805 if (gld->elmGl)
806 elm_glview_changed_set(gld->elmGl);
807
808 // If not using Evas_GL, we need to call on_pixel() manually.
809 if (!gld->useEGL)
810 on_pixels(gld, gld->r1);
811
812 return EINA_TRUE; // Keep calling us.
813}
814
815static void init_evas_gl(GLData *gld)
816{
817 if (!gld->useEGL)
818 return;
819
820 gld->sfc_w = gld->win_w;
821 gld->sfc_h = gld->win_h;
822
823 // Get the Evas / canvas from the elm window (that the Evas_Object "lives on"), which is itself an Evas_Object created by Elm, so not sure if it was created internally with Ecore_Evas.
824 gld->canvas = evas_object_evas_get(gld->win);
825 // An Ecore_Evas holds an Evas.
826 // Get the Ecore_Evas that wraps an Evas.
827 gld->ee = ecore_evas_ecore_evas_get(gld->canvas); // Only use this on Evas that was created with Ecore_Evas.
828
829#if USE_ELM_GL
830 // Add a GLView
831 gld->elmGl = elm_glview_add(gld->win);
832 evas_object_size_hint_align_set(gld->elmGl, EVAS_HINT_FILL, EVAS_HINT_FILL);
833 evas_object_size_hint_weight_set(gld->elmGl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
834 elm_glview_mode_set(gld->elmGl, 0 | ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH | ELM_GLVIEW_DIRECT);
835 elm_glview_resize_policy_set(gld->elmGl, ELM_GLVIEW_RESIZE_POLICY_RECREATE); // Destroy the current surface on a resize and create a new one.
836 elm_glview_render_policy_set(gld->elmGl, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND);
837// elm_glview_render_policy_set(gld->elmGl, ELM_GLVIEW_RENDER_POLICY_ALWAYS);
838 // These get called in the render thread I think.
839 // None let me pass data, so this is why we are adding "gld" data to the object below.
840 // Maybe we can use elm_object_signal_callback_add or elm_object_item_signal_callback_add (edje signals)?
841 //elm_glview_init_func_set(gld->elmGl, _init_gl); // Not actually needed, it gets done in on_pixels.
842 elm_glview_del_func_set(gld->elmGl, _del_gl);
843 elm_glview_resize_func_set(gld->elmGl, _resize_gl);
844 elm_glview_render_func_set(gld->elmGl, (Elm_GLView_Func_Cb) _draw_gl);
845
846 // Not needed, the resize callback above deals with that.
847 //elm_win_resize_object_add(gld->win, gld->elmGl);
848 gld->glApi = elm_glview_gl_api_get(gld->elmGl);
849 evas_object_data_set(gld->elmGl, "gld", gld);
850 evas_object_show(gld->elmGl);
851 elm_box_pack_end(gld->bx, gld->elmGl);
852#else
853 // get the evas gl handle for doing gl things
854 gld->evasGl = evas_gl_new(gld->canvas);
855 gld->glApi = evas_gl_api_get(gld->evasGl);
856
857 // Set a surface config
858 gld->cfg = evas_gl_config_new();
859 gld->cfg->color_format = EVAS_GL_RGBA_8888;
860 gld->cfg->depth_bits = EVAS_GL_DEPTH_BIT_32;
861 gld->cfg->stencil_bits = EVAS_GL_STENCIL_NONE;
862 gld->cfg->options_bits = EVAS_GL_OPTIONS_DIRECT;
863
864 // create a surface and context
865 gld->sfc = evas_gl_surface_create(gld->evasGl, gld->cfg, gld->sfc_w, gld->sfc_h);
866 gld->ctx = evas_gl_context_create(gld->evasGl, NULL); // The second NULL is for sharing contexts I think, which might be what we want to do with Irrlicht. It's not documented.
867
868 // Set up the image object, a filled one by default.
869 gld->r1 = evas_object_image_filled_add(gld->canvas);
870
871 // attach important data we need to the object using key names. This just
872 // avoids some global variables and means we can do nice cleanup. You can
873 // avoid this if you are lazy
874 // Not actually needed, with evas we can pass data pointers to stuff.
875 //evas_object_data_set(gld->r1, "gld", gld);
876
877 // when the object is deleted - call the on_del callback. like the above,
878 // this is just being clean
879 evas_object_event_callback_add(gld->r1, EVAS_CALLBACK_DEL, _clean_gl, gld);
880
881 // set up an actual pixel size for the buffer data. it may be different
882 // to the output size. any windowing system has something like this, just
883 // evas has 2 sizes, a pixel size and the output object size
884 evas_object_image_size_set(gld->r1, gld->sfc_w, gld->sfc_h);
885 // Not actualy needed, as we create the image already filled.
886 //evas_object_image_fill_set(gld->r1, 0, 0, gld->sfc_w, gld->sfc_h);
887
888 // These two are not in the original example, but I get black r1 when I leave them out.
889 evas_object_size_hint_align_set(gld->r1, EVAS_HINT_FILL, EVAS_HINT_FILL);
890 evas_object_size_hint_weight_set(gld->r1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
891
892 // set up the native surface info to use the context and surface created
893 // above
894 evas_gl_native_surface_get(gld->evasGl, gld->sfc, &(gld->ns));
895 evas_object_image_native_surface_set(gld->r1, &(gld->ns));
896 evas_object_image_pixels_get_callback_set(gld->r1, on_pixels, gld);
897
898 // move the image object somewhere, resize it and show it. any windowing
899 // system would need this kind of thing - place a child "window"
900 // Hmm, no need to resize it anyway, it's sized above.
901 evas_object_move(gld->r1, 0, 0);
902 //evas_object_resize(gld->r1, gld->sfc_w, gld->sfc_h);
903 elm_win_resize_object_add(gld->win, gld->r1);
904 evas_object_show(gld->r1);
905 elm_box_pack_end(gld->bx, gld->r1);
906
907 evas_object_event_callback_add(gld->r1, EVAS_CALLBACK_MOUSE_DOWN, _cb_mouse_down_GL, gld);
908// evas_object_event_callback_add(gld->r1, EVAS_CALLBACK_KEY_DOWN, _on_camera_input_down, gld);
909// evas_object_event_callback_add(gld->r1, EVAS_CALLBACK_KEY_UP, _on_camera_input_up, gld);
910#endif
911
912 // NOTE: if you delete r1, this animator will keep running trying to access
913 // r1 so you'd better delete this animator with ecore_animator_del() or
914 // structure how you do animation differently. you can also attach it like
915 // evasGl, sfc, etc. etc. if this animator is specific to this object
916 // only and delete it in the del handler for the obj.
917 //
918 // TODO - apparently the proper way to deal with the new async rendering is to have this animator do the dirty thing, and call the Irrlicht rendering stuff in the on_pixel call set above.
919 // That still leaves the problem of the Irrlicht setup being in the main thread. Which also should be done in on_pixel, as that's done in the correct thread.
920
921 // Jiggling this seems to produce a trade off between flickering and frame rate. Nothing else changed the flickering.
922 ecore_animator_frametime_set(0.04); // Default is 1/30, or 0.033333
923 gld->animator = ecore_animator_add(doFrame, gld); // This animator will be called every frame tick, which defaults to 1/30 seconds.
924
925 return;
926}
927
928
929//-------------------------//
930
931
932static Evas_Object *_content_image_new(Evas_Object *parent, const char *img)
933{
934 Evas_Object *ic;
935
936 ic = elm_icon_add(parent);
937 elm_image_file_set(ic, img, NULL);
938 return ic;
939}
940
941static void _promote(void *data, Evas_Object *obj , void *event_info )
942{
943 elm_naviframe_item_promote(data);
944}
945
946static char *_grid_label_get(void *data, Evas_Object *obj, const char *part)
947{
948 ezGrid *thisGrid = data;
949 char buf[256];
950
951 if (!strcmp(part, "elm.text"))
952 {
953 int count = eina_clist_count(&(thisGrid->accounts));
954
955 if (0 == count)
956 snprintf(buf, sizeof(buf), "%s (no accounts)", thisGrid->name);
957 else if (1 == count)
958 snprintf(buf, sizeof(buf), "%s (%d account)", thisGrid->name, count);
959 else
960 snprintf(buf, sizeof(buf), "%s (%d accounts)", thisGrid->name, count);
961 }
962 else
963 snprintf(buf, sizeof(buf), "%s", thisGrid->loginURI);
964 return strdup(buf);
965}
966
967static Evas_Object *_grid_content_get(void *data, Evas_Object *obj, const char *part)
968{
969 ezGrid *thisGrid = data;
970 Evas_Object *ic = elm_icon_add(obj);
971
972 if (!strcmp(part, "elm.swallow.icon"))
973 elm_icon_standard_set(ic, thisGrid->icon);
974
975 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
976 return ic;
977}
978
979static char * _account_label_get(void *data, Evas_Object *obj, const char *part)
980{
981 ezAccount *thisAccount = data;
982 char buf[256];
983
984 buf[0] = '\0';
985 if (!strcmp(part, "elm.text"))
986 snprintf(buf, sizeof(buf), "%s", thisAccount->name);
987
988 return strdup(buf);
989}
990
991static Evas_Object *_account_content_get(void *data, Evas_Object *obj, const char *part)
992{
993 ezAccount *thisAccount = data;
994 Evas_Object *ic = elm_icon_add(obj);
995
996 if (!strcmp(part, "elm.swallow.icon"))
997 elm_icon_standard_set(ic, thisAccount->icon);
998
999 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
1000 return ic;
1001}
1002
1003static char *_viewer_label_get(void *data, Evas_Object *obj, const char *part)
1004{
1005 ezViewer *thisViewer = data;
1006 char buf[256];
1007
1008 if (!strcmp(part, "elm.text"))
1009 snprintf(buf, sizeof(buf), "%s", thisViewer->name);
1010 else
1011 snprintf(buf, sizeof(buf), "%s", thisViewer->version);
1012 return strdup(buf);
1013}
1014
1015static Evas_Object *_viewer_content_get(void *data, Evas_Object *obj, const char *part)
1016{
1017 ezViewer *thisViewer = data;
1018 Evas_Object *ic = elm_icon_add(obj);
1019
1020 if (!strcmp(part, "elm.swallow.icon"))
1021 elm_icon_standard_set(ic, thisViewer->icon);
1022
1023 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
1024 return ic;
1025}
1026
1027
1028static void _grid_sel_cb(void *data, Evas_Object *obj, void *event_info)
1029{
1030 ezGrid *thisGrid = data;
1031 GLData *gld = thisGrid->gld;
1032 char buf[PATH_MAX];
1033
1034// sprintf(buf, "dillo -f -g '%dx%d+%d+%d' %s &", gld->win_w - (gld->win_w / 5), gld->win_h - 30, gld->win_w / 5, gld->win_y, thisGrid->splashPage);
1035 sprintf(buf, "uzbl -g '%dx%d+%d+%d' -u %s &", gld->win_w - (gld->win_w / 5), gld->win_h - 30, gld->win_w / 5, gld->win_y, thisGrid->splashPage);
1036 printf("%s ### genlist obj [%p], item pointer [%p]\n", buf, obj, event_info);
1037// comment this out for now, busy dealing with input stuff, don't want to trigger this multiple times.
1038// system(buf);
1039}
1040
1041static void cb_mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info)
1042{
1043 Evas_Event_Mouse_Move *ev = event_info;
1044 Evas_Object *orig = data;
1045 Evas_Coord x, y;
1046 Evas_Map *p;
1047 int i, w, h;
1048
1049 if (!ev->buttons) return;
1050 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1051 evas_object_move(obj,
1052 x + (ev->cur.canvas.x - ev->prev.output.x),
1053 y + (ev->cur.canvas.y - ev->prev.output.y));
1054 evas_object_image_size_get(orig, &w, &h);
1055 p = evas_map_new(4);
1056 evas_object_map_enable_set(orig, EINA_TRUE);
1057// evas_object_raise(orig);
1058 for (i = 0; i < 4; i++)
1059 {
1060 Evas_Object *hand;
1061 char key[32];
1062
1063 snprintf(key, sizeof(key), "h-%i\n", i);
1064 hand = evas_object_data_get(orig, key);
1065 evas_object_raise(hand);
1066 evas_object_geometry_get(hand, &x, &y, NULL, NULL);
1067 x += 15;
1068 y += 15;
1069 evas_map_point_coord_set(p, i, x, y, 0);
1070 if (i == 0) evas_map_point_image_uv_set(p, i, 0, 0);
1071 else if (i == 1) evas_map_point_image_uv_set(p, i, w, 0);
1072 else if (i == 2) evas_map_point_image_uv_set(p, i, w, h);
1073 else if (i == 3) evas_map_point_image_uv_set(p, i, 0, h);
1074 }
1075 evas_object_map_set(orig, p);
1076 evas_map_free(p);
1077}
1078
1079static void create_handles(Evas_Object *obj)
1080{
1081 int i;
1082 Evas_Coord x, y, w, h;
1083
1084 evas_object_geometry_get(obj, &x, &y, &w, &h);
1085 for (i = 0; i < 4; i++)
1086 {
1087 Evas_Object *hand;
1088 char buf[PATH_MAX];
1089 char key[32];
1090
1091 hand = evas_object_image_filled_add(evas_object_evas_get(obj));
1092 evas_object_resize(hand, 31, 31);
1093 snprintf(buf, sizeof(buf), "%s/media/pt.png", elm_app_data_dir_get());
1094 evas_object_image_file_set(hand, buf, NULL);
1095 if (i == 0) evas_object_move(hand, x - 15, y - 15);
1096 else if (i == 1) evas_object_move(hand, x + w - 15, y - 15);
1097 else if (i == 2) evas_object_move(hand, x + w - 15, y + h - 15);
1098 else if (i == 3) evas_object_move(hand, x - 15, y + h - 15);
1099 evas_object_event_callback_add(hand, EVAS_CALLBACK_MOUSE_MOVE, cb_mouse_move, obj);
1100 evas_object_show(hand);
1101 snprintf(key, sizeof(key), "h-%i\n", i);
1102 evas_object_data_set(obj, key, hand);
1103 }
1104}
1105
1106static Evas_Object *_toolbar_menu_add(Evas_Object *win, Evas_Object *tb, char *label)
1107{
1108 Evas_Object *menu= NULL;
1109 Elm_Object_Item *tb_it;
1110//, *menu_it;
1111
1112 tb_it = elm_toolbar_item_append(tb, NULL, label, NULL, NULL);
1113 elm_toolbar_item_menu_set(tb_it, EINA_TRUE);
1114 // Priority is for when toolbar items are set to hide or menu when there are too many of them. They get hidden or put on the menu based on priority.
1115 elm_toolbar_item_priority_set(tb_it, 9999);
1116 elm_toolbar_menu_parent_set(tb, win);
1117 menu = elm_toolbar_item_menu_get(tb_it);
1118
1119 return menu;
1120}
1121
1122static Evas_Object *fang_win_add(GLData *gld)
1123{
1124 Evas_Object *win, *bg;
1125
1126 // In theory this should create an EWS window, in practice, I'm not seeing any difference.
1127 // Guess I'll have to implement my own internal window manager. I don't think a basic one will be that hard. Famous last words.
1128// elm_config_engine_set("ews");
1129 win = elm_win_add(gld->win, "inlined", ELM_WIN_INLINED_IMAGE);
1130 // On mouse down we try to shift focus to the backing image, this seems to be the correct thing to force focus onto it's widgets.
1131 // According to the Elm inlined image window example, this is what's needed to.
1132 evas_object_event_callback_add(elm_win_inlined_image_object_get(win), EVAS_CALLBACK_MOUSE_DOWN, _cb_mouse_down_elm, gld);
1133 elm_win_alpha_set(win, EINA_TRUE);
1134
1135 // Apparently transparent is not good enough for ELM backgrounds, so make it a rectangle.
1136 // Apparently coz ELM prefers stuff to have edjes. A bit over the top if all I want is a transparent rectangle.
1137 bg = evas_object_rectangle_add(evas_object_evas_get(win));
1138 evas_object_color_set(bg, 50, 0, 100, 100);
1139 evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1140 elm_win_resize_object_add(win, bg);
1141 evas_object_show(bg);
1142
1143 return win;
1144}
1145
1146static void fang_win_complete(GLData *gld, Evas_Object *win, int x, int y, int w, int h)
1147{
1148 // image object for win is unlinked to its pos/size - so manual control
1149 // this allows also for using map and other things with it.
1150 evas_object_move(elm_win_inlined_image_object_get(win), x, y);
1151 // Odd, it needs to be resized twice. WTF?
1152 evas_object_resize(win, w, h);
1153 evas_object_resize(elm_win_inlined_image_object_get(win), w, h);
1154 evas_object_show(win);
1155 create_handles(elm_win_inlined_image_object_get(win));
1156}
1157
1158static void overlay_add(GLData *gld)
1159{
1160 Evas_Object *bg;
1161//, *bx, *tb, *menu;
1162// Elm_Object_Item *tb_it, *menu_it;
1163
1164 // There many are reasons for this window.
1165 // The first is to cover the GL and provide something to click on to change focus.
1166 // The second is to provide something to click on for all the GL type clicking stuff that needs to be done. In other words, no click through,we catch the clicks here.
1167 // So we can probably avoid the following issue -
1168 // How to do click through? evas_object_pass_events_set(rectangle, EINA_TRUE), and maybe need to do that to the underlaying window to?
1169 // Though if the rectangle is entirely transparent, or even hidden, events might pass through anyway.
1170 // Gotta have click through on the parts where there's no other window.
1171 // The third is to have the other windows live here.
1172 // This idea doesn't work, as it breaks the damn focus again.
1173 // Don't think it's needed anyway.
1174 // While on the subject of layers, need a HUD layer of some sort, but Irrlicht might support that itself.
1175
1176 gld->winwin = elm_win_add(gld->win, "inlined", ELM_WIN_INLINED_IMAGE);
1177 // On mouse down we try to shift focus to the backing image, this seems to be the correct thing to force focus onto it's widgets.
1178 // According to the Elm inlined image window example, this is what's needed to.
1179 evas_object_event_callback_add(elm_win_inlined_image_object_get(gld->winwin), EVAS_CALLBACK_MOUSE_DOWN, _cb_mouse_down_elm, gld);
1180 // In this code, we are making our own camera, so grab it's input when we are focused.
1181 evas_object_event_callback_add(gld->winwin, EVAS_CALLBACK_KEY_DOWN, _on_camera_input_down, gld);
1182 evas_object_event_callback_add(gld->winwin, EVAS_CALLBACK_KEY_UP, _on_camera_input_up, gld);
1183 elm_object_event_callback_add(gld->winwin, _cb_event_GL, gld);
1184
1185 elm_win_alpha_set(gld->winwin, EINA_TRUE);
1186 // Apparently transparent is not good enough for ELM backgrounds, so make it a rectangle.
1187 // Apparently coz ELM prefers stuff to have edjes. A bit over the top if all I want is a transparent rectangle.
1188 bg = evas_object_rectangle_add(evas_object_evas_get(gld->winwin));
1189 evas_object_color_set(bg, 0, 0, 0, 0);
1190 evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1191 elm_win_resize_object_add(gld->winwin, bg);
1192 evas_object_show(bg);
1193
1194 // image object for win is unlinked to its pos/size - so manual control
1195 // this allows also for using map and other things with it.
1196 evas_object_move(elm_win_inlined_image_object_get(gld->winwin), 0, 0);
1197 // Odd, it needs to be resized twice. WTF?
1198 evas_object_resize(gld->winwin, gld->win_w, gld->win_h);
1199 evas_object_resize(elm_win_inlined_image_object_get(gld->winwin), gld->win_w, gld->win_h);
1200 evas_object_show(gld->winwin);
1201}
1202
1203static void chat_add(GLData *gld)
1204{
1205 Evas_Object *win, *bx, *en;
1206
1207 win = fang_win_add(gld);
1208
1209 bx = elm_box_add(win);
1210 elm_win_resize_object_add(win, bx);
1211 evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1212 evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
1213
1214 en = elm_entry_add(win);
1215 elm_entry_scrollable_set(en, EINA_TRUE);
1216 evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1217 evas_object_size_hint_align_set(en, EVAS_HINT_FILL, EVAS_HINT_FILL);
1218 elm_object_text_set(en, "History is shown here");
1219 elm_entry_editable_set(en, EINA_FALSE);
1220 evas_object_show(en);
1221 elm_box_pack_end(bx, en);
1222
1223 en = elm_entry_add(win);
1224 elm_entry_scrollable_set(en, EINA_TRUE);
1225 evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1226 evas_object_size_hint_align_set(en, EVAS_HINT_FILL, EVAS_HINT_FILL);
1227 elm_object_text_set(en, "");
1228 elm_entry_editable_set(en, EINA_TRUE);
1229 evas_object_show(en);
1230 elm_box_pack_end(bx, en);
1231
1232 evas_object_show(bx);
1233
1234 fang_win_complete(gld, win, 30, 500, gld->win_w / 3, gld->win_h / 3);
1235}
1236
1237
1238static void woMan_add(GLData *gld)
1239{
1240// Evas_Object *win, *bg, *bx, *ic, *bb, *av, *en, *bt, *nf, *tab, *tb, *gridList, *viewerList, *menu;
1241 Evas_Object *win, *bx, *bt, *nf, *tab, *tb, *gridList, *viewerList, *menu;
1242 Elm_Object_Item *tb_it, *menu_it, *tab_it;
1243// char buf[PATH_MAX];
1244 int i;
1245
1246 win = fang_win_add(gld);
1247
1248 bx = elm_box_add(win);
1249 elm_win_resize_object_add(win, bx);
1250 evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1251 evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
1252
1253 // A tab thingy.
1254 tb = elm_toolbar_add(win);
1255 evas_object_size_hint_weight_set(tb, EVAS_HINT_EXPAND, 0.0);
1256 evas_object_size_hint_align_set(tb, EVAS_HINT_FILL, EVAS_HINT_FILL);
1257 elm_toolbar_shrink_mode_set(tb, ELM_TOOLBAR_SHRINK_SCROLL);
1258
1259 // Menu.
1260 tb_it = elm_toolbar_item_append(tb, NULL, "Menu", NULL, NULL);
1261 elm_toolbar_item_menu_set(tb_it, EINA_TRUE);
1262 // Priority is for when toolbar items are set to hide or menu when there are too many of them. They get hidden or put on the menu based on priority.
1263 elm_toolbar_item_priority_set(tb_it, 9999);
1264 elm_toolbar_menu_parent_set(tb, win);
1265 menu = elm_toolbar_item_menu_get(tb_it);
1266
1267 menu_it = elm_menu_item_add(menu, NULL, NULL, "edit", NULL, NULL);
1268 elm_menu_item_add(menu, menu_it, NULL, "preferences", NULL, NULL);
1269 menu_it = elm_menu_item_add(menu, NULL, NULL, "help", NULL, NULL);
1270 elm_menu_item_add(menu, menu_it, NULL, "about woMan", NULL, NULL);
1271 elm_menu_item_separator_add(menu, NULL);
1272 menu_it = elm_menu_item_add(menu, NULL, NULL, "advanced", NULL, NULL);
1273 elm_menu_item_add(menu, menu_it, NULL, "debug settings", NULL, NULL);
1274
1275 // The toolbar needs to be packed into the box AFTER the menus are added.
1276 elm_box_pack_end(bx, tb);
1277 evas_object_show(tb);
1278
1279 gridList = elm_genlist_add(win);
1280 grids = eina_hash_stringshared_new(free);
1281
1282 grid_gic = elm_genlist_item_class_new();
1283 grid_gic->item_style = "double_label";
1284 grid_gic->func.text_get = _grid_label_get;
1285 grid_gic->func.content_get = _grid_content_get;
1286 grid_gic->func.state_get = NULL;
1287 grid_gic->func.del = NULL;
1288 for (i = 0; NULL != gridTest[i][0]; i++)
1289 {
1290 ezGrid *thisGrid = calloc(1, sizeof(ezGrid));
1291
1292 if (thisGrid)
1293 {
1294 eina_clist_init(&(thisGrid->accounts));
1295 eina_clist_init(&(thisGrid->landmarks));
1296 thisGrid->name = gridTest[i][0];
1297 thisGrid->loginURI = gridTest[i][1];
1298 thisGrid->splashPage = gridTest[i][2];
1299 thisGrid->icon = "folder";
1300 thisGrid->gld = gld;
1301 thisGrid->item = elm_genlist_item_append(gridList, grid_gic, thisGrid, NULL, ELM_GENLIST_ITEM_TREE, _grid_sel_cb, thisGrid);
1302 eina_hash_add(grids, thisGrid->name, thisGrid);
1303 }
1304 }
1305
1306 account_gic = elm_genlist_item_class_new();
1307 account_gic->item_style = "default";
1308 account_gic->func.text_get = _account_label_get;
1309 account_gic->func.content_get = _account_content_get;
1310 account_gic->func.state_get = NULL;
1311 account_gic->func.del = NULL;
1312 for (i = 0; NULL != accountTest[i][0]; i++)
1313 {
1314 ezAccount *thisAccount = calloc(1, sizeof(ezAccount));
1315 ezGrid *grid = eina_hash_find(grids, accountTest[i][0]);
1316
1317 if (thisAccount && grid)
1318 {
1319 thisAccount->name = accountTest[i][1];
1320 thisAccount->password = accountTest[i][2];
1321 thisAccount->icon = "file";
1322 elm_genlist_item_append(gridList, account_gic, thisAccount, grid->item, ELM_GENLIST_ITEM_NONE, NULL, NULL);
1323 eina_clist_add_tail(&(grid->accounts), &(thisAccount->grid));
1324 }
1325 }
1326
1327 // Viewers stuff
1328 viewerList = elm_genlist_add(win);
1329 viewer_gic = elm_genlist_item_class_new();
1330 viewer_gic->item_style = "double_label";
1331 viewer_gic->func.text_get = _viewer_label_get;
1332 viewer_gic->func.content_get = _viewer_content_get;
1333 viewer_gic->func.state_get = NULL;
1334 viewer_gic->func.del = NULL;
1335 for (i = 0; NULL != viewerTest[i][0]; i++)
1336 {
1337 ezViewer *thisViewer = calloc(1, sizeof(ezViewer));
1338
1339 if (thisViewer)
1340 {
1341 thisViewer->name = viewerTest[i][0];
1342 thisViewer->version = viewerTest[i][1];
1343 thisViewer->path = viewerTest[i][2];
1344 thisViewer->icon = "file";
1345 thisViewer->item = elm_genlist_item_append(viewerList, viewer_gic, thisViewer, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
1346 }
1347 }
1348
1349 // Toolbar pages
1350 nf = elm_naviframe_add(win);
1351 evas_object_size_hint_weight_set(nf, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1352 evas_object_size_hint_align_set(nf, EVAS_HINT_FILL, EVAS_HINT_FILL);
1353 evas_object_show(nf);
1354
1355 tab = viewerList; tab_it = elm_naviframe_item_push(nf, NULL, NULL, NULL, tab, NULL); elm_naviframe_item_title_enabled_set(tab_it, EINA_FALSE, EINA_TRUE); elm_toolbar_item_append(tb, NULL, "Viewers", _promote, tab_it);
1356 tab = _content_image_new(win, img3); tab_it = elm_naviframe_item_push(nf, NULL, NULL, NULL, tab, NULL); elm_naviframe_item_title_enabled_set(tab_it, EINA_FALSE, EINA_TRUE); elm_toolbar_item_append(tb, NULL, "Landmarks", _promote, tab_it);
1357 tab = gridList; tab_it = elm_naviframe_item_push(nf, NULL, NULL, NULL, tab, NULL); elm_naviframe_item_title_enabled_set(tab_it, EINA_FALSE, EINA_TRUE); elm_toolbar_item_append(tb, NULL, "Grids", _promote, tab_it);
1358 elm_box_pack_end(bx, nf);
1359
1360#if USE_EO
1361 // Not ready for prime time yet, or I'm missing a step. Causes it to hang after closing the window.
1362 // Slightly better now, it bitches instead of hanging.
1363 bt = eo_add(ELM_OBJ_BUTTON_CLASS, win);
1364 elm_object_text_set(bt, "Login"); // No eo interface for this that I can find.
1365 eo_do(bt,
1366// evas_obj_text_set("Login"),
1367 evas_obj_size_hint_align_set(EVAS_HINT_FILL, EVAS_HINT_FILL),
1368 evas_obj_size_hint_weight_set(EVAS_HINT_EXPAND, 0.0),
1369 evas_obj_visibility_set(EINA_TRUE)
1370 );
1371#else
1372 bt = elm_button_add(win);
1373 elm_object_text_set(bt, "Login");
1374 evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
1375 evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
1376 evas_object_show(bt);
1377#endif
1378// evas_object_smart_callback_add(bt, "clicked", NULL, NULL);
1379 elm_box_pack_end(bx, bt);
1380 evas_object_show(bx);
1381
1382 fang_win_complete(gld, win, 30, 30, gld->win_w / 3, gld->win_h / 3);
1383}
1384
1385EAPI_MAIN int elm_main(int argc, char **argv)
1386{
1387// Evas_Object *bg, *menu, *bt, *tb;
1388 Evas_Object *menu, *tb;
1389 Elm_Object_Item *tb_it;
1390//, *menu_it;
1391 EPhysics_Body *boundary;
1392 EPhysics_World *world;
1393 EPhysics_Body *box_body1, *box_body2;
1394 Evas_Object *box1, *box2;
1395 GLData *gld = NULL;
1396// char buf[PATH_MAX];
1397// int i;
1398// Eina_Bool gotWebKit = elm_need_web(); // Initialise ewebkit if it exists, or return EINA_FALSE if it don't.
1399
1400 _log_domain = eina_log_domain_register("extantz", NULL);
1401 // Don't do this, we need to clean up other stuff to, so set a clean up function below.
1402 //elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
1403
1404 // If you want efl to handle finding your bin/lib/data dirs, you must do this below.
1405 elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR);
1406 elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
1407 elm_app_info_set(elm_main, "datadir", "media/sky_03.jpg");
1408 fprintf(stdout, "prefix was set to: %s\n", elm_app_prefix_dir_get());
1409 fprintf(stdout, "data directory is: %s\n", elm_app_data_dir_get());
1410 fprintf(stdout, "library directory is: %s\n", elm_app_lib_dir_get());
1411 fprintf(stdout, "locale directory is: %s\n", elm_app_locale_dir_get());
1412
1413 // These are set via the elementary_config tool, which is hard to find.
1414 elm_config_finger_size_set(0);
1415 elm_config_scale_set(1.0);
1416
1417 // alloc a data struct to hold our relevant gl info in
1418 if (!(gld = calloc(1, sizeof(GLData)))) return 1;
1419 gldata_init(gld);
1420
1421 // Set the engine to opengl_x11, then open our window.
1422 if (gld->useEGL)
1423 elm_config_preferred_engine_set("opengl_x11");
1424 gld->win = elm_win_add(NULL, "extantz", ELM_WIN_BASIC);
1425 // Set preferred engine back to default from config
1426 elm_config_preferred_engine_set(NULL);
1427
1428#if USE_PHYSICS
1429 if (!ephysics_init())
1430 return 1;
1431#endif
1432
1433 elm_win_title_set(gld->win, "extantz virtual world manager");
1434 evas_object_smart_callback_add(gld->win, "delete,request", _on_done, gld);
1435
1436 // Get the screen size.
1437 elm_win_screen_size_get(gld->win, &gld->win_x, &gld->win_y, &gld->scr_w, &gld->scr_h);
1438 gld->win_x = gld->win_x + (gld->scr_w / 3);
1439 gld->win_w = gld->scr_w / 2;
1440 gld->win_h = gld->scr_h - 30;
1441
1442 // Note, we don't need an Elm_bg, the entire thing gets covered with the GL rendering surface anyway.
1443#if 0
1444 bg = elm_bg_add(gld->win);
1445 elm_bg_load_size_set(bg, gld->win_w, gld->win_h);
1446 elm_bg_option_set(bg, ELM_BG_OPTION_CENTER);
1447 snprintf(buf, sizeof(buf), "%s/media/sky_03.jpg", elm_app_data_dir_get());
1448 elm_bg_file_set(bg, buf, NULL);
1449 evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1450 elm_win_resize_object_add(gld->win, bg);
1451 evas_object_show(bg);
1452#endif
1453
1454 gld->bx = elm_box_add(gld->win);
1455 evas_object_size_hint_weight_set(gld->bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1456 evas_object_size_hint_align_set(gld->bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
1457 elm_win_resize_object_add(gld->win, gld->bx);
1458 evas_object_show(gld->bx);
1459
1460 overlay_add(gld);
1461 woMan_add(gld);
1462 chat_add(gld);
1463
1464 // Gotta do this after adding the windows, otherwise the menu renders under the window.
1465 // This sucks, gotta redefine this menu each time we create a new window?
1466 // Also, GL focus gets lost when any menu is used. sigh
1467
1468 // A toolbar thingy.
1469 tb = elm_toolbar_add(gld->win);
1470 evas_object_size_hint_weight_set(tb, EVAS_HINT_EXPAND, 0.0);
1471 evas_object_size_hint_align_set(tb, EVAS_HINT_FILL, EVAS_HINT_FILL);
1472 elm_toolbar_shrink_mode_set(tb, ELM_TOOLBAR_SHRINK_SCROLL);
1473 elm_toolbar_align_set(tb, 0.0);
1474
1475 // Menus.
1476 menu = _toolbar_menu_add(gld->win, tb, "file");
1477 elm_menu_item_add(menu, NULL, NULL, "quit", _on_done, gld);
1478
1479 menu = _toolbar_menu_add(gld->win, tb, "edit");
1480 elm_menu_item_add(menu, NULL, NULL, "preferences", NULL, NULL);
1481
1482 menu = _toolbar_menu_add(gld->win, tb, "view");
1483 menu = _toolbar_menu_add(gld->win, tb, "world");
1484 menu = _toolbar_menu_add(gld->win, tb, "tools");
1485
1486 menu = _toolbar_menu_add(gld->win, tb, "help");
1487 elm_menu_item_add(menu, NULL, NULL, "grid help", NULL, NULL);
1488 elm_menu_item_separator_add(menu, NULL);
1489 elm_menu_item_add(menu, NULL, NULL, "extantz blogs", NULL, NULL);
1490 elm_menu_item_add(menu, NULL, NULL, "extantz forum", NULL, NULL);
1491 elm_menu_item_separator_add(menu, NULL);
1492 elm_menu_item_add(menu, NULL, NULL, "about extantz", NULL, NULL);
1493
1494 menu = _toolbar_menu_add(gld->win, tb, "advanced");
1495 elm_menu_item_add(menu, NULL, NULL, "debug settings", NULL, NULL);
1496
1497 menu = _toolbar_menu_add(gld->win, tb, "god");
1498
1499 // Other stuff in the toolbar.
1500 tb_it = elm_toolbar_item_append(tb, NULL, NULL, NULL, NULL);
1501 elm_toolbar_item_separator_set(tb_it, EINA_TRUE);
1502 tb_it = elm_toolbar_item_append(tb, NULL, "restriction icons", NULL, NULL);
1503 tb_it = elm_toolbar_item_append(tb, NULL, NULL, NULL, NULL);
1504 elm_toolbar_item_separator_set(tb_it, EINA_TRUE);
1505 tb_it = elm_toolbar_item_append(tb, NULL, "hop://localhost/Anarchadia 152, 155, 51 - Lost plot (Adult)", NULL, NULL);
1506 tb_it = elm_toolbar_item_append(tb, NULL, NULL, NULL, NULL);
1507 elm_toolbar_item_separator_set(tb_it, EINA_TRUE);
1508 tb_it = elm_toolbar_item_append(tb, NULL, "date time:o'clock", NULL, NULL);
1509
1510 // The toolbar needs to be packed into the box AFTER the menus are added.
1511 evas_object_show(tb);
1512 elm_box_pack_start(gld->bx, tb);
1513
1514 // This does elm_box_pack_end(), so needs to be after the others.
1515 init_evas_gl(gld);
1516
1517 evas_object_show(gld->bx);
1518
1519#if USE_PHYSICS
1520 // ePhysics stuff.
1521 world = ephysics_world_new();
1522 ephysics_world_render_geometry_set(world, 0, 0, -50, gld->win_w, gld->win_h, 100);
1523
1524 boundary = ephysics_body_bottom_boundary_add(world);
1525 ephysics_body_restitution_set(boundary, 1);
1526 ephysics_body_friction_set(boundary, 0);
1527
1528 boundary = ephysics_body_top_boundary_add(world);
1529 ephysics_body_restitution_set(boundary, 1);
1530 ephysics_body_friction_set(boundary, 0);
1531
1532 boundary = ephysics_body_left_boundary_add(world);
1533 ephysics_body_restitution_set(boundary, 1);
1534 ephysics_body_friction_set(boundary, 0);
1535
1536 boundary = ephysics_body_right_boundary_add(world);
1537 ephysics_body_restitution_set(boundary, 1);
1538 ephysics_body_friction_set(boundary, 0);
1539
1540 box1 = elm_image_add(gld->win);
1541 elm_image_file_set(box1, PACKAGE_DATA_DIR "/media/" EPHYSICS_TEST_THEME ".edj", "blue-cube");
1542 evas_object_move(box1, gld->win_w / 2 - 80, gld->win_h - 200);
1543 evas_object_resize(box1, 70, 70);
1544 evas_object_show(box1);
1545
1546 box_body1 = ephysics_body_box_add(world);
1547 ephysics_body_evas_object_set(box_body1, box1, EINA_TRUE);
1548 ephysics_body_restitution_set(box_body1, 0.7);
1549 ephysics_body_friction_set(box_body1, 0);
1550 ephysics_body_linear_velocity_set(box_body1, -150, 200, 0);
1551 ephysics_body_angular_velocity_set(box_body1, 0, 0, 36);
1552 ephysics_body_sleeping_threshold_set(box_body1, 0.1, 0.1);
1553
1554 box2 = elm_image_add(gld->win);
1555 elm_image_file_set(box2, PACKAGE_DATA_DIR "/media/" EPHYSICS_TEST_THEME ".edj", "purple-cube");
1556 evas_object_move(box2, gld->win_w / 2 + 10, gld->win_h - 200);
1557 evas_object_resize(box2, 70, 70);
1558 evas_object_show(box2);
1559
1560 box_body2 = ephysics_body_box_add(world);
1561 ephysics_body_evas_object_set(box_body2, box2, EINA_TRUE);
1562 ephysics_body_restitution_set(box_body2, 0.7);
1563 ephysics_body_friction_set(box_body2, 0);
1564 ephysics_body_linear_velocity_set(box_body2, 80, -60, 0);
1565 ephysics_body_angular_velocity_set(box_body2, 0, 0, 360);
1566 ephysics_body_sleeping_threshold_set(box_body2, 0.1, 0.1);
1567
1568 ephysics_world_gravity_set(world, 0, 0, 0);
1569#endif
1570
1571 evas_object_move(gld->win, gld->win_x, gld->win_y);
1572 evas_object_resize(gld->win, gld->win_w, gld->win_h);
1573 evas_object_show(gld->win);
1574
1575 _resize_winwin(gld);
1576
1577 elm_run();
1578
1579#if USE_PHYSICS
1580 ephysics_world_del(world);
1581 ephysics_shutdown();
1582#endif
1583
1584 elm_shutdown();
1585
1586 return 0;
1587}
1588ELM_MAIN()
diff --git a/src/extantz/extantz.edc b/src/extantz/extantz.edc
new file mode 100644
index 0000000..b4ed0b3
--- /dev/null
+++ b/src/extantz/extantz.edc
@@ -0,0 +1,30 @@
1externals {
2 external: "elm";
3}
4
5collections {
6#define ADD_CUBE(_group, _file) \
7 images { \
8 image: #_file##".png" COMP; \
9 } \
10 group { \
11 name: #_group; \
12 parts { \
13 part { \
14 name: "cube"; \
15 type: IMAGE; \
16 mouse_events: 1; \
17 repeat_events: 0; \
18 description { \
19 state: "default" 0.0; \
20 image.normal: #_file##".png"; \
21 } \
22 } \
23 } \
24 }
25
26ADD_CUBE(blue-cube, cube-blue);
27ADD_CUBE(purple-cube, cube-purple);
28
29#undef ADD_CUBE
30}
diff --git a/src/extantz/extantz.h b/src/extantz/extantz.h
new file mode 100644
index 0000000..afb94af
--- /dev/null
+++ b/src/extantz/extantz.h
@@ -0,0 +1,215 @@
1#define USE_EO 0
2#define USE_PHYSICS 1
3#define USE_EGL 1 // If using Evas_GL, though it might be via Elm.
4#define USE_ELM_GL 1
5#define USE_IRR 1
6#define USE_DEMO 1
7#define DO_GEARS 0
8
9#if USE_EO
10 /* Enable access to unstable EFL API that are still in beta */
11 #define EFL_BETA_API_SUPPORT 1
12 /* Enable access to unstable EFL EO API. */
13 #define EFL_EO_API_SUPPORT 1
14#endif
15
16#include <Elementary.h>
17#include <elm_widget_glview.h>
18#include <Evas_GL.h>
19#include <EPhysics.h>
20#include "extantzCamera.h"
21
22
23#ifdef GL_GLES
24#include <EGL/egl.h>
25#include <EGL/eglext.h>
26#else
27# include <GL/glext.h>
28# include <GL/glx.h>
29#endif
30
31
32#ifdef __cplusplus
33/*
34In the Irrlicht Engine, everything can be found in the namespace 'irr'. So if
35you want to use a class of the engine, you have to write irr:: before the name
36of the class. For example to use the IrrlichtDevice write: irr::IrrlichtDevice.
37To get rid of the irr:: in front of the name of every class, we tell the
38compiler that we use that namespace from now on, and we will not have to write
39irr:: anymore.
40*/
41using namespace irr;
42
43/*
44There are 5 sub namespaces in the Irrlicht Engine. Take a look at them, you can
45read a detailed description of them in the documentation by clicking on the top
46menu item 'Namespace List' or by using this link:
47http://irrlicht.sourceforge.net/docu/namespaces.html
48Like the irr namespace, we do not want these 5 sub namespaces now, to keep this
49example simple. Hence, we tell the compiler again that we do not want always to
50write their names.
51*/
52using namespace core;
53using namespace scene;
54using namespace video;
55
56extern "C"{
57#else
58
59// Irrlicht stuff. It's C++, so we gotta use incomplete types.
60typedef struct IrrlichtDevice IrrlichtDevice;
61typedef struct IVideoDriver IVideoDriver;
62typedef struct ISceneManager ISceneManager;
63typedef struct ICameraSceneNode ICameraSceneNode;
64
65#endif
66
67
68#define CRI(...) EINA_LOG_DOM_CRIT(_log_domain, _VA_ARGS__)
69#define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
70#define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
71#define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
72#define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
73
74extern int _log_domain;
75
76
77typedef struct _Gear Gear;
78typedef struct _GLData GLData;
79
80typedef enum
81{
82 EZP_NONE,
83 EZP_AURORA,
84 EZP_OPENSIM,
85 EZP_SECOND_LIFE,
86 EZP_SLEDJHAMR,
87 EZP_TRITIUM
88} ezPlatform;
89
90typedef struct
91{
92 char *name;
93 char *version; // Version string.
94 char *path; // OS filesystem path to the viewer install.
95 char *icon;
96 uint16_t tag; // The UUID of the texture used in the avatar bake hack.
97 uint8_t r, g, b; // Colour used for the in world tag.
98 Elm_Object_Item *item;
99} ezViewer;
100
101typedef struct
102{
103 Eina_Clist accounts;
104 Eina_Clist landmarks;
105 char *name;
106 char *loginURI;
107 char *splashPage;
108 char *helperURI;
109 char *website;
110 char *supportPage;
111 char *registerPage;
112 char *passwordPage;
113 char *icon;
114 ezPlatform platform;
115 ezViewer *viewer;
116 Elm_Object_Item *item;
117GLData *gld; // Just a temporary evil hack to pass gld to _grid_sel_cb().
118} ezGrid;
119
120typedef struct
121{
122 Eina_Clist grid;
123 char *name;
124 char *password; // Think we need to pass unencrypted passwords to the viewer. B-(
125 char *icon;
126 ezViewer *viewer;
127} ezAccount;
128
129typedef struct
130{
131 Eina_Clist grid;
132 char *name;
133 char *sim;
134 char *screenshot;
135 short x, y, z;
136} ezLandmark;
137
138
139
140struct _Gear
141{
142 GLfloat *vertices;
143 GLuint vbo;
144 int count;
145};
146
147// GL related data here.
148struct _GLData
149{
150 Evas_Object *win, *winwin;
151
152 Ecore_Evas *ee;
153 Evas *canvas;
154 Evas_Native_Surface ns;
155
156 Evas_GL_Context *ctx;
157 Evas_GL_Surface *sfc;
158 Evas_GL_Config *cfg;
159 Evas_GL *evasGl; // The Evas way.
160 Evas_Object *elmGl; // The Elm way.
161 Evas_GL_API *glApi;
162
163 GLuint program;
164 GLuint vtx_shader;
165 GLuint fgmt_shader;
166 int scr_w, scr_h; // The size of the screen.
167 int win_w, win_h; // The size of the window.
168 int win_x, win_y; // The position of the window.
169 int sfc_w, sfc_h; // This is what Irrlicht is using, size of the GL image surface / glview.
170 int img_w, img_h; // Size of the viewport. DON'T reuse sfc_* here. Despite the fach that sfc_* is only used in the init when Irricht is disabled? WTF?
171 int useEGL : 1;
172 int useIrr : 1;
173 int doneIrr : 1;
174 int gearsInited : 1;
175 int resized : 1;
176
177 Evas_Object *bx, *r1;
178 Ecore_Animator *animator;
179
180 IrrlichtDevice *device;
181 IVideoDriver *driver;
182 ISceneManager *smgr;
183 ICameraSceneNode *camera;
184
185 cameraMove *move;
186
187 // Gear Stuff
188 GLfloat view_rotx;
189 GLfloat view_roty;
190 GLfloat view_rotz;
191
192 Gear *gear1;
193 Gear *gear2;
194 Gear *gear3;
195
196 GLfloat angle;
197
198 GLuint proj_location;
199 GLuint light_location;
200 GLuint color_location;
201
202 GLfloat proj[16];
203 GLfloat light[3];
204};
205
206
207EAPI int startIrr(GLData *gld);
208EAPI void drawIrr_start(GLData *gld);
209EAPI void drawIrr_end(GLData *gld);
210EAPI void finishIrr(GLData *gld);
211
212#ifdef __cplusplus
213}
214#endif
215
diff --git a/src/extantz/extantzCamera.cpp b/src/extantz/extantzCamera.cpp
new file mode 100644
index 0000000..6a7d36a
--- /dev/null
+++ b/src/extantz/extantzCamera.cpp
@@ -0,0 +1,282 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5// The above is the copyright notice for CSceneNodeAnimatorCameraFPS.cpp,
6// According to the Irrlicht docs, that's just a demo and you are supposed to use it as an example for writing your own FPS style camera.
7// I'll be writing my own camera code, that includes first person, third person, and free camera styles.
8// I'll start with CSceneNodeAnimatorCameraFPS.cpp and morph it until it suits me.
9// As such, I expect lots of Nikolaus Gebhardt's code to go away.
10// To be replaced by my code, which will be copyright and licensed under the same license as the rest of extantz.
11
12// Initally I'll make it SecondLife like, coz that's what my muscle memory is used to.
13// It will get extended and made generic though.
14
15#include "extantzCamera.h"
16#include "IVideoDriver.h"
17#include "ISceneManager.h"
18#include "Keycodes.h"
19#include "ICursorControl.h"
20#include "ICameraSceneNode.h"
21#include "ISceneNodeAnimatorCollisionResponse.h"
22
23namespace irr
24{
25namespace scene
26{
27
28// Irrlicht hard codes a reference to the original FPS camera code inside it's scene manager. This is that code extracted so we can be more flexible.
29// TODO - Hmmm, Where's CursorControl come from? Ah, passed to the scene manager constructor, it's a GUI thing that we need to replace with an EFL thing. But only for mouselook mode.
30ICameraSceneNode *addExtantzCamera(ISceneManager* sm, ISceneNode* parent, s32 id)
31{
32 ICameraSceneNode* node = sm->addCameraSceneNode(parent, core::vector3df(), core::vector3df(0, 0, 100), id, true);
33 if (node)
34 {
35// ISceneNodeAnimator* anm = new extantzCamera(CursorControl);
36 ISceneNodeAnimator* anm = new extantzCamera();
37
38 // Bind the node's rotation to its target. This is consistent with 1.4.2 and below.
39 node->bindTargetAndRotation(true);
40 node->addAnimator(anm);
41 anm->drop();
42 }
43
44 return node;
45}
46
47
48//! constructor
49//extantzCamera::extantzCamera(gui::ICursorControl* cursorControl)
50// : CursorControl(cursorControl), MaxVerticalAngle(88.0f), MoveSpeed(0.4f), RotateSpeed(100.0f), JumpSpeed(3.0f),
51extantzCamera::extantzCamera()
52 : MaxVerticalAngle(88.0f), MouseYDirection(1.0f), LastAnimationTime(0), NoVerticalMovement(false)
53{
54 #ifdef _DEBUG
55 setDebugName("extantzCamera");
56 #endif
57
58 move.jump = 0.0; // Coz otherwise we start in jumping mode.
59 move.MoveSpeed = 0.1f;
60 move.RotateSpeed = 1.0f;
61 move.JumpSpeed = 3.0f;
62
63// if (CursorControl)
64// CursorControl->grab();
65}
66
67
68//! destructor
69extantzCamera::~extantzCamera()
70{
71// if (CursorControl)
72// CursorControl->drop();
73}
74
75
76void extantzCamera::animateNode(ISceneNode* node, u32 timeMs)
77{
78 if (!node || node->getType() != ESNT_CAMERA)
79 return;
80
81 ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);
82
83 if (0 == LastAnimationTime)
84 {
85 camera->updateAbsolutePosition();
86// if (CursorControl )
87// {
88// CursorControl->setPosition(0.5f, 0.5f);
89// CursorPos = CenterCursor = CursorControl->getRelativePosition();
90// }
91
92 LastAnimationTime = timeMs;
93 }
94
95 // If the camera isn't the active camera, and receiving input, then don't process it.
96 // TODO - it never is, coz we are bypassing that, but can we replace this with something else?
97 if(!camera->isInputReceiverEnabled())
98 {
99// return;
100 }
101
102 scene::ISceneManager * smgr = camera->getSceneManager();
103 if(smgr && smgr->getActiveCamera() != camera)
104 return;
105
106 // get time
107 f32 timeDiff = (f32) (timeMs - LastAnimationTime);
108 LastAnimationTime = timeMs;
109
110 // update position
111 core::vector3df pos = camera->getPosition();
112
113 // Update rotation
114 core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition());
115 core::vector3df relativeRotation = target.getHorizontalAngle();
116
117#if 0
118 if (CursorControl)
119 {
120 if (CursorPos != CenterCursor)
121 {
122 relativeRotation.Y -= (0.5f - CursorPos.X) * move.RotateSpeed;
123 relativeRotation.X -= (0.5f - CursorPos.Y) * move.RotateSpeed * MouseYDirection;
124
125 // X < MaxVerticalAngle or X > 360-MaxVerticalAngle
126
127 if (relativeRotation.X > MaxVerticalAngle*2 &&
128 relativeRotation.X < 360.0f-MaxVerticalAngle)
129 {
130 relativeRotation.X = 360.0f-MaxVerticalAngle;
131 }
132 else
133 if (relativeRotation.X > MaxVerticalAngle &&
134 relativeRotation.X < 360.0f-MaxVerticalAngle)
135 {
136 relativeRotation.X = MaxVerticalAngle;
137 }
138
139 // Do the fix as normal, special case below
140 // reset cursor position to the centre of the window.
141 CursorControl->setPosition(0.5f, 0.5f);
142 CenterCursor = CursorControl->getRelativePosition();
143
144 // needed to avoid problems when the event receiver is disabled
145 CursorPos = CenterCursor;
146 }
147
148 // Special case, mouse is whipped outside of window before it can update.
149 video::IVideoDriver* driver = smgr->getVideoDriver();
150 core::vector2d<u32> mousepos(u32(CursorControl->getPosition().X), u32(CursorControl->getPosition().Y));
151 core::rect<u32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);
152
153 // Only if we are moving outside quickly.
154 bool reset = !screenRect.isPointInside(mousepos);
155
156 if(reset)
157 {
158 // Force a reset.
159 CursorControl->setPosition(0.5f, 0.5f);
160 CenterCursor = CursorControl->getRelativePosition();
161 CursorPos = CenterCursor;
162 }
163 }
164#else
165 relativeRotation.Y -= move.r * move.RotateSpeed;
166 relativeRotation.X -= move.s * move.RotateSpeed * MouseYDirection;
167
168 // X < MaxVerticalAngle or X > 360-MaxVerticalAngle
169
170 if ((relativeRotation.X > (MaxVerticalAngle * 2)) && (relativeRotation.X < (360.0f - MaxVerticalAngle)))
171 relativeRotation.X = 360.0f - MaxVerticalAngle;
172 else if ((relativeRotation.X > MaxVerticalAngle) && (relativeRotation.X < (360.0f - MaxVerticalAngle)))
173 relativeRotation.X = MaxVerticalAngle;
174#endif
175
176 // set target
177
178 target.set(0,0, core::max_(1.f, pos.getLength()));
179 core::vector3df movedir = target;
180
181 core::matrix4 mat;
182 mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0));
183 mat.transformVect(target);
184
185 if (NoVerticalMovement)
186 {
187 mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0));
188 mat.transformVect(movedir);
189 }
190 else
191 {
192 movedir = target;
193 }
194
195 movedir.normalize();
196
197 pos += movedir * timeDiff * move.MoveSpeed * move.x;
198
199 // strafing
200 core::vector3df strafevect = target;
201 strafevect = strafevect.crossProduct(camera->getUpVector());
202
203 if (NoVerticalMovement)
204 strafevect.Y = 0.0f;
205
206 strafevect.normalize();
207
208 pos += strafevect * timeDiff * move.MoveSpeed * move.y;
209
210 // For jumping, we find the collision response animator attached to our camera
211 // and if it's not falling, we tell it to jump.
212 if (0.0 < move.jump)
213 {
214 const ISceneNodeAnimatorList& animators = camera->getAnimators();
215 ISceneNodeAnimatorList::ConstIterator it = animators.begin();
216 while(it != animators.end())
217 {
218 if(ESNAT_COLLISION_RESPONSE == (*it)->getType())
219 {
220 ISceneNodeAnimatorCollisionResponse * collisionResponse =
221 static_cast<ISceneNodeAnimatorCollisionResponse *>(*it);
222
223 if(!collisionResponse->isFalling())
224 collisionResponse->jump(move.JumpSpeed);
225 }
226
227 it++;
228 }
229 }
230
231 // write translation
232 camera->setPosition(pos);
233
234 // write right target
235 target += pos;
236 camera->setTarget(target);
237}
238
239
240ISceneNodeAnimator* extantzCamera::createClone(ISceneNode* node, ISceneManager* newManager)
241{
242// extantzCamera *newAnimator = new extantzCamera(CursorControl);
243 extantzCamera *newAnimator = new extantzCamera();
244 return newAnimator;
245}
246
247#ifdef __cplusplus
248extern "C" {
249#endif
250
251cameraMove *getCameraMove(ICameraSceneNode *camera)
252{
253 cameraMove *cm = NULL;
254
255 if (camera)
256 {
257 const ISceneNodeAnimatorList &animators = camera->getAnimators();
258 ISceneNodeAnimatorList::ConstIterator it = animators.begin();
259 while(it != animators.end())
260 {
261 // TODO - We assume FPS == extantzCamera, coz Irrlicht hard codes the camera types in an enum, which is a pain to add to from outside.
262 if(ESNAT_CAMERA_FPS == (*it)->getType())
263 {
264 extantzCamera *ec = static_cast<extantzCamera *>(*it);
265
266 cm = &(ec->move);
267 }
268
269 it++;
270 }
271 }
272 return cm;
273}
274
275#ifdef __cplusplus
276}
277#endif
278
279
280} // namespace scene
281} // namespace irr
282
diff --git a/src/extantz/extantzCamera.h b/src/extantz/extantzCamera.h
new file mode 100644
index 0000000..9d74236
--- /dev/null
+++ b/src/extantz/extantzCamera.h
@@ -0,0 +1,101 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#ifndef __EXTANTZ_CAMERA_H_INCLUDED__
6#define __EXTANTZ_CAMERA_H_INCLUDED__
7
8
9#ifdef __cplusplus
10#include <ISceneNodeAnimator.h>
11#include <vector2d.h>
12#include <position2d.h>
13#include <SKeyMap.h>
14#include <irrArray.h>
15#include <ICameraSceneNode.h>
16
17using namespace irr;
18using namespace scene;
19
20extern "C"{
21#else
22typedef struct extantzCamera extantzCamera;
23typedef struct ICameraSceneNode ICameraSceneNode;
24#endif
25
26typedef struct
27{
28 float x, y, z;
29 float r, s, t;
30 float jump;
31 float JumpSpeed, RotateSpeed, MoveSpeed;
32} cameraMove;
33
34cameraMove *getCameraMove(ICameraSceneNode *camera);
35
36#ifdef __cplusplus
37}
38
39
40//namespace irr::gui
41//{
42// class ICursorControl;
43//}
44
45
46namespace irr
47{
48namespace scene
49{
50 ICameraSceneNode *addExtantzCamera(ISceneManager* sm, ISceneNode* parent, s32 id);
51
52 class extantzCamera : public ISceneNodeAnimator
53 {
54 public:
55
56 //! Constructor
57// extantzCamera(gui::ICursorControl* cursorControl);
58 extantzCamera();
59
60 //! Destructor
61 virtual ~extantzCamera();
62
63 //! Animates the scene node, currently only works on cameras
64 virtual void animateNode(ISceneNode* node, u32 timeMs);
65
66 //! This animator will receive events when attached to the active camera
67 virtual bool isEventReceiverEnabled() const
68 {
69 return false;
70 }
71
72 //! Returns the type of this animator
73 virtual ESCENE_NODE_ANIMATOR_TYPE getType() const
74 {
75 return ESNAT_CAMERA_FPS;
76 }
77
78 //! Creates a clone of this animator.
79 /** Please note that you will have to drop
80 (IReferenceCounted::drop()) the returned pointer once you're
81 done with it. */
82 virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0);
83
84 bool NoVerticalMovement;
85 // -1.0f for inverted mouse, defaults to 1.0f
86 f32 MouseYDirection;
87
88 cameraMove move;
89
90 private:
91 f32 MaxVerticalAngle;
92 s32 LastAnimationTime;
93// core::position2d<f32> CenterCursor, CursorPos;
94 };
95};
96};
97#endif
98
99
100#endif // __EXTANTZ_CAMERA_H_INCLUDED__
101