Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/framework/windowFramework.cxx

Go to the documentation of this file.
00001 // Filename: windowFramework.cxx
00002 // Created by:  drose (02Apr02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
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 // This number is chosen arbitrarily to override any settings in model
00052 // files.
00053 static const int override_priority = 100;
00054 
00055 TypeHandle WindowFramework::_type_handle;
00056 
00057 ////////////////////////////////////////////////////////////////////
00058 //     Function: WindowFramework::Constructor
00059 //       Access: Protected
00060 //  Description: 
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 //     Function: WindowFramework::Destructor
00081 //       Access: Public, Virtual
00082 //  Description: 
00083 ////////////////////////////////////////////////////////////////////
00084 WindowFramework::
00085 ~WindowFramework() {
00086   close_window();
00087 }
00088 
00089 ////////////////////////////////////////////////////////////////////
00090 //     Function: WindowFramework::open_window
00091 //       Access: Protected
00092 //  Description: Opens the actual window.  This is normally called
00093 //               only from PandaFramework::open_window().
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     // No GSG, no window.
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   // Set up a 3-d camera for the window by default.
00114   make_camera();
00115   return _window;
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //     Function: WindowFramework::close_window
00120 //       Access: Protected
00121 //  Description: Closes the window.  This is normally called
00122 //               from PandaFramework::close_window().
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 //     Function: WindowFramework::get_camera_group
00147 //       Access: Public
00148 //  Description: Returns the node above the collection of 3-d cameras
00149 //               in the scene graph.  This node may be moved around to
00150 //               represent the viewpoint.
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 //     Function: WindowFramework::get_render
00162 //       Access: Public
00163 //  Description: Returns the root of the 3-d scene graph.
00164 ////////////////////////////////////////////////////////////////////
00165 const NodePath &WindowFramework::
00166 get_render() {
00167   if (_render.is_empty()) {
00168     _render = NodePath("render");
00169 
00170     // This is maybe here temporarily, and maybe not.
00171     _render.set_two_sided(0);
00172   }
00173   return _render;
00174 }
00175 
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: WindowFramework::get_render_2d
00178 //       Access: Public
00179 //  Description: Returns the root of the 2-d scene graph.
00180 ////////////////////////////////////////////////////////////////////
00181 const NodePath &WindowFramework::
00182 get_render_2d() {
00183   if (_render_2d.is_empty()) {
00184     _render_2d = NodePath("render_2d");
00185 
00186     // Some standard properties for the 2-d display.
00187 
00188     // It's particularly important to turn off the depth test,
00189     // since we'll be keeping the same depth buffer already filled
00190     // by the previously-drawn 3-d scene--we don't want to pay for
00191     // a clear operation, but we also don't want to collide with
00192     // that depth buffer.
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     // Now set up a 2-d camera to view render_2d.
00202 
00203     // Get the first channel on the window.  This will be the only
00204     // channel on non-SGI hardware.
00205     PT(GraphicsChannel) channel = _window->get_channel(0);
00206 
00207     // Make a layer on the channel to hold our display region.
00208     PT(GraphicsLayer) layer = channel->make_layer();
00209     
00210     // And create a display region that covers the entire window.
00211     PT(DisplayRegion) dr = layer->make_display_region();
00212     
00213     // Finally, we need a camera to associate with the display region.
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 //     Function: WindowFramework::get_aspect_2d
00237 //       Access: Public
00238 //  Description: Returns the node under the 2-d scene graph that is
00239 //               scaled to suit the window's aspect ratio.
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       // An aspect ratio of 0.0 means to try to infer it.
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 //     Function: WindowFramework::get_mouse
00269 //       Access: Public
00270 //  Description: Returns the node in the data graph corresponding to
00271 //               the mouse associated with this window.
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 //     Function: WindowFramework::enable_keyboard
00287 //       Access: Public
00288 //  Description: Creates a ButtonThrower to listen to button presses
00289 //               and throw them as events.
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 //     Function: WindowFramework::setup_trackball
00315 //       Access: Public
00316 //  Description: Sets up the mouse to trackball around the camera.
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 //     Function: WindowFramework::center_trackball
00342 //       Access: Public
00343 //  Description: Centers the trackball on the indicated object, and
00344 //               scales the trackball motion suitably.
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   // We expect at least a geometric bounding volume around the world.
00354   nassertv(volume != (BoundingVolume *)NULL);
00355   nassertv(volume->is_of_type(GeometricBoundingVolume::get_class_type()));
00356   GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, volume);
00357   
00358   // Determine the bounding sphere around the world.  The topmost
00359   // BoundingVolume might itself be a sphere (it's likely), but since
00360   // it might not, we'll take no chances and make our own sphere.
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   // Choose a suitable distance to view the whole volume in our frame.
00386   // This is based on the camera lens in use.  Determine the lens
00387   // based on the first camera; this will be the default camera.
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     // Ensure the far plane is far enough back to see the entire object.
00403     float ideal_far_plane = distance + radius;
00404     lens->set_far(max(lens->get_default_far(), ideal_far_plane)); 
00405 
00406     // And that the near plane is far enough forward.
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   // Also set the movement scale on the trackball to be consistent
00415   // with the size of the model and the lens field-of-view.
00416   _trackball->set_forward_scale(distance * 0.006);
00417 }
00418 
00419 ////////////////////////////////////////////////////////////////////
00420 //     Function: WindowFramework::load_models
00421 //       Access: Public
00422 //  Description: Loads up all the model files listed in the indicated
00423 //               argument list.  If first_arg is supplied, it is the
00424 //               first argument in the list to consider.
00425 //
00426 //               Returns true if all models loaded successfully, or
00427 //               false if at least one of them had an error.
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 //     Function: WindowFramework::load_models
00442 //       Access: Public
00443 //  Description: Loads up all the model files listed in the indicated
00444 //               argument list.
00445 //
00446 //               Returns true if all models loaded successfully, or
00447 //               false if at least one of them had an error.
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 //     Function: WindowFramework::load_model
00469 //       Access: Public
00470 //  Description: Loads up the indicated model and returns the new
00471 //               NodePath, or the empty NodePath if the model could
00472 //               not be loaded.
00473 ////////////////////////////////////////////////////////////////////
00474 NodePath WindowFramework::
00475 load_model(const NodePath &parent, Filename filename) {
00476   nout << "Loading " << filename << "\n";
00477 
00478   // If the filename already exists where it is, or if it is fully
00479   // qualified, don't search along the model path for it.
00480   bool search = !(filename.is_fully_qualified() || filename.exists());
00481 
00482   // We allow loading image files here.  Check to see if it might be
00483   // an image file, based on the filename extension.
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       // The extension isn't a known model file type, is it a known
00492       // image extension?
00493       PNMFileTypeRegistry *reg = PNMFileTypeRegistry::get_ptr();
00494       PNMFileType *image_type =
00495         reg->get_type_from_extension(extension);
00496       if (image_type != (PNMFileType *)NULL) {
00497         // It is a known image extension.
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 //     Function: WindowFramework::load_default_model
00521 //       Access: Public
00522 //  Description: Loads our favorite blue triangle.  This is intended
00523 //               to provide some default geometry to have *something*
00524 //               to look at for testing, when no other models are
00525 //               provided.
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 //     Function: WindowFramework::loop_animations
00570 //       Access: Public
00571 //  Description: Looks for characters and their matching animation
00572 //               files in the scene graph; binds and loops any
00573 //               matching animations found.
00574 ////////////////////////////////////////////////////////////////////
00575 void WindowFramework::
00576 loop_animations() {
00577   // If we happened to load up both a character file and its matching
00578   // animation file, attempt to bind them together now and start the
00579   // animations looping.
00580   auto_bind(get_render().node(), _anim_controls, ~0);
00581   _anim_controls.loop_all(true);
00582 }
00583 
00584 ////////////////////////////////////////////////////////////////////
00585 //     Function: WindowFramework::set_wireframe
00586 //       Access: Public
00587 //  Description: Forces wireframe state (true) or restores default
00588 //               rendering (false).
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 //     Function: WindowFramework::set_texture
00617 //       Access: Public
00618 //  Description: Forces textures off (false) or restores default
00619 //               rendering (true).
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 //     Function: WindowFramework::set_two_sided
00640 //       Access: Public
00641 //  Description: Forces two-sided rendering (true) or restores default
00642 //               rendering (false).
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 //     Function: WindowFramework::set_one_sided_reverse
00666 //       Access: Public
00667 //  Description: Toggles one-sided reverse mode.  In this mode, the
00668 //               front sides of one-sided polygons are culled instead
00669 //               of the back side.
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 //     Function: WindowFramework::set_lighting
00694 //       Access: Public
00695 //  Description: Turns lighting on (true) or off (false).
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 //     Function: WindowFramework::set_background_type
00720 //       Access: Public
00721 //  Description: Sets the background of the window to one of the
00722 //               pre-canned background types (or to BT_other, which
00723 //               indicates the user intends to set up his own special
00724 //               background mode).
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 //     Function: WindowFramework::make_camera
00767 //       Access: Protected
00768 //  Description: Makes a new 3-d camera for the window.
00769 ////////////////////////////////////////////////////////////////////
00770 PT(Camera) WindowFramework::
00771 make_camera() {
00772   // Get the first channel on the window.  This will be the only
00773   // channel on non-SGI hardware.
00774   PT(GraphicsChannel) channel = _window->get_channel(0);
00775 
00776   // Make a layer on the channel to hold our display region.
00777   PT(GraphicsLayer) layer = channel->make_layer();
00778 
00779   // And create a display region that covers the entire window.
00780   PT(DisplayRegion) dr = layer->make_display_region();
00781 
00782   // Finally, we need a camera to associate with the display region.
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 //     Function: WindowFramework::setup_lights
00804 //       Access: Protected
00805 //  Description: Makes light nodes and attaches them to the camera for
00806 //               viewing the scene.
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 //     Function: WindowFramework::load_image_as_model
00828 //       Access: Private
00829 //  Description: Loads the indicated image file as a texture, and
00830 //               creates a polygon to render it.  Returns the new
00831 //               model.
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   // Yes, it is an image file; make a texture out of it.
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   // Ok, now make a polygon to show the texture.
00853   PT(GeomNode) card_geode = new GeomNode("card");
00854 
00855   // Choose the dimensions of the polygon appropriately.
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 }

Generated on Fri May 2 00:38:55 2003 for Panda by doxygen1.3