00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "windowFramework.h"
00020 #include "pandaFramework.h"
00021 #include "mouseAndKeyboard.h"
00022 #include "buttonThrower.h"
00023 #include "transform2sg.h"
00024 #include "dSearchPath.h"
00025 #include "filename.h"
00026 #include "loader.h"
00027 #include "keyboardButton.h"
00028 #include "geomTri.h"
00029 #include "texturePool.h"
00030 #include "textureAttrib.h"
00031 #include "perspectiveLens.h"
00032 #include "orthographicLens.h"
00033 #include "auto_bind.h"
00034 #include "ambientLight.h"
00035 #include "directionalLight.h"
00036 #include "lightAttrib.h"
00037 #include "boundingSphere.h"
00038 #include "deg_2_rad.h"
00039 #include "config_framework.h"
00040 #include "depthTestAttrib.h"
00041 #include "depthWriteAttrib.h"
00042 #include "cullFaceAttrib.h"
00043 #include "pgTop.h"
00044 #include "geomNode.h"
00045 #include "geomTristrip.h"
00046 #include "texture.h"
00047 #include "pnmImage.h"
00048 #include "loaderFileTypeRegistry.h"
00049 #include "pnmFileTypeRegistry.h"
00050
00051
00052
00053 static const int override_priority = 100;
00054
00055 TypeHandle WindowFramework::_type_handle;
00056
00057
00058
00059
00060
00061
00062 WindowFramework::
00063 WindowFramework(PandaFramework *panda_framework) :
00064 _panda_framework(panda_framework)
00065 {
00066 _alight = (AmbientLight *)NULL;
00067 _dlight = (DirectionalLight *)NULL;
00068 _got_keyboard = false;
00069 _got_trackball = false;
00070 _got_lights = false;
00071 _wireframe_enabled = false;
00072 _texture_enabled = true;
00073 _two_sided_enabled = false;
00074 _one_sided_reverse_enabled = false;
00075 _lighting_enabled = false;
00076 _background_type = BT_default;
00077 }
00078
00079
00080
00081
00082
00083
00084 WindowFramework::
00085 ~WindowFramework() {
00086 close_window();
00087 }
00088
00089
00090
00091
00092
00093
00094
00095 GraphicsWindow *WindowFramework::
00096 open_window(const WindowProperties &props, GraphicsEngine *engine,
00097 GraphicsPipe *pipe) {
00098 nassertr(_window == (GraphicsWindow *)NULL, _window);
00099
00100 PT(GraphicsStateGuardian) gsg = engine->make_gsg(pipe);
00101 if (gsg == (GraphicsStateGuardian *)NULL) {
00102
00103 framework_cat.fatal() << "open_window: failed to create gsg object!\n";
00104 return NULL;
00105 }
00106
00107 _window = engine->make_window(pipe, gsg);
00108 if (_window != (GraphicsWindow *)NULL) {
00109 _window->request_properties(props);
00110 set_background_type(_background_type);
00111 }
00112
00113
00114 make_camera();
00115 return _window;
00116 }
00117
00118
00119
00120
00121
00122
00123
00124 void WindowFramework::
00125 close_window() {
00126 _window.clear();
00127 _camera_group.remove_node();
00128 _render.remove_node();
00129 _render_2d.remove_node();
00130 _mouse.remove_node();
00131
00132 _alight = (AmbientLight *)NULL;
00133 _dlight = (DirectionalLight *)NULL;
00134 _got_keyboard = false;
00135 _got_trackball = false;
00136 _got_lights = false;
00137
00138 _wireframe_enabled = false;
00139 _texture_enabled = true;
00140 _two_sided_enabled = false;
00141 _one_sided_reverse_enabled = false;
00142 _lighting_enabled = false;
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152 const NodePath &WindowFramework::
00153 get_camera_group() {
00154 if (_camera_group.is_empty()) {
00155 _camera_group = get_render().attach_new_node("camera_group");
00156 }
00157 return _camera_group;
00158 }
00159
00160
00161
00162
00163
00164
00165 const NodePath &WindowFramework::
00166 get_render() {
00167 if (_render.is_empty()) {
00168 _render = NodePath("render");
00169
00170
00171 _render.set_two_sided(0);
00172 }
00173 return _render;
00174 }
00175
00176
00177
00178
00179
00180
00181 const NodePath &WindowFramework::
00182 get_render_2d() {
00183 if (_render_2d.is_empty()) {
00184 _render_2d = NodePath("render_2d");
00185
00186
00187
00188
00189
00190
00191
00192
00193 CPT(RenderAttrib) dt = DepthTestAttrib::make(DepthTestAttrib::M_none);
00194 CPT(RenderAttrib) dw = DepthWriteAttrib::make(DepthWriteAttrib::M_off);
00195 _render_2d.node()->set_attrib(dt, 1);
00196 _render_2d.node()->set_attrib(dw, 1);
00197
00198 _render_2d.set_material_off(1);
00199 _render_2d.set_two_sided(1, 1);
00200
00201
00202
00203
00204
00205 PT(GraphicsChannel) channel = _window->get_channel(0);
00206
00207
00208 PT(GraphicsLayer) layer = channel->make_layer();
00209
00210
00211 PT(DisplayRegion) dr = layer->make_display_region();
00212
00213
00214 PT(Camera) camera = new Camera("camera2d");
00215 NodePath camera_np = _render_2d.attach_new_node(camera);
00216
00217 PT(Lens) lens = new OrthographicLens;
00218
00219 static const float left = -1.0f;
00220 static const float right = 1.0f;
00221 static const float bottom = -1.0f;
00222 static const float top = 1.0f;
00223 lens->set_film_size(right - left, top - bottom);
00224 lens->set_film_offset((right + left) * 0.5, (top + bottom) * 0.5);
00225 lens->set_near_far(-1000, 1000);
00226
00227 camera->set_lens(lens);
00228 camera->set_scene(_render_2d);
00229 dr->set_camera(camera_np);
00230 }
00231
00232 return _render_2d;
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 const NodePath &WindowFramework::
00242 get_aspect_2d() {
00243 if (_aspect_2d.is_empty()) {
00244 _aspect_2d = get_render_2d().attach_new_node(new PGTop("aspect_2d"));
00245
00246 float this_aspect_ratio = aspect_ratio;
00247 if (this_aspect_ratio == 0.0f) {
00248
00249 this_aspect_ratio = 1.0f;
00250
00251 WindowProperties properties = _window->get_properties();
00252 if (!properties.has_size()) {
00253 properties = _window->get_requested_properties();
00254 }
00255 if (properties.has_size() && properties.get_y_size() != 0.0f) {
00256 this_aspect_ratio =
00257 (float)properties.get_x_size() / (float)properties.get_y_size();
00258 }
00259 }
00260
00261 _aspect_2d.set_scale(1.0f / this_aspect_ratio, 1.0f, 1.0f);
00262 }
00263
00264 return _aspect_2d;
00265 }
00266
00267
00268
00269
00270
00271
00272
00273 const NodePath &WindowFramework::
00274 get_mouse() {
00275 if (_mouse.is_empty()) {
00276 nassertr(_window->get_num_input_devices() > 0, _mouse);
00277 NodePath data_root = _panda_framework->get_data_root();
00278 MouseAndKeyboard *mouse_node =
00279 new MouseAndKeyboard(_window, 0, "mouse");
00280 _mouse = data_root.attach_new_node(mouse_node);
00281 }
00282 return _mouse;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291 void WindowFramework::
00292 enable_keyboard() {
00293 if (_got_keyboard) {
00294 return;
00295 }
00296
00297 if (_window->get_num_input_devices() > 0) {
00298 NodePath mouse = get_mouse();
00299
00300 PT(ButtonThrower) bt = new ButtonThrower("kb-events");
00301 bt->add_parameter(EventParameter(this));
00302 ModifierButtons mods;
00303 mods.add_button(KeyboardButton::shift());
00304 mods.add_button(KeyboardButton::control());
00305 mods.add_button(KeyboardButton::alt());
00306 bt->set_modifier_buttons(mods);
00307 mouse.attach_new_node(bt);
00308 }
00309
00310 _got_keyboard = true;
00311 }
00312
00313
00314
00315
00316
00317
00318 void WindowFramework::
00319 setup_trackball() {
00320 if (_got_trackball) {
00321 return;
00322 }
00323
00324 if (_window->get_num_input_devices() > 0) {
00325 NodePath mouse = get_mouse();
00326 NodePath camera = get_camera_group();
00327
00328 _trackball = new Trackball("trackball");
00329 _trackball->set_pos(LVector3f::forward() * 50.0);
00330 mouse.attach_new_node(_trackball);
00331
00332 PT(Transform2SG) tball2cam = new Transform2SG("tball2cam");
00333 tball2cam->set_node(camera.node());
00334 _trackball->add_child(tball2cam);
00335 }
00336
00337 _got_trackball = true;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346 void WindowFramework::
00347 center_trackball(const NodePath &object) {
00348 if (_trackball == (Trackball *)NULL) {
00349 return;
00350 }
00351
00352 PT(BoundingVolume) volume = object.get_bounds();
00353
00354 nassertv(volume != (BoundingVolume *)NULL);
00355 nassertv(volume->is_of_type(GeometricBoundingVolume::get_class_type()));
00356 GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, volume);
00357
00358
00359
00360
00361 PT(BoundingSphere) sphere = new BoundingSphere;
00362 if (!sphere->extend_by(gbv)) {
00363 framework_cat.warning()
00364 << "Cannot determine bounding volume of " << object << "\n";
00365 return;
00366 }
00367
00368 if (sphere->is_infinite()) {
00369 framework_cat.warning()
00370 << "Infinite bounding volume for " << object << "\n";
00371 return;
00372 }
00373
00374 if (sphere->is_empty()) {
00375 framework_cat.warning()
00376 << "Empty bounding volume for " << object << "\n";
00377 return;
00378 }
00379
00380 LPoint3f center = sphere->get_center();
00381 float radius = sphere->get_radius();
00382
00383 float distance = 50.0f;
00384
00385
00386
00387
00388 Lens *lens = (Lens *)NULL;
00389 if (!_cameras.empty()) {
00390 Cameras::const_iterator ci;
00391 for (ci = _cameras.begin();
00392 ci != _cameras.end() && lens == (Lens *)NULL;
00393 ++ci) {
00394 lens = (*ci)->get_lens();
00395 }
00396 }
00397
00398 if (lens != (Lens *)NULL) {
00399 LVecBase2f fov = lens->get_fov();
00400 distance = radius / ctan(deg_2_rad(min(fov[0], fov[1]) / 2.0f));
00401
00402
00403 float ideal_far_plane = distance + radius;
00404 lens->set_far(max(lens->get_default_far(), ideal_far_plane));
00405
00406
00407 float ideal_near_plane = distance - radius;
00408 lens->set_near(min(lens->get_default_near(), ideal_near_plane));
00409 }
00410
00411 _trackball->set_origin(center);
00412 _trackball->set_pos(LVector3f::forward() * distance);
00413
00414
00415
00416 _trackball->set_forward_scale(distance * 0.006);
00417 }
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 bool WindowFramework::
00430 load_models(const NodePath &parent, int argc, char *argv[], int first_arg) {
00431 pvector<Filename> files;
00432
00433 for (int i = first_arg; i < argc && argv[i] != (char *)NULL; i++) {
00434 files.push_back(Filename::from_os_specific(argv[i]));
00435 }
00436
00437 return load_models(parent, files);
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449 bool WindowFramework::
00450 load_models(const NodePath &parent, const pvector<Filename> &files) {
00451 bool all_ok = true;
00452
00453 NodePath render = get_render();
00454
00455 pvector<Filename>::const_iterator fi;
00456 for (fi = files.begin(); fi != files.end(); ++fi) {
00457 const Filename &filename = (*fi);
00458 NodePath model = load_model(parent, filename);
00459 if (model.is_empty()) {
00460 all_ok = false;
00461 }
00462 }
00463
00464 return all_ok;
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474 NodePath WindowFramework::
00475 load_model(const NodePath &parent, Filename filename) {
00476 nout << "Loading " << filename << "\n";
00477
00478
00479
00480 bool search = !(filename.is_fully_qualified() || filename.exists());
00481
00482
00483
00484 bool is_image = false;
00485 string extension = filename.get_extension();
00486 if (!extension.empty()) {
00487 LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_ptr();
00488 LoaderFileType *model_type =
00489 reg->get_type_from_extension(extension);
00490 if (model_type == (LoaderFileType *)NULL) {
00491
00492
00493 PNMFileTypeRegistry *reg = PNMFileTypeRegistry::get_ptr();
00494 PNMFileType *image_type =
00495 reg->get_type_from_extension(extension);
00496 if (image_type != (PNMFileType *)NULL) {
00497
00498 is_image = true;
00499 }
00500 }
00501 }
00502
00503 Loader loader;
00504 PT(PandaNode) node;
00505 if (is_image) {
00506 node = load_image_as_model(filename);
00507 } else {
00508 node = loader.load_sync(filename, search);
00509 }
00510
00511 if (node == (PandaNode *)NULL) {
00512 nout << "Unable to load " << filename << "\n";
00513 return NodePath::not_found();
00514 }
00515
00516 return parent.attach_new_node(node);
00517 }
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 NodePath WindowFramework::
00528 load_default_model(const NodePath &parent) {
00529 PTA_Vertexf coords;
00530 PTA_TexCoordf uvs;
00531 PTA_Normalf norms;
00532 PTA_Colorf colors;
00533 PTA_ushort cindex;
00534
00535 coords.push_back(Vertexf::rfu(0.0, 0.0, 0.0));
00536 coords.push_back(Vertexf::rfu(1.0, 0.0, 0.0));
00537 coords.push_back(Vertexf::rfu(0.0, 0.0, 1.0));
00538 uvs.push_back(TexCoordf(0.0, 0.0));
00539 uvs.push_back(TexCoordf(1.0, 0.0));
00540 uvs.push_back(TexCoordf(0.0, 1.0));
00541 norms.push_back(Normalf::back());
00542 colors.push_back(Colorf(0.5, 0.5, 1.0, 1.0));
00543 cindex.push_back(0);
00544 cindex.push_back(0);
00545 cindex.push_back(0);
00546
00547 PT(GeomTri) geom = new GeomTri;
00548 geom->set_num_prims(1);
00549 geom->set_coords(coords);
00550 geom->set_texcoords(uvs, G_PER_VERTEX);
00551 geom->set_normals(norms, G_PER_PRIM);
00552 geom->set_colors(colors, G_PER_VERTEX, cindex);
00553
00554 CPT(RenderState) state = RenderState::make_empty();
00555 Texture *tex = TexturePool::load_texture("rock-floor.rgb");
00556 if (tex != (Texture *)NULL) {
00557 tex->set_minfilter(Texture::FT_linear);
00558 tex->set_magfilter(Texture::FT_linear);
00559 state = state->add_attrib(TextureAttrib::make(tex));
00560 }
00561
00562 GeomNode *geomnode = new GeomNode("tri");
00563 geomnode->add_geom(geom, state);
00564
00565 return parent.attach_new_node(geomnode);
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575 void WindowFramework::
00576 loop_animations() {
00577
00578
00579
00580 auto_bind(get_render().node(), _anim_controls, ~0);
00581 _anim_controls.loop_all(true);
00582 }
00583
00584
00585
00586
00587
00588
00589
00590 void WindowFramework::
00591 set_wireframe(bool enable) {
00592 if (enable == _wireframe_enabled) {
00593 return;
00594 }
00595
00596 NodePath render = get_render();
00597
00598 if (enable) {
00599 render.set_render_mode_wireframe(override_priority);
00600 render.set_two_sided(true, override_priority);
00601 } else {
00602 render.clear_render_mode();
00603 if (!_two_sided_enabled) {
00604 render.clear_two_sided();
00605 }
00606 if (_one_sided_reverse_enabled) {
00607 CPT(RenderAttrib) attrib = CullFaceAttrib::make_reverse();
00608 render.node()->set_attrib(attrib);
00609 }
00610 }
00611
00612 _wireframe_enabled = enable;
00613 }
00614
00615
00616
00617
00618
00619
00620
00621 void WindowFramework::
00622 set_texture(bool enable) {
00623 if (enable == _texture_enabled) {
00624 return;
00625 }
00626
00627 NodePath render = get_render();
00628
00629 if (!enable) {
00630 render.set_texture_off(override_priority);
00631 } else {
00632 render.clear_texture();
00633 }
00634
00635 _texture_enabled = enable;
00636 }
00637
00638
00639
00640
00641
00642
00643
00644 void WindowFramework::
00645 set_two_sided(bool enable) {
00646 if (enable == _two_sided_enabled) {
00647 return;
00648 }
00649
00650 NodePath render = get_render();
00651
00652 if (enable) {
00653 render.set_two_sided(true, override_priority);
00654 } else {
00655 if (!_wireframe_enabled) {
00656 render.clear_two_sided();
00657 }
00658 }
00659
00660 _two_sided_enabled = enable;
00661 _one_sided_reverse_enabled = false;
00662 }
00663
00664
00665
00666
00667
00668
00669
00670
00671 void WindowFramework::
00672 set_one_sided_reverse(bool enable) {
00673 if (enable == _one_sided_reverse_enabled) {
00674 return;
00675 }
00676
00677 NodePath render = get_render();
00678
00679 if (!_wireframe_enabled) {
00680 if (enable) {
00681 CPT(RenderAttrib) attrib = CullFaceAttrib::make_reverse();
00682 render.node()->set_attrib(attrib);
00683 } else {
00684 render.clear_two_sided();
00685 }
00686 }
00687
00688 _two_sided_enabled = false;
00689 _one_sided_reverse_enabled = enable;
00690 }
00691
00692
00693
00694
00695
00696
00697 void WindowFramework::
00698 set_lighting(bool enable) {
00699 if (enable == _lighting_enabled) {
00700 return;
00701 }
00702
00703 NodePath render = get_render();
00704
00705 if (enable) {
00706 if (!_got_lights) {
00707 setup_lights();
00708 }
00709 render.node()->set_attrib(LightAttrib::make(LightAttrib::O_add,
00710 _alight, _dlight));
00711 } else {
00712 render.node()->clear_attrib(LightAttrib::get_class_type());
00713 }
00714
00715 _lighting_enabled = enable;
00716 }
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726 void WindowFramework::
00727 set_background_type(WindowFramework::BackgroundType type) {
00728 _background_type = type;
00729
00730 if (_window != (GraphicsWindow *)NULL) {
00731 switch (_background_type) {
00732 case BT_other:
00733 break;
00734
00735 case BT_default:
00736 _window->set_clear_color_active(true);
00737 _window->set_clear_depth_active(true);
00738 _window->set_clear_color(Colorf(win_background_r, win_background_g,
00739 win_background_b, 1.0f));
00740 _window->set_clear_depth(1.0f);
00741 break;
00742
00743 case BT_gray:
00744 _window->set_clear_color_active(true);
00745 _window->set_clear_depth_active(true);
00746 _window->set_clear_color(Colorf(0.3f, 0.3f, 0.3f, 1.0f));
00747 _window->set_clear_depth(1.0f);
00748 break;
00749
00750 case BT_black:
00751 _window->set_clear_color_active(true);
00752 _window->set_clear_depth_active(true);
00753 _window->set_clear_color(Colorf(0.0f, 0.0f, 0.0f, 1.0f));
00754 _window->set_clear_depth(1.0f);
00755 break;
00756
00757 case BT_none:
00758 _window->set_clear_color_active(false);
00759 _window->set_clear_depth_active(false);
00760 break;
00761 }
00762 }
00763 }
00764
00765
00766
00767
00768
00769
00770 PT(Camera) WindowFramework::
00771 make_camera() {
00772
00773
00774 PT(GraphicsChannel) channel = _window->get_channel(0);
00775
00776
00777 PT(GraphicsLayer) layer = channel->make_layer();
00778
00779
00780 PT(DisplayRegion) dr = layer->make_display_region();
00781
00782
00783 PT(Camera) camera = new Camera("camera");
00784 NodePath camera_np = get_camera_group().attach_new_node(camera);
00785 _cameras.push_back(camera);
00786
00787 PT(Lens) lens = new PerspectiveLens;
00788 WindowProperties properties = _window->get_properties();
00789 if (!properties.has_size()) {
00790 properties = _window->get_requested_properties();
00791 }
00792 if (properties.has_size()) {
00793 lens->set_film_size(properties.get_x_size(), properties.get_y_size());
00794 }
00795 camera->set_lens(lens);
00796 camera->set_scene(get_render());
00797 dr->set_camera(camera_np);
00798
00799 return camera;
00800 }
00801
00802
00803
00804
00805
00806
00807
00808 void WindowFramework::
00809 setup_lights() {
00810 if (_got_lights) {
00811 return;
00812 }
00813
00814 NodePath camera_group = get_camera_group();
00815 NodePath light_group = camera_group.attach_new_node("lights");
00816
00817 _alight = new AmbientLight("ambient");
00818 _alight->set_color(Colorf(0.2f, 0.2f, 0.2f, 1.0f));
00819 _dlight = new DirectionalLight("directional");
00820 light_group.attach_new_node(_alight);
00821 light_group.attach_new_node(_dlight);
00822
00823 _got_lights = true;
00824 }
00825
00826
00827
00828
00829
00830
00831
00832
00833 PT(PandaNode) WindowFramework::
00834 load_image_as_model(const Filename &filename) {
00835 PNMImageHeader header;
00836 if (!header.read_header(filename)) {
00837 return NULL;
00838 }
00839
00840 int x_size = header.get_x_size();
00841 int y_size = header.get_y_size();
00842 bool has_alpha = header.has_alpha();
00843
00844
00845 PT(Texture) tex = new Texture;
00846 if (!tex->read(filename)) {
00847 return NULL;
00848 }
00849 tex->set_minfilter(Texture::FT_linear_mipmap_linear);
00850 tex->set_magfilter(Texture::FT_linear);
00851
00852
00853 PT(GeomNode) card_geode = new GeomNode("card");
00854
00855
00856 float left = -x_size / 2.0;
00857 float right = x_size / 2.0;
00858 float bottom = -y_size / 2.0;
00859 float top = y_size / 2.0;
00860
00861 GeomTristrip *geoset = new GeomTristrip;
00862 PTA_int lengths=PTA_int::empty_array(0);
00863 lengths.push_back(4);
00864
00865 PTA_Vertexf verts;
00866 verts.push_back(Vertexf::rfu(left, 0.02f, top));
00867 verts.push_back(Vertexf::rfu(left, 0.02f, bottom));
00868 verts.push_back(Vertexf::rfu(right, 0.02f, top));
00869 verts.push_back(Vertexf::rfu(right, 0.02f, bottom));
00870
00871 geoset->set_num_prims(1);
00872 geoset->set_lengths(lengths);
00873
00874 geoset->set_coords(verts);
00875
00876 PTA_TexCoordf uvs;
00877 uvs.push_back(TexCoordf(0.0f, 1.0f));
00878 uvs.push_back(TexCoordf(0.0f, 0.0f));
00879 uvs.push_back(TexCoordf(1.0f, 1.0f));
00880 uvs.push_back(TexCoordf(1.0f, 0.0f));
00881
00882 geoset->set_texcoords(uvs, G_PER_VERTEX);
00883
00884 card_geode->add_geom(geoset);
00885 card_geode->set_attrib(TextureAttrib::make(tex));
00886 if (has_alpha) {
00887 card_geode->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00888 }
00889
00890 return card_geode.p();
00891 }