scenemanager is stl-free
[fegdk.git] / tools / test / test.cpp
blob5af528261e69751bb921c9044dc98ececf84a2f2
1 // this tool is a reference application for all FEGDK features.
2 // it is also a good "howto" guide, cause it's documented relatively good.
3 // just use grep and read code comments.
4 //
5 // the application is forked off of a years-old "mdlview" app, which is bundled too
6 //
7 // tool is supposed to draw some appropriate model (which can change anytime), play/stop music and sound effects, draw debugging information, showcase rendering features, let the user change rendering modes, use console, etc.
9 #include <fegdk/config.h>
10 #ifndef SOUND_DISABLED
11 #define ENABLE_MUSIC 1
12 #else
13 #define ENABLE_MUSIC 0
14 #endif
16 #define ENABLE_FONT 1
18 #include <fegdk/pch.h> // we don't use precompiled headers most of the time. i must change it to something apropriate someday...
20 #include <fegdk/f_application.h>
21 #include <fegdk/f_engine.h>
22 #include <fegdk/f_model.h>
24 #if ENABLE_FONT
25 #include <fegdk/f_fontft.h>
26 #endif
28 #if ENABLE_MUSIC
29 #include <fegdk/f_oggvorbis.h>
30 #include <fegdk/f_modmusic.h>
31 #include <fegdk/wavfile.h>
32 #endif
34 #include <fegdk/f_console.h>
36 #include <fegdk/f_input.h>
37 #include <fegdk/f_baseviewport.h>
38 #include <fegdk/f_animation.h>
39 #include <fegdk/f_timer.h>
40 #include <fegdk/f_baserenderer.h>
41 #include <fegdk/f_effectparms.h>
42 #include <fegdk/f_resourcemgr.h>
43 #include <fegdk/f_drawutil.h>
44 #include <fegdk/f_scenemanager.h>
46 #include <fegdk/f_lightsource.h>
48 #include <GL/gl.h> // gl is STILL required, cause we need it to draw some stuff. it will be removed when the engine will be more feature-complete.
50 #include <fegdk/f_parser.h>
51 #include <fegdk/f_types.h>
53 #include <fegdk/netmanager.h>
54 #include <fegdk/animsequencer.h>
56 //#include <fegdk/physx.h>
57 #include <fegdk/entitymanager.h>
58 #include <fegdk/entclasses.h>
60 #include <vector>
62 using namespace fe;
64 class TestApp : public application
67 private:
69 smartPtr <animContainer> mpAnimContainer;
70 smartPtr <animation> mpAnimation;
71 std::vector <smartPtr <sceneObject> > mpModels;
72 int mCurrentModel;
73 matrix4 mMatrix;
74 float mAngleX;
75 float mAngleY;
76 float mDist;
77 fe::ulong mFrameTime;
78 fe::ulong mPrevTime;
79 #if ENABLE_MUSIC
80 // vorbisFile* mpMusic;
81 smartPtr <modMusic> mpMod;
82 smartPtr <vorbisFile> mpVorbis;
83 smartPtr <wavFile> mpWav;
84 #endif
86 #if ENABLE_FONT
87 smartPtr< fontFT > mpFont;
88 smartPtr< fontFT > mpBoldFont;
89 #endif
91 smartPtr <netManager> mpNetManager;
92 smartPtr <netSocket> mpRSocket;
94 bool mbDrawHelp;
95 bool mbPlayMusic;
96 bool mbDrawModel;
97 bool mbWireframe;
98 bool mbShadowVolume;
99 bool mbShadows;
100 bool mbTangents;
102 enum { MAX_POINTS_ON_WINDING = 64 };
103 struct winding_t {
104 vector3 points[MAX_POINTS_ON_WINDING];
105 int npoints;
106 winding_t *next;
109 struct cluster_t;
111 struct portal_t {
112 vector3 points[MAX_POINTS_ON_WINDING];
113 int npoints;
114 portal_t *next[2];
115 cluster_t *clusters[2];
119 struct cluster_t {
120 portal_t *portals;
121 winding_t *faces;
122 cluster_t *next;
125 cluster_t *mpClusters;
126 cluster_t *mpCurrentCluster;
128 void free_prt (void)
130 cluster_t *next;
131 for (cluster_t *c = mpClusters; c; c = next)
133 next = c->next;
134 portal_t *nextp;
135 for (portal_t *p = c->portals; p; p = nextp)
137 int side = p->clusters[0] == c ? 0 : 1;
138 nextp = p->next[side];
139 delete p;
141 winding_t *nextf;
142 for (winding_t *f = c->faces; f; f = nextf)
144 nextf = f->next;
145 delete f;
147 delete c;
151 void load_prt (void)
153 charParser p (NULL, "test.prt", true);
154 // magic, numclusters, numportals, numfaces
155 p.getToken ();
156 p.getToken ();
157 int nclusters = atoi (p.token ());
158 p.getToken ();
159 int nportals = atoi (p.token ());
160 p.getToken ();
161 int nfaces = atoi (p.token ());
162 int i;
164 // create clusters
165 for (i = 0; i < nclusters; i++)
167 cluster_t *clust = new cluster_t;
168 memset (clust, 0, sizeof (cluster_t));
169 clust->next = mpClusters;
170 mpClusters = clust;
173 for (i = 0; i < nportals; i++)
175 int nclust;
176 int k;
177 cluster_t *c;
178 portal_t *port = new portal_t;
179 memset (port, 0, sizeof (portal_t));
180 p.getToken (); // npoints
181 port->npoints = atoi (p.token ());
182 p.getToken (); // clust1
183 nclust = atoi (p.token ());
184 for (k = 0, c = mpClusters; k < nclust && c; k++, c = c->next);
185 port->next[0] = c->portals;
186 c->portals = port;
187 port->clusters[0] = c;
188 p.getToken (); // clust2
189 nclust = atoi (p.token ());
190 for (k = 0, c = mpClusters; k < nclust && c; k++, c = c->next);
191 port->next[1] = c->portals;
192 c->portals = port;
193 port->clusters[1] = c;
194 p.getToken (); // hint
195 // points
196 for (k = 0; k < port->npoints; k++)
198 p.matchToken ("(");
199 p.getToken ();
200 port->points[k][0] = atof (p.token ());
201 p.getToken ();
202 port->points[k][1] = atof (p.token ());
203 p.getToken ();
204 port->points[k][2] = atof (p.token ());
205 p.matchToken (")");
209 for (i = 0; i < nfaces; i++)
211 winding_t *face = new winding_t;
212 memset (face, 0, sizeof (winding_t));
213 p.errMode (0);
214 if (p.getToken ()) // numpoints
215 break;
216 p.errMode (1);
217 face->npoints = atoi (p.token ());
218 p.getToken (); // cluster
219 int nclust = atoi (p.token ());
220 int k;
221 cluster_t *c;
222 for (k = 0, c = mpClusters; k < nclust && c; k++, c = c->next);
223 face->next = c->faces;
224 c->faces = face;
225 // points
226 for (k = 0; k < face->npoints; k++)
228 p.matchToken ("(");
229 p.getToken ();
230 face->points[k][0] = atof (p.token ());
231 p.getToken ();
232 face->points[k][1] = atof (p.token ());
233 p.getToken ();
234 face->points[k][2] = atof (p.token ());
235 p.matchToken (")");
241 public:
243 TestApp (void)
245 mbDrawHelp = false;
246 mbPlayMusic = false;
247 mbDrawModel = true;
248 mbWireframe = false;
249 mbShadowVolume = false;
250 mbShadows = false;
251 mbTangents = false;
253 mDist = 30.f;
254 mpClusters = NULL;
257 bool isFullscreen (void)
259 return false;
262 void init ()
264 // mMatrix.identity ();
265 mMatrix.camera (vector3 (0, -300, 0), vector3::zero, vector3 (0, 0, 1));
266 // (vector3&)mMatrix._11 = -(vector3&)mMatrix._11;
267 // (vector3&)mMatrix._22 = (vector3&)mMatrix._22;
268 // (vector3&)mMatrix._33 = (vector3&)mMatrix._33;
270 sceneObject *mdl;
271 sceneObject *root = new sceneObject (NULL);
272 for (int j = 0; j < 10; j++)
274 for (int i = 0; i < 10; i++)
276 mdl = g_engine->getResourceMgr ()->createModel ("models/lmtest.bmdl");
277 matrix4 m = mdl->getRelativeMatrix ();
278 m._41 += (i-5) * 200;
279 m._43 += (j-5) * 200;
280 mdl->setRelativeMatrix (m);
281 mdl->update (sceneObject::F_RECALC_MATRIX);
282 root->addChild (mdl);
286 mpModels.push_back (root);
287 mpModels.push_back (g_engine->getResourceMgr ()->createModel ("models/crate.bmdl"));
288 //mpModels.push_back (g_engine->getResourceMgr ()->createModel ("models/hierarchy.bmdl"));
289 mpAnimContainer = new animContainer;
290 mpAnimation = g_engine->getResourceMgr ()->createAnimation ("animations/baking.anm");
291 mpAnimContainer->addAnim (mpAnimation);
292 mpModels.push_back (g_engine->getResourceMgr ()->createModel ("models/baking.bmdl", mpAnimContainer));
293 mCurrentModel = 0;
294 #if ENABLE_MUSIC
295 mpVorbis = new vorbisFile ("audio/test.ogg");
296 mpMod = new modMusic ("audio/dreamfish-sanxion.mod");
297 mpWav = new wavFile ("audio/test.wav");
298 #endif
300 #if ENABLE_FONT
301 mpFont = g_engine->getResourceMgr ()->createFontFT ("ter-116n.pcf");
302 mpBoldFont = g_engine->getResourceMgr ()->createFontFT ("ter-116b.pcf");
303 #endif
304 if (mpModels[mCurrentModel])
305 g_engine->getSceneManager ()->add (mpModels[mCurrentModel]);
307 mpNetManager = new netManager ();
308 mpRSocket = mpNetManager->createReceivingSocket (6666);
310 load_prt ();
311 mpCurrentCluster = mpClusters;
315 void free ()
317 #if ENABLE_MUSIC
318 mpVorbis = NULL;
319 mpMod = NULL;
320 mpWav = NULL;
321 #endif
323 mpModels.clear ();
324 #if ENABLE_FONT
325 mpFont = NULL;
326 #endif
329 void update ()
331 application::update ();
332 // mpModel->update ();
333 g_engine->getSceneManager ()->update ();
335 // if (g_engine->getConsole ()->isVisible ())
336 // return;
338 mPrevTime = mFrameTime;
339 mFrameTime = (int) (g_engine->getTimer ()->getTime () * 1000);
341 const float speed = 100;
343 smartPtr <inputDevice> inp = g_engine->getInputDevice ();
345 // FIXME: had to be done through key bindings
346 // if (inp->getState ()->isPressed (Key_UpArrow))
347 // mDist += speed * (mFrameTime - mPrevTime) * 0.001;
348 // if (inp->getState ()->isPressed (Key_DownArrow))
349 // mDist -= speed * (mFrameTime - mPrevTime) * 0.001;
351 mMatrix._43 = 0;
353 static point prevPt;
354 point pt = inp->getCursorPos ();
356 int x = (int)pt.x - (int)prevPt.x;
357 int y = (int)pt.y - (int)prevPt.y;
359 prevPt = pt;
361 if (inp->getState ()->isPressed (Key_Mouse1))
363 // rotate
364 matrix4 r;
365 r.rotateX (-y * 0.01);
366 mMatrix = mMatrix * r;
367 r.rotateY (-x * 0.01);
368 mMatrix = mMatrix * r;
370 else if (inp->getState ()->isPressed (Key_Mouse2))
372 mDist -= y * 2;
375 if (mDist < 0)
376 mDist = 0;
378 mMatrix._43 = mDist;
380 char message[256];
381 int len = mpRSocket->recive (message, sizeof (message));
382 if (len > 0)
384 printf ("message:\n%s\n", message);
388 #if 0
389 void renderShadowVolume (const modelPtr &mdl, const lightSource &ls) const
391 // build shadow volume from provided ls
392 mdl->buildShadowVolume (ls);
394 // const modelTriangles_t &tris = model->getTriangles ();
396 // set states to make shadow volume visible in a way we want to
397 // glEnable (GL_BLEND);
398 // glBlendFunc (GL_ONE, GL_ONE);
399 glDepthMask (GL_FALSE);
401 // set transforms
402 glMatrixMode (GL_MODELVIEW);
403 const matrix4 &m = mdl->getWorldMatrix ();
404 matrix4 modelview = m * g_engine->getEffectParms ()->getMatrix (effectParm_ViewMatrix);
405 glLoadMatrixf ( (GLfloat*)&modelview);
407 // draw
408 glDepthFunc (GL_LESS);
409 glDepthMask (GL_FALSE);
410 g_engine->getDrawUtil ()->setCullMode (drawUtil::cull_front);
411 glColor3f (1, 0, 0);
412 // model->renderShadowVolume ();
413 g_engine->getDrawUtil ()->setCullMode (drawUtil::cull_back);
414 glColor3f (0, 1, 0);
415 // mdl->renderShadowVolume ();
416 glDepthMask (GL_TRUE);
417 glDepthFunc (GL_LEQUAL);
419 // cancel states
420 glDisable (GL_BLEND);
421 // glDepthMask (GL_TRUE);
423 // recurse. remember - renderShadowVolume doesn't recurse, cause it is requirement of rendering queue implementation
424 /* for (size_t i = 0; i < mdl->numChildren (); i++)
426 if (mdl->getChild (i)->isTypeOf (model::TypeId))
428 renderShadowVolume (mdl->getChild (i).dynamicCast <model> (), ls);
432 #endif
434 void render () const
436 application::render ();
437 g_engine->getRenderer ()->clear (0, NULL, baseRenderer::clear_target | baseRenderer::clear_z, float4 (.2f, .8f, .8f, 1), 1, 0);
439 // setup view and projection transforms for the scene
440 matrix4 worldview = mMatrix;
441 matrix4 viewproj;
442 smartPtr <baseViewport> vp = g_engine->getViewport ();
443 viewproj.projection (60.f*3.14f/180.f, vp->getHeight () / (float)vp->getWidth (), .1f, 10000.f);
444 g_engine->getEffectParms ()->setMatrix (effectParm_ViewMatrix, worldview);
445 g_engine->getEffectParms ()->setMatrix (effectParm_ProjMatrix, viewproj);
446 g_engine->getSceneManager ()->draw ();
448 #if 1
449 // draw current leaf
450 if (mpClusters)
452 matrix4 mtx = worldview;;
453 glMatrixMode (GL_PROJECTION);
454 glLoadMatrixf ((GLfloat*)&viewproj);
455 glMatrixMode (GL_MODELVIEW);
456 glLoadMatrixf ((GLfloat*)&mtx);
457 glDisable (GL_TEXTURE_2D);
458 glColor4f (0,0,1,1);
459 cluster_t *c;
460 for (c = mpClusters; c; c = c->next)
462 if (c == mpCurrentCluster)
463 glColor4f (0, 1, 0, 1);
464 else
465 glColor4f (0, 0, 1, 1);
466 winding_t *f;
467 for (f = c->faces; f; f = f->next)
469 glBegin (GL_LINE_LOOP);
470 for (int p = 0; p < f->npoints; p++)
472 glVertex3fv (&f->points[p].x);
474 glEnd ();
477 c = mpCurrentCluster;
478 int side = 0;
479 for (portal_t *port = c->portals; port; port = port->next[side])
481 side = port->clusters[0] == c ? 0 : 1;
482 vector3 origin(0,0,0);
483 glColor4f (1,1,1,1);
484 glBegin (GL_LINE_LOOP);
485 for (int p = 0; p < port->npoints; p++)
487 glVertex3fv (&port->points[p].x);
489 glEnd ();
490 origin /= port->npoints;
491 vector3 v1, v2;
492 v1 = port->points[2] - port->points[1];
493 v2 = port->points[0] - port->points[1];
494 vector3 norm = v1.cross (v2);
495 norm.normalize ();
496 glColor4f (1, 0, 0, 1);
497 glBegin (GL_LINES);
498 glVertex3fv (&origin.x);
499 origin += norm*2;
500 glVertex3fv (&origin.x);
501 glEnd ();
504 #endif
506 lightSource ls;
507 ls.setType (lightSource::spot);
508 ls.setPosition (vector3 (110, 0, 200));
509 ls.setDirection (vector3 (-1, 0, 0));
511 /* if (mbShadowVolume)
513 glMatrixMode (GL_PROJECTION);
514 glLoadMatrixf ( (GLfloat*)&viewproj);
515 if (mpModels[mCurrentModel])
516 renderShadowVolume (mpModels[mCurrentModel], ls);
519 #if ENABLE_FONT
520 cStr s;
521 #if 0
522 s.printf ("leaf faces: %d", leafs[currentLeaf_].windings.size ());
523 mpFont->drawTextString (s.c_str (), 0, 100, 0xffffffff);
524 s.printf ("%s", leafs[currentLeaf_].opaque ? "opaque" : "translucent");
525 mpFont->drawTextString (s.c_str (), 0, 110, 0xffffffff);
526 #endif
528 if (mbDrawHelp)
530 int h = mpFont->getTextHeight ();
531 int y = mpFont->getTextHeight () * 2;
532 mpFont->drawTextString ("'m' - toggle mod playback", 0, y, 0xffffffff);
533 y+=h;
534 mpFont->drawTextString ("'o' - toggle ogg-vorbis playback", 0, y, 0xffffffff);
535 y+=h;
536 mpFont->drawTextString ("'w' - toggle wav playback", 0, y, 0xffffffff);
537 y+=h;
538 mpFont->drawTextString ("'t' - toggle 3d model", 0, y, 0xffffffff);
539 y+=h;
540 mpFont->drawTextString ("'v' - toggle shadowvolume", 0, y, 0xffffffff);
541 y+=h;
542 mpFont->drawTextString ("'s' - toggle shadows", 0, y, 0xffffffff);
543 y+=h;
544 mpFont->drawTextString ("'p' - toggle tangents", 0, y, 0xffffffff);
545 y+=h;
546 mpFont->drawTextString ("'a' - restart animation of current scene", 0, y, 0xffffffff);
547 y+=h;
549 else
551 mpFont->drawTextString ("press 'h' for help", 0, mpFont->getTextHeight () * 2, 0xffffffff);
554 // draw text
555 mpFont->drawTextString ("Test [$Revision$]", 0, 0, 0xffffffff);
557 // draw fps
558 static float fFPS = 0.0f;
559 static float fLastTime = 0.0f;
560 static unsigned long dwFrames = 0L;
561 float fTime;
562 fTime = g_engine->getTimer ()->getTime ();
563 dwFrames++;
564 if (fTime - fLastTime > 0.5f)
566 fFPS = dwFrames / (fTime - fLastTime);
567 fLastTime = fTime;
568 dwFrames = 0L;
570 s.printf ("fps: %.2f", fFPS);
571 mpBoldFont->drawTextString (s.c_str (), 0, mpBoldFont->getTextHeight (), float4 (1,1,0,1));
572 #endif
576 void keyDown (int keycode)
578 static bool pause = false;
579 if (keycode == Key_Escape)
580 g_engine->quit ();
581 else if (keycode == '[')
583 if (mpCurrentCluster == mpClusters)
584 mpCurrentCluster = NULL;
585 for (cluster_t *c = mpClusters; c; c = c->next)
587 if (c->next == mpCurrentCluster)
589 mpCurrentCluster = c;
590 break;
594 else if (keycode == ']')
596 mpCurrentCluster = mpCurrentCluster->next;
597 if (!mpCurrentCluster)
598 mpCurrentCluster = mpClusters;
600 else if (keycode == 'b') {
601 // physics stuff
602 entityManager *em = g_engine->getEntManager ();
603 entPhysXObj *en = (entPhysXObj *)em->createEntity (ECLASS_PHYSXOBJ);
604 fprintf (stderr, "entity is %x\n", en);
605 sceneObject *m = g_engine->getResourceMgr()->createModel ("models/crate.bmdl");
606 fprintf (stderr, "crate is %x\n",m);
607 en->setModel (m);
608 en->setInitPos (vector3 (0,0,100));
609 // physx_add_entity (en);
610 g_engine->getSceneManager ()->add (m);
612 else if (keycode == 'a')
614 g_engine->getAnimSequencer ()->startAnimation (mpModels.back (), mpAnimation);
616 else if (keycode == 'h')
618 mbDrawHelp = !mbDrawHelp;
620 else if (keycode == 't')
622 mbDrawModel = !mbDrawModel;
623 if (!mbDrawModel)
625 if (mpModels[mCurrentModel])
626 g_engine->getSceneManager ()->remove (mpModels[mCurrentModel]);
628 else
630 if (mpModels[mCurrentModel])
631 g_engine->getSceneManager ()->add (mpModels[mCurrentModel]);
634 #if ENABLE_MUSIC
635 else if (keycode == 'm')
637 mbPlayMusic = !mbPlayMusic;
638 if (mbPlayMusic)
639 mpMod->play (true);
640 else
641 mpMod->stop ();
643 else if (keycode == 'o')
645 if (mpVorbis->isPlaying ())
647 mpVorbis->stop ();
649 else
651 mpVorbis->play (true);
654 else if (keycode == 'w')
656 if (mpWav->isPlaying ())
658 mpWav->stop ();
660 else
662 mpWav->play (true);
665 #endif
666 else if (keycode == 'v')
668 mbShadowVolume = !mbShadowVolume;
670 else if (keycode == Key_Tab)
672 g_engine->getSceneManager ()->remove (mpModels[mCurrentModel]);
673 mCurrentModel++;
674 mCurrentModel %= mpModels.size ();
675 g_engine->getSceneManager ()->add (mpModels[mCurrentModel]);
677 else if (keycode == Key_Space)
679 /* // next sequence
680 animationSequencer *s = mpModel->getAnimationSequencer ();
681 if (s)
683 int n = s->numSequences ();
684 int c = s->getSequence ();
685 c++;
686 if (c >= n)
687 c = 0;
688 s->setSequence (c, g_engine->getTimer ()->getTime ());
691 else if ( (keycode &~ Key_CharFlag) == 'p')
693 // pause = !pause;
694 // mpMusic->pause (pause);
698 const char* dataPath ()
700 return "data";
705 main (int argc, char *argv[])
707 // init objects
708 engine* e = new engine;
709 smartPtr <application> app = new TestApp;
711 // run application through the engine
712 e->run (app, argc, argv);
714 app = NULL;
715 delete e;
717 #if defined (_DEBUG) && defined (_MSC_VER)
718 _CrtDumpMemoryLeaks ();
719 #endif
720 fprintf (stderr, "exit.\n");
721 return 0;
724 // eof