framework.cxx 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198
  1. // Filename: framework.cxx
  2. // Created by: cary (25Mar99)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. // We need to include bitMask.h first to avoid a VC++ compiler bug
  6. // related to 2 parameter templates
  7. #include <bitMask.h>
  8. #include "framework.h"
  9. #include "config_framework.h"
  10. #include <pystub.h>
  11. // Since framework.cxx includes pystub.h, no program that links with
  12. // framework needs to do so. No Python code should attempt to link
  13. // with libframework.so.
  14. #include <cullTraverser.h>
  15. #include <appTraverser.h>
  16. #include <directRenderTraverser.h>
  17. #include <mouse.h>
  18. #include <mouseWatcher.h>
  19. #include <buttonThrower.h>
  20. #include <eventHandler.h>
  21. #include <throw_event.h>
  22. #include <camera.h>
  23. #include <geom.h>
  24. #include <geomprimitives.h>
  25. #include <renderRelation.h>
  26. #include <dataRelation.h>
  27. #include <geomNode.h>
  28. #include <namedNode.h>
  29. #include <pt_NamedNode.h>
  30. #include <colorTransition.h>
  31. #include <renderModeTransition.h>
  32. #include <renderModeAttribute.h>
  33. #include <materialTransition.h>
  34. #include <dataGraphTraversal.h>
  35. #include <trackball.h>
  36. #include <driveInterface.h>
  37. #include <transform2sg.h>
  38. #include <texture.h>
  39. #include <texturePool.h>
  40. #include <textureTransition.h>
  41. #include <textureAttribute.h>
  42. #include <interactiveGraphicsPipe.h>
  43. #include <noninteractiveGraphicsPipe.h>
  44. #include <graphicsWindow.h>
  45. #include <list>
  46. #include <lightTransition.h>
  47. #include <lightAttribute.h>
  48. #include <materialTransition.h>
  49. #include <materialAttribute.h>
  50. #include <animControl.h>
  51. #include <animControlCollection.h>
  52. #include <auto_bind.h>
  53. #include <ambientLight.h>
  54. #include <directionalLight.h>
  55. #include <pointLight.h>
  56. #include <spotlight.h>
  57. #include <dconfig.h>
  58. #include <cullFaceTransition.h>
  59. #include <cullFaceAttribute.h>
  60. #include <pruneTransition.h>
  61. #include <dftraverser.h>
  62. #include <renderBuffer.h>
  63. #include <loader.h>
  64. #include <fogTransition.h>
  65. #include <fogAttribute.h>
  66. #include <clockObject.h>
  67. #include <compose_matrix.h>
  68. #include <notify.h>
  69. #include <nullTransitionWrapper.h>
  70. #include <nullAttributeWrapper.h>
  71. #include <nullLevelState.h>
  72. #include <sceneGraphReducer.h>
  73. #include <textNode.h>
  74. #include <depthTestTransition.h>
  75. #include <depthWriteTransition.h>
  76. #include <orthoProjection.h>
  77. #include <transparencyTransition.h>
  78. #include <bamReader.h>
  79. #include <collisionRay.h>
  80. #include <collisionNode.h>
  81. #include <collisionTraverser.h>
  82. #include <collisionHandlerFloor.h>
  83. #include <nodePath.h>
  84. #include <multiplexStream.h>
  85. #ifdef USE_IPC
  86. #include <ipc_file.h>
  87. #include <ipc_mutex.h>
  88. #include <ipc_thread.h>
  89. #endif
  90. Configure(framework);
  91. ConfigureFn(framework) {
  92. }
  93. AppTraverser *app_traverser;
  94. PT_NamedNode data_root;
  95. PT_NamedNode root;
  96. PT(GeomNode) geomnode;
  97. PT_NamedNode render;
  98. PT_NamedNode cameras;
  99. PT(MouseAndKeyboard) mak;
  100. PT(MouseWatcher) mouse_watcher;
  101. PT(Trackball) trackball;
  102. PT(DriveInterface) drive_interface;
  103. static Node *current_trackball = NULL;
  104. static Node *alt_trackball = NULL;
  105. NodeAttributes initial_state;
  106. Texture* ttex;
  107. PT(GraphicsPipe) main_pipe;
  108. PT(GraphicsPipe) rib_pipe;
  109. PT(GraphicsWindow) main_win;
  110. PT(GraphicsWindow) rib_win;
  111. RenderRelation* first_arc;
  112. PT_NamedNode lights;
  113. PT(AmbientLight) light;
  114. PT(DirectionalLight) dlight;
  115. bool have_dlight = false;
  116. PT(PointLight) plight;
  117. PT(Spotlight) slight;
  118. PT(Material) material;
  119. PT(Fog) fog;
  120. // Framerate vars
  121. PT_NamedNode framerate_top;
  122. RenderRelation *framerate_arc = (RenderRelation*)0L;
  123. PT_NamedNode framerate_node;
  124. PT(GraphicsLayer) framerate_layer;
  125. PT_Node framerate_font;
  126. PT(TextNode) framerate_text;
  127. Loader loader;
  128. EventHandler event_handler(EventQueue::get_global_event_queue());
  129. std::string chan_config = "single";
  130. static double start_time = 0.0;
  131. static int start_frame_count = 0;
  132. void (*extra_display_func)() = NULL;
  133. void (*define_keys)(EventHandler&) = NULL;
  134. void (*extra_overrides_func)(ChanCfgOverrides&, std::string&) = NULL;
  135. void (*first_init)() = NULL;
  136. void (*additional_idle)() = NULL;
  137. #ifdef USE_IPC
  138. static bool forked_draw = framework.GetBool("fork-draw", false);
  139. static mutex run_render;
  140. static bool render_running = true;
  141. static bool quit_draw = false;
  142. static thread* draw_thread;
  143. #endif
  144. static CollisionTraverser *col_trans = NULL;
  145. static CollisionHandlerFloor *col_handler = NULL;
  146. static CollisionNode *ray_node = NULL;
  147. class GeomNorms : public GeomLine
  148. {
  149. public:
  150. GeomNorms(void) : GeomLine() {}
  151. virtual Geom *explode() const {
  152. return new GeomNorms(*this);
  153. }
  154. static TypeHandle get_class_type(void) {
  155. return _type_handle;
  156. }
  157. static void init_type(void) {
  158. GeomLine::init_type();
  159. register_type(_type_handle, "GeomNorms",
  160. GeomLine::get_class_type());
  161. }
  162. virtual TypeHandle get_type(void) const {
  163. return get_class_type();
  164. }
  165. private:
  166. static TypeHandle _type_handle;
  167. };
  168. TypeHandle GeomNorms::_type_handle;
  169. // Since the Normal*Traversers don't care about state, we don't need
  170. // to accumulate the RenderTransitions, so it will template on
  171. // NullTransition.
  172. class NormalAddTraverser :
  173. public TraverserVisitor<NullTransitionWrapper, NullLevelState> {
  174. public:
  175. NormalAddTraverser(GraphicsStateGuardian *gsg) : _gsg(gsg) {}
  176. bool reached_node(Node*, NullAttributeWrapper&, NullLevelState&);
  177. // No need to declare a forward_arc() function that simply returns
  178. // true; this is the default behavior.
  179. public:
  180. GraphicsStateGuardian *_gsg;
  181. };
  182. bool NormalAddTraverser::
  183. reached_node(Node *node, NullAttributeWrapper &, NullLevelState &) {
  184. if (node->is_of_type(GeomNode::get_class_type())) {
  185. GeomNorms *gn = new GeomNorms;
  186. GeomNode *geom = DCAST(GeomNode, node);
  187. int vert_count = 0;
  188. int i;
  189. for (i = 0; i < geom->get_num_geoms(); i++) {
  190. dDrawable *d = geom->get_geom(i);
  191. if (d->is_of_type(Geom::get_class_type())) {
  192. Geom *g = DCAST(Geom, d);
  193. for (int j=0; j<g->get_num_prims(); ++j)
  194. vert_count += g->get_length(j);
  195. }
  196. }
  197. if (vert_count > 0) {
  198. PTA_Vertexf verts(2 * vert_count);
  199. for (i = 0; i < geom->get_num_geoms(); i++) {
  200. dDrawable *d = geom->get_geom(i);
  201. if (d->is_of_type(Geom::get_class_type())) {
  202. PTA_Vertexf lverts;
  203. PTA_ushort iverts;
  204. GeomBindType vbond;
  205. Geom *g = DCAST(Geom, d);
  206. g->get_coords(lverts, vbond, iverts);
  207. int vert_idx = 0;
  208. if (g->get_binding(G_NORMAL) == G_OFF) {
  209. for (int j=0; j<g->get_num_prims(); ++j) {
  210. for (int k=0; k<g->get_length(j); ++k, ++vert_idx) {
  211. verts[2 * vert_idx] = lverts[vert_idx];
  212. verts[(2 * vert_idx) + 1] = lverts[vert_idx];
  213. }
  214. }
  215. } else {
  216. PTA_Normalf lnorms;
  217. PTA_ushort inorms;
  218. GeomBindType nbond;
  219. g->get_normals(lnorms, nbond, inorms);
  220. for (int j=0; j<g->get_num_prims(); ++j) {
  221. for (int k=0; k<g->get_length(j); ++k, ++vert_idx) {
  222. verts[2 * vert_idx] = lverts[vert_idx];
  223. verts[(2 * vert_idx) + 1] = lverts[vert_idx]
  224. + lnorms[vert_idx];
  225. }
  226. }
  227. }
  228. }
  229. }
  230. gn->set_num_prims(vert_count);
  231. gn->set_coords(verts, G_PER_VERTEX);
  232. }
  233. geom->add_geom(gn);
  234. }
  235. return true;
  236. }
  237. class NormalDelTraverser :
  238. public TraverserVisitor<NullTransitionWrapper, NullLevelState> {
  239. public:
  240. NormalDelTraverser(GraphicsStateGuardian *gsg) : _gsg(gsg) {}
  241. bool reached_node(Node*, NullAttributeWrapper&, NullLevelState&);
  242. public:
  243. GraphicsStateGuardian *_gsg;
  244. };
  245. bool NormalDelTraverser::
  246. reached_node(Node *node, NullAttributeWrapper &, NullLevelState &) {
  247. if (node->is_of_type(GeomNode::get_class_type())) {
  248. GeomNode *geom = DCAST(GeomNode, node);
  249. int i, j;
  250. do {
  251. for (i = 0, j = -1;
  252. i < geom->get_num_geoms();
  253. ++i) {
  254. if (geom->get_geom(i)->is_of_type(GeomNorms::get_class_type())) {
  255. j = i;
  256. }
  257. }
  258. if (j != -1) {
  259. geom->remove_geom(j);
  260. }
  261. } while (j != -1);
  262. }
  263. return true;
  264. }
  265. void render_frame(GraphicsPipe *pipe) {
  266. app_traverser->traverse(render);
  267. int num_windows = pipe->get_num_windows();
  268. for (int w = 0; w < num_windows; w++) {
  269. GraphicsWindow *win = pipe->get_window(w);
  270. win->get_gsg()->render_frame(initial_state);
  271. }
  272. ClockObject::get_global_clock()->tick();
  273. throw_event("NewFrame");
  274. }
  275. // to be used with new display callback system
  276. class DisplayCallback : public GraphicsWindow::Callback {
  277. public:
  278. virtual void draw(bool) {
  279. render_frame(main_pipe);
  280. if (extra_display_func != NULL)
  281. extra_display_func();
  282. }
  283. };
  284. // to be used with old GLUT callback system
  285. void display_func( void ) {
  286. render_frame(main_pipe);
  287. if (extra_display_func != NULL)
  288. extra_display_func();
  289. }
  290. void set_lighting(bool enabled) {
  291. if (enabled) {
  292. // Enable the lights on the initial state.
  293. LightAttribute *la = new LightAttribute;
  294. la->set_on(light.p());
  295. if (have_dlight) {
  296. la->set_on(dlight.p());
  297. }
  298. initial_state.set_attribute(LightTransition::get_class_type(), la);
  299. } else {
  300. // Remove the lights from the initial state.
  301. initial_state.clear_attribute(LightTransition::get_class_type());
  302. }
  303. }
  304. // to be used with new display callback system
  305. class IdleCallback : public GraphicsWindow::Callback {
  306. public:
  307. virtual void idle(void) {
  308. // Initiate the data traversal, to send device data down its
  309. // respective pipelines.
  310. traverse_data_graph(data_root);
  311. // Perform the collision traversal, if we have a collision
  312. // traverser standing by.
  313. if (col_trans != (CollisionTraverser *)NULL) {
  314. col_trans->traverse(render);
  315. }
  316. // Throw any events generated recently.
  317. event_handler.process_events();
  318. if (additional_idle != NULL) {
  319. (*additional_idle)();
  320. }
  321. }
  322. };
  323. // to be used with old GLUT callback system
  324. void idle_func( void )
  325. {
  326. // Initiate the data traversal, to send device data down its
  327. // respective pipelines.
  328. traverse_data_graph(data_root);
  329. // Throw any events generated recently.
  330. event_handler.process_events();
  331. }
  332. void resize_func(int w, int h)
  333. {
  334. main_win->resized(w, h);
  335. }
  336. void unpause_draw(void);
  337. void event_esc(CPT_Event) {
  338. #ifdef USE_IPC
  339. if (forked_draw) {
  340. quit_draw = true;
  341. unpause_draw();
  342. mutex_lock m(run_render);
  343. }
  344. #endif
  345. double now = ClockObject::get_global_clock()->get_time();
  346. double delta = now - start_time;
  347. int frame_count = ClockObject::get_global_clock()->get_frame_count();
  348. int num_frames = frame_count - start_frame_count;
  349. if (num_frames > 0) {
  350. nout << endl << num_frames << " frames in " << delta << " seconds" << endl;
  351. double x = ((double)num_frames) / delta;
  352. nout << x << " fps average (" << 1000.0 / x << "ms)" << endl;
  353. }
  354. // The Escape key was pressed. Exit the application.
  355. main_pipe = NULL;
  356. main_win = NULL;
  357. rib_pipe = NULL;
  358. rib_win = NULL;
  359. #ifdef HAVE_NET
  360. if (PStatClient::get_global_pstats()->is_connected()) {
  361. nout << "Disconnecting from stats host" << endl;
  362. PStatClient::get_global_pstats()->disconnect();
  363. }
  364. #endif
  365. exit(0);
  366. }
  367. void event_f(CPT_Event) {
  368. double now = ClockObject::get_global_clock()->get_time();
  369. double delta = now - start_time;
  370. int frame_count = ClockObject::get_global_clock()->get_frame_count();
  371. int num_frames = frame_count - start_frame_count;
  372. if (num_frames > 0) {
  373. nout << endl << num_frames << " frames in " << delta << " seconds" << endl;
  374. double x = ((double)num_frames) / delta;
  375. nout << x << " fps average (" << 1000.0 / x << "ms)" << endl;
  376. // Reset the frame rate counter for the next press of 'f'.
  377. start_time = now;
  378. start_frame_count = frame_count;
  379. }
  380. }
  381. void event_S(CPT_Event) {
  382. #ifdef HAVE_NET
  383. nout << "Connecting to stats host" << endl;
  384. PStatClient::get_global_pstats()->connect();
  385. #else
  386. nout << "Stats host not supported." << endl;
  387. #endif
  388. }
  389. void event_A(CPT_Event) {
  390. #ifdef HAVE_NET
  391. if (PStatClient::get_global_pstats()->is_connected()) {
  392. nout << "Disconnecting from stats host" << endl;
  393. PStatClient::get_global_pstats()->disconnect();
  394. } else {
  395. nout << "Stats host is already disconnected." << endl;
  396. }
  397. #else
  398. nout << "Stats host not supported." << endl;
  399. #endif
  400. }
  401. void setup_framerate(void) {
  402. if (framerate_top != (NamedNode*)0L)
  403. return;
  404. framerate_top = new NamedNode("framerate_top");
  405. framerate_node = new NamedNode("framerate");
  406. framerate_arc = new RenderRelation(framerate_top, framerate_node);
  407. // Setup some overrides to turn off certain properties which we probably
  408. // won't need for 2-d objects.
  409. framerate_arc->set_transition(new DepthTestTransition(DepthTestProperty::M_none), 1);
  410. framerate_arc->set_transition(new DepthWriteTransition(DepthWriteTransition::off()), 1);
  411. framerate_arc->set_transition(new LightTransition(LightTransition::all_off()), 1);
  412. framerate_arc->set_transition(new MaterialTransition(MaterialTransition::off()), 1);
  413. framerate_arc->set_transition(new CullFaceTransition(CullFaceProperty::M_cull_none), 1);
  414. // create a 2-d camera.
  415. PT(Camera) cam2d = new Camera("framerate_cam");
  416. new RenderRelation(framerate_node, cam2d);
  417. cam2d->set_scene(framerate_top);
  418. Frustumf frustum2d;
  419. frustum2d.make_ortho_2D();
  420. cam2d->set_projection(OrthoProjection(frustum2d));
  421. // Now create a new layer
  422. // eventually this should be done through chanconfig'
  423. GraphicsChannel *chan = main_win->get_channel(0);
  424. nassertv(chan != (GraphicsChannel*)0L);
  425. framerate_layer = chan->make_layer();
  426. nassertv(framerate_layer != (GraphicsLayer *)0L);
  427. framerate_layer->set_active(true);
  428. DisplayRegion *dr = framerate_layer->make_display_region();
  429. nassertv(dr != (DisplayRegion *)0L);
  430. dr->set_camera(cam2d);
  431. // load the font
  432. framerate_font = loader.load_sync("cmtt12");
  433. if (framerate_font != (NamedNode *)0L) {
  434. framerate_text = new TextNode("framerate_text");
  435. new RenderRelation(framerate_node, framerate_text);
  436. LMatrix4f mat = LMatrix4f::scale_mat(0.05) *
  437. LMatrix4f::translate_mat(-0.95, 0.0, 0.95);
  438. framerate_text->set_transform(mat);
  439. framerate_text->set_font(framerate_font.p());
  440. framerate_text->set_card_color(0.5, 0.5, 0.5, 0.5);
  441. framerate_text->set_card_as_margin(0.5, 0.5, 0.2, 0.2);
  442. framerate_text->set_frame_color(1., 0., 0., 1.);
  443. framerate_text->set_frame_as_margin(0.5, 0.5, 0.2, 0.2);
  444. framerate_text->set_align(TM_ALIGN_LEFT);
  445. framerate_text->set_text_color(1., 1., 1., 1.);
  446. framerate_text->set_text("blah");
  447. }
  448. }
  449. void handle_framerate(void) {
  450. static bool first_time = true;
  451. static int buffer_count;
  452. static int buffer_size = framework.GetInt("framerate-buffer", 60);
  453. static double *prev_times = (double*)0L;
  454. static double *deltas = (double*)0L;
  455. if (framerate_layer == (GraphicsLayer*)0L)
  456. return;
  457. if (!framerate_layer->is_active()) {
  458. first_time = true;
  459. return;
  460. }
  461. double now = ClockObject::get_global_clock()->get_time();
  462. if (first_time) {
  463. if (prev_times == (double*)0L) {
  464. prev_times = new double[buffer_size];
  465. deltas = new double[buffer_size];
  466. }
  467. buffer_count = 0;
  468. prev_times[buffer_count++] = now;
  469. first_time = false;
  470. } else if (buffer_count < buffer_size) {
  471. deltas[buffer_count-1] = now - prev_times[buffer_count-1];
  472. prev_times[buffer_count++] = now;
  473. } else {
  474. deltas[buffer_size-1] = now - prev_times[buffer_size-1];
  475. double delta = 0.;
  476. for (int i=0; i<buffer_size; ++i)
  477. delta += deltas[i];
  478. delta = delta / (double)buffer_size;
  479. double fps = 1. / delta;
  480. delta *= 1000.;
  481. ostringstream os;
  482. // I've decided that one digit to the right of the decimal should be
  483. // enough for now. If we need more, it's easy to extend.
  484. int ifps = (int)fps;
  485. fps = fps - (double)ifps;
  486. fps *= 10.;
  487. int rfps = (int)fps;
  488. int idelta = (int)delta;
  489. delta = delta - (double)idelta;
  490. delta *= 10.;
  491. int rdelta = (int)delta;
  492. os << ifps << "." << rfps << " fps (" << idelta << "." << rdelta
  493. << " ms)";
  494. framerate_text->set_text(os.str());
  495. // now roll everything down one
  496. for (int j=0; j<buffer_size-1; ++j) {
  497. prev_times[j] = prev_times[j+1];
  498. deltas[j] = deltas[j+1];
  499. }
  500. prev_times[buffer_size-1] = now;
  501. }
  502. }
  503. void event_f_full(CPT_Event) {
  504. static bool is_on = true;
  505. setup_framerate();
  506. framerate_layer->set_active(is_on);
  507. is_on = !is_on;
  508. }
  509. void event_t(CPT_Event) {
  510. // The "t" key was pressed. Toggle the showing of textures.
  511. static bool textures_enabled = true;
  512. textures_enabled = !textures_enabled;
  513. if (textures_enabled) {
  514. // Remove the override from the initial state.
  515. initial_state.clear_attribute(TextureTransition::get_class_type());
  516. } else {
  517. // Set an override on the initial state to disable texturing.
  518. TextureAttribute *ta = new TextureAttribute;
  519. ta->set_priority(100);
  520. initial_state.set_attribute(TextureTransition::get_class_type(), ta);
  521. }
  522. }
  523. void event_l(CPT_Event) {
  524. // The "l" key was pressed. Toggle lighting.
  525. static bool lighting_enabled = false;
  526. lighting_enabled = !lighting_enabled;
  527. set_lighting(lighting_enabled);
  528. }
  529. void event_w(CPT_Event) {
  530. // The "w" key was pressed. Toggle wireframe mode.
  531. static bool wireframe_mode = false;
  532. wireframe_mode = !wireframe_mode;
  533. if (!wireframe_mode) {
  534. // Set the normal, filled mode on the render arc.
  535. RenderModeAttribute *rma = new RenderModeAttribute;
  536. rma->set_mode(RenderModeProperty::M_filled);
  537. CullFaceAttribute *cfa = new CullFaceAttribute;
  538. cfa->set_mode(CullFaceProperty::M_cull_clockwise);
  539. initial_state.set_attribute(RenderModeTransition::get_class_type(), rma);
  540. initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  541. } else {
  542. // Set the initial state up for wireframe mode.
  543. RenderModeAttribute *rma = new RenderModeAttribute;
  544. rma->set_mode(RenderModeProperty::M_wireframe);
  545. CullFaceAttribute *cfa = new CullFaceAttribute;
  546. cfa->set_mode(CullFaceProperty::M_cull_none);
  547. initial_state.set_attribute(RenderModeTransition::get_class_type(), rma);
  548. initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  549. }
  550. }
  551. void event_b(CPT_Event) {
  552. // The 'b' key was pressed. Toggle backface culling.
  553. static bool backface_mode = false;
  554. backface_mode = !backface_mode;
  555. if (backface_mode) {
  556. material->set_twoside(true);
  557. CullFaceAttribute *cfa = new CullFaceAttribute;
  558. cfa->set_mode(CullFaceProperty::M_cull_none);
  559. initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  560. } else {
  561. material->set_twoside(false);
  562. CullFaceAttribute *cfa = new CullFaceAttribute;
  563. cfa->set_mode(CullFaceProperty::M_cull_clockwise);
  564. initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  565. }
  566. }
  567. void event_R(CPT_Event) {
  568. // The "R" key was pressed. Dump a RIB file.
  569. if (rib_win == (GraphicsWindow*)0L)
  570. return;
  571. nout << "Writing RIB frame " << rib_win->get_frame_number() << "\n";
  572. render_frame(rib_pipe);
  573. }
  574. void event_grave(CPT_Event) {
  575. PixelBuffer p;
  576. GraphicsStateGuardian* g = main_win->get_gsg();
  577. const RenderBuffer& r = g->get_render_buffer(RenderBuffer::T_front);
  578. p.set_xsize(main_win->get_width());
  579. p.set_ysize(main_win->get_height());
  580. p._image = PTA_uchar(main_win->get_width() * main_win->get_height() * 3);
  581. p.copy(main_win->get_gsg(),
  582. main_win->get_gsg()->get_current_display_region(),r);
  583. ostringstream s;
  584. s << "frame" << main_win->get_frame_number() << ".pnm";
  585. p.write(s.str());
  586. }
  587. void event_n(CPT_Event) {
  588. static bool normals_on = false;
  589. normals_on = !normals_on;
  590. if (normals_on) {
  591. NormalAddTraverser trav(main_win->get_gsg());
  592. df_traverse(render, trav, NullAttributeWrapper(), NullLevelState(),
  593. RenderRelation::get_class_type());
  594. } else {
  595. NormalDelTraverser trav(main_win->get_gsg());
  596. df_traverse(render, trav, NullAttributeWrapper(), NullLevelState(),
  597. RenderRelation::get_class_type());
  598. }
  599. }
  600. void event_C(CPT_Event) {
  601. static bool showing_collision_solids = false;
  602. showing_collision_solids = !showing_collision_solids;
  603. if (showing_collision_solids) {
  604. // So we'll break down and use the NodePath interface in
  605. // framework. We haven't used it here before, but it's such a
  606. // splendid interface; why not use it?
  607. NodePath render_path(render);
  608. render_path.show_collision_solids();
  609. } else {
  610. NodePath render_path(render);
  611. render_path.hide_collision_solids();
  612. }
  613. }
  614. void event_N(CPT_Event) {
  615. nout << "Reducing scene graph.\n";
  616. SceneGraphReducer gr(RenderRelation::get_class_type());
  617. gr.apply_transitions(root);
  618. int num_reduced = gr.flatten(root, true);
  619. nout << "Removed " << num_reduced << " arcs.\n";
  620. }
  621. // switch_trackball() is a local function to fiddle with the dgraph
  622. // arcs to make a different trackball be in control of the mouse.
  623. static void
  624. switch_trackball(Node *trackball) {
  625. if (current_trackball != NULL) {
  626. remove_child(mouse_watcher, current_trackball,
  627. DataRelation::get_class_type());
  628. }
  629. current_trackball = trackball;
  630. if (current_trackball != NULL) {
  631. new DataRelation(mouse_watcher, current_trackball);
  632. }
  633. }
  634. // set_alt_trackball() should be called by user code to change the
  635. // alternate trackball that is in effect when the user presses "c".
  636. void
  637. set_alt_trackball(Node *tb) {
  638. if (tb == NULL) {
  639. switch_trackball(trackball);
  640. } else {
  641. alt_trackball = tb;
  642. switch_trackball(alt_trackball);
  643. }
  644. }
  645. static void
  646. start_drive() {
  647. // Extract the current position from the trackball.
  648. LMatrix4f mat = trackball->get_trans_mat();
  649. LPoint3f scale, hpr, xyz;
  650. decompose_matrix(mat, scale, hpr, xyz);
  651. if (hpr[2] > 90) {
  652. hpr[0] += 180.0;
  653. }
  654. hpr[1] = 0.0;
  655. hpr[2] = 0.0;
  656. drive_interface->set_pos(xyz);
  657. drive_interface->set_hpr(hpr);
  658. // Make sure the ray-downcaster is set, so we maintain a constant
  659. // height above the ground.
  660. if (col_trans == (CollisionTraverser *)NULL) {
  661. ray_node = new CollisionNode("ray");
  662. ray_node->set_into_collide_mask(0);
  663. ray_node->set_from_collide_mask(drive_mask);
  664. NodeRelation *arc = new RenderRelation(cameras, ray_node);
  665. ray_node->add_solid(new CollisionRay(LPoint3f(0.0, 0.0, 0.0),
  666. LVector3f::down()));
  667. arc->set_transition(new PruneTransition);
  668. col_trans = new CollisionTraverser;
  669. col_handler = new CollisionHandlerFloor;
  670. col_handler->set_offset(drive_height);
  671. col_trans->add_collider(ray_node, col_handler);
  672. col_handler->add_collider(ray_node, drive_interface);
  673. }
  674. }
  675. static void
  676. stop_drive() {
  677. // Extract the current position from the drive interface and
  678. // restore it to the trackball.
  679. LPoint3f xyz = drive_interface->get_pos();
  680. LPoint3f hpr = drive_interface->get_hpr();
  681. LPoint3f scale(1.0, 1.0, 1.0);
  682. LMatrix4f mat;
  683. compose_matrix(mat, scale, hpr, xyz);
  684. trackball->set_mat(invert(mat));
  685. trackball->reset_origin_here();
  686. }
  687. void event_c(CPT_Event) {
  688. // "c" key pressed: change to alternate controls.
  689. if (current_trackball == trackball) {
  690. if (alt_trackball != NULL) {
  691. switch_trackball(alt_trackball);
  692. }
  693. } else {
  694. if (current_trackball == drive_interface) {
  695. stop_drive();
  696. }
  697. switch_trackball(trackball);
  698. }
  699. }
  700. void event_D(CPT_Event) {
  701. // "D" key pressed: toggle drive controls.
  702. if (current_trackball == drive_interface) {
  703. stop_drive();
  704. switch_trackball(trackball);
  705. } else {
  706. start_drive();
  707. set_alt_trackball(drive_interface);
  708. }
  709. }
  710. void event_g(CPT_Event) {
  711. // "g" key pressed: toggle fog.
  712. static bool fog_mode = false;
  713. fog_mode = !fog_mode;
  714. if (fog_mode) {
  715. FogAttribute *fa = new FogAttribute;
  716. fa->set_on(fog);
  717. initial_state.set_attribute(FogTransition::get_class_type(), fa);
  718. } else {
  719. FogAttribute *fa = new FogAttribute;
  720. initial_state.set_attribute(FogTransition::get_class_type(), fa);
  721. }
  722. }
  723. #ifdef USE_IPC
  724. void pause_draw(void) {
  725. if (!render_running)
  726. return;
  727. run_render.lock();
  728. render_running = false;
  729. nout << "draw thread paused" << endl;
  730. }
  731. void unpause_draw(void) {
  732. if (render_running)
  733. return;
  734. run_render.unlock();
  735. render_running = true;
  736. nout << "draw thread continuing" << endl;
  737. }
  738. void draw_loop(void*) {
  739. for (;!quit_draw;) {
  740. mutex_lock m(run_render);
  741. main_win->update();
  742. handle_framerate();
  743. }
  744. nout << "draw thread exiting" << endl;
  745. }
  746. void event_x(CPT_Event) {
  747. // "x" key pressed: pause/unpause draw
  748. if (!forked_draw)
  749. return;
  750. if (render_running)
  751. pause_draw();
  752. else
  753. unpause_draw();
  754. }
  755. #endif
  756. int framework_main(int argc, char *argv[]) {
  757. pystub();
  758. /*
  759. // The first thing we should do is to set up a multiplexing Notify.
  760. MultiplexStream *mstream = new MultiplexStream;
  761. Notify::ptr()->set_ostream_ptr(mstream, true);
  762. mstream->add_standard_output();
  763. mstream->add_system_debug();
  764. string framework_notify_output = framework.GetString("framework-notify-output", "");
  765. if (!framework_notify_output.empty()) {
  766. if (!mstream->add_file(framework_notify_output)) {
  767. framework_cat.error()
  768. << "Unable to open " << framework_notify_output << " for output.\n";
  769. } else {
  770. framework_cat.info()
  771. << "Sending Notify output to " << framework_notify_output << "\n";
  772. }
  773. }
  774. */
  775. GeomNorms::init_type();
  776. #ifndef DEBUG
  777. // This just makes sure that no one changed the value of a
  778. // _type_handle member after the type was registered. It shouldn't
  779. // ever happen. If it did, most likely two classes are sharing the
  780. // same _type_handle variable for some reason.
  781. TypeRegistry::reregister_types();
  782. #endif
  783. app_traverser = new AppTraverser(RenderRelation::get_class_type());
  784. // Allow the specification of multiple files on the command
  785. // line. This is handy, for instance, to load up both a character
  786. // and its animation file.
  787. typedef vector<Filename> Files;
  788. Files files;
  789. if (first_init != NULL)
  790. first_init();
  791. for (int a = 1; a < argc; a++)
  792. if ((argv[a] != (char*)0L) && ((argv[a])[0] != '-') &&
  793. ((argv[a])[0] != '+') && ((argv[a])[0] != '#'))
  794. files.push_back(Filename::from_os_specific(argv[a]));
  795. // load display modules
  796. GraphicsPipe::resolve_modules();
  797. nout << "Known pipe types:" << endl;
  798. GraphicsPipe::_factory.write_types(nout, 2);
  799. // Create a window
  800. main_pipe = GraphicsPipe::_factory.
  801. make_instance(InteractiveGraphicsPipe::get_class_type());
  802. if (main_pipe == (GraphicsPipe*)0L) {
  803. nout << "No interactive pipe is available! Check your Configrc!\n";
  804. exit(1);
  805. }
  806. cout << "Opened a '" << main_pipe->get_type().get_name()
  807. << "' interactive graphics pipe." << endl;
  808. rib_pipe = GraphicsPipe::_factory.
  809. make_instance(NoninteractiveGraphicsPipe::get_class_type());
  810. if (rib_pipe == (GraphicsPipe*)0L)
  811. cout << "Did not open a non-interactive graphics pipe, features related"
  812. << " to that will\nbe disabled." << endl;
  813. else
  814. cout << "Opened a '" << rib_pipe->get_type().get_name()
  815. << "' non-interactive graphics pipe." << endl;
  816. ChanCfgOverrides override;
  817. // need to find a better way to differentiate unsigned int from regular
  818. override.setField(ChanCfgOverrides::Mask,
  819. ((unsigned int)(W_DOUBLE|W_DEPTH|W_MULTISAMPLE)));
  820. override.setField(ChanCfgOverrides::Title, "Demo");
  821. std::string conf = framework.GetString("chan-config", chan_config);
  822. if (extra_overrides_func != NULL)
  823. extra_overrides_func(override, conf);
  824. // Create the render node
  825. render = new NamedNode("render");
  826. // make a node for the cameras to live under
  827. cameras = new NamedNode("cameras");
  828. RenderRelation* arc1 = new RenderRelation(render, cameras);
  829. main_win = ChanConfig(main_pipe, conf, cameras, render, override);
  830. assert(main_win != (GraphicsWindow*)0L);
  831. // is ok if this doesn't work or returns NULL
  832. if (rib_pipe != (GraphicsPipe*)0L) {
  833. Node *rib_cameras = new NamedNode("rib_cameras");
  834. new RenderRelation(render, rib_cameras);
  835. rib_win = ChanConfig(rib_pipe, "single", rib_cameras, render, override);
  836. }
  837. // Make a node for the lights to live under. We put the lights in
  838. // with the cameras, so they'll stay locked to our point-of-view.
  839. lights = new NamedNode("lights");
  840. new RenderRelation(cameras, lights);
  841. light = new AmbientLight( "ambient" );
  842. dlight = new DirectionalLight( "directional" );
  843. plight = new PointLight( "point" );
  844. plight->set_constant_attenuation( 2.0 );
  845. plight->set_linear_attenuation( 1.0 );
  846. plight->set_quadratic_attenuation( 0.5 );
  847. slight = new Spotlight( "spot" );
  848. new RenderRelation( lights, light );
  849. #if 0
  850. new RenderRelation( lights, dlight );
  851. new RenderRelation( lights, plight );
  852. new RenderRelation( lights, slight );
  853. #endif
  854. // Turn on culling.
  855. CullFaceAttribute *cfa = new CullFaceAttribute;
  856. cfa->set_mode(CullFaceProperty::M_cull_clockwise);
  857. initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  858. // Set up a default material
  859. material = new Material;
  860. material->set_ambient( Colorf( 1, 1, 1, 1 ) );
  861. MaterialAttribute *ma = new MaterialAttribute;
  862. ma->set_on(material);
  863. initial_state.set_attribute(MaterialTransition::get_class_type(), ma);
  864. // Set up a default fog
  865. fog = new Fog;
  866. // Create the data graph root.
  867. data_root = new NamedNode( "data" );
  868. // Create a mouse and put it in the data graph.
  869. mak = new MouseAndKeyboard( main_win, 0 );
  870. new DataRelation(data_root, mak);
  871. // Create a MouseWatcher underneath the mouse, so we can have some
  872. // 2-d control effects.
  873. mouse_watcher = new MouseWatcher("mouse_watcher");
  874. new DataRelation(mak, mouse_watcher);
  875. mouse_watcher->set_button_down_pattern("mw-%r-%b");
  876. mouse_watcher->set_button_up_pattern("mw-%r-%b-up");
  877. mouse_watcher->set_enter_pattern("mw-in-%r");
  878. mouse_watcher->set_leave_pattern("mw-out-%r");
  879. // Create a trackball to handle the mouse input.
  880. trackball = new Trackball("trackball");
  881. trackball->set_pos(LVector3f::forward() * 50.0);
  882. // Also create a drive interface. The user might switch to this
  883. // later.
  884. drive_interface = new DriveInterface("drive_interface");
  885. new DataRelation(mouse_watcher, trackball);
  886. current_trackball = trackball;
  887. // Connect the trackball output to the camera's transform.
  888. PT(Transform2SG) tball2cam = new Transform2SG("tball2cam");
  889. tball2cam->set_arc(arc1);
  890. new DataRelation(trackball, tball2cam);
  891. new DataRelation(drive_interface, tball2cam);
  892. // Create a ButtonThrower to throw events from the keyboard.
  893. PT(ButtonThrower) et = new ButtonThrower("kb-events");
  894. new DataRelation(mouse_watcher, et);
  895. root = new NamedNode("root");
  896. first_arc = new RenderRelation(render, root, 100);
  897. if (files.empty() && framework.GetBool("have-omnitriangle", true)) {
  898. // The user did not specify an file. Create some default
  899. // geometry.
  900. PTA_Vertexf coords;
  901. PTA_TexCoordf uvs;
  902. PTA_Normalf norms;
  903. PTA_Colorf colors;
  904. PTA_ushort cindex;
  905. coords.push_back(Vertexf::rfu(0.0, 0.0, 0.0));
  906. coords.push_back(Vertexf::rfu(1.0, 0.0, 0.0));
  907. coords.push_back(Vertexf::rfu(0.0, 0.0, 1.0));
  908. uvs.push_back(TexCoordf(0.0, 0.0));
  909. uvs.push_back(TexCoordf(1.0, 0.0));
  910. uvs.push_back(TexCoordf(0.0, 1.0));
  911. norms.push_back(Normalf::back());
  912. colors.push_back(Colorf(0.5, 0.5, 1.0, 1.0));
  913. cindex.push_back(0);
  914. cindex.push_back(0);
  915. cindex.push_back(0);
  916. PT(GeomTri) geom = new GeomTri;
  917. geom->set_num_prims(1);
  918. geom->set_coords(coords, G_PER_VERTEX);
  919. geom->set_texcoords(uvs, G_PER_VERTEX);
  920. geom->set_normals(norms, G_PER_PRIM);
  921. geom->set_colors(colors, G_PER_VERTEX, cindex);
  922. geomnode = new GeomNode;
  923. geomnode->add_geom(geom.p());
  924. RenderRelation *arc = new RenderRelation(root, geomnode, 10);
  925. first_arc = arc;
  926. Texture *tex = TexturePool::load_texture("rock-floor.rgb");
  927. if (tex != (Texture *)NULL) {
  928. tex->set_minfilter(Texture::FT_linear);
  929. tex->set_magfilter(Texture::FT_linear);
  930. arc->set_transition(new TextureTransition(tex));
  931. }
  932. } else {
  933. // Load up some geometry from one or more files.
  934. Files::const_iterator fi;
  935. for (fi = files.begin();
  936. fi != files.end();
  937. ++fi) {
  938. const Filename &filename = (*fi);
  939. PT_Node node = loader.load_sync(filename);
  940. if (node == (Node *)NULL) {
  941. nout << "Unable to load file " << filename << "\n";
  942. } else {
  943. new RenderRelation(root, node);
  944. }
  945. }
  946. // If we happened to load up both a character file and its
  947. // matching animation file, attempt to bind them together now.
  948. AnimControlCollection anim_controls;
  949. auto_bind(root, anim_controls, ~0);
  950. // And start looping any animations we successfully bound.
  951. anim_controls.loop_all(true);
  952. }
  953. // Set up keyboard events.
  954. event_handler.add_hook("escape", event_esc);
  955. event_handler.add_hook("q", event_esc);
  956. event_handler.add_hook("f", event_f);
  957. event_handler.add_hook("F", event_f_full);
  958. event_handler.add_hook("t", event_t);
  959. event_handler.add_hook("l", event_l);
  960. event_handler.add_hook("w", event_w);
  961. event_handler.add_hook("b", event_b);
  962. event_handler.add_hook("R", event_R);
  963. event_handler.add_hook("grave", event_grave);
  964. event_handler.add_hook("n", event_n);
  965. event_handler.add_hook("c", event_c);
  966. event_handler.add_hook("D", event_D);
  967. event_handler.add_hook("g", event_g);
  968. event_handler.add_hook("C", event_C);
  969. event_handler.add_hook("N", event_N);
  970. event_handler.add_hook("S", event_S);
  971. event_handler.add_hook("A", event_A);
  972. #ifdef USE_IPC
  973. event_handler.add_hook("x", event_x);
  974. #endif
  975. if (define_keys != NULL)
  976. define_keys(event_handler);
  977. // Now that we've called define_keys() (which might or might not
  978. // set have_dlight), we can turn on lighting.
  979. set_lighting(false);
  980. // Tick the clock once so we won't count the time spent loading up
  981. // files, above, in our frame rate average.
  982. ClockObject::get_global_clock()->tick();
  983. start_time = ClockObject::get_global_clock()->get_time();
  984. start_frame_count = ClockObject::get_global_clock()->get_frame_count();
  985. if (framework.Defined("clear-value")) {
  986. float cf = framework.GetFloat("clear-value", 0.);
  987. Colorf c(cf, cf, cf, 1.);
  988. main_win->get_gsg()->set_color_clear_value(c);
  989. }
  990. if (!main_win->supports_update()) {
  991. nout
  992. << "Window type " << main_win->get_type()
  993. << " supports only the glut-style main loop interface.\n";
  994. main_win->register_draw_function(display_func);
  995. main_win->register_idle_function(idle_func);
  996. main_win->register_resize_function(resize_func);
  997. main_win->main_loop();
  998. } else {
  999. DisplayCallback dcb;
  1000. main_win->set_draw_callback(&dcb);
  1001. IdleCallback icb;
  1002. #ifdef USE_IPC
  1003. if (forked_draw) {
  1004. nout << "forking draw thread" << endl;
  1005. draw_thread = thread::create(draw_loop);
  1006. for (;;)
  1007. icb.idle();
  1008. } else
  1009. #endif
  1010. {
  1011. main_win->set_idle_callback(&icb);
  1012. for (;;) {
  1013. main_win->update();
  1014. handle_framerate();
  1015. }
  1016. }
  1017. }
  1018. return 1;
  1019. }