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.
5 // the application is forked off of a years-old "mdlview" app, which is bundled too
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
13 #define ENABLE_MUSIC 0
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>
25 #include <fegdk/f_fontft.h>
29 #include <fegdk/f_oggvorbis.h>
30 #include <fegdk/f_modmusic.h>
31 #include <fegdk/wavfile.h>
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>
64 class TestApp
: public application
69 smartPtr
<animContainer
> mpAnimContainer
;
70 smartPtr
<animation
> mpAnimation
;
71 std::vector
<smartPtr
<sceneObject
> > mpModels
;
80 // vorbisFile* mpMusic;
81 smartPtr
<modMusic
> mpMod
;
82 smartPtr
<vorbisFile
> mpVorbis
;
83 smartPtr
<wavFile
> mpWav
;
87 smartPtr
< fontFT
> mpFont
;
88 smartPtr
< fontFT
> mpBoldFont
;
91 smartPtr
<netManager
> mpNetManager
;
92 smartPtr
<netSocket
> mpRSocket
;
102 enum { MAX_POINTS_ON_WINDING
= 64 };
104 vector3 points
[MAX_POINTS_ON_WINDING
];
112 vector3 points
[MAX_POINTS_ON_WINDING
];
115 cluster_t
*clusters
[2];
125 cluster_t
*mpClusters
;
126 cluster_t
*mpCurrentCluster
;
131 for (cluster_t
*c
= mpClusters
; c
; c
= next
)
135 for (portal_t
*p
= c
->portals
; p
; p
= nextp
)
137 int side
= p
->clusters
[0] == c
? 0 : 1;
138 nextp
= p
->next
[side
];
142 for (winding_t
*f
= c
->faces
; f
; f
= nextf
)
153 charParser
p (NULL
, "test.prt", true);
154 // magic, numclusters, numportals, numfaces
157 int nclusters
= atoi (p
.token ());
159 int nportals
= atoi (p
.token ());
161 int nfaces
= atoi (p
.token ());
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
;
173 for (i
= 0; i
< nportals
; i
++)
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
;
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
;
193 port
->clusters
[1] = c
;
194 p
.getToken (); // hint
196 for (k
= 0; k
< port
->npoints
; k
++)
200 port
->points
[k
][0] = atof (p
.token ());
202 port
->points
[k
][1] = atof (p
.token ());
204 port
->points
[k
][2] = atof (p
.token ());
209 for (i
= 0; i
< nfaces
; i
++)
211 winding_t
*face
= new winding_t
;
212 memset (face
, 0, sizeof (winding_t
));
214 if (p
.getToken ()) // numpoints
217 face
->npoints
= atoi (p
.token ());
218 p
.getToken (); // cluster
219 int nclust
= atoi (p
.token ());
222 for (k
= 0, c
= mpClusters
; k
< nclust
&& c
; k
++, c
= c
->next
);
223 face
->next
= c
->faces
;
226 for (k
= 0; k
< face
->npoints
; k
++)
230 face
->points
[k
][0] = atof (p
.token ());
232 face
->points
[k
][1] = atof (p
.token ());
234 face
->points
[k
][2] = atof (p
.token ());
249 mbShadowVolume
= false;
257 bool isFullscreen (void)
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;
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
));
295 mpVorbis
= new vorbisFile ("audio/test.ogg");
296 mpMod
= new modMusic ("audio/dreamfish-sanxion.mod");
297 mpWav
= new wavFile ("audio/test.wav");
301 mpFont
= g_engine
->getResourceMgr ()->createFontFT ("ter-116n.pcf");
302 mpBoldFont
= g_engine
->getResourceMgr ()->createFontFT ("ter-116b.pcf");
304 if (mpModels
[mCurrentModel
])
305 g_engine
->getSceneManager ()->add (mpModels
[mCurrentModel
]);
307 mpNetManager
= new netManager ();
308 mpRSocket
= mpNetManager
->createReceivingSocket (6666);
311 mpCurrentCluster
= mpClusters
;
331 application::update ();
332 // mpModel->update ();
333 g_engine
->getSceneManager ()->update ();
335 // if (g_engine->getConsole ()->isVisible ())
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;
354 point pt
= inp
->getCursorPos ();
356 int x
= (int)pt
.x
- (int)prevPt
.x
;
357 int y
= (int)pt
.y
- (int)prevPt
.y
;
361 if (inp
->getState ()->isPressed (Key_Mouse1
))
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
))
381 int len
= mpRSocket
->recive (message
, sizeof (message
));
384 printf ("message:\n%s\n", message
);
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
);
402 glMatrixMode (GL_MODELVIEW
);
403 const matrix4
&m
= mdl
->getWorldMatrix ();
404 matrix4 modelview
= m
* g_engine
->getEffectParms ()->getMatrix (effectParm_ViewMatrix
);
405 glLoadMatrixf ( (GLfloat
*)&modelview
);
408 glDepthFunc (GL_LESS
);
409 glDepthMask (GL_FALSE
);
410 g_engine
->getDrawUtil ()->setCullMode (drawUtil::cull_front
);
412 // model->renderShadowVolume ();
413 g_engine
->getDrawUtil ()->setCullMode (drawUtil::cull_back
);
415 // mdl->renderShadowVolume ();
416 glDepthMask (GL_TRUE
);
417 glDepthFunc (GL_LEQUAL
);
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);
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
;
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 ();
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
);
460 for (c
= mpClusters
; c
; c
= c
->next
)
462 if (c
== mpCurrentCluster
)
463 glColor4f (0, 1, 0, 1);
465 glColor4f (0, 0, 1, 1);
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
);
477 c
= mpCurrentCluster
;
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);
484 glBegin (GL_LINE_LOOP
);
485 for (int p
= 0; p
< port
->npoints
; p
++)
487 glVertex3fv (&port
->points
[p
].x
);
490 origin
/= port
->npoints
;
492 v1
= port
->points
[2] - port
->points
[1];
493 v2
= port
->points
[0] - port
->points
[1];
494 vector3 norm
= v1
.cross (v2
);
496 glColor4f (1, 0, 0, 1);
498 glVertex3fv (&origin
.x
);
500 glVertex3fv (&origin
.x
);
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);
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);
530 int h
= mpFont
->getTextHeight ();
531 int y
= mpFont
->getTextHeight () * 2;
532 mpFont
->drawTextString ("'m' - toggle mod playback", 0, y
, 0xffffffff);
534 mpFont
->drawTextString ("'o' - toggle ogg-vorbis playback", 0, y
, 0xffffffff);
536 mpFont
->drawTextString ("'w' - toggle wav playback", 0, y
, 0xffffffff);
538 mpFont
->drawTextString ("'t' - toggle 3d model", 0, y
, 0xffffffff);
540 mpFont
->drawTextString ("'v' - toggle shadowvolume", 0, y
, 0xffffffff);
542 mpFont
->drawTextString ("'s' - toggle shadows", 0, y
, 0xffffffff);
544 mpFont
->drawTextString ("'p' - toggle tangents", 0, y
, 0xffffffff);
546 mpFont
->drawTextString ("'a' - restart animation of current scene", 0, y
, 0xffffffff);
551 mpFont
->drawTextString ("press 'h' for help", 0, mpFont
->getTextHeight () * 2, 0xffffffff);
555 mpFont
->drawTextString ("Test [$Revision$]", 0, 0, 0xffffffff);
558 static float fFPS
= 0.0f
;
559 static float fLastTime
= 0.0f
;
560 static unsigned long dwFrames
= 0L;
562 fTime
= g_engine
->getTimer ()->getTime ();
564 if (fTime
- fLastTime
> 0.5f
)
566 fFPS
= dwFrames
/ (fTime
- fLastTime
);
570 s
.printf ("fps: %.2f", fFPS
);
571 mpBoldFont
->drawTextString (s
.c_str (), 0, mpBoldFont
->getTextHeight (), float4 (1,1,0,1));
576 void keyDown (int keycode
)
578 static bool pause
= false;
579 if (keycode
== Key_Escape
)
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
;
594 else if (keycode
== ']')
596 mpCurrentCluster
= mpCurrentCluster
->next
;
597 if (!mpCurrentCluster
)
598 mpCurrentCluster
= mpClusters
;
600 else if (keycode
== 'b') {
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
);
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
;
625 if (mpModels
[mCurrentModel
])
626 g_engine
->getSceneManager ()->remove (mpModels
[mCurrentModel
]);
630 if (mpModels
[mCurrentModel
])
631 g_engine
->getSceneManager ()->add (mpModels
[mCurrentModel
]);
635 else if (keycode
== 'm')
637 mbPlayMusic
= !mbPlayMusic
;
643 else if (keycode
== 'o')
645 if (mpVorbis
->isPlaying ())
651 mpVorbis
->play (true);
654 else if (keycode
== 'w')
656 if (mpWav
->isPlaying ())
666 else if (keycode
== 'v')
668 mbShadowVolume
= !mbShadowVolume
;
670 else if (keycode
== Key_Tab
)
672 g_engine
->getSceneManager ()->remove (mpModels
[mCurrentModel
]);
674 mCurrentModel
%= mpModels
.size ();
675 g_engine
->getSceneManager ()->add (mpModels
[mCurrentModel
]);
677 else if (keycode
== Key_Space
)
680 animationSequencer *s = mpModel->getAnimationSequencer ();
683 int n = s->numSequences ();
684 int c = s->getSequence ();
688 s->setSequence (c, g_engine->getTimer ()->getTime ());
691 else if ( (keycode
&~ Key_CharFlag
) == 'p')
694 // mpMusic->pause (pause);
698 const char* dataPath ()
705 main (int argc
, char *argv
[])
708 engine
* e
= new engine
;
709 smartPtr
<application
> app
= new TestApp
;
711 // run application through the engine
712 e
->run (app
, argc
, argv
);
717 #if defined (_DEBUG) && defined (_MSC_VER)
718 _CrtDumpMemoryLeaks ();
720 fprintf (stderr
, "exit.\n");