From 783ba052d790722e34d4a69593b0db1a9c40b535 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 28 Mar 2002 01:51:13 +0000 Subject: [PATCH] pgraph lighting, optional offset decal implementation --- panda/src/collide/collisionSolid.cxx | 11 +- panda/src/display/graphicsEngine.cxx | 130 +++-- panda/src/display/graphicsEngine.h | 11 +- panda/src/display/graphicsStateGuardian.I | 22 + panda/src/display/graphicsStateGuardian.cxx | 17 +- panda/src/display/graphicsStateGuardian.h | 9 +- panda/src/dxgsg/dxGraphicsStateGuardian.cxx | 8 + panda/src/framework/framework.cxx | 5 + panda/src/glgsg/config_glgsg.cxx | 5 + panda/src/glgsg/config_glgsg.h | 1 + panda/src/glgsg/glGraphicsStateGuardian.cxx | 370 ++++++++----- panda/src/glgsg/glGraphicsStateGuardian.h | 8 +- panda/src/gobj/lens.cxx | 11 + panda/src/gobj/lens.h | 1 + panda/src/gsgbase/graphicsStateGuardianBase.h | 8 +- panda/src/light/Sources.pp | 47 +- panda/src/light/ambientLight.I | 17 + panda/src/light/ambientLight.cxx | 112 +++- panda/src/light/ambientLight.h | 88 ++-- panda/src/light/config_light.cxx | 12 + panda/src/light/directionalLight.I | 98 +++- panda/src/light/directionalLight.cxx | 185 ++++++- panda/src/light/directionalLight.h | 113 ++-- panda/src/light/light.I | 98 ++++ panda/src/light/light.cxx | 102 +++- panda/src/light/light.h | 113 ++-- panda/src/light/lightAttrib.I | 88 ++++ panda/src/light/lightAttrib.cxx | 489 ++++++++++++++++++ panda/src/light/lightAttrib.h | 116 +++++ panda/src/light/lightLensNode.I | 17 + panda/src/light/lightLensNode.cxx | 115 ++++ panda/src/light/lightLensNode.h | 81 +++ panda/src/light/lightNode.I | 17 + panda/src/light/lightNode.cxx | 115 ++++ panda/src/light/lightNode.h | 83 +++ panda/src/light/light_composite1.cxx | 4 +- panda/src/light/light_composite2.cxx | 1 - panda/src/light/pointLight.I | 96 ++-- panda/src/light/pointLight.cxx | 188 ++++++- panda/src/light/pointLight.h | 123 ++--- panda/src/light/spotlight.I | 143 ++--- panda/src/light/spotlight.cxx | 397 ++++++++------ panda/src/light/spotlight.h | 147 +++--- panda/src/pgraph/Sources.pp | 3 + panda/src/pgraph/cullHandler.cxx | 4 +- panda/src/pgraph/cullTraverserData.cxx | 1 + panda/src/pgraph/pandaNode.cxx | 15 +- panda/src/pgraph/pandaNode.h | 2 + panda/src/pgraph/qpcullTraverser.I | 134 +++-- panda/src/pgraph/qpcullTraverser.cxx | 65 ++- panda/src/pgraph/qpcullTraverser.h | 32 +- panda/src/pgraph/qplensNode.I | 25 +- panda/src/pgraph/qplensNode.cxx | 36 ++ panda/src/pgraph/qplensNode.h | 7 +- panda/src/pgraph/renderState.cxx | 1 + panda/src/pgraph/sceneSetup.I | 145 ++++++ panda/src/pgraph/sceneSetup.cxx | 20 + panda/src/pgraph/sceneSetup.h | 66 +++ panda/src/testbed/demo.cxx | 3 - panda/src/testbed/pview.cxx | 41 +- 60 files changed, 3490 insertions(+), 932 deletions(-) create mode 100644 panda/src/light/ambientLight.I create mode 100644 panda/src/light/light.I create mode 100644 panda/src/light/lightAttrib.I create mode 100644 panda/src/light/lightAttrib.cxx create mode 100644 panda/src/light/lightAttrib.h create mode 100644 panda/src/light/lightLensNode.I create mode 100644 panda/src/light/lightLensNode.cxx create mode 100644 panda/src/light/lightLensNode.h create mode 100644 panda/src/light/lightNode.I create mode 100644 panda/src/light/lightNode.cxx create mode 100644 panda/src/light/lightNode.h create mode 100644 panda/src/pgraph/sceneSetup.I create mode 100644 panda/src/pgraph/sceneSetup.cxx create mode 100644 panda/src/pgraph/sceneSetup.h diff --git a/panda/src/collide/collisionSolid.cxx b/panda/src/collide/collisionSolid.cxx index 8c71621558..99f011966f 100644 --- a/panda/src/collide/collisionSolid.cxx +++ b/panda/src/collide/collisionSolid.cxx @@ -100,7 +100,9 @@ update_viz(Node *parent) { // Function: CollisionSolid::get_viz // Access: Public // Description: Returns a GeomNode that may be rendered to visualize -// the CollisionSolid. +// the CollisionSolid. This is used during the cull +// traversal to render the CollisionNodes that have been +// made visible. //////////////////////////////////////////////////////////////////// qpGeomNode *CollisionSolid:: get_viz() { @@ -386,6 +388,7 @@ get_solid_viz_state() { (CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise), RenderModeAttrib::make(RenderModeAttrib::M_filled), TransparencyAttrib::make(TransparencyAttrib::M_alpha)); + base_state->ref(); // once more to guard against static destruction } if (_tangible) { @@ -393,6 +396,7 @@ get_solid_viz_state() { if (tangible_state == (const RenderState *)NULL) { tangible_state = base_state->add_attrib (ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 1.0f, 0.5f))); + tangible_state->ref(); } return tangible_state; @@ -401,6 +405,7 @@ get_solid_viz_state() { if (intangible_state == (const RenderState *)NULL) { intangible_state = base_state->add_attrib (ColorAttrib::make_flat(Colorf(1.0f, 0.3f, 0.5f, 0.5f))); + intangible_state->ref(); } return intangible_state; } @@ -425,6 +430,7 @@ get_wireframe_viz_state() { (CullFaceAttrib::make(CullFaceAttrib::M_cull_none), RenderModeAttrib::make(RenderModeAttrib::M_wireframe), TransparencyAttrib::make(TransparencyAttrib::M_none)); + base_state->ref(); // once more to guard against static destruction } if (_tangible) { @@ -432,6 +438,7 @@ get_wireframe_viz_state() { if (tangible_state == (const RenderState *)NULL) { tangible_state = base_state->add_attrib (ColorAttrib::make_flat(Colorf(0.0f, 0.0f, 1.0f, 1.0f))); + tangible_state->ref(); } return tangible_state; @@ -440,6 +447,7 @@ get_wireframe_viz_state() { if (intangible_state == (const RenderState *)NULL) { intangible_state = base_state->add_attrib (ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 0.0f, 1.0f))); + intangible_state->ref(); } return intangible_state; } @@ -463,6 +471,7 @@ get_other_viz_state() { (CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise), RenderModeAttrib::make(RenderModeAttrib::M_filled), TransparencyAttrib::make(TransparencyAttrib::M_alpha)); + base_state->ref(); // once more to guard against static destruction } // We don't bother to make a distinction here between tangible and diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 9b392574e8..0c8e3e7e57 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -111,6 +111,7 @@ cull_and_draw_together() { Windows::iterator wi; for (wi = _windows.begin(); wi != _windows.end(); ++wi) { GraphicsWindow *win = (*wi); + win->get_gsg()->reset_frame(); win->clear(); int num_display_regions = win->get_num_display_regions(); @@ -135,12 +136,13 @@ cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr) { GraphicsStateGuardian *gsg = win->get_gsg(); nassertv(gsg != (GraphicsStateGuardian *)NULL); - if (set_gsg_lens(gsg, dr)) { + PT(SceneSetup) scene_setup = setup_scene(dr->get_qpcamera(), gsg); + if (setup_gsg(gsg, scene_setup)) { DisplayRegionStack old_dr = gsg->push_display_region(dr); gsg->prepare_display_region(); DrawCullHandler cull_handler(gsg); - do_cull(&cull_handler, dr->get_qpcamera(), gsg); + do_cull(&cull_handler, scene_setup, gsg); gsg->pop_display_region(old_dr); } @@ -158,6 +160,7 @@ cull_bin_draw() { Windows::iterator wi; for (wi = _windows.begin(); wi != _windows.end(); ++wi) { GraphicsWindow *win = (*wi); + win->get_gsg()->reset_frame(); win->clear(); int num_display_regions = win->get_num_display_regions(); @@ -187,64 +190,64 @@ cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr) { cull_result = new CullResult(gsg); } - BinCullHandler cull_handler(cull_result); - do_cull(&cull_handler, dr->get_qpcamera(), gsg); - - cull_result->finish_cull(); - - // Save the results for next frame. - dr->_cull_result = cull_result->make_next(); - - // Now draw. - do_draw(cull_result, gsg, dr); + PT(SceneSetup) scene_setup = setup_scene(dr->get_qpcamera(), gsg); + if (scene_setup != (SceneSetup *)NULL) { + BinCullHandler cull_handler(cull_result); + do_cull(&cull_handler, scene_setup, gsg); + + cull_result->finish_cull(); + + // Save the results for next frame. + dr->_cull_result = cull_result->make_next(); + + // Now draw. + do_draw(cull_result, scene_setup, gsg, dr); + } } //////////////////////////////////////////////////////////////////// -// Function: GraphicsEngine::do_cull +// Function: GraphicsEngine::setup_scene // Access: Private -// Description: Fires off a cull traversal using the indicated camera. +// Description: Returns a new SceneSetup object appropriate for +// rendering the scene from the indicated camera, or +// NULL if the scene should not be rendered for some +// reason. //////////////////////////////////////////////////////////////////// -void GraphicsEngine:: -do_cull(CullHandler *cull_handler, const qpNodePath &camera, - GraphicsStateGuardian *gsg) { - // Statistics - PStatTimer timer(_cull_pcollector); - +PT(SceneSetup) GraphicsEngine:: +setup_scene(const qpNodePath &camera, GraphicsStateGuardian *gsg) { if (camera.is_empty()) { // No camera, no draw. - return; + return NULL; } qpCamera *camera_node; - DCAST_INTO_V(camera_node, camera.node()); + DCAST_INTO_R(camera_node, camera.node(), NULL); if (!camera_node->is_active()) { // Camera inactive, no draw. - return; + return NULL; } Lens *lens = camera_node->get_lens(); if (lens == (Lens *)NULL) { // No lens, no draw. - return; + return NULL; } - qpNodePath scene = camera_node->get_scene(); - if (scene.is_empty()) { + qpNodePath scene_root = camera_node->get_scene(); + if (scene_root.is_empty()) { // No scene, no draw. - return; + return NULL; } - qpCullTraverser trav; - trav.set_cull_handler(cull_handler); - trav.set_camera_mask(camera_node->get_camera_mask()); + PT(SceneSetup) scene_setup = new SceneSetup; // We will need both the camera transform (the net transform to the // camera from the scene) and the world transform (the camera // transform inverse, or the net transform to the scene from the // camera). - CPT(TransformState) camera_transform = camera.get_transform(scene); - CPT(TransformState) world_transform = scene.get_transform(camera); + CPT(TransformState) camera_transform = camera.get_transform(scene_root); + CPT(TransformState) world_transform = scene_root.get_transform(camera); // The render transform is the same as the world transform, except // it is converted into the GSG's internal coordinate system. This @@ -259,8 +262,31 @@ do_cull(CullHandler *cull_handler, const qpNodePath &camera, render_transform = cs_transform->compose(render_transform); } - trav.set_camera_transform(camera_transform); - trav.set_render_transform(render_transform); + scene_setup->set_scene_root(scene_root); + scene_setup->set_camera(camera_node); + scene_setup->set_lens(lens); + scene_setup->set_camera_transform(camera_transform); + scene_setup->set_render_transform(render_transform); + + return scene_setup; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsEngine::do_cull +// Access: Private +// Description: Fires off a cull traversal using the indicated camera. +//////////////////////////////////////////////////////////////////// +void GraphicsEngine:: +do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, + GraphicsStateGuardian *gsg) { + // Statistics + PStatTimer timer(_cull_pcollector); + + qpCullTraverser trav; + trav.set_cull_handler(cull_handler); + trav.set_depth_offset_decals(gsg->depth_offset_decals()); + trav.set_scene(scene_setup); + trav.set_camera_mask(scene_setup->get_camera()->get_camera_mask()); if (qpview_frustum_cull) { // If we're to be performing view-frustum culling, determine the @@ -268,20 +294,20 @@ do_cull(CullHandler *cull_handler, const qpNodePath &camera, // First, we have to get the current viewing frustum, which comes // from the lens. - PT(BoundingVolume) bv = lens->make_bounds(); + PT(BoundingVolume) bv = scene_setup->get_lens()->make_bounds(); if (bv != (BoundingVolume *)NULL && bv->is_of_type(GeometricBoundingVolume::get_class_type())) { // Transform it into the appropriate coordinate space. PT(GeometricBoundingVolume) local_frustum; local_frustum = DCAST(GeometricBoundingVolume, bv->make_copy()); - local_frustum->xform(camera_transform->get_mat()); + local_frustum->xform(scene_setup->get_camera_transform()->get_mat()); trav.set_view_frustum(local_frustum); } } - trav.traverse(scene); + trav.traverse(scene_setup->get_scene_root()); } //////////////////////////////////////////////////////////////////// @@ -290,12 +316,12 @@ do_cull(CullHandler *cull_handler, const qpNodePath &camera, // Description: Draws the previously-culled scene. //////////////////////////////////////////////////////////////////// void GraphicsEngine:: -do_draw(CullResult *cull_result, GraphicsStateGuardian *gsg, - DisplayRegion *dr) { +do_draw(CullResult *cull_result, SceneSetup *scene_setup, + GraphicsStateGuardian *gsg, DisplayRegion *dr) { // Statistics PStatTimer timer(_draw_pcollector); - if (set_gsg_lens(gsg, dr)) { + if (setup_gsg(gsg, scene_setup)) { DisplayRegionStack old_dr = gsg->push_display_region(dr); gsg->prepare_display_region(); cull_result->draw(); @@ -304,25 +330,21 @@ do_draw(CullResult *cull_result, GraphicsStateGuardian *gsg, } //////////////////////////////////////////////////////////////////// -// Function: GraphicsEngine::set_gsg_lens +// Function: GraphicsEngine::setup_gsg // Access: Private -// Description: Sets up the GSG to draw with the lens from the -// indicated DisplayRegion. Returns true if the lens is -// acceptable, false otherwise. +// Description: Sets up the GSG to draw the indicated scene. Returns +// true if the scene (and its lens) is acceptable, false +// otherwise. //////////////////////////////////////////////////////////////////// bool GraphicsEngine:: -set_gsg_lens(GraphicsStateGuardian *gsg, DisplayRegion *dr) { - const qpNodePath &camera = dr->get_qpcamera(); - if (camera.is_empty()) { - // No camera, no draw. +setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup) { + if (scene_setup == (SceneSetup *)NULL) { + // No scene, no draw. return false; } - qpCamera *camera_node; - DCAST_INTO_R(camera_node, camera.node(), false); - - Lens *lens = camera_node->get_lens(); - if (lens == (Lens *)NULL) { + const Lens *lens = scene_setup->get_lens(); + if (lens == (const Lens *)NULL) { // No lens, no draw. return false; } @@ -335,5 +357,7 @@ set_gsg_lens(GraphicsStateGuardian *gsg, DisplayRegion *dr) { return false; } + gsg->set_scene(scene_setup); + return true; } diff --git a/panda/src/display/graphicsEngine.h b/panda/src/display/graphicsEngine.h index d24b18b7a8..bedb9f9212 100644 --- a/panda/src/display/graphicsEngine.h +++ b/panda/src/display/graphicsEngine.h @@ -21,6 +21,7 @@ #include "pandabase.h" #include "graphicsWindow.h" +#include "sceneSetup.h" #include "pointerTo.h" #include "pset.h" #include "pStatCollector.h" @@ -58,12 +59,14 @@ private: void cull_bin_draw(); void cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr); - void do_cull(CullHandler *cull_handler, const qpNodePath &camera, + PT(SceneSetup) setup_scene(const qpNodePath &camera, + GraphicsStateGuardian *gsg); + void do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, GraphicsStateGuardian *gsg); - void do_draw(CullResult *cull_result, GraphicsStateGuardian *gsg, - DisplayRegion *dr); + void do_draw(CullResult *cull_result, SceneSetup *scene_setup, + GraphicsStateGuardian *gsg, DisplayRegion *dr); - bool set_gsg_lens(GraphicsStateGuardian *gsg, DisplayRegion *dr); + bool setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup); Pipeline *_pipeline; diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index d97d0677d8..4bbffaa76b 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -96,6 +96,28 @@ is_closed() const { return (_win == (GraphicsWindow *)NULL); } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::set_scene +// Access: Public +// Description: Sets the SceneSetup object that indicates the initial +// camera position, etc. This must be called before +// traversal begins. +//////////////////////////////////////////////////////////////////// +INLINE void GraphicsStateGuardian:: +set_scene(SceneSetup *scene_setup) { + _scene_setup = scene_setup; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_scene +// Access: Public +// Description: Returns the SceneSetup object. +//////////////////////////////////////////////////////////////////// +INLINE SceneSetup *GraphicsStateGuardian:: +get_scene() const { + return _scene_setup; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::set_state // Access: Public diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index e2b2556689..39fff07ea0 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -836,6 +836,17 @@ prepare_lens() { return false; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::reset_frame +// Access: Public, Virtual +// Description: Called before each frame is rendered, to allow the +// GSG a chance to do any internal cleanup before +// beginning the frame. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +reset_frame() { +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::wants_normals // Access: Public, Virtual @@ -899,15 +910,15 @@ end_decal(GeomNode *) { } //////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::polygon_offset_decals +// Function: GraphicsStateGuardian::depth_offset_decals // Access: Public, Virtual // Description: Returns true if this GSG can implement decals using a -// PolygonOffsetAttrib, or false if that is unreliable +// DepthOffsetAttrib, or false if that is unreliable // and the three-step rendering process should be used // instead. //////////////////////////////////////////////////////////////////// bool GraphicsStateGuardian:: -polygon_offset_decals() { +depth_offset_decals() { return false; } diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index b1b29848dc..bb31c7a571 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -27,6 +27,7 @@ #include "lensStack.h" #include "graphicsStateGuardianBase.h" +#include "sceneSetup.h" #include "nodeTransition.h" #include "nodeTransitionCache.h" #include "luse.h" @@ -92,6 +93,9 @@ PUBLISHED: public: INLINE bool is_closed() const; + INLINE void set_scene(SceneSetup *scene_setup); + INLINE SceneSetup *get_scene() const; + virtual TextureContext *prepare_texture(Texture *tex); virtual void apply_texture(TextureContext *tc); virtual void release_texture(TextureContext *tc); @@ -124,6 +128,7 @@ public: INLINE void enable_normals(bool val) { _normals_enabled = val; } + virtual void reset_frame(); // These functions will be queried by the GeomIssuer to determine if // it should issue normals, texcoords, and/or colors, based on the @@ -135,7 +140,7 @@ public: virtual void begin_decal(GeomNode *base_geom, AllTransitionsWrapper &attrib); virtual void end_decal(GeomNode *base_geom); - virtual bool polygon_offset_decals(); + virtual bool depth_offset_decals(); virtual CPT(RenderState) begin_decal_base_first(); virtual CPT(RenderState) begin_decal_nested(); virtual CPT(RenderState) begin_decal_base_second(); @@ -217,6 +222,8 @@ protected: #endif protected: + PT(SceneSetup) _scene_setup; + class StateInfo { public: INLINE StateInfo(TypeHandle type); diff --git a/panda/src/dxgsg/dxGraphicsStateGuardian.cxx b/panda/src/dxgsg/dxGraphicsStateGuardian.cxx index 1e03891188..3a1e9a0117 100644 --- a/panda/src/dxgsg/dxGraphicsStateGuardian.cxx +++ b/panda/src/dxgsg/dxGraphicsStateGuardian.cxx @@ -4757,6 +4757,7 @@ apply_fog(Fog *fog) { // Description: //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian::apply_light( PointLight* light ) { +#if 0 // The light position will be relative to the current matrix, so // we have to know what the current matrix is. Find a better // solution later. @@ -4780,6 +4781,7 @@ void DXGraphicsStateGuardian::apply_light( PointLight* light ) { alight.dvAttenuation2 = (D3DVALUE)light->get_quadratic_attenuation(); HRESULT res = scrn.pD3DDevice->SetLight(_cur_light_id, &alight); +#endif } //////////////////////////////////////////////////////////////////// @@ -4788,6 +4790,7 @@ void DXGraphicsStateGuardian::apply_light( PointLight* light ) { // Description: //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian::apply_light( DirectionalLight* light ) { +#if 0 // The light position will be relative to the current matrix, so // we have to know what the current matrix is. Find a better // solution later. @@ -4815,6 +4818,7 @@ void DXGraphicsStateGuardian::apply_light( DirectionalLight* light ) { HRESULT res = scrn.pD3DDevice->SetLight(_cur_light_id, &alight); // scrn.pD3DDevice->LightEnable( _cur_light_id, TRUE ); // scrn.pD3DDevice->SetRenderState( D3DRENDERSTATE_LIGHTING, TRUE ); +#endif } //////////////////////////////////////////////////////////////////// @@ -4823,6 +4827,7 @@ void DXGraphicsStateGuardian::apply_light( DirectionalLight* light ) { // Description: //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian::apply_light( Spotlight* light ) { +#if 0 // The light position will be relative to the current matrix, so // we have to know what the current matrix is. Find a better // solution later. @@ -4900,6 +4905,7 @@ void DXGraphicsStateGuardian::apply_light( Spotlight* light ) { HRESULT res = scrn.pD3DDevice->SetLight(_cur_light_id, &alight); #endif // WBD_GL_MODE +#endif } //////////////////////////////////////////////////////////////////// @@ -5194,6 +5200,7 @@ issue_render_mode(const RenderModeTransition *attrib) { // Description: //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian::issue_light(const LightTransition *attrib ) { +#if 0 nassertv(attrib->get_default_dir() != TD_on); // Initialize the current ambient light total and currently enabled @@ -5285,6 +5292,7 @@ void DXGraphicsStateGuardian::issue_light(const LightTransition *attrib ) { call_dxLightModelAmbient(_cur_ambient_light); enable_color_material(true); } +#endif } /* diff --git a/panda/src/framework/framework.cxx b/panda/src/framework/framework.cxx index c9fef8485e..95a9ba4190 100644 --- a/panda/src/framework/framework.cxx +++ b/panda/src/framework/framework.cxx @@ -325,6 +325,8 @@ void display_func( void ) { void set_lighting(bool enabled) { if (enabled) { + cerr << "lighting is no longer supported in old scene graph.\n"; + /* // Enable the lights on the initial state. PT(LightTransition) la = new LightTransition; la->set_on(light.p()); @@ -333,6 +335,7 @@ void set_lighting(bool enabled) { la->set_on(dlight.p()); } render_arc->set_transition(la); + */ } else { // Remove the lights from the initial state. @@ -1081,6 +1084,7 @@ int framework_main(int argc, char *argv[]) { lights = new NamedNode("lights"); new RenderRelation(cameras, lights); + /* light = new AmbientLight( "ambient" ); dlight = new DirectionalLight( "directional" ); plight = new PointLight( "point" ); @@ -1094,6 +1098,7 @@ int framework_main(int argc, char *argv[]) { new RenderRelation( lights, plight ); new RenderRelation( lights, slight ); #endif + */ // Turn on culling. CullFaceTransition *cfa = new CullFaceTransition(CullFaceProperty::M_cull_clockwise); diff --git a/panda/src/glgsg/config_glgsg.cxx b/panda/src/glgsg/config_glgsg.cxx index f1ce844f69..7ce74499cb 100644 --- a/panda/src/glgsg/config_glgsg.cxx +++ b/panda/src/glgsg/config_glgsg.cxx @@ -65,6 +65,11 @@ bool gl_save_mipmaps = config_glgsg.GetBool("gl-save-mipmaps", false); // variable. bool gl_auto_normalize_lighting = config_glgsg.GetBool("auto-normalize-lighting", false); +// Configure this true to try to implement decals using a +// DepthOffsetAttrib, false to do them with the more reliable 3-pass +// rendering method instead. +bool gl_depth_offset_decals = config_glgsg.GetBool("depth-offset-decals", false); + // Configure this true to indicate the current version of GL fully // supports textures with B, G, R ordering; false if it only supports // R, G, B. false will always work, but true might be faster if the diff --git a/panda/src/glgsg/config_glgsg.h b/panda/src/glgsg/config_glgsg.h index f1a710bfce..607bf0898b 100644 --- a/panda/src/glgsg/config_glgsg.h +++ b/panda/src/glgsg/config_glgsg.h @@ -32,6 +32,7 @@ extern bool gl_force_mipmaps; extern bool gl_show_mipmaps; extern bool gl_save_mipmaps; extern bool gl_auto_normalize_lighting; +extern bool gl_depth_offset_decals; extern bool gl_supports_bgr; // Ways to implement decals. diff --git a/panda/src/glgsg/glGraphicsStateGuardian.cxx b/panda/src/glgsg/glGraphicsStateGuardian.cxx index ca7721d1c8..544f4f31c3 100644 --- a/panda/src/glgsg/glGraphicsStateGuardian.cxx +++ b/panda/src/glgsg/glGraphicsStateGuardian.cxx @@ -66,6 +66,7 @@ #include "pointShapeTransition.h" #include "polygonOffsetTransition.h" #include "textureAttrib.h" +#include "lightAttrib.h" #include "cullFaceAttrib.h" #include "transparencyAttrib.h" #include "depthTestAttrib.h" @@ -327,6 +328,9 @@ reset() { la->issue(this); ta->issue(this); + Material empty; + apply_material(&empty); + if (gl_cheap_textures) { glgsg_cat.info() << "Setting glHint() for fastest textures.\n"; @@ -1019,16 +1023,9 @@ draw_sprite(GeomSprite *geom, GeomContext *) { // save the modelview matrix const LMatrix4f &modelview_mat = _transform->get_mat(); - // get the camera information - - // Hmm, this doesn't work any more, since we don't store the camera - // pointer in new scene graph land. Need to find a better way to - // get the current window's aspect ratio. Here's a temporary hack - // for now. - - // float aspect_ratio = - // get_current_camera()->get_lens()->get_aspect_ratio(); - float aspect_ratio = 1.333333; + // We don't need to mess with the aspect ratio, since we are now + // using the default projection matrix, which has the right aspect + // ratio built in. // load up our own matrices glMatrixMode(GL_MODELVIEW); @@ -1088,7 +1085,7 @@ draw_sprite(GeomSprite *geom, GeomContext *) { // y direction if (y_overall) - scaled_height = geom->_y_texel_ratio[0] * half_height * aspect_ratio; + scaled_height = geom->_y_texel_ratio[0] * half_height; else { nassertv(((int)geom->_y_texel_ratio.size() >= geom->get_num_prims())); y_walk = &geom->_y_texel_ratio[0]; @@ -1170,7 +1167,7 @@ draw_sprite(GeomSprite *geom, GeomContext *) { scaled_width = cur_image._x_ratio * half_width; if (y_overall == false) - scaled_height = cur_image._y_ratio * half_height * aspect_ratio; + scaled_height = cur_image._y_ratio * half_height; // if not G_OVERALL, do some trig for this z rotate if (theta_on) { @@ -2526,58 +2523,48 @@ apply_fog(qpFog *fog) { // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// -void GLGraphicsStateGuardian::apply_light( PointLight* light ) -{ - // The light position will be relative to the current matrix, so - // we have to know what the current matrix is. Find a better - // solution later. -#ifdef GSG_VERBOSE - glgsg_cat.debug() - << "glMatrixMode(GL_MODELVIEW)" << endl; - glgsg_cat.debug() - << "glPushMatrix()" << endl; - glgsg_cat.debug() - << "glLoadIdentity()" << endl; -#endif +void GLGraphicsStateGuardian:: +apply_light(PointLight *light) { + // We need to temporarily load a new matrix so we can define the + // light in a known coordinate system. We pick the transform of the + // root. (Alternatively, we could leave the current transform where + // it is and compute the light position relative to that transform + // instead of relative to the root, by composing with the matrix + // computed by _transform->invert_compose(render_transform). But I + // think loading a completely new matrix is simpler.) glMatrixMode(GL_MODELVIEW); glPushMatrix(); + glLoadMatrixf(_scene_setup->get_render_transform()->get_mat().get_data()); - glLoadMatrixf(LMatrix4f::convert_mat(_coordinate_system, CS_yup_right) - .get_data()); - - GLenum id = get_light_id( _cur_light_id ); - Colorf black(0, 0, 0, 1); + GLenum id = get_light_id(_cur_light_id); + static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f); glLightfv(id, GL_AMBIENT, black.get_data()); glLightfv(id, GL_DIFFUSE, light->get_color().get_data()); - glLightfv(id, GL_SPECULAR, light->get_specular().get_data()); + glLightfv(id, GL_SPECULAR, light->get_specular_color().get_data()); - // Position needs to specify x, y, z, and w - // w == 1 implies non-infinite position - LPoint3f pos = get_rel_pos( light, _current_camera ); - LPoint4f fpos( pos[0], pos[1], pos[2], 1 ); - glLightfv( id, GL_POSITION, fpos.get_data() ); + // Position needs to specify x, y, z, and w + // w == 1 implies non-infinite position + qpNodePath light_np(light); + const LMatrix4f &light_mat = light_np.get_mat(qpNodePath()); + LPoint3f pos = light->get_point() * light_mat; + + LPoint4f fpos(pos[0], pos[1], pos[2], 1.0f); + glLightfv(id, GL_POSITION, fpos.get_data()); // GL_SPOT_DIRECTION is not significant when cutoff == 180 - // Exponent == 0 implies uniform light distribution - glLightf( id, GL_SPOT_EXPONENT, 0 ); + // Exponent == 0 implies uniform light distribution + glLightf(id, GL_SPOT_EXPONENT, 0.0f); // Cutoff == 180 means uniform point light source - glLightf( id, GL_SPOT_CUTOFF, 180.0 ); + glLightf(id, GL_SPOT_CUTOFF, 180.0f); - glLightf( id, GL_CONSTANT_ATTENUATION, - light->get_constant_attenuation() ); - glLightf( id, GL_LINEAR_ATTENUATION, - light->get_linear_attenuation() ); - glLightf( id, GL_QUADRATIC_ATTENUATION, - light->get_quadratic_attenuation() ); + const LVecBase3f &att = light->get_attenuation(); + glLightf(id, GL_CONSTANT_ATTENUATION, att[0]); + glLightf(id, GL_LINEAR_ATTENUATION, att[1]); + glLightf(id, GL_QUADRATIC_ATTENUATION, att[2]); glPopMatrix(); - -#ifdef GSG_VERBOSE - glgsg_cat.debug() - << "glPopMatrix()" << endl; -#endif report_errors(); } @@ -2586,56 +2573,43 @@ void GLGraphicsStateGuardian::apply_light( PointLight* light ) // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// -void GLGraphicsStateGuardian::apply_light( DirectionalLight* light ) -{ - // The light position will be relative to the current matrix, so - // we have to know what the current matrix is. Find a better - // solution later. -#ifdef GSG_VERBOSE - glgsg_cat.debug() - << "glMatrixMode(GL_MODELVIEW)" << endl; - glgsg_cat.debug() - << "glPushMatrix()" << endl; - glgsg_cat.debug() - << "glLoadIdentity()" << endl; -#endif +void GLGraphicsStateGuardian:: +apply_light(DirectionalLight *light) { + // See the comment about this transform change in PointLight, above. glMatrixMode(GL_MODELVIEW); glPushMatrix(); - glLoadMatrixf(LMatrix4f::convert_mat(_coordinate_system, CS_yup_right) - .get_data()); + glLoadMatrixf(_scene_setup->get_render_transform()->get_mat().get_data()); GLenum id = get_light_id( _cur_light_id ); - Colorf black(0, 0, 0, 1); + static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f); glLightfv(id, GL_AMBIENT, black.get_data()); glLightfv(id, GL_DIFFUSE, light->get_color().get_data()); - glLightfv(id, GL_SPECULAR, light->get_specular().get_data()); + glLightfv(id, GL_SPECULAR, light->get_specular_color().get_data()); - // Position needs to specify x, y, z, and w - // w == 0 implies light is at infinity - LPoint3f dir = get_rel_forward( light, _current_camera, - _coordinate_system ); - LPoint4f pos( -dir[0], -dir[1], -dir[2], 0 ); - glLightfv( id, GL_POSITION, pos.get_data() ); + // Position needs to specify x, y, z, and w. + // w == 0 implies light is at infinity + qpNodePath light_np(light); + const LMatrix4f &light_mat = light_np.get_mat(qpNodePath()); + LVector3f dir = light->get_direction() * light_mat; + LPoint4f fdir(-dir[0], -dir[1], -dir[2], 0); + glLightfv(id, GL_POSITION, fdir.get_data()); // GL_SPOT_DIRECTION is not significant when cutoff == 180 // In this case, position x, y, z specifies direction // Exponent == 0 implies uniform light distribution - glLightf( id, GL_SPOT_EXPONENT, 0 ); + glLightf(id, GL_SPOT_EXPONENT, 0.0f); // Cutoff == 180 means uniform point light source - glLightf( id, GL_SPOT_CUTOFF, 180.0 ); + glLightf(id, GL_SPOT_CUTOFF, 180.0f); - // Default attenuation values (only spotlight can modify these) - glLightf( id, GL_CONSTANT_ATTENUATION, 1 ); - glLightf( id, GL_LINEAR_ATTENUATION, 0 ); - glLightf( id, GL_QUADRATIC_ATTENUATION, 0 ); + // Default attenuation values (only spotlight and point light can + // modify these) + glLightf(id, GL_CONSTANT_ATTENUATION, 1.0f); + glLightf(id, GL_LINEAR_ATTENUATION, 0.0f); + glLightf(id, GL_QUADRATIC_ATTENUATION, 0.0f); glPopMatrix(); -#ifdef GSG_VERBOSE - glgsg_cat.debug() - << "glPopMatrix()" << endl; -#endif report_errors(); } @@ -2644,54 +2618,42 @@ void GLGraphicsStateGuardian::apply_light( DirectionalLight* light ) // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// -void GLGraphicsStateGuardian::apply_light( Spotlight* light ) -{ - // The light position will be relative to the current matrix, so - // we have to know what the current matrix is. Find a better - // solution later. -#ifdef GSG_VERBOSE - glgsg_cat.debug() - << "glMatrixMode(GL_MODELVIEW)" << endl; - glgsg_cat.debug() - << "glPushMatrix()" << endl; - glgsg_cat.debug() - << "glLoadIdentity()" << endl; -#endif +void GLGraphicsStateGuardian:: +apply_light(Spotlight *light) { + Lens *lens = light->get_lens(); + nassertv(lens != (Lens *)NULL); + + // See the comment about this transform change in PointLight, above. glMatrixMode(GL_MODELVIEW); glPushMatrix(); - glLoadMatrixf(LMatrix4f::convert_mat(_coordinate_system, CS_yup_right) - .get_data()); + glLoadMatrixf(_scene_setup->get_render_transform()->get_mat().get_data()); - GLenum id = get_light_id( _cur_light_id ); - Colorf black(0, 0, 0, 1); + GLenum id = get_light_id(_cur_light_id); + static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f); glLightfv(id, GL_AMBIENT, black.get_data()); glLightfv(id, GL_DIFFUSE, light->get_color().get_data()); - glLightfv(id, GL_SPECULAR, light->get_specular().get_data()); + glLightfv(id, GL_SPECULAR, light->get_specular_color().get_data()); - // Position needs to specify x, y, z, and w - // w == 1 implies non-infinite position - LPoint3f pos = get_rel_pos( light, _current_camera ); - LPoint4f fpos( pos[0], pos[1], pos[2], 1 ); - glLightfv( id, GL_POSITION, fpos.get_data() ); + // Position needs to specify x, y, z, and w + // w == 1 implies non-infinite position + qpNodePath light_np(light); + const LMatrix4f &light_mat = light_np.get_mat(qpNodePath()); + LPoint3f pos = lens->get_nodal_point() * light_mat; + LVector3f dir = lens->get_view_vector() * light_mat; - glLightfv( id, GL_SPOT_DIRECTION, - get_rel_forward( light, _current_camera, - _coordinate_system ).get_data() ); - glLightf( id, GL_SPOT_EXPONENT, light->get_exponent() ); - glLightf( id, GL_SPOT_CUTOFF, - light->get_cutoff_angle() ); - glLightf( id, GL_CONSTANT_ATTENUATION, - light->get_constant_attenuation() ); - glLightf( id, GL_LINEAR_ATTENUATION, - light->get_linear_attenuation() ); - glLightf( id, GL_QUADRATIC_ATTENUATION, - light->get_quadratic_attenuation() ); + LPoint4f fpos(pos[0], pos[1], pos[2], 1.0f); + glLightfv(id, GL_POSITION, fpos.get_data()); + glLightfv(id, GL_SPOT_DIRECTION, dir.get_data()); + + glLightf(id, GL_SPOT_EXPONENT, light->get_exponent()); + glLightf(id, GL_SPOT_CUTOFF, lens->get_hfov()); + + const LVecBase3f &att = light->get_attenuation(); + glLightf(id, GL_CONSTANT_ATTENUATION, att[0]); + glLightf(id, GL_LINEAR_ATTENUATION, att[1]); + glLightf(id, GL_QUADRATIC_ATTENUATION, att[2]); glPopMatrix(); -#ifdef GSG_VERBOSE - glgsg_cat.debug() - << "glPopMatrix()" << endl; -#endif report_errors(); } @@ -2700,8 +2662,8 @@ void GLGraphicsStateGuardian::apply_light( Spotlight* light ) // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// -void GLGraphicsStateGuardian::apply_light( AmbientLight* ) -{ +void GLGraphicsStateGuardian:: +apply_light(AmbientLight *) { // Ambient lights are handled as a special case in issue_light(). } @@ -2984,6 +2946,7 @@ issue_render_mode(const RenderModeTransition *attrib) { //////////////////////////////////////////////////////////////////// void GLGraphicsStateGuardian::issue_light(const LightTransition *attrib ) { +#if 0 nassertv(attrib->get_default_dir() != TD_on); // activate(); @@ -3075,6 +3038,7 @@ void GLGraphicsStateGuardian::issue_light(const LightTransition *attrib ) call_glLightModelAmbient(cur_ambient_light); } report_errors(); +#endif } //////////////////////////////////////////////////////////////////// @@ -3491,6 +3455,104 @@ issue_texture(const TextureAttrib *attrib) { report_errors(); } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::issue_light +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void GLGraphicsStateGuardian:: +issue_light(const LightAttrib *attrib) { + // Initialize the current ambient light total and newly enabled + // light list + Colorf cur_ambient_light(0.0f, 0.0f, 0.0f, 1.0f); + int i; + for (i = 0; i < _max_lights; i++) { + _light_info[i]._next_enabled = false; + } + + int num_enabled = 0; + int num_lights = attrib->get_num_lights(); + if (attrib->get_operation() == LightAttrib::O_remove) { + num_lights = 0; + } + for (int li = 0; li < num_lights; li++) { + Light *light = attrib->get_light(li); + nassertv(light != (Light *)NULL); + + num_enabled++; + enable_lighting(true); + + if (light->get_type() == AmbientLight::get_class_type()) { + // Ambient lights don't require specific light ids; simply add + // in the ambient contribution to the current total + cur_ambient_light += light->get_color(); + + } else { + // Check to see if this light has already been bound to an id + _cur_light_id = -1; + for (i = 0; i < _max_lights; i++) { + if (_light_info[i]._light == light) { + // Light has already been bound to an id, we only need to + // enable the light, not reapply it. + _cur_light_id = -2; + enable_light(i, true); + _light_info[i]._next_enabled = true; + break; + } + } + + // See if there are any unbound light ids + if (_cur_light_id == -1) { + for (i = 0; i < _max_lights; i++) { + if (_light_info[i]._light == (Light *)NULL) { + _light_info[i]._light = light; + _cur_light_id = i; + break; + } + } + } + + // If there were no unbound light ids, see if we can replace + // a currently unused but previously bound id + if (_cur_light_id == -1) { + for (i = 0; i < _max_lights; i++) { + if (!attrib->has_light(_light_info[i]._light)) { + _light_info[i]._light = light; + _cur_light_id = i; + break; + } + } + } + + if (_cur_light_id >= 0) { + enable_light(_cur_light_id, true); + _light_info[i]._next_enabled = true; + + // We need to do something different for each type of light + light->apply(this); + } else if (_cur_light_id == -1) { + glgsg_cat.error() + << "issue_light() - failed to bind light to id" << endl; + } + } + } + + // Disable all unused lights + for (i = 0; i < _max_lights; i++) { + if (!_light_info[i]._next_enabled) { + enable_light(i, false); + } + } + + // If no lights were enabled, disable lighting + if (num_enabled == 0) { + enable_lighting(false); + } else { + call_glLightModelAmbient(cur_ambient_light); + } + report_errors(); +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::issue_material // Access: Public, Virtual @@ -3501,6 +3563,10 @@ issue_material(const MaterialAttrib *attrib) { const Material *material = attrib->get_material(); if (material != (const Material *)NULL) { apply_material(material); + } else { + // Apply a default material when materials are turned off. + Material empty; + apply_material(&empty); } report_errors(); } @@ -3711,9 +3777,9 @@ issue_depth_offset(const DepthOffsetAttrib *attrib) { int offset = attrib->get_offset(); if (offset != 0) { - GLfloat newfactor = 1.0f; - GLfloat newunits = (GLfloat)offset; - glPolygonOffset(newfactor, newunits); + // The relationship between these two parameters is a little + // unclear and poorly explained in the GL man pages. + glPolygonOffset((GLfloat) -offset, (GLfloat) -offset); enable_polygon_offset(true); } else { @@ -3723,6 +3789,43 @@ issue_depth_offset(const DepthOffsetAttrib *attrib) { report_errors(); } +static CPT(RenderState) +get_unlit_state() { + static CPT(RenderState) state = NULL; + if (state == (const RenderState *)NULL) { + state = RenderState::make(LightAttrib::make_all_off()); + state->ref(); + } + return state; +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::reset_frame +// Access: Public, Virtual +// Description: Called before each frame is rendered, to allow the +// GSG a chance to do any internal cleanup before +// beginning the frame. +//////////////////////////////////////////////////////////////////// +void GLGraphicsStateGuardian:: +reset_frame() { + // Undo any lighting we had enabled last frame, to force the lights + // to be reissued, in case their parameters or positions have + // changed between frames. + if (_lighting_enabled_this_frame) { + for (int i = 0; i < _max_lights; i++) { + enable_light(i, false); + _light_info[i]._light = (Light *)NULL; + } + + // Also force the lighting state to unlit, so that issue_light() + // will be guaranteed to be called next frame even if we have the + // same set of light pointers we had this frame. + modify_state(get_unlit_state()); + + _lighting_enabled_this_frame = false; + } +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::wants_normals // Access: Public, Virtual @@ -3888,6 +3991,19 @@ end_decal(GeomNode *base_geom) { report_errors(); } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::depth_offset_decals +// Access: Public, Virtual +// Description: Returns true if this GSG can implement decals using a +// DepthOffsetAttrib, or false if that is unreliable +// and the three-step rendering process should be used +// instead. +//////////////////////////////////////////////////////////////////// +bool GLGraphicsStateGuardian:: +depth_offset_decals() { + return gl_depth_offset_decals; +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::get_internal_coordinate_system // Access: Public, Virtual diff --git a/panda/src/glgsg/glGraphicsStateGuardian.h b/panda/src/glgsg/glGraphicsStateGuardian.h index 27f8c6a499..7492d1e6f4 100644 --- a/panda/src/glgsg/glGraphicsStateGuardian.h +++ b/panda/src/glgsg/glGraphicsStateGuardian.h @@ -164,7 +164,7 @@ public: // virtual void issue_color(const ColorAttrib *attrib); virtual void issue_tex_matrix(const TexMatrixAttrib *attrib); virtual void issue_texture(const TextureAttrib *attrib); - // virtual void issue_light(const LightAttrib *attrib); + virtual void issue_light(const LightAttrib *attrib); virtual void issue_material(const MaterialAttrib *attrib); virtual void issue_render_mode(const RenderModeAttrib *attrib); virtual void issue_texture_apply(const TextureApplyAttrib *attrib); @@ -180,12 +180,16 @@ public: // virtual void issue_stencil(const StencilAttrib *attrib); // virtual void issue_clip_plane(const ClipPlaneAttrib *attrib); + virtual void reset_frame(); + virtual bool wants_normals(void) const; virtual bool wants_texcoords(void) const; virtual void begin_decal(GeomNode *base_geom, AllTransitionsWrapper &attrib); virtual void end_decal(GeomNode *base_geom); + virtual bool depth_offset_decals(); + virtual CoordinateSystem get_internal_coordinate_system() const; virtual float compute_distance_to(const LPoint3f &point) const; @@ -357,7 +361,7 @@ protected: class LightInfo { public: INLINE LightInfo(); - PT_Light _light; + PT(Light) _light; bool _enabled; bool _next_enabled; }; diff --git a/panda/src/gobj/lens.cxx b/panda/src/gobj/lens.cxx index 5ab060218b..0b65852a7d 100644 --- a/panda/src/gobj/lens.cxx +++ b/panda/src/gobj/lens.cxx @@ -467,6 +467,17 @@ get_up_vector() const { return _up_vector; } +//////////////////////////////////////////////////////////////////// +// Function: Lens::get_nodal_point +// Access: Published +// Description: Returns the center point of the lens: the point from +// which the lens is viewing. +//////////////////////////////////////////////////////////////////// +LPoint3f Lens:: +get_nodal_point() const { + return get_view_mat().get_row3(3); +} + //////////////////////////////////////////////////////////////////// // Function: Lens::set_iod_offset // Access: Published diff --git a/panda/src/gobj/lens.h b/panda/src/gobj/lens.h index 8a47e26982..a883d75a00 100644 --- a/panda/src/gobj/lens.h +++ b/panda/src/gobj/lens.h @@ -99,6 +99,7 @@ PUBLISHED: void set_view_vector(const LVector3f &view_vector, const LVector3f &up_vector); const LVector3f &get_view_vector() const; const LVector3f &get_up_vector() const; + LPoint3f get_nodal_point() const; void set_iod_offset(float offset); float get_iod_offset() const; diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index 1d42e1c1ae..ea708b5a7b 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -123,6 +123,8 @@ class LensNode; //////////////////////////////////////////////////////////////////// class EXPCL_PANDA GraphicsStateGuardianBase : public TypedReferenceCount { public: + virtual void reset_frame()=0; + // These functions will be queried by the GeomIssuer to determine if // it should issue normals, texcoords, and/or colors, based on the // GSG's current state. @@ -154,11 +156,11 @@ public: // coordinate space differently. virtual float compute_distance_to(const LPoint3f &point) const=0; - // These are used to implement decals. If polygon_offset_decals() + // These are used to implement decals. If depth_offset_decals() // returns true, none of the remaining functions will be called, - // since polygon offsets can be used to implement decals fully (and + // since depth offsets can be used to implement decals fully (and // usually faster). - virtual bool polygon_offset_decals()=0; + virtual bool depth_offset_decals()=0; virtual CPT(RenderState) begin_decal_base_first()=0; virtual CPT(RenderState) begin_decal_nested()=0; virtual CPT(RenderState) begin_decal_base_second()=0; diff --git a/panda/src/light/Sources.pp b/panda/src/light/Sources.pp index 3ce7f101c5..c0ae1c8aa7 100644 --- a/panda/src/light/Sources.pp +++ b/panda/src/light/Sources.pp @@ -8,24 +8,47 @@ linmath #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx - #define SOURCES \ - ambientLight.h config_light.h directionalLight.I \ - directionalLight.h light.h \ - lightTransition.I lightTransition.h pointLight.I \ - pointLight.h pt_Light.h spotlight.I spotlight.h \ - vector_PT_Light.h + ambientLight.I ambientLight.h \ + config_light.h \ + directionalLight.I directionalLight.h \ + light.I light.h \ + lightAttrib.I lightAttrib.h \ + lightLensNode.I lightLensNode.h \ + lightNode.I lightNode.h \ + lightTransition.I lightTransition.h \ + pointLight.I pointLight.h \ + pt_Light.h \ + spotlight.I spotlight.h \ + vector_PT_Light.h #define INCLUDED_SOURCES \ - ambientLight.cxx config_light.cxx directionalLight.cxx light.cxx \ - lightTransition.cxx pointLight.cxx \ - pt_Light.cxx spotlight.cxx vector_PT_Light.cxx + ambientLight.cxx \ + config_light.cxx \ + directionalLight.cxx \ + light.cxx \ + lightAttrib.cxx \ + lightLensNode.cxx \ + lightNode.cxx \ + lightTransition.cxx \ + pointLight.cxx \ + pt_Light.cxx \ + spotlight.cxx \ + vector_PT_Light.cxx #define INSTALL_HEADERS \ - ambientLight.h directionalLight.I directionalLight.h light.h \ + ambientLight.I ambientLight.h \ + directionalLight.I directionalLight.h \ + light.I light.h \ + lightAttrib.I lightAttrib.h \ + lightLensNode.I lightLensNode.h \ + lightNode.I lightNode.h \ lightNameClass.h \ - lightTransition.I lightTransition.h pointLight.I pointLight.h \ - pt_Light.h spotlight.I spotlight.h vector_PT_Light.h + lightTransition.I lightTransition.h \ + pointLight.I pointLight.h \ + pt_Light.h \ + spotlight.I spotlight.h \ + vector_PT_Light.h #define IGATESCAN all diff --git a/panda/src/light/ambientLight.I b/panda/src/light/ambientLight.I new file mode 100644 index 0000000000..bc623c6c85 --- /dev/null +++ b/panda/src/light/ambientLight.I @@ -0,0 +1,17 @@ +// Filename: ambientLight.I +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// diff --git a/panda/src/light/ambientLight.cxx b/panda/src/light/ambientLight.cxx index ebecce851d..204e180c0c 100644 --- a/panda/src/light/ambientLight.cxx +++ b/panda/src/light/ambientLight.cxx @@ -15,36 +15,54 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #include "ambientLight.h" +#include "graphicsStateGuardian.h" +#include "bamWriter.h" +#include "bamReader.h" +#include "datagram.h" +#include "datagramIterator.h" -#include - -//////////////////////////////////////////////////////////////////// -// Static variables -//////////////////////////////////////////////////////////////////// TypeHandle AmbientLight::_type_handle; //////////////////////////////////////////////////////////////////// // Function: AmbientLight::Constructor -// Access: +// Access: Published // Description: //////////////////////////////////////////////////////////////////// -AmbientLight::AmbientLight(const string& name) : NamedNode(name) +AmbientLight:: +AmbientLight(const string &name) : + LightNode(name) { - set_color(Colorf(0.2, 0.2, 0.2, 1)); } //////////////////////////////////////////////////////////////////// -// Function: AmbientLight::output +// Function: AmbientLight::Copy Constructor +// Access: Protected +// Description: Do not call the copy constructor directly; instead, +// use make_copy() or copy_subgraph() to make a copy of +// a node. +//////////////////////////////////////////////////////////////////// +AmbientLight:: +AmbientLight(const AmbientLight ©) : + LightNode(copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: AmbientLight::make_copy // Access: Public, Virtual -// Description: +// Description: Returns a newly-allocated PandaNode that is a shallow +// copy of this one. It will be a different pointer, +// but its internal data may or may not be shared with +// that of the original PandaNode. No children will be +// copied. //////////////////////////////////////////////////////////////////// -void AmbientLight:: -output(ostream &out) const { - NamedNode::output(out); +PandaNode *AmbientLight:: +make_copy() const { + return new AmbientLight(*this); } - //////////////////////////////////////////////////////////////////// // Function: AmbientLight::write // Access: Public, Virtual @@ -53,6 +71,70 @@ output(ostream &out) const { void AmbientLight:: write(ostream &out, int indent_level) const { indent(out, indent_level) << *this << ":\n"; - indent(out, indent_level + 2) << "color " << _color << "\n"; + indent(out, indent_level + 2) + << "color " << get_color() << "\n"; } +//////////////////////////////////////////////////////////////////// +// Function: AmbientLight::apply +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void AmbientLight:: +apply(GraphicsStateGuardian *gsg) { + gsg->apply_light(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: AmbientLight::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// AmbientLight. +//////////////////////////////////////////////////////////////////// +void AmbientLight:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: AmbientLight::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void AmbientLight:: +write_datagram(BamWriter *manager, Datagram &dg) { + LightNode::write_datagram(manager, dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: AmbientLight::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type AmbientLight is encountered +// in the Bam file. It should create the AmbientLight +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *AmbientLight:: +make_from_bam(const FactoryParams ¶ms) { + AmbientLight *node = new AmbientLight(""); + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + node->fillin(scan, manager); + + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: AmbientLight::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new AmbientLight. +//////////////////////////////////////////////////////////////////// +void AmbientLight:: +fillin(DatagramIterator &scan, BamReader *manager) { + LightNode::fillin(scan, manager); +} diff --git a/panda/src/light/ambientLight.h b/panda/src/light/ambientLight.h index 74bc41fad3..2f7ca3ba7c 100644 --- a/panda/src/light/ambientLight.h +++ b/panda/src/light/ambientLight.h @@ -15,67 +15,59 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #ifndef AMBIENTLIGHT_H #define AMBIENTLIGHT_H -// -//////////////////////////////////////////////////////////////////// -// Includes -//////////////////////////////////////////////////////////////////// -#include -#include -#include -#include "pmap.h" -#include -#include "light.h" +#include "pandabase.h" -//////////////////////////////////////////////////////////////////// -// Defines -//////////////////////////////////////////////////////////////////// +#include "lightNode.h" //////////////////////////////////////////////////////////////////// // Class : AmbientLight -// Description : +// Description : A light source that seems to illuminate all points in +// space at once. This kind of light need not actually +// be part of the scene graph, since it has no meaningful +// position. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA AmbientLight : public Light, public NamedNode -{ - PUBLISHED: +class EXPCL_PANDA AmbientLight : public LightNode { +PUBLISHED: + AmbientLight(const string &name); - AmbientLight( const string& name = "" ); - ~AmbientLight( void ) { } +protected: + AmbientLight(const AmbientLight ©); - public: +public: + virtual PandaNode *make_copy() const; + virtual void write(ostream &out, int indent_level) const; + +public: + virtual void apply(GraphicsStateGuardian *gsg); - virtual void output( ostream &out ) const; - virtual void write( ostream &out, int indent_level = 0 ) const; +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); - virtual void apply( GraphicsStateGuardian* gsg ) { - gsg->apply_light( this ); - } +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); - public: +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + LightNode::init_type(); + register_type(_type_handle, "AmbientLight", + LightNode::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - static TypeHandle get_class_type( void ) { - return _type_handle; - } - static void init_type( void ) { - Light::init_type(); - NamedNode::init_type(); - register_type( _type_handle, "AmbientLight", - Light::get_class_type(), - NamedNode::get_class_type() ); - } - virtual TypeHandle get_type( void ) const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - virtual TypeHandle get_light_type( void ) const { - return get_class_type(); - } - - private: - - static TypeHandle _type_handle; +private: + static TypeHandle _type_handle; }; INLINE ostream &operator << (ostream &out, const AmbientLight &light) { @@ -83,4 +75,6 @@ INLINE ostream &operator << (ostream &out, const AmbientLight &light) { return out; } +#include "ambientLight.I" + #endif diff --git a/panda/src/light/config_light.cxx b/panda/src/light/config_light.cxx index ddb801d406..a93477de33 100644 --- a/panda/src/light/config_light.cxx +++ b/panda/src/light/config_light.cxx @@ -20,6 +20,9 @@ #include "ambientLight.h" #include "directionalLight.h" #include "light.h" +#include "lightAttrib.h" +#include "lightLensNode.h" +#include "lightNode.h" #include "lightTransition.h" #include "pointLight.h" #include "spotlight.h" @@ -33,7 +36,16 @@ ConfigureFn(config_light) { AmbientLight::init_type(); DirectionalLight::init_type(); Light::init_type(); + LightAttrib::init_type(); + LightLensNode::init_type(); + LightNode::init_type(); LightTransition::init_type(); PointLight::init_type(); Spotlight::init_type(); + + LightAttrib::register_with_read_factory(); + AmbientLight::register_with_read_factory(); + DirectionalLight::register_with_read_factory(); + PointLight::register_with_read_factory(); + Spotlight::register_with_read_factory(); } diff --git a/panda/src/light/directionalLight.I b/panda/src/light/directionalLight.I index 7c60186334..789c7625ab 100644 --- a/panda/src/light/directionalLight.I +++ b/panda/src/light/directionalLight.I @@ -16,22 +16,108 @@ // //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// -// Function: DirectionalLight::get_specular +// Function: DirectionalLight::CData::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE Colorf DirectionalLight::get_specular( void ) const +INLINE DirectionalLight::CData:: +CData() : + _specular_color(1.0f, 1.0f, 1.0f, 1.0f), + _point(0.0f, 0.0f, 0.0f), + _direction(LVector3f::forward()) { - return _specular; } //////////////////////////////////////////////////////////////////// -// Function: DirectionalLight::set_specular +// Function: DirectionalLight::CData::Copy Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE void DirectionalLight::set_specular( const Colorf& color ) +INLINE DirectionalLight::CData:: +CData(const DirectionalLight::CData ©) : + _specular_color(copy._specular_color), + _point(copy._point), + _direction(copy._direction) { - _specular = color; +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::get_specular_color +// Access: Public +// Description: Returns the color of specular highlights generated by +// the light. +//////////////////////////////////////////////////////////////////// +INLINE const Colorf &DirectionalLight:: +get_specular_color() const { + CDReader cdata(_cycler); + return cdata->_specular_color; +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::set_specular_color +// Access: Public +// Description: Sets the color of specular highlights generated by +// the light. +//////////////////////////////////////////////////////////////////// +INLINE void DirectionalLight:: +set_specular_color(const Colorf &color) { + CDWriter cdata(_cycler); + cdata->_specular_color = color; +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::get_point +// Access: Public +// Description: Returns the point in space at which the light is +// located. This is local to the coordinate space in +// which the light is assigned. +// +// This actually has no bearing on the visual effect of +// the light, since the light is rendered as if it were +// infinitely far away. This is only used to create a +// visible representation of the light. +//////////////////////////////////////////////////////////////////// +INLINE const LPoint3f &DirectionalLight:: +get_point() const { + CDReader cdata(_cycler); + return cdata->_point; +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::set_point +// Access: Public +// Description: Sets the point in space at which the light is located. +//////////////////////////////////////////////////////////////////// +INLINE void DirectionalLight:: +set_point(const LPoint3f &point) { + CDWriter cdata(_cycler); + cdata->_point = point; + mark_viz_stale(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::get_direction +// Access: Public +// Description: Returns the direction in which the light is aimed. +// This is local to the coordinate space in which the +// light is assigned. +//////////////////////////////////////////////////////////////////// +INLINE const LVector3f &DirectionalLight:: +get_direction() const { + CDReader cdata(_cycler); + return cdata->_direction; +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::set_direction +// Access: Public +// Description: Sets the direction in which the light is aimed. +//////////////////////////////////////////////////////////////////// +INLINE void DirectionalLight:: +set_direction(const LVector3f &direction) { + CDWriter cdata(_cycler); + cdata->_direction = direction; + mark_viz_stale(); } diff --git a/panda/src/light/directionalLight.cxx b/panda/src/light/directionalLight.cxx index 0512ea4546..b5d1306e25 100644 --- a/panda/src/light/directionalLight.cxx +++ b/panda/src/light/directionalLight.cxx @@ -15,35 +15,106 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// -#include + #include "directionalLight.h" +#include "graphicsStateGuardian.h" +#include "bamWriter.h" +#include "bamReader.h" +#include "datagram.h" +#include "datagramIterator.h" -#include - -//////////////////////////////////////////////////////////////////// -// Static variables -//////////////////////////////////////////////////////////////////// TypeHandle DirectionalLight::_type_handle; //////////////////////////////////////////////////////////////////// -// Function: DirectionalLight::Constructor -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -DirectionalLight::DirectionalLight(const string& name) : NamedNode(name) -{ - set_color(Colorf(1, 1, 1, 1)); - set_specular(Colorf(1, 1, 1, 1)); -} - -//////////////////////////////////////////////////////////////////// -// Function: DirectionalLight::output +// Function: DirectionalLight::CData::make_copy // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// +CycleData *DirectionalLight::CData:: +make_copy() const { + return new CData(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::CData::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void DirectionalLight::CData:: +write_datagram(BamWriter *, Datagram &dg) const { + _specular_color.write_datagram(dg); + _point.write_datagram(dg); + _direction.write_datagram(dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::CData::fillin +// Access: Public, Virtual +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new Light. +//////////////////////////////////////////////////////////////////// +void DirectionalLight::CData:: +fillin(DatagramIterator &scan, BamReader *) { + _specular_color.read_datagram(scan); + _point.read_datagram(scan); + _direction.read_datagram(scan); +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +DirectionalLight:: +DirectionalLight(const string &name) : + LightNode(name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::Copy Constructor +// Access: Protected +// Description: Do not call the copy constructor directly; instead, +// use make_copy() or copy_subgraph() to make a copy of +// a node. +//////////////////////////////////////////////////////////////////// +DirectionalLight:: +DirectionalLight(const DirectionalLight ©) : + LightNode(copy), + _cycler(copy._cycler) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::make_copy +// Access: Public, Virtual +// Description: Returns a newly-allocated PandaNode that is a shallow +// copy of this one. It will be a different pointer, +// but its internal data may or may not be shared with +// that of the original PandaNode. No children will be +// copied. +//////////////////////////////////////////////////////////////////// +PandaNode *DirectionalLight:: +make_copy() const { + return new DirectionalLight(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::xform +// Access: Public, Virtual +// Description: Transforms the contents of this PandaNode by the +// indicated matrix, if it means anything to do so. For +// most kinds of PandaNodes, this does nothing. +//////////////////////////////////////////////////////////////////// void DirectionalLight:: -output(ostream &out) const { - NamedNode::output(out); +xform(const LMatrix4f &mat) { + LightNode::xform(mat); + CDWriter cdata(_cycler); + cdata->_point = cdata->_point * mat; + cdata->_direction = cdata->_direction * mat; + mark_viz_stale(); } //////////////////////////////////////////////////////////////////// @@ -54,6 +125,76 @@ output(ostream &out) const { void DirectionalLight:: write(ostream &out, int indent_level) const { indent(out, indent_level) << *this << ":\n"; - indent(out, indent_level + 2) << "color " << _color << "\n"; - indent(out, indent_level + 2) << "specular " << _specular << "\n"; + indent(out, indent_level + 2) + << "color " << get_color() << "\n"; + indent(out, indent_level + 2) + << "specular color " << get_specular_color() << "\n"; + indent(out, indent_level + 2) + << "direction " << get_direction() << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::apply +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DirectionalLight:: +apply(GraphicsStateGuardian *gsg) { + gsg->apply_light(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// DirectionalLight. +//////////////////////////////////////////////////////////////////// +void DirectionalLight:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void DirectionalLight:: +write_datagram(BamWriter *manager, Datagram &dg) { + LightNode::write_datagram(manager, dg); + manager->write_cdata(dg, _cycler); +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type DirectionalLight is encountered +// in the Bam file. It should create the DirectionalLight +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *DirectionalLight:: +make_from_bam(const FactoryParams ¶ms) { + DirectionalLight *node = new DirectionalLight(""); + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + node->fillin(scan, manager); + + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: DirectionalLight::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new DirectionalLight. +//////////////////////////////////////////////////////////////////// +void DirectionalLight:: +fillin(DatagramIterator &scan, BamReader *manager) { + LightNode::fillin(scan, manager); + manager->read_cdata(scan, _cycler); } diff --git a/panda/src/light/directionalLight.h b/panda/src/light/directionalLight.h index fdec119872..36fd9eed95 100644 --- a/panda/src/light/directionalLight.h +++ b/panda/src/light/directionalLight.h @@ -15,74 +15,87 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #ifndef DIRECTIONALLIGHT_H #define DIRECTIONALLIGHT_H -// -//////////////////////////////////////////////////////////////////// -// Includes -//////////////////////////////////////////////////////////////////// -#include -#include -#include -#include "pmap.h" -#include -#include "light.h" +#include "pandabase.h" -//////////////////////////////////////////////////////////////////// -// Defines -//////////////////////////////////////////////////////////////////// +#include "lightNode.h" //////////////////////////////////////////////////////////////////// // Class : DirectionalLight -// Description : +// Description : A light shining from infinitely far away in a +// particular direction, like sunlight. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA DirectionalLight : public Light, public NamedNode -{ - PUBLISHED: +class EXPCL_PANDA DirectionalLight : public LightNode { +PUBLISHED: + DirectionalLight(const string &name); - DirectionalLight( const string& name = "" ); - ~DirectionalLight( void ) { } +protected: + DirectionalLight(const DirectionalLight ©); - INLINE Colorf get_specular( void ) const; - INLINE void set_specular( const Colorf& color ); +public: + virtual PandaNode *make_copy() const; + virtual void xform(const LMatrix4f &mat); + virtual void write(ostream &out, int indent_level) const; +PUBLISHED: + INLINE const Colorf &get_specular_color() const; + INLINE void set_specular_color(const Colorf &color); + + INLINE const LPoint3f &get_point() const; + INLINE void set_point(const LPoint3f &point); + + INLINE const LVector3f &get_direction() const; + INLINE void set_direction(const LVector3f &direction); + +public: + virtual void apply(GraphicsStateGuardian *gsg); + +private: + // This is the data that must be cycled between pipeline stages. + class EXPCL_PANDA CData : public CycleData { public: + INLINE CData(); + INLINE CData(const CData ©); + virtual CycleData *make_copy() const; + virtual void write_datagram(BamWriter *manager, Datagram &dg) const; + virtual void fillin(DatagramIterator &scan, BamReader *manager); - virtual void output( ostream &out ) const; - virtual void write( ostream &out, int indent_level = 0 ) const; + Colorf _specular_color; + LPoint3f _point; + LVector3f _direction; + }; - virtual void apply( GraphicsStateGuardian* gsg ) { - gsg->apply_light( this ); - } + PipelineCycler _cycler; + typedef CycleDataReader CDReader; + typedef CycleDataWriter CDWriter; - protected: +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); - Colorf _specular; +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); - public: +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + LightNode::init_type(); + register_type(_type_handle, "DirectionalLight", + LightNode::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - static TypeHandle get_class_type( void ) { - return _type_handle; - } - static void init_type( void ) { - Light::init_type(); - NamedNode::init_type(); - register_type( _type_handle, "DirectionalLight", - Light::get_class_type(), - NamedNode::get_class_type() ); - } - virtual TypeHandle get_type( void ) const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - virtual TypeHandle get_light_type( void ) const { - return get_class_type(); - } - - private: - - static TypeHandle _type_handle; +private: + static TypeHandle _type_handle; }; INLINE ostream &operator << (ostream &out, const DirectionalLight &light) { diff --git a/panda/src/light/light.I b/panda/src/light/light.I new file mode 100644 index 0000000000..f84f095812 --- /dev/null +++ b/panda/src/light/light.I @@ -0,0 +1,98 @@ +// Filename: light.I +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: Light::CData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Light::CData:: +CData() : + _color(1.0f, 1.0f, 1.0f, 1.0f), + _viz_geom_stale(true) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::CData::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Light::CData:: +CData(const Light::CData ©) : + _color(copy._color), + _viz_geom(copy._viz_geom), + _viz_geom_stale(copy._viz_geom_stale) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Light:: +Light() { +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Light:: +Light(const Light ©) : + _cycler(copy._cycler) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::get_color +// Access: Published +// Description: Returns the basic color of the light. +//////////////////////////////////////////////////////////////////// +INLINE const Colorf &Light:: +get_color() const { + CDReader cdata(_cycler); + return cdata->_color; +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::set_color +// Access: Published +// Description: Sets the basic color of the light. +//////////////////////////////////////////////////////////////////// +INLINE void Light:: +set_color(const Colorf &color) { + CDWriter cdata(_cycler); + cdata->_color = color; + mark_viz_stale(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::mark_viz_stale +// Access: Public +// Description: Indicates that the internal visualization object will +// need to be updated. +//////////////////////////////////////////////////////////////////// +INLINE void Light:: +mark_viz_stale() { + CDWriter cdata(_cycler); + cdata->_viz_geom_stale = true; +} diff --git a/panda/src/light/light.cxx b/panda/src/light/light.cxx index 2d23e1d514..65d40d77c4 100644 --- a/panda/src/light/light.cxx +++ b/panda/src/light/light.cxx @@ -15,9 +15,107 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #include "light.h" +#include "bamWriter.h" +#include "bamReader.h" +#include "datagram.h" +#include "datagramIterator.h" + +TypeHandle Light::_type_handle; + //////////////////////////////////////////////////////////////////// -// Static variables +// Function: Light::CData::make_copy +// Access: Public, Virtual +// Description: //////////////////////////////////////////////////////////////////// -TypeHandle Light::_type_handle; +CycleData *Light::CData:: +make_copy() const { + return new CData(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::CData::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void Light::CData:: +write_datagram(BamWriter *, Datagram &dg) const { + _color.write_datagram(dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::CData::fillin +// Access: Public, Virtual +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new Light. +//////////////////////////////////////////////////////////////////// +void Light::CData:: +fillin(DatagramIterator &scan, BamReader *) { + _color.read_datagram(scan); +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::Destructor +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +Light:: +~Light() { +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::get_viz +// Access: Public +// Description: Returns a GeomNode that may be rendered to visualize +// the Light. This is used during the cull traversal to +// render the Lights that have been made visible. +//////////////////////////////////////////////////////////////////// +qpGeomNode *Light:: +get_viz() { + CDReader cdata(_cycler); + if (cdata->_viz_geom_stale) { + CDWriter cdata_w(_cycler, cdata); + + cdata_w->_viz_geom = new qpGeomNode("viz"); + fill_viz_geom(cdata_w->_viz_geom); + cdata_w->_viz_geom_stale = false; + } + return cdata->_viz_geom; +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::fill_viz_geom +// Access: Protected, Virtual +// Description: Fills the indicated GeomNode up with Geoms suitable +// for rendering this light. +//////////////////////////////////////////////////////////////////// +void Light:: +fill_viz_geom(qpGeomNode *) { +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::write_datagram +// Access: Protected +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void Light:: +write_datagram(BamWriter *manager, Datagram &dg) { + manager->write_cdata(dg, _cycler); +} + +//////////////////////////////////////////////////////////////////// +// Function: Light::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new Light. +//////////////////////////////////////////////////////////////////// +void Light:: +fillin(DatagramIterator &scan, BamReader *manager) { + manager->read_cdata(scan, _cycler); +} diff --git a/panda/src/light/light.h b/panda/src/light/light.h index 4a04b2f9d2..66440f8f1b 100644 --- a/panda/src/light/light.h +++ b/panda/src/light/light.h @@ -15,63 +15,96 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #ifndef LIGHT_H #define LIGHT_H -// -//////////////////////////////////////////////////////////////////// -// Includes -//////////////////////////////////////////////////////////////////// -#include -#include -#include -#include +#include "pandabase.h" -//////////////////////////////////////////////////////////////////// -// Defines -//////////////////////////////////////////////////////////////////// +#include "referenceCount.h" +#include "luse.h" +#include "cycleData.h" +#include "cycleDataReader.h" +#include "cycleDataWriter.h" +#include "pipelineCycler.h" +#include "qpgeomNode.h" + +class PandaNode; +class GraphicsStateGuardian; //////////////////////////////////////////////////////////////////// // Class : Light -// Description : +// Description : The abstract interface to all kinds of lights. The +// actual light objects also inherit from PandaNode, and +// can therefore be added to the scene graph at some +// arbitrary point to define the coordinate system of +// effect. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA Light : virtual public ReferenceCount -{ - PUBLISHED: +class EXPCL_PANDA Light : virtual public ReferenceCount { + // We inherit from ReferenceCount instead of TypedReferenceCount so + // that LightNode does not inherit from TypedObject twice. Note + // that we also inherit virtually from ReferenceCount for the same + // reason. +PUBLISHED: + INLINE Light(); + INLINE Light(const Light ©); + virtual ~Light(); - Light( void ) { _color.set(0.0, 0.0, 0.0, 1.0); } - virtual ~Light( void ) { } + virtual PandaNode *as_node()=0; - INLINE Colorf get_color(void) const { return _color; } - INLINE void set_color(const Colorf& color) { _color = color; } + INLINE const Colorf &get_color() const; + INLINE void set_color(const Colorf &color); - virtual void output(ostream &out) const=0; - virtual void write(ostream &out, int indent_level = 0) const=0; +public: + virtual void output(ostream &out) const=0; + virtual void write(ostream &out, int indent_level) const=0; + virtual void apply(GraphicsStateGuardian *gsg)=0; - public: - virtual void apply( GraphicsStateGuardian* gsg ) = 0; + qpGeomNode *get_viz(); - protected: +protected: + virtual void fill_viz_geom(qpGeomNode *viz_geom); + INLINE void mark_viz_stale(); - Colorf _color; +private: + // This is the data that must be cycled between pipeline stages. + class EXPCL_PANDA CData : public CycleData { + public: + INLINE CData(); + INLINE CData(const CData ©); + virtual CycleData *make_copy() const; + virtual void write_datagram(BamWriter *manager, Datagram &dg) const; + virtual void fillin(DatagramIterator &scan, BamReader *manager); - public: + Colorf _color; - static TypeHandle get_class_type( void ) { - return _type_handle; - } - static void init_type( void ) { - ReferenceCount::init_type(); - register_type( _type_handle, "Light", - ReferenceCount::get_class_type() ); - } - virtual TypeHandle get_light_type( void ) const { - return get_class_type(); - } + PT(qpGeomNode) _viz_geom; + bool _viz_geom_stale; + }; - private: + PipelineCycler _cycler; + typedef CycleDataReader CDReader; + typedef CycleDataWriter CDWriter; - static TypeHandle _type_handle; +protected: + void write_datagram(BamWriter *manager, Datagram &dg); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ReferenceCount::init_type(); + register_type(_type_handle, "Light", + ReferenceCount::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + +private: + static TypeHandle _type_handle; }; INLINE ostream &operator << (ostream &out, const Light &light) { @@ -79,4 +112,6 @@ INLINE ostream &operator << (ostream &out, const Light &light) { return out; } +#include "light.I" + #endif diff --git a/panda/src/light/lightAttrib.I b/panda/src/light/lightAttrib.I new file mode 100644 index 0000000000..c78b6322d0 --- /dev/null +++ b/panda/src/light/lightAttrib.I @@ -0,0 +1,88 @@ +// Filename: lightAttrib.I +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::Constructor +// Access: Private +// Description: Use LightAttrib::make() to construct a new +// LightAttrib object. +//////////////////////////////////////////////////////////////////// +INLINE LightAttrib:: +LightAttrib() { + _operation = O_set; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::get_operation +// Access: Published +// Description: Returns the basic operation type of the LightAttrib. +// If this is O_set, the lights listed here completely +// replace any lights that were already on. If this is +// O_add, the lights here are added to the set of of +// lights that were already on, and if O_remove, the +// lights here are removed from the set of lights that +// were on. +//////////////////////////////////////////////////////////////////// +INLINE LightAttrib::Operation LightAttrib:: +get_operation() const { + return _operation; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::get_num_lights +// Access: Published +// Description: Returns the number of lights listed in the attribute. +//////////////////////////////////////////////////////////////////// +INLINE int LightAttrib:: +get_num_lights() const { + return _lights.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::get_light +// Access: Published +// Description: Returns the nth lights listed in the attribute. +//////////////////////////////////////////////////////////////////// +INLINE Light *LightAttrib:: +get_light(int n) const { + nassertr(n >= 0 && n < (int)_lights.size(), (Light *)NULL); + return _lights[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::is_identity +// Access: Published +// Description: Returns true if this is an identity attrib: it does +// not change the set of lights in use. +//////////////////////////////////////////////////////////////////// +INLINE bool LightAttrib:: +is_identity() const { + return _operation != O_set && _lights.empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::is_all_off +// Access: Published +// Description: Returns true if this attrib turns off all lights and +// turns none on. +//////////////////////////////////////////////////////////////////// +INLINE bool LightAttrib:: +is_all_off() const { + return _operation == O_set && _lights.empty(); +} diff --git a/panda/src/light/lightAttrib.cxx b/panda/src/light/lightAttrib.cxx new file mode 100644 index 0000000000..9c3059ab00 --- /dev/null +++ b/panda/src/light/lightAttrib.cxx @@ -0,0 +1,489 @@ +// Filename: lightAttrib.cxx +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "lightAttrib.h" +#include "pandaNode.h" +#include "graphicsStateGuardianBase.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "datagram.h" +#include "datagramIterator.h" + +TypeHandle LightAttrib::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make_all_off +// Access: Published, Static +// Description: Constructs a new LightAttrib object that turns off +// all lights (and hence disables lighting). +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make_all_off() { + LightAttrib *attrib = new LightAttrib; + attrib->_operation = O_set; + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make +// Access: Published, Static +// Description: Constructs a new LightAttrib object that turns on (or +// off, according to op) the indicate light(s). +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make(LightAttrib::Operation op, Light *light) { + LightAttrib *attrib = new LightAttrib; + attrib->_operation = op; + attrib->_lights.push_back(light); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make +// Access: Published, Static +// Description: Constructs a new LightAttrib object that turns on (or +// off, according to op) the indicate light(s). +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make(LightAttrib::Operation op, Light *light1, Light *light2) { + LightAttrib *attrib = new LightAttrib; + attrib->_operation = op; + attrib->_lights.push_back(light1); + attrib->_lights.push_back(light2); + + attrib->_lights.sort(); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make +// Access: Published, Static +// Description: Constructs a new LightAttrib object that turns on (or +// off, according to op) the indicate light(s). +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make(LightAttrib::Operation op, Light *light1, Light *light2, + Light *light3) { + LightAttrib *attrib = new LightAttrib; + attrib->_operation = op; + attrib->_lights.push_back(light1); + attrib->_lights.push_back(light2); + attrib->_lights.push_back(light3); + + attrib->_lights.sort(); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make +// Access: Published, Static +// Description: Constructs a new LightAttrib object that turns on (or +// off, according to op) the indicate light(s). +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make(LightAttrib::Operation op, Light *light1, Light *light2, + Light *light3, Light *light4) { + LightAttrib *attrib = new LightAttrib; + attrib->_operation = op; + attrib->_lights.push_back(light1); + attrib->_lights.push_back(light2); + attrib->_lights.push_back(light3); + attrib->_lights.push_back(light4); + + attrib->_lights.sort(); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::has_light +// Access: Published +// Description: Returns true if the indicated light is listed in the +// attrib, false otherwise. +//////////////////////////////////////////////////////////////////// +bool LightAttrib:: +has_light(Light *light) const { + return _lights.find(light) != _lights.end(); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::issue +// Access: Public, Virtual +// Description: Calls the appropriate method on the indicated GSG +// to issue the graphics commands appropriate to the +// given attribute. This is normally called +// (indirectly) only from +// GraphicsStateGuardian::set_state() or modify_state(). +//////////////////////////////////////////////////////////////////// +void LightAttrib:: +issue(GraphicsStateGuardianBase *gsg) const { + gsg->issue_light(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void LightAttrib:: +output(ostream &out) const { + out << get_type() << ":"; + if (_operation == O_set && _lights.empty()) { + out << "all off"; + } else { + switch (_operation) { + case O_set: + out << "set"; + break; + case O_add: + out << "add"; + break; + case O_remove: + out << "remove"; + break; + } + + Lights::const_iterator li; + for (li = _lights.begin(); li != _lights.end(); ++li) { + Light *light = (*li); + out << " " << light->get_type(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::compare_to_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived LightAttrib +// types to return a unique number indicating whether +// this LightAttrib is equivalent to the other one. +// +// This should return 0 if the two LightAttrib objects +// are equivalent, a number less than zero if this one +// should be sorted before the other one, and a number +// greater than zero otherwise. +// +// This will only be called with two LightAttrib +// objects whose get_type() functions return the same. +//////////////////////////////////////////////////////////////////// +int LightAttrib:: +compare_to_impl(const RenderAttrib *other) const { + const LightAttrib *ta; + DCAST_INTO_R(ta, other, 0); + + if (_operation != ta->_operation) { + return (int)_operation - (int)ta->_operation; + } + + Lights::const_iterator li = _lights.begin(); + Lights::const_iterator oli = ta->_lights.begin(); + + while (li != _lights.end() && oli != ta->_lights.end()) { + Light *light = (*li); + Light *other_light = (*oli); + + if (light != other_light) { + return light < other_light ? -1 : 1; + } + + ++li; + ++oli; + } + + if (li != _lights.end()) { + return 1; + } + if (oli != ta->_lights.end()) { + return -1; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::compose_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived RenderAttrib +// types to specify how two consecutive RenderAttrib +// objects of the same type interact. +// +// This should return the result of applying the other +// RenderAttrib to a node in the scene graph below this +// RenderAttrib, which was already applied. In most +// cases, the result is the same as the other +// RenderAttrib (that is, a subsequent RenderAttrib +// completely replaces the preceding one). On the other +// hand, some kinds of RenderAttrib (for instance, +// ColorTransformAttrib) might combine in meaningful +// ways. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +compose_impl(const RenderAttrib *other) const { + const LightAttrib *ta; + DCAST_INTO_R(ta, other, 0); + + if (ta->_operation == O_set) { + // If the other type is O_set, it doesn't matter what we are. + return ta; + } + + if (_operation == ta->_operation) { + // If the operation types match, the composition is simply the + // union. + return do_add(ta, _operation); + + } else if (ta->_operation == O_remove) { + // If the other operation type is remove, and our type is add or + // set, then remove. + return do_remove(ta, _operation); + + } else if (_operation == O_remove) { + // If our type is remove, then the other one wins. + return ta; + + } else { + // Otherwise, the result is the union. + return do_add(ta, _operation); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::invert_compose_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived RenderAttrib +// types to specify how two consecutive RenderAttrib +// objects of the same type interact. +// +// See invert_compose() and compose_impl(). +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +invert_compose_impl(const RenderAttrib *other) const { + // I think in this case the other attrib always wins. Maybe this + // needs a bit more thought. It's hard to imagine that it's even + // important to compute this properly. + return other; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make_default_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived LightAttrib +// types to specify what the default property for a +// LightAttrib of this type should be. +// +// This should return a newly-allocated LightAttrib of +// the same type that corresponds to whatever the +// standard default for this kind of LightAttrib is. +//////////////////////////////////////////////////////////////////// +RenderAttrib *LightAttrib:: +make_default_impl() const { + return new LightAttrib; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::do_add +// Access: Private +// Description: Returns a new LightAttrib that represents all the +// lights of this attrib, with those of the other one +// added in. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +do_add(const LightAttrib *other, LightAttrib::Operation op) const { + Lights::const_iterator ai = _lights.begin(); + Lights::const_iterator bi = other->_lights.begin(); + + // Create a new LightAttrib that will hold the result. + LightAttrib *new_attrib = new LightAttrib; + new_attrib->_operation = op; + back_insert_iterator result = + back_inserter(new_attrib->_lights); + + while (ai != _lights.end() && bi != other->_lights.end()) { + if ((*ai) < (*bi)) { + // Here is a light that we have in the original, which is not + // present in the secondary. + *result = *ai; + ++ai; + ++result; + } else if ((*bi) < (*ai)) { + // Here is a new light we have in the secondary, that was not + // present in the original. + *result = *bi; + ++bi; + ++result; + } else { + // Here is a light we have in both. + *result = *ai; + ++ai; + ++bi; + ++result; + } + } + + while (ai != _lights.end()) { + *result = *ai; + ++ai; + ++result; + } + + while (bi != other->_lights.end()) { + *result = *bi; + ++bi; + ++result; + } + + return return_new(new_attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::do_remove +// Access: Private +// Description: Returns a new LightAttrib that represents all the +// lights of this attrib, with those of the other one +// removed. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +do_remove(const LightAttrib *other, LightAttrib::Operation op) const { + Lights::const_iterator ai = _lights.begin(); + Lights::const_iterator bi = other->_lights.begin(); + + // Create a new LightAttrib that will hold the result. + LightAttrib *new_attrib = new LightAttrib; + new_attrib->_operation = op; + back_insert_iterator result = + back_inserter(new_attrib->_lights); + + while (ai != _lights.end() && bi != other->_lights.end()) { + if ((*ai) < (*bi)) { + // Here is a light that we have in the original, which is + // not present in the secondary. Keep it. + *result = *ai; + ++ai; + ++result; + } else if ((*bi) < (*ai)) { + // Here is a new light we have in the secondary, that was + // not present in the original. Ignore it. + ++bi; + } else { + // Here is a light we have in both. Drop it. + ++ai; + ++bi; + } + } + + while (ai != _lights.end()) { + *result = *ai; + ++ai; + ++result; + } + + return return_new(new_attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// LightAttrib. +//////////////////////////////////////////////////////////////////// +void LightAttrib:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void LightAttrib:: +write_datagram(BamWriter *manager, Datagram &dg) { + RenderAttrib::write_datagram(manager, dg); + + dg.add_int8((int)_operation); + PN_uint16 num_lights = _lights.size(); + nassertv(num_lights == _lights.size()); + dg.add_uint16(num_lights); + + Lights::const_iterator li; + for (li = _lights.begin(); li != _lights.end(); ++li) { + Light *light = (*li); + manager->write_pointer(dg, light->as_node()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int LightAttrib:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = RenderAttrib::complete_pointers(p_list, manager); + + Lights::iterator li; + for (li = _lights.begin(); li != _lights.end(); ++li) { + PandaNode *node; + DCAST_INTO_R(node, p_list[pi++], pi); + (*li) = node->as_light(); + } + + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type LightAttrib is encountered +// in the Bam file. It should create the LightAttrib +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *LightAttrib:: +make_from_bam(const FactoryParams ¶ms) { + LightAttrib *attrib = new LightAttrib; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + attrib->fillin(scan, manager); + + return attrib; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new LightAttrib. +//////////////////////////////////////////////////////////////////// +void LightAttrib:: +fillin(DatagramIterator &scan, BamReader *manager) { + RenderAttrib::fillin(scan, manager); + + _operation = (Operation)scan.get_int8(); + int num_lights = scan.get_uint16(); + + for (int i = 0; i < num_lights; i++) { + manager->read_pointer(scan); + _lights.push_back(NULL); + } +} diff --git a/panda/src/light/lightAttrib.h b/panda/src/light/lightAttrib.h new file mode 100644 index 0000000000..be556eb22c --- /dev/null +++ b/panda/src/light/lightAttrib.h @@ -0,0 +1,116 @@ +// Filename: lightAttrib.h +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef LIGHTATTRIB_H +#define LIGHTATTRIB_H + +#include "pandabase.h" + +#include "light.h" +#include "renderAttrib.h" +#include "ordered_vector.h" + +//////////////////////////////////////////////////////////////////// +// Class : LightAttrib +// Description : Indicates which set of lights should be considered +// "on" to illuminate geometry at this level and below. +// A LightAttrib can either add lights or remove lights +// from the total set of "on" lights. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA LightAttrib : public RenderAttrib { +private: + INLINE LightAttrib(); + +PUBLISHED: + enum Operation { + O_set, + O_add, + O_remove + }; + + static CPT(RenderAttrib) make_all_off(); + static CPT(RenderAttrib) make(Operation op, + Light *light); + static CPT(RenderAttrib) make(Operation op, + Light *light1, Light *light2); + static CPT(RenderAttrib) make(Operation op, + Light *light1, Light *light2, + Light *light3); + static CPT(RenderAttrib) make(Operation op, + Light *light1, Light *light2, + Light *light3, Light *light4); + + INLINE Operation get_operation() const; + + INLINE int get_num_lights() const; + INLINE Light *get_light(int n) const; + bool has_light(Light *light) const; + + INLINE bool is_identity() const; + INLINE bool is_all_off() const; + +public: + virtual void issue(GraphicsStateGuardianBase *gsg) const; + virtual void output(ostream &out) const; + +protected: + virtual int compare_to_impl(const RenderAttrib *other) const; + virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; + virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const; + virtual RenderAttrib *make_default_impl() const; + +private: + CPT(RenderAttrib) do_add(const LightAttrib *other, Operation op) const; + CPT(RenderAttrib) do_remove(const LightAttrib *other, Operation op) const; + +private: + Operation _operation; + typedef ov_set< PT(Light) > Lights; + Lights _lights; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + RenderAttrib::init_type(); + register_type(_type_handle, "LightAttrib", + RenderAttrib::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "lightAttrib.I" + +#endif + diff --git a/panda/src/light/lightLensNode.I b/panda/src/light/lightLensNode.I new file mode 100644 index 0000000000..f852cb4083 --- /dev/null +++ b/panda/src/light/lightLensNode.I @@ -0,0 +1,17 @@ +// Filename: lightLensNode.I +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// diff --git a/panda/src/light/lightLensNode.cxx b/panda/src/light/lightLensNode.cxx new file mode 100644 index 0000000000..7c29c1969d --- /dev/null +++ b/panda/src/light/lightLensNode.cxx @@ -0,0 +1,115 @@ +// Filename: lightLensNode.cxx +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "lightLensNode.h" +#include "bamWriter.h" +#include "bamReader.h" +#include "datagram.h" +#include "datagramIterator.h" + +TypeHandle LightLensNode::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: LightLensNode::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +LightLensNode:: +LightLensNode(const string &name) : + qpLensNode(name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: LightLensNode::Copy Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +LightLensNode:: +LightLensNode(const LightLensNode ©) : + Light(copy), + qpLensNode(copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: LightLensNode::as_node +// Access: Published, Virtual +// Description: Returns the Light object upcast to a PandaNode. +//////////////////////////////////////////////////////////////////// +PandaNode *LightLensNode:: +as_node() { + return this; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightLensNode::as_light +// Access: Public, Virtual +// Description: Cross-casts the node to a Light pointer, if it is one +// of the four kinds of Light nodes, or returns NULL if +// it is not. +//////////////////////////////////////////////////////////////////// +Light *LightLensNode:: +as_light() { + return this; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightLensNode::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void LightLensNode:: +output(ostream &out) const { + qpLensNode::output(out); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightLensNode::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void LightLensNode:: +write(ostream &out, int indent_level) const { + qpLensNode::write(out, indent_level); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightLensNode::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void LightLensNode:: +write_datagram(BamWriter *manager, Datagram &dg) { + qpLensNode::write_datagram(manager, dg); + Light::write_datagram(manager, dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightLensNode::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new LightLensNode. +//////////////////////////////////////////////////////////////////// +void LightLensNode:: +fillin(DatagramIterator &scan, BamReader *manager) { + qpLensNode::fillin(scan, manager); + Light::fillin(scan, manager); +} diff --git a/panda/src/light/lightLensNode.h b/panda/src/light/lightLensNode.h new file mode 100644 index 0000000000..dffc01cd5e --- /dev/null +++ b/panda/src/light/lightLensNode.h @@ -0,0 +1,81 @@ +// Filename: lightLensNode.h +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef LIGHTLENSNODE_H +#define LIGHTLENSNODE_H + +#include "pandabase.h" + +#include "light.h" +#include "qplensNode.h" + +//////////////////////////////////////////////////////////////////// +// Class : LightLensNode +// Description : A derivative of Light and of LensNode. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA LightLensNode : public Light, public qpLensNode { +PUBLISHED: + LightLensNode(const string &name); + +protected: + LightLensNode(const LightLensNode ©); + +public: + virtual PandaNode *as_node(); + virtual Light *as_light(); + +PUBLISHED: + // We have to explicitly publish these because they resolve the + // multiple inheritance. + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level = 0) const; + +public: + virtual void write_datagram(BamWriter *manager, Datagram &dg); + +protected: + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + Light::init_type(); + qpLensNode::init_type(); + register_type(_type_handle, "LightLensNode", + Light::get_class_type(), + qpLensNode::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +INLINE ostream &operator << (ostream &out, const LightLensNode &light) { + light.output(out); + return out; +} + +#include "lightLensNode.I" + +#endif diff --git a/panda/src/light/lightNode.I b/panda/src/light/lightNode.I new file mode 100644 index 0000000000..a73b589115 --- /dev/null +++ b/panda/src/light/lightNode.I @@ -0,0 +1,17 @@ +// Filename: lightNode.I +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// diff --git a/panda/src/light/lightNode.cxx b/panda/src/light/lightNode.cxx new file mode 100644 index 0000000000..036aaa69e9 --- /dev/null +++ b/panda/src/light/lightNode.cxx @@ -0,0 +1,115 @@ +// Filename: lightNode.cxx +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "lightNode.h" +#include "bamWriter.h" +#include "bamReader.h" +#include "datagram.h" +#include "datagramIterator.h" + +TypeHandle LightNode::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: LightNode::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +LightNode:: +LightNode(const string &name) : + PandaNode(name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: LightNode::Copy Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +LightNode:: +LightNode(const LightNode ©) : + Light(copy), + PandaNode(copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: LightNode::as_node +// Access: Published, Virtual +// Description: Returns the Light object upcast to a PandaNode. +//////////////////////////////////////////////////////////////////// +PandaNode *LightNode:: +as_node() { + return this; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightNode::as_light +// Access: Public, Virtual +// Description: Cross-casts the node to a Light pointer, if it is one +// of the four kinds of Light nodes, or returns NULL if +// it is not. +//////////////////////////////////////////////////////////////////// +Light *LightNode:: +as_light() { + return this; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightNode::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void LightNode:: +output(ostream &out) const { + PandaNode::output(out); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightNode::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void LightNode:: +write(ostream &out, int indent_level) const { + PandaNode::write(out, indent_level); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightNode::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void LightNode:: +write_datagram(BamWriter *manager, Datagram &dg) { + PandaNode::write_datagram(manager, dg); + Light::write_datagram(manager, dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightNode::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new LightNode. +//////////////////////////////////////////////////////////////////// +void LightNode:: +fillin(DatagramIterator &scan, BamReader *manager) { + PandaNode::fillin(scan, manager); + Light::fillin(scan, manager); +} diff --git a/panda/src/light/lightNode.h b/panda/src/light/lightNode.h new file mode 100644 index 0000000000..66955a19d6 --- /dev/null +++ b/panda/src/light/lightNode.h @@ -0,0 +1,83 @@ +// Filename: lightNode.h +// Created by: drose (26Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef LIGHTNODE_H +#define LIGHTNODE_H + +#include "pandabase.h" + +#include "light.h" +#include "pandaNode.h" + +//////////////////////////////////////////////////////////////////// +// Class : LightNode +// Description : A derivative of Light and of PandaNode. All kinds of +// Light except Spotlight (which must inherit from +// LensNode instead) inherit from this class. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA LightNode : public Light, public PandaNode { +PUBLISHED: + LightNode(const string &name); + +protected: + LightNode(const LightNode ©); + +public: + virtual PandaNode *as_node(); + virtual Light *as_light(); + +PUBLISHED: + // We have to explicitly publish these because they resolve the + // multiple inheritance. + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level = 0) const; + +public: + virtual void write_datagram(BamWriter *manager, Datagram &dg); + +protected: + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + Light::init_type(); + PandaNode::init_type(); + register_type(_type_handle, "LightNode", + Light::get_class_type(), + PandaNode::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +INLINE ostream &operator << (ostream &out, const LightNode &light) { + light.output(out); + return out; +} + +#include "lightNode.I" + +#endif diff --git a/panda/src/light/light_composite1.cxx b/panda/src/light/light_composite1.cxx index 464f33b470..94b1f7a9f4 100644 --- a/panda/src/light/light_composite1.cxx +++ b/panda/src/light/light_composite1.cxx @@ -1,5 +1,7 @@ - #include "light.cxx" +#include "lightAttrib.cxx" +#include "lightLensNode.cxx" +#include "lightNode.cxx" #include "lightTransition.cxx" #include "pt_Light.cxx" #include "vector_PT_Light.cxx" diff --git a/panda/src/light/light_composite2.cxx b/panda/src/light/light_composite2.cxx index 6c44107b3a..db36046448 100644 --- a/panda/src/light/light_composite2.cxx +++ b/panda/src/light/light_composite2.cxx @@ -1,4 +1,3 @@ - #include "config_light.cxx" #include "ambientLight.cxx" #include "spotlight.cxx" diff --git a/panda/src/light/pointLight.I b/panda/src/light/pointLight.I index 559db21242..f4f47a6b35 100644 --- a/panda/src/light/pointLight.I +++ b/panda/src/light/pointLight.I @@ -16,82 +16,106 @@ // //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// -// Function: PointLight::get_specular +// Function: PointLight::CData::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE Colorf PointLight::get_specular( void ) const +INLINE PointLight::CData:: +CData() : + _specular_color(1.0f, 1.0f, 1.0f, 1.0f), + _attenuation(1.0f, 0.0f, 0.0f), + _point(0.0f, 0.0f, 0.0f) { - return _specular; } //////////////////////////////////////////////////////////////////// -// Function: PointLight::set_specular +// Function: PointLight::CData::Copy Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE void PointLight::set_specular( const Colorf& color ) +INLINE PointLight::CData:: +CData(const PointLight::CData ©) : + _specular_color(copy._specular_color), + _attenuation(copy._attenuation), + _point(copy._point) { - _specular = color; } //////////////////////////////////////////////////////////////////// -// Function: PointLight::get_constant_attenuation +// Function: PointLight::get_specular_color // Access: Public -// Description: +// Description: Returns the color of specular highlights generated by +// the light. //////////////////////////////////////////////////////////////////// -INLINE float PointLight::get_constant_attenuation( void ) const -{ - return _constant_attenuation; +INLINE const Colorf &PointLight:: +get_specular_color() const { + CDReader cdata(_cycler); + return cdata->_specular_color; } //////////////////////////////////////////////////////////////////// -// Function: PointLight::set_constant_attenuation +// Function: PointLight::set_specular_color // Access: Public -// Description: +// Description: Sets the color of specular highlights generated by +// the light. //////////////////////////////////////////////////////////////////// -INLINE void PointLight::set_constant_attenuation( float att ) -{ - _constant_attenuation = att; +INLINE void PointLight:: +set_specular_color(const Colorf &color) { + CDWriter cdata(_cycler); + cdata->_specular_color = color; } //////////////////////////////////////////////////////////////////// -// Function: PointLight::get_linear_attenuation +// Function: PointLight::get_attenuation // Access: Public -// Description: +// Description: Returns the terms of the attenuation equation for the +// light. These are, in order, the constant, linear, +// and quadratic terms based on the distance from the +// point to the vertex. //////////////////////////////////////////////////////////////////// -INLINE float PointLight::get_linear_attenuation( void ) const -{ - return _linear_attenuation; +INLINE const LVecBase3f &PointLight:: +get_attenuation() const { + CDReader cdata(_cycler); + return cdata->_attenuation; } //////////////////////////////////////////////////////////////////// -// Function: PointLight::set_linear_attenuation +// Function: PointLight::set_attenuation // Access: Public -// Description: +// Description: Sets the terms of the attenuation equation for the +// light. These are, in order, the constant, linear, +// and quadratic terms based on the distance from the +// point to the vertex. //////////////////////////////////////////////////////////////////// -INLINE void PointLight::set_linear_attenuation( float att ) -{ - _linear_attenuation = att; +INLINE void PointLight:: +set_attenuation(const LVecBase3f &attenuation) { + CDWriter cdata(_cycler); + cdata->_attenuation = attenuation; } //////////////////////////////////////////////////////////////////// -// Function: PointLight::get_quadratic_attenuation +// Function: PointLight::get_point // Access: Public -// Description: +// Description: Returns the point in space at which the light is +// located. This is local to the coordinate space in +// which the light is assigned. //////////////////////////////////////////////////////////////////// -INLINE float PointLight::get_quadratic_attenuation( void ) const -{ - return _quadratic_attenuation; +INLINE const LPoint3f &PointLight:: +get_point() const { + CDReader cdata(_cycler); + return cdata->_point; } //////////////////////////////////////////////////////////////////// -// Function: PointLight::set_quadratic_attenuation +// Function: PointLight::set_point // Access: Public -// Description: +// Description: Sets the point in space at which the light is located. //////////////////////////////////////////////////////////////////// -INLINE void PointLight::set_quadratic_attenuation( float att ) -{ - _quadratic_attenuation = att; +INLINE void PointLight:: +set_point(const LPoint3f &point) { + CDWriter cdata(_cycler); + cdata->_point = point; + mark_viz_stale(); } diff --git a/panda/src/light/pointLight.cxx b/panda/src/light/pointLight.cxx index 99099394b1..dd5b591b0d 100644 --- a/panda/src/light/pointLight.cxx +++ b/panda/src/light/pointLight.cxx @@ -15,36 +15,105 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// -#include "pointLight.h" -//////////////////////////////////////////////////////////////////// -// Static variables -//////////////////////////////////////////////////////////////////// +#include "pointLight.h" +#include "graphicsStateGuardian.h" +#include "bamWriter.h" +#include "bamReader.h" +#include "datagram.h" +#include "datagramIterator.h" + TypeHandle PointLight::_type_handle; //////////////////////////////////////////////////////////////////// -// Function: PointLight::Constructor -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -PointLight::PointLight(const string& name) : NamedNode(name) -{ - set_color(Colorf(1, 1, 1, 1)); - set_specular(Colorf(1, 1, 1, 1)); - - set_constant_attenuation(1); - set_linear_attenuation(0); - set_quadratic_attenuation(0); -} - -//////////////////////////////////////////////////////////////////// -// Function: PointLight::output +// Function: PointLight::CData::make_copy // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// +CycleData *PointLight::CData:: +make_copy() const { + return new CData(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::CData::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void PointLight::CData:: +write_datagram(BamWriter *, Datagram &dg) const { + _specular_color.write_datagram(dg); + _attenuation.write_datagram(dg); + _point.write_datagram(dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::CData::fillin +// Access: Public, Virtual +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new Light. +//////////////////////////////////////////////////////////////////// +void PointLight::CData:: +fillin(DatagramIterator &scan, BamReader *) { + _specular_color.read_datagram(scan); + _attenuation.read_datagram(scan); + _point.read_datagram(scan); +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +PointLight:: +PointLight(const string &name) : + LightNode(name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::Copy Constructor +// Access: Protected +// Description: Do not call the copy constructor directly; instead, +// use make_copy() or copy_subgraph() to make a copy of +// a node. +//////////////////////////////////////////////////////////////////// +PointLight:: +PointLight(const PointLight ©) : + LightNode(copy), + _cycler(copy._cycler) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::make_copy +// Access: Public, Virtual +// Description: Returns a newly-allocated PandaNode that is a shallow +// copy of this one. It will be a different pointer, +// but its internal data may or may not be shared with +// that of the original PandaNode. No children will be +// copied. +//////////////////////////////////////////////////////////////////// +PandaNode *PointLight:: +make_copy() const { + return new PointLight(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::xform +// Access: Public, Virtual +// Description: Transforms the contents of this PandaNode by the +// indicated matrix, if it means anything to do so. For +// most kinds of PandaNodes, this does nothing. +//////////////////////////////////////////////////////////////////// void PointLight:: -output(ostream &out) const { - NamedNode::output(out); +xform(const LMatrix4f &mat) { + LightNode::xform(mat); + CDWriter cdata(_cycler); + cdata->_point = cdata->_point * mat; + mark_viz_stale(); } //////////////////////////////////////////////////////////////////// @@ -55,9 +124,76 @@ output(ostream &out) const { void PointLight:: write(ostream &out, int indent_level) const { indent(out, indent_level) << *this << ":\n"; - indent(out, indent_level + 2) << "color " << _color << "\n"; - indent(out, indent_level + 2) << "specular " << _specular << "\n"; indent(out, indent_level + 2) - << "attenuation " << _constant_attenuation << ", " - << _linear_attenuation << ", " << _quadratic_attenuation << "\n"; + << "color " << get_color() << "\n"; + indent(out, indent_level + 2) + << "specular color " << get_specular_color() << "\n"; + indent(out, indent_level + 2) + << "attenuation " << get_attenuation() << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::apply +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void PointLight:: +apply(GraphicsStateGuardian *gsg) { + gsg->apply_light(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// PointLight. +//////////////////////////////////////////////////////////////////// +void PointLight:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void PointLight:: +write_datagram(BamWriter *manager, Datagram &dg) { + LightNode::write_datagram(manager, dg); + manager->write_cdata(dg, _cycler); +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type PointLight is encountered +// in the Bam file. It should create the PointLight +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *PointLight:: +make_from_bam(const FactoryParams ¶ms) { + PointLight *node = new PointLight(""); + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + node->fillin(scan, manager); + + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: PointLight::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new PointLight. +//////////////////////////////////////////////////////////////////// +void PointLight:: +fillin(DatagramIterator &scan, BamReader *manager) { + LightNode::fillin(scan, manager); + manager->read_cdata(scan, _cycler); } diff --git a/panda/src/light/pointLight.h b/panda/src/light/pointLight.h index 10a83008c6..50566758fc 100644 --- a/panda/src/light/pointLight.h +++ b/panda/src/light/pointLight.h @@ -15,86 +15,87 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #ifndef POINTLIGHT_H #define POINTLIGHT_H -// -//////////////////////////////////////////////////////////////////// -// Includes -//////////////////////////////////////////////////////////////////// -#include -#include -#include -#include "pmap.h" -#include -#include "light.h" +#include "pandabase.h" -//////////////////////////////////////////////////////////////////// -// Defines -//////////////////////////////////////////////////////////////////// +#include "lightNode.h" //////////////////////////////////////////////////////////////////// // Class : PointLight -// Description : +// Description : A light originating from a single point in space, and +// shining in all directions. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA PointLight : public Light, public NamedNode -{ - PUBLISHED: +class EXPCL_PANDA PointLight : public LightNode { +PUBLISHED: + PointLight(const string &name); - PointLight( const string& name = "" ); - ~PointLight( void ) { } +protected: + PointLight(const PointLight ©); - INLINE Colorf get_specular( void ) const; - INLINE void set_specular( const Colorf& color ); +public: + virtual PandaNode *make_copy() const; + virtual void xform(const LMatrix4f &mat); + virtual void write(ostream &out, int indent_level) const; - INLINE float get_constant_attenuation( void ) const; - INLINE void set_constant_attenuation( float att ); - - INLINE float get_linear_attenuation( void ) const; - INLINE void set_linear_attenuation( float att ); - - INLINE float get_quadratic_attenuation( void ) const; - INLINE void set_quadratic_attenuation( float att ); +PUBLISHED: + INLINE const Colorf &get_specular_color() const; + INLINE void set_specular_color(const Colorf &color); + + INLINE const LVecBase3f &get_attenuation() const; + INLINE void set_attenuation(const LVecBase3f &attenuation); + + INLINE const LPoint3f &get_point() const; + INLINE void set_point(const LPoint3f &point); + +public: + virtual void apply(GraphicsStateGuardian *gsg); +private: + // This is the data that must be cycled between pipeline stages. + class EXPCL_PANDA CData : public CycleData { public: + INLINE CData(); + INLINE CData(const CData ©); + virtual CycleData *make_copy() const; + virtual void write_datagram(BamWriter *manager, Datagram &dg) const; + virtual void fillin(DatagramIterator &scan, BamReader *manager); - virtual void output( ostream &out ) const; - virtual void write( ostream &out, int indent_level = 0 ) const; + Colorf _specular_color; + LVecBase3f _attenuation; + LPoint3f _point; + }; - virtual void apply( GraphicsStateGuardian* gsg ) { - gsg->apply_light( this ); - } + PipelineCycler _cycler; + typedef CycleDataReader CDReader; + typedef CycleDataWriter CDWriter; - protected: +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); - Colorf _specular; - float _constant_attenuation; - float _linear_attenuation; - float _quadratic_attenuation; +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); - public: +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + LightNode::init_type(); + register_type(_type_handle, "PointLight", + LightNode::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - static TypeHandle get_class_type( void ) { - return _type_handle; - } - static void init_type( void ) { - Light::init_type(); - NamedNode::init_type(); - register_type( _type_handle, "PointLight", - Light::get_class_type(), - NamedNode::get_class_type() ); - } - virtual TypeHandle get_type( void ) const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - virtual TypeHandle get_light_type( void ) const { - return get_class_type(); - } - - private: - - static TypeHandle _type_handle; +private: + static TypeHandle _type_handle; }; INLINE ostream &operator << (ostream &out, const PointLight &light) { diff --git a/panda/src/light/spotlight.I b/panda/src/light/spotlight.I index e5212cfa70..862f236958 100644 --- a/panda/src/light/spotlight.I +++ b/panda/src/light/spotlight.I @@ -16,102 +16,111 @@ // //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// -// Function: Spotlight::get_exponent +// Function: Spotlight::CData::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE float Spotlight::get_exponent( void ) const +INLINE Spotlight::CData:: +CData() : + _exponent(0.0f), + _specular_color(1.0f, 1.0f, 1.0f, 1.0f), + _attenuation(1.0f, 0.0f, 0.0f) { - return _exponent; +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::CData::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Spotlight::CData:: +CData(const Spotlight::CData ©) : + _exponent(copy._exponent), + _specular_color(copy._specular_color), + _attenuation(copy._attenuation) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::get_exponent +// Access: Public +// Description: Returns the exponent that controls the amount of +// light falloff from the center of the spotlight. See +// set_exponent(). +//////////////////////////////////////////////////////////////////// +INLINE float Spotlight:: +get_exponent() const { + CDReader cdata(_cycler); + return cdata->_exponent; } //////////////////////////////////////////////////////////////////// // Function: Spotlight::set_exponent // Access: Public -// Description: +// Description: Sets the exponent that controls the amount of light +// falloff from the center of the spotlight. The light +// is attenuated by the cosine of the angle between the +// direction of the light and the direction of the point +// being lighted, raised to the power of this exponent. +// Thus, higher exponents result in a more focused light +// source, regardless of the field-of-view of the lens. //////////////////////////////////////////////////////////////////// -INLINE void Spotlight::set_exponent( float exponent ) -{ - _exponent = exponent; +INLINE void Spotlight:: +set_exponent(float exponent) { + CDWriter cdata(_cycler); + cdata->_exponent = exponent; } //////////////////////////////////////////////////////////////////// -// Function: Spotlight::get_specular +// Function: Spotlight::get_specular_color // Access: Public -// Description: +// Description: Returns the color of specular highlights generated by +// the light. //////////////////////////////////////////////////////////////////// -INLINE Colorf Spotlight::get_specular( void ) const -{ - return _specular; +INLINE const Colorf &Spotlight:: +get_specular_color() const { + CDReader cdata(_cycler); + return cdata->_specular_color; } //////////////////////////////////////////////////////////////////// -// Function: Spotlight::set_specular +// Function: Spotlight::set_specular_color // Access: Public -// Description: +// Description: Sets the color of specular highlights generated by +// the light. //////////////////////////////////////////////////////////////////// -INLINE void Spotlight::set_specular( const Colorf& color ) -{ - _specular = color; +INLINE void Spotlight:: +set_specular_color(const Colorf &color) { + CDWriter cdata(_cycler); + cdata->_specular_color = color; } //////////////////////////////////////////////////////////////////// -// Function: Spotlight::get_constant_attenuation +// Function: Spotlight::get_attenuation // Access: Public -// Description: +// Description: Returns the terms of the attenuation equation for the +// light. These are, in order, the constant, linear, +// and quadratic terms based on the distance from the +// point to the vertex. //////////////////////////////////////////////////////////////////// -INLINE float Spotlight::get_constant_attenuation( void ) const -{ - return _constant_attenuation; +INLINE const LVecBase3f &Spotlight:: +get_attenuation() const { + CDReader cdata(_cycler); + return cdata->_attenuation; } //////////////////////////////////////////////////////////////////// -// Function: Spotlight::set_constant_attenuation +// Function: Spotlight::set_attenuation // Access: Public -// Description: +// Description: Sets the terms of the attenuation equation for the +// light. These are, in order, the constant, linear, +// and quadratic terms based on the distance from the +// point to the vertex. //////////////////////////////////////////////////////////////////// -INLINE void Spotlight::set_constant_attenuation( float att ) -{ - _constant_attenuation = att; -} - -//////////////////////////////////////////////////////////////////// -// Function: Spotlight::get_linear_attenuation -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE float Spotlight::get_linear_attenuation( void ) const -{ - return _linear_attenuation; -} - -//////////////////////////////////////////////////////////////////// -// Function: Spotlight::set_linear_attenuation -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void Spotlight::set_linear_attenuation( float att ) -{ - _linear_attenuation = att; -} - -//////////////////////////////////////////////////////////////////// -// Function: Spotlight::get_quadratic_attenuation -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE float Spotlight::get_quadratic_attenuation( void ) const -{ - return _quadratic_attenuation; -} - -//////////////////////////////////////////////////////////////////// -// Function: Spotlight::set_quadratic_attenuation -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void Spotlight::set_quadratic_attenuation( float att ) -{ - _quadratic_attenuation = att; +INLINE void Spotlight:: +set_attenuation(const LVecBase3f &attenuation) { + CDWriter cdata(_cycler); + cdata->_attenuation = attenuation; } diff --git a/panda/src/light/spotlight.cxx b/panda/src/light/spotlight.cxx index 594066e54c..829426722c 100644 --- a/panda/src/light/spotlight.cxx +++ b/panda/src/light/spotlight.cxx @@ -15,50 +15,124 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #include "spotlight.h" -#include "lightTransition.h" -#include "config_light.h" +#include "graphicsStateGuardian.h" +#include "bamWriter.h" +#include "bamReader.h" +#include "datagram.h" +#include "datagramIterator.h" +#include "colorAttrib.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//////////////////////////////////////////////////////////////////// -// Static variables -//////////////////////////////////////////////////////////////////// TypeHandle Spotlight::_type_handle; //////////////////////////////////////////////////////////////////// -// Function: Spotlight::Constructor -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -Spotlight::Spotlight(const string& name) : LensNode(name) -{ - set_exponent(1); - - set_color(Colorf(1, 1, 1, 1)); - set_specular(Colorf(1, 1, 1, 1)); - - set_constant_attenuation(1); - set_linear_attenuation(0); - set_quadratic_attenuation(0); -} - -//////////////////////////////////////////////////////////////////// -// Function: Spotlight::output +// Function: Spotlight::CData::make_copy // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// +CycleData *Spotlight::CData:: +make_copy() const { + return new CData(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::CData::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void Spotlight::CData:: +write_datagram(BamWriter *, Datagram &dg) const { + dg.add_float32(_exponent); + _specular_color.write_datagram(dg); + _attenuation.write_datagram(dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::CData::fillin +// Access: Public, Virtual +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new Light. +//////////////////////////////////////////////////////////////////// +void Spotlight::CData:: +fillin(DatagramIterator &scan, BamReader *) { + _exponent = scan.get_float32(); + _specular_color.read_datagram(scan); + _attenuation.read_datagram(scan); +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +Spotlight:: +Spotlight(const string &name) : + LightLensNode(name) +{ + cerr << "Creating " << *this << ", this = " << (int)this + << " node this = " << (int)(PandaNode *)this + << " light this = " << (int)(Light *)this + << " bounded this = " << (int)(BoundedObject *)this << "\n"; + _internal_bound.get_bound(); + cerr << "got bound 1\n"; + get_internal_bound(); + cerr << "got bound 2\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::foo +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// void Spotlight:: -output(ostream &out) const { - NamedNode::output(out); +foo() { + cerr << "checking bound\n"; + get_internal_bound(); + cerr << "done\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::Copy Constructor +// Access: Protected +// Description: Do not call the copy constructor directly; instead, +// use make_copy() or copy_subgraph() to make a copy of +// a node. +//////////////////////////////////////////////////////////////////// +Spotlight:: +Spotlight(const Spotlight ©) : + LightLensNode(copy), + _cycler(copy._cycler) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::make_copy +// Access: Public, Virtual +// Description: Returns a newly-allocated PandaNode that is a shallow +// copy of this one. It will be a different pointer, +// but its internal data may or may not be shared with +// that of the original PandaNode. No children will be +// copied. +//////////////////////////////////////////////////////////////////// +PandaNode *Spotlight:: +make_copy() const { + return new Spotlight(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::xform +// Access: Public, Virtual +// Description: Transforms the contents of this PandaNode by the +// indicated matrix, if it means anything to do so. For +// most kinds of PandaNodes, this does nothing. +//////////////////////////////////////////////////////////////////// +void Spotlight:: +xform(const LMatrix4f &mat) { + LightLensNode::xform(mat); + mark_viz_stale(); } //////////////////////////////////////////////////////////////////// @@ -69,47 +143,53 @@ output(ostream &out) const { void Spotlight:: write(ostream &out, int indent_level) const { indent(out, indent_level) << *this << ":\n"; - indent(out, indent_level + 2) << "color " << _color << "\n"; - indent(out, indent_level + 2) << "specular " << _specular << "\n"; indent(out, indent_level + 2) - << "attenuation " << _constant_attenuation << ", " - << _linear_attenuation << ", " << _quadratic_attenuation << "\n"; - indent(out, indent_level + 2) << "exponent " << _exponent << "\n"; + << "color " << get_color() << "\n"; + indent(out, indent_level + 2) + << "specular color " << get_specular_color() << "\n"; + indent(out, indent_level + 2) + << "attenuation " << get_attenuation() << "\n"; + indent(out, indent_level + 2) + << "exponent " << get_exponent() << "\n"; + + Lens *lens = get_lens(); + if (lens != (Lens *)NULL) { + lens->write(out, indent_level + 2); + } } //////////////////////////////////////////////////////////////////// -// Function: Spotlight::get_cutoff_angle -// Access: +// Function: Spotlight::apply +// Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// -float Spotlight::get_cutoff_angle(void) const -{ - Lens* proj = ((LensNode *)this)->get_lens(); - float cutoff = 0; - if (proj->get_type() == PerspectiveLens::get_class_type()) { - const LVecBase2f &fov = ((PerspectiveLens *)proj)->get_fov(); - cutoff = fov[0]; - } - else - light_cat.error() - << "Spotlight::get_cutoff_angle() - spotlight has a non " - << "perspective lens!" << endl; - return cutoff; +void Spotlight:: +apply(GraphicsStateGuardian *gsg) { + gsg->apply_light(this); } //////////////////////////////////////////////////////////////////// // Function: Spotlight::make_image -// Access: -// Description: +// Access: Public +// Description: Generates an image into the indicated texture of a +// circle with a soft edge that corresponds to the +// falloff of the spotlight. This is intended to be +// used to implement projected texture spotlights; the +// image can be applied to geometry with UV's computed +// appropriate to simulate the texture's region of +// influence. +// +// Returns true if the image is successfully generated, +// false otherwise. //////////////////////////////////////////////////////////////////// -bool Spotlight::make_image(Texture* texture, float radius) -{ +bool Spotlight:: +make_image(Texture *texture, float radius) { if (texture == NULL) { light_cat.error() << "Spotlight::make_image() - NULL texture" << endl; return false; } - PixelBuffer* pb = texture->_pbuffer; + PixelBuffer *pb = texture->_pbuffer; int size = pb->get_xsize(); if (size == 0) { light_cat.error() @@ -117,14 +197,13 @@ bool Spotlight::make_image(Texture* texture, float radius) return false; } - uchar color[3]; - color[0] = (int)(_color[0] * 255.0f); - color[1] = (int)(_color[1] * 255.0f); - color[2] = (int)(_color[2] * 255.0f); + const Colorf &color = get_color(); + + RGBColorf scaled_color; + scaled_color[0] = (color[0] * 255.0f); + scaled_color[1] = (color[1] * 255.0f); + scaled_color[2] = (color[2] * 255.0f); - // float cutoff = get_cutoff_angle(); - // float dist = 1 / (float)tan(cutoff); - // int bufsize = size * size * 3; int half_width = (size - 2) / 2; float dXY = 1 / (float)half_width; float Y = dXY + dXY; @@ -144,13 +223,13 @@ bool Spotlight::make_image(Texture* texture, float radius) intensity = 1.0f; else if (D < 1.0f) intensity = pow(cos((D-radius) / - (1.0f-radius) * (MathNumbers::pi_f*0.5f)), _exponent); + (1.0f-radius) * (MathNumbers::pi_f*0.5f)), get_exponent()); else intensity = 0; - C[0] = (uchar)(intensity * color[0]); - C[1] = (uchar)(intensity * color[1]); - C[2] = (uchar)(intensity * color[2]); + C[0] = (uchar)(intensity * scaled_color[0]); + C[1] = (uchar)(intensity * scaled_color[1]); + C[2] = (uchar)(intensity * scaled_color[2]); tx = x + half_width; @@ -173,100 +252,90 @@ bool Spotlight::make_image(Texture* texture, float radius) } //////////////////////////////////////////////////////////////////// -// Function: Spotlight::make_geometry -// Access: -// Description: +// Function: Spotlight::fill_viz_geom +// Access: Protected, Virtual +// Description: Fills the indicated GeomNode up with Geoms suitable +// for rendering this light. //////////////////////////////////////////////////////////////////// -NamedNode* Spotlight:: -make_geometry(float intensity, float length, int num_facets) -{ - Colorf diffuse = _color; - diffuse[3] = intensity; - Colorf black(0.0f, 0.0f, 0.0f, intensity); - float radius = length * (float)tan(deg_2_rad(get_cutoff_angle())); - float ang_inc = 2.0f*MathNumbers::pi_f / (float)num_facets; - int num_verts = num_facets + 1; - int num_indices = num_facets + 2; - LVector3f offset(0.0f, length, 0.0f); - LPoint3f first_last_vert(radius, length, 0.0f); - - PTA_Vertexf coords=PTA_Vertexf::empty_array(num_verts); - PTA_ushort vindex=PTA_ushort::empty_array(num_indices); - PTA_Colorf colors=PTA_Colorf::empty_array(2); - PTA_ushort cindex=PTA_ushort::empty_array(num_indices); - PTA_int lengths=PTA_int::empty_array(1); - - lengths[0] = num_indices; - - float ang = ang_inc; - LPoint3f origin(0.0f, 0.0f, 0.0f); - LVector3f x_axis(1.0f, 0.0f, 0.0f); - LVector3f z_axis(0.0f, 0.0f, 1.0f); - LPoint3f dx, dz; - float t; - - coords[0] = origin; - coords[1] = first_last_vert; - vindex[0] = 0; - vindex[1] = 1; - vindex[num_indices-1] = 1; - - int i; - for (i = 2; i < num_indices-1; i++) { - float sine,cosine; - - csincos(ang,&sine,&cosine); - t = cosine * radius; - dx = x_axis * t; - t = sine * radius; - dz = z_axis * t; - coords[i] = dx + dz + offset; - ang += ang_inc; - vindex[i] = i; +void Spotlight:: +fill_viz_geom(qpGeomNode *viz_geom) { + Lens *lens = get_lens(); + if (lens == (Lens *)NULL) { + return; + } + + PT(Geom) geom = lens->make_geometry(); + if (geom == (Geom *)NULL) { + return; } - colors[0] = diffuse; - colors[1] = black; - cindex[0] = 0; - for (i = 1; i < num_indices; i++) - cindex[i] = 1; - - GeomTrifan* tfan = new GeomTrifan; - tfan->set_coords(coords, vindex); - tfan->set_colors(colors, G_PER_VERTEX, cindex); - tfan->set_num_prims(1); - tfan->set_lengths(lengths); - - GeomNode* geomnode = new GeomNode("spotlight_frustum_geom"); - geomnode->add_geom(tfan); - - NamedNode* root = new NamedNode("spotlight_frustum"); - RenderRelation* root_arc = new RenderRelation(root, geomnode); - - // Disable lighting - LightTransition *light_trans = - new LightTransition(LightTransition::all_off()); - root_arc->set_transition(light_trans); - - // Disable texturing - TextureTransition *tex_trans = - new TextureTransition(TextureTransition::off()); - root_arc->set_transition(tex_trans); - - // Turn off writes to Z - DepthWriteTransition *depth_trans = - new DepthWriteTransition(DepthWriteTransition::off()); - root_arc->set_transition(depth_trans); - - // Enable transparency - TransparencyTransition *col_trans = - new TransparencyTransition(TransparencyProperty::M_alpha); - root_arc->set_transition(col_trans); - - // Disable culling - CullFaceTransition *cull_trans = - new CullFaceTransition(CullFaceProperty::M_cull_none); - root_arc->set_transition(cull_trans); - - return root; + viz_geom->add_geom(geom, get_viz_state()); +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::get_viz_state +// Access: Private +// Description: Returns a RenderState for rendering the spotlight +// visualization. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) Spotlight:: +get_viz_state() { + return RenderState::make + (ColorAttrib::make_flat(get_color())); +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// Spotlight. +//////////////////////////////////////////////////////////////////// +void Spotlight:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void Spotlight:: +write_datagram(BamWriter *manager, Datagram &dg) { + LightLensNode::write_datagram(manager, dg); + manager->write_cdata(dg, _cycler); +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type Spotlight is encountered +// in the Bam file. It should create the Spotlight +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *Spotlight:: +make_from_bam(const FactoryParams ¶ms) { + Spotlight *node = new Spotlight(""); + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + node->fillin(scan, manager); + + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: Spotlight::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new Spotlight. +//////////////////////////////////////////////////////////////////// +void Spotlight:: +fillin(DatagramIterator &scan, BamReader *manager) { + LightLensNode::fillin(scan, manager); + manager->read_cdata(scan, _cycler); } diff --git a/panda/src/light/spotlight.h b/panda/src/light/spotlight.h index ba2962948a..b336b3ae5d 100644 --- a/panda/src/light/spotlight.h +++ b/panda/src/light/spotlight.h @@ -15,98 +15,105 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #ifndef SPOTLIGHT_H #define SPOTLIGHT_H -// -//////////////////////////////////////////////////////////////////// -// Includes -//////////////////////////////////////////////////////////////////// -#include -#include -#include -#include "pmap.h" -#include -#include -#include "light.h" -#include +#include "pandabase.h" -//////////////////////////////////////////////////////////////////// -// Defines -//////////////////////////////////////////////////////////////////// +#include "lightLensNode.h" //////////////////////////////////////////////////////////////////// // Class : Spotlight -// Description : +// Description : A light originating from a single point in space, and +// shining in a particular direction, with a cone-shaped +// falloff. +// +// The Spotlight frustum is defined using a Lens, so it +// can have any of the properties that a camera lens can +// have. +// +// Note that the class is named Spotlight instead of +// SpotLight, because "spotlight" is a single English +// word, instead of two words. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA Spotlight : public Light, public LensNode -{ - PUBLISHED: +class EXPCL_PANDA Spotlight : public LightLensNode { +PUBLISHED: + Spotlight(const string &name); + void foo(); - Spotlight( const string& name = "" ); - ~Spotlight( void ) { } +protected: + Spotlight(const Spotlight ©); - INLINE float get_exponent( void ) const; - INLINE void set_exponent( float exponent ); +public: + virtual PandaNode *make_copy() const; + virtual void xform(const LMatrix4f &mat); + virtual void write(ostream &out, int indent_level) const; - float get_cutoff_angle( void ) const; +PUBLISHED: + INLINE float get_exponent() const; + INLINE void set_exponent(float exponent); + + INLINE const Colorf &get_specular_color() const; + INLINE void set_specular_color(const Colorf &color); + + INLINE const LVecBase3f &get_attenuation() const; + INLINE void set_attenuation(const LVecBase3f &attenuation); + +public: + virtual void apply(GraphicsStateGuardian *gsg); - INLINE Colorf get_specular( void ) const; - INLINE void set_specular( const Colorf& color ); + bool make_image(Texture *texture, float radius); - INLINE float get_constant_attenuation( void ) const; - INLINE void set_constant_attenuation( float att ); +protected: + virtual void fill_viz_geom(qpGeomNode *viz_geom); - INLINE float get_linear_attenuation( void ) const; - INLINE void set_linear_attenuation( float att ); - - INLINE float get_quadratic_attenuation( void ) const; - INLINE void set_quadratic_attenuation( float att ); +private: + CPT(RenderState) get_viz_state(); +private: + // This is the data that must be cycled between pipeline stages. + class EXPCL_PANDA CData : public CycleData { public: + INLINE CData(); + INLINE CData(const CData ©); + virtual CycleData *make_copy() const; + virtual void write_datagram(BamWriter *manager, Datagram &dg) const; + virtual void fillin(DatagramIterator &scan, BamReader *manager); - virtual void output( ostream &out ) const; - virtual void write( ostream &out, int indent_level = 0 ) const; + float _exponent; + Colorf _specular_color; + LVecBase3f _attenuation; + }; - virtual void apply( GraphicsStateGuardian* gsg ) { - gsg->apply_light( this ); - } + PipelineCycler _cycler; + typedef CycleDataReader CDReader; + typedef CycleDataWriter CDWriter; - bool make_image(Texture* texture, float radius = 0.7); - NamedNode* make_geometry(float intensity = 0.05, float length = 20.0, - int num_facets = 36); +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); - protected: +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); - float _exponent; - Colorf _specular; - float _constant_attenuation; - float _linear_attenuation; - float _quadratic_attenuation; +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + LightLensNode::init_type(); + register_type(_type_handle, "Spotlight", + LightLensNode::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - public: - - static TypeHandle get_class_type( void ) { - return _type_handle; - } - static void init_type( void ) { - Light::init_type(); - LensNode::init_type(); - register_type( _type_handle, "Spotlight", - Light::get_class_type(), - LensNode::get_class_type() ); - } - virtual TypeHandle get_type( void ) const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - virtual TypeHandle get_light_type( void ) const { - return get_class_type(); - } - - private: - - static TypeHandle _type_handle; +private: + static TypeHandle _type_handle; }; INLINE ostream &operator << (ostream &out, const Spotlight &light) { diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 8e7ee7609e..2177ab9e4e 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -52,6 +52,7 @@ renderModeAttrib.I renderModeAttrib.h \ renderState.I renderState.h \ qpsceneGraphReducer.I qpsceneGraphReducer.h \ + sceneSetup.I sceneSetup.h \ selectiveChildNode.I selectiveChildNode.h \ qpsequenceNode.I qpsequenceNode.h \ showBoundsEffect.I showBoundsEffect.h \ @@ -111,6 +112,7 @@ renderModeAttrib.cxx \ renderState.cxx \ qpsceneGraphReducer.cxx \ + sceneSetup.cxx \ selectiveChildNode.cxx \ qpsequenceNode.cxx \ showBoundsEffect.cxx \ @@ -172,6 +174,7 @@ renderModeAttrib.I renderModeAttrib.h \ renderState.I renderState.h \ qpsceneGraphReducer.I qpsceneGraphReducer.h \ + sceneSetup.I sceneSetup.h \ selectiveChildNode.I selectiveChildNode.h \ qpsequenceNode.I qpsequenceNode.h \ showBoundsEffect.I showBoundsEffect.h \ diff --git a/panda/src/pgraph/cullHandler.cxx b/panda/src/pgraph/cullHandler.cxx index 49c8bda51f..c796444220 100644 --- a/panda/src/pgraph/cullHandler.cxx +++ b/panda/src/pgraph/cullHandler.cxx @@ -29,11 +29,9 @@ // Description: //////////////////////////////////////////////////////////////////// CullHandler:: -~CullHandler() -{ +~CullHandler() { } - //////////////////////////////////////////////////////////////////// // Function: CullHandler::record_object // Access: Public, Virtual diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index 925f067e56..b0f524157a 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -157,6 +157,7 @@ get_fake_view_frustum_cull_state() { TextureAttrib::make_off(), RenderModeAttrib::make(RenderModeAttrib::M_wireframe), 1000); + state->ref(); // once more to guard against static destruction } return state; } diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 62281104b7..602a938b55 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -1143,6 +1143,18 @@ is_geom_node() const { return false; } +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::as_light +// Access: Public, Virtual +// Description: Cross-casts the node to a Light pointer, if it is one +// of the four kinds of Light nodes, or returns NULL if +// it is not. +//////////////////////////////////////////////////////////////////// +Light *PandaNode:: +as_light() { + return NULL; +} + //////////////////////////////////////////////////////////////////// // Function: PandaNode::propagate_stale_bound // Access: Protected, Virtual @@ -1244,7 +1256,8 @@ recompute_bound() { //////////////////////////////////////////////////////////////////// BoundingVolume *PandaNode:: recompute_internal_bound() { - return _internal_bound.recompute_bound(); + BoundingVolume *result = _internal_bound.recompute_bound(); + return result; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index ddc91fa722..bd5ed8de7b 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -43,6 +43,7 @@ class qpNodePathComponent; class qpCullTraverser; class CullTraverserData; +class Light; //////////////////////////////////////////////////////////////////// // Class : PandaNode @@ -163,6 +164,7 @@ PUBLISHED: public: virtual bool is_geom_node() const; + virtual Light *as_light(); protected: // Inherited from BoundedObject diff --git a/panda/src/pgraph/qpcullTraverser.I b/panda/src/pgraph/qpcullTraverser.I index db754d3890..b71184a56e 100644 --- a/panda/src/pgraph/qpcullTraverser.I +++ b/panda/src/pgraph/qpcullTraverser.I @@ -17,6 +17,59 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: qpCullTraverser::set_scene +// Access: Public +// Description: Sets the SceneSetup object that indicates the initial +// camera position, etc. This must be called before +// traversal begins. +//////////////////////////////////////////////////////////////////// +INLINE void qpCullTraverser:: +set_scene(SceneSetup *scene_setup) { + _scene_setup = scene_setup; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCullTraverser::get_scene +// Access: Public +// Description: Returns the SceneSetup object. +//////////////////////////////////////////////////////////////////// +INLINE SceneSetup *qpCullTraverser:: +get_scene() const { + return _scene_setup; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCullTraverser::get_camera_transform +// Access: Public +// Description: Returns the position of the camera relative to the +// starting node, without any compensating +// coordinate-system transforms that might have been +// introduced for the purposes of rendering. +//////////////////////////////////////////////////////////////////// +INLINE const TransformState *qpCullTraverser:: +get_camera_transform() const { + return _scene_setup->get_camera_transform(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCullTraverser::get_render_transform +// Access: Public +// Description: Returns the position of the starting node relative +// to the camera, pretransformed as appropriate for +// rendering. +// +// Note that this value is always the position of the +// starting node, not the current node, even if it is +// sampled during a traversal. To get the render +// transform of the current node check in the current +// CullTraverserData. +//////////////////////////////////////////////////////////////////// +INLINE const TransformState *qpCullTraverser:: +get_render_transform() const { + return _scene_setup->get_render_transform(); +} + //////////////////////////////////////////////////////////////////// // Function: qpCullTraverser::set_initial_state // Access: Public @@ -41,6 +94,31 @@ get_initial_state() const { return _initial_state; } +//////////////////////////////////////////////////////////////////// +// Function: qpCullTraverser::set_depth_offset_decals +// Access: Public +// Description: Sets the depth_offset_decals flag. If this is true, +// decals will be rendered using DepthOffsetAttribs; +// otherwise, decals will be rendered with a more +// expensive three-pass system. This is normally set +// from the corresponding flag in the GSG. +//////////////////////////////////////////////////////////////////// +INLINE void qpCullTraverser:: +set_depth_offset_decals(bool flag) { + _depth_offset_decals = flag; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCullTraverser::get_depth_offset_decals +// Access: Public +// Description: Returns the depth_offset_decals flag. See +// set_depth_offset_decals(). +//////////////////////////////////////////////////////////////////// +INLINE bool qpCullTraverser:: +get_depth_offset_decals() const { + return _depth_offset_decals; +} + //////////////////////////////////////////////////////////////////// // Function: qpCullTraverser::set_camera_mask // Access: Public @@ -64,62 +142,6 @@ get_camera_mask() const { return _camera_mask; } -//////////////////////////////////////////////////////////////////// -// Function: qpCullTraverser::set_camera_transform -// Access: Public -// Description: Specifies the position of the camera relative to the -// starting node, without any compensating -// coordinate-system transforms that might have been -// introduced for the purposes of rendering. -//////////////////////////////////////////////////////////////////// -INLINE void qpCullTraverser:: -set_camera_transform(const TransformState *camera_transform) { - _camera_transform = camera_transform; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpCullTraverser::get_camera_transform -// Access: Public -// Description: Returns the position of the camera relative to the -// starting node, without any compensating -// coordinate-system transforms that might have been -// introduced for the purposes of rendering. -//////////////////////////////////////////////////////////////////// -INLINE const TransformState *qpCullTraverser:: -get_camera_transform() const { - return _camera_transform; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpCullTraverser::set_render_transform -// Access: Public -// Description: Specifies the position of the starting node relative -// to the camera, pretransformed as appropriate for -// rendering. -//////////////////////////////////////////////////////////////////// -INLINE void qpCullTraverser:: -set_render_transform(const TransformState *render_transform) { - _render_transform = render_transform; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpCullTraverser::get_render_transform -// Access: Public -// Description: Returns the position of the starting node relative -// to the camera, pretransformed as appropriate for -// rendering. -// -// Note that this value is always the position of the -// starting node, not the current node, even if it is -// sampled during a traversal. To get the render -// transform of the current node check in the current -// CullTraverserData. -//////////////////////////////////////////////////////////////////// -INLINE const TransformState *qpCullTraverser:: -get_render_transform() const { - return _render_transform; -} - //////////////////////////////////////////////////////////////////// // Function: qpCullTraverser::set_view_frustum // Access: Public diff --git a/panda/src/pgraph/qpcullTraverser.cxx b/panda/src/pgraph/qpcullTraverser.cxx index 3fcce17610..7cfb682978 100644 --- a/panda/src/pgraph/qpcullTraverser.cxx +++ b/panda/src/pgraph/qpcullTraverser.cxx @@ -30,6 +30,7 @@ #include "colorAttrib.h" #include "renderModeAttrib.h" #include "cullFaceAttrib.h" +#include "depthOffsetAttrib.h" TypeHandle qpCullTraverser::_type_handle; @@ -42,9 +43,7 @@ TypeHandle qpCullTraverser::_type_handle; qpCullTraverser:: qpCullTraverser() { _initial_state = RenderState::make_empty(); - _camera_mask = DrawMask::all_on(); - _camera_transform = DCAST(TransformState, TransformState::make_identity()); - _render_transform = DCAST(TransformState, TransformState::make_identity()); + _depth_offset_decals = false; _cull_handler = (CullHandler *)NULL; } @@ -55,10 +54,9 @@ qpCullTraverser() { //////////////////////////////////////////////////////////////////// qpCullTraverser:: qpCullTraverser(const qpCullTraverser ©) : + _scene_setup(copy._scene_setup), _initial_state(copy._initial_state), - _camera_mask(copy._camera_mask), - _camera_transform(copy._camera_transform), - _render_transform(copy._render_transform), + _depth_offset_decals(copy._depth_offset_decals), _view_frustum(copy._view_frustum), _guard_band(copy._guard_band), _cull_handler(copy._cull_handler) @@ -71,11 +69,12 @@ qpCullTraverser(const qpCullTraverser ©) : // Description: Begins the traversal from the indicated node. //////////////////////////////////////////////////////////////////// void qpCullTraverser:: -traverse(qpNodePath &root) { +traverse(const qpNodePath &root) { nassertv(_cull_handler != (CullHandler *)NULL); - - CullTraverserData data(root, - _render_transform, TransformState::make_identity(), + nassertv(_scene_setup != (SceneSetup *)NULL); + + CullTraverserData data(root, get_render_transform(), + TransformState::make_identity(), _initial_state, _view_frustum, _guard_band); traverse(data); } @@ -112,7 +111,7 @@ traverse(CullTraverserData &data) { // now. This maybe isn't the perfect time to call it, but it's // good enough; and at this time we have all the information we // need for it. - fog->get_fog()->adjust_to_camera(_camera_transform); + fog->get_fog()->adjust_to_camera(get_camera_transform()); } if (node->has_cull_callback()) { @@ -133,10 +132,13 @@ traverse(CullTraverserData &data) { // node's space. //////////////////////////////////////////////////////////////////// void qpCullTraverser:: -traverse_below(const CullTraverserData &data) { +traverse_below(CullTraverserData &data) { PandaNode *node = data.node(); const RenderEffects *node_effects = node->get_effects(); - if (node_effects->has_decal()) { + bool has_decal = node_effects->has_decal(); + if (has_decal && !_depth_offset_decals) { + // Start the three-pass decal rendering if we're not using + // DepthOffsetAttribs to implement decals. start_decal(data); } else { @@ -150,7 +152,21 @@ traverse_below(const CullTraverserData &data) { _cull_handler->record_object(object); } } - + + if (has_decal) { + // If we *are* implementing decals with DepthOffsetAttribs, + // apply it now, so that each child of this node gets offset by + // a tiny amount. + data._state = data._state->compose(get_depth_offset_state()); +#ifndef NDEBUG + // This is just a sanity check message. + if (!node->is_geom_node()) { + pgraph_cat.error() + << "DecalEffect applied to " << *node << ", not a GeomNode.\n"; + } +#endif + } + // Now visit all the node's children. We cannot use the // node->get_children() interface, because that will keep a read // pointer open, and we might end up changing this node during the @@ -246,6 +262,7 @@ get_bounds_outer_viz_state() { (ColorAttrib::make_flat(Colorf(0.3f, 1.0f, 0.5f, 1.0f)), RenderModeAttrib::make(RenderModeAttrib::M_wireframe), CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise)); + state->ref(); // once more to guard against static destruction } return state; } @@ -266,6 +283,26 @@ get_bounds_inner_viz_state() { (ColorAttrib::make_flat(Colorf(0.15f, 0.5f, 0.25f, 1.0f)), RenderModeAttrib::make(RenderModeAttrib::M_wireframe), CullFaceAttrib::make(CullFaceAttrib::M_cull_counter_clockwise)); + state->ref(); // once more to guard against static destruction + } + return state; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCullTraverser::get_depth_offset_state +// Access: Private, Static +// Description: Returns a RenderState for increasing the DepthOffset +// by one. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) qpCullTraverser:: +get_depth_offset_state() { + // Once someone asks for this pointer, we hold its reference count + // and never free it. + static CPT(RenderState) state = (const RenderState *)NULL; + if (state == (const RenderState *)NULL) { + state = RenderState::make + (DepthOffsetAttrib::make(1)); + state->ref(); // once more to guard against static destruction } return state; } diff --git a/panda/src/pgraph/qpcullTraverser.h b/panda/src/pgraph/qpcullTraverser.h index c287b1f9d8..ed5ee4e957 100644 --- a/panda/src/pgraph/qpcullTraverser.h +++ b/panda/src/pgraph/qpcullTraverser.h @@ -22,6 +22,7 @@ #include "pandabase.h" #include "geom.h" +#include "sceneSetup.h" #include "renderState.h" #include "transformState.h" #include "geometricBoundingVolume.h" @@ -48,17 +49,20 @@ public: qpCullTraverser(); qpCullTraverser(const qpCullTraverser ©); + INLINE void set_scene(SceneSetup *scene_setup); + INLINE SceneSetup *get_scene() const; + + INLINE void set_camera_mask(const DrawMask &camera_mask); + INLINE const DrawMask &get_camera_mask() const; + + INLINE const TransformState *get_camera_transform() const; + INLINE const TransformState *get_render_transform() const; + INLINE void set_initial_state(const RenderState *initial_state); INLINE const RenderState *get_initial_state() const; - INLINE void set_camera_mask(const DrawMask &draw_mask); - INLINE const DrawMask &get_camera_mask() const; - - INLINE void set_camera_transform(const TransformState *camera_transform); - INLINE const TransformState *get_camera_transform() const; - - INLINE void set_render_transform(const TransformState *render_transform); - INLINE const TransformState *get_render_transform() const; + INLINE void set_depth_offset_decals(bool flag); + INLINE bool get_depth_offset_decals() const; INLINE void set_view_frustum(GeometricBoundingVolume *view_frustum); INLINE GeometricBoundingVolume *get_view_frustum() const; @@ -69,24 +73,24 @@ public: INLINE void set_cull_handler(CullHandler *cull_handler); INLINE CullHandler *get_cull_handler() const; - void traverse(qpNodePath &root); + void traverse(const qpNodePath &root); void traverse(CullTraverserData &data); - void traverse_below(const CullTraverserData &data); + void traverse_below(CullTraverserData &data); private: void show_bounds(CullTraverserData &data); PT(Geom) make_bounds_viz(const BoundingVolume &vol); CPT(RenderState) get_bounds_outer_viz_state(); CPT(RenderState) get_bounds_inner_viz_state(); - + CPT(RenderState) get_depth_offset_state(); void start_decal(const CullTraverserData &data); CullableObject *r_get_decals(CullTraverserData &data, CullableObject *decals); - CPT(RenderState) _initial_state; + PT(SceneSetup) _scene_setup; DrawMask _camera_mask; - CPT(TransformState) _camera_transform; - CPT(TransformState) _render_transform; + CPT(RenderState) _initial_state; + bool _depth_offset_decals; PT(GeometricBoundingVolume) _view_frustum; PT(GeometricBoundingVolume) _guard_band; CullHandler *_cull_handler; diff --git a/panda/src/pgraph/qplensNode.I b/panda/src/pgraph/qplensNode.I index 8a38886336..5f35d0fa64 100644 --- a/panda/src/pgraph/qplensNode.I +++ b/panda/src/pgraph/qplensNode.I @@ -17,29 +17,6 @@ //////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////// -// Function: qpLensNode::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE qpLensNode:: -qpLensNode(const string &name) : - PandaNode(name) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: qpLensNode::Copy Constructor -// Access: Protected -// Description: -//////////////////////////////////////////////////////////////////// -INLINE qpLensNode:: -qpLensNode(const qpLensNode ©) : - PandaNode(copy), - _lens(copy._lens) -{ -} - //////////////////////////////////////////////////////////////////// // Function: copy_lens // Access: Public @@ -73,6 +50,6 @@ set_lens(Lens *lens) { // not yet a Lens associated. //////////////////////////////////////////////////////////////////// INLINE Lens *qpLensNode:: -get_lens() { +get_lens() const { return _lens; } diff --git a/panda/src/pgraph/qplensNode.cxx b/panda/src/pgraph/qplensNode.cxx index 4fdad50a9c..62567839f2 100644 --- a/panda/src/pgraph/qplensNode.cxx +++ b/panda/src/pgraph/qplensNode.cxx @@ -21,6 +21,42 @@ TypeHandle qpLensNode::_type_handle; +//////////////////////////////////////////////////////////////////// +// Function: qpLensNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +qpLensNode:: +qpLensNode(const string &name) : + PandaNode(name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: qpLensNode::Copy Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +qpLensNode:: +qpLensNode(const qpLensNode ©) : + PandaNode(copy), + _lens(copy._lens) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: qpLensNode::xform +// Access: Public, Virtual +// Description: Transforms the contents of this PandaNode by the +// indicated matrix, if it means anything to do so. For +// most kinds of PandaNodes, this does nothing. +//////////////////////////////////////////////////////////////////// +void qpLensNode:: +xform(const LMatrix4f &mat) { + PandaNode::xform(mat); + // We need to actually transform the lens here. +} + //////////////////////////////////////////////////////////////////// // Function: qpLensNode::make_copy // Access: Public, Virtual diff --git a/panda/src/pgraph/qplensNode.h b/panda/src/pgraph/qplensNode.h index ad84b958a1..63bd2cf0bf 100644 --- a/panda/src/pgraph/qplensNode.h +++ b/panda/src/pgraph/qplensNode.h @@ -34,20 +34,21 @@ //////////////////////////////////////////////////////////////////// class EXPCL_PANDA qpLensNode : public PandaNode { PUBLISHED: - INLINE qpLensNode(const string &name); + qpLensNode(const string &name); protected: - INLINE qpLensNode(const qpLensNode ©); + qpLensNode(const qpLensNode ©); public: virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level = 0) const; + virtual void xform(const LMatrix4f &mat); virtual PandaNode *make_copy() const; PUBLISHED: INLINE void copy_lens(const Lens &lens); INLINE void set_lens(Lens *lens); - INLINE Lens *get_lens(); + INLINE Lens *get_lens() const; bool is_in_view(const LPoint3f &pos); diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index d226ff069d..3ef7ec1a29 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -119,6 +119,7 @@ RenderState:: // as to the computed result (if any), so neither object will be // tempted to destruct. Go ahead and remove ourselves from the // other cache. + nassertv(other->_composition_cache.count(this) == 1); other->_composition_cache.erase(this); // It's all right if the other state destructs now, since it diff --git a/panda/src/pgraph/sceneSetup.I b/panda/src/pgraph/sceneSetup.I new file mode 100644 index 0000000000..662e3d9ca0 --- /dev/null +++ b/panda/src/pgraph/sceneSetup.I @@ -0,0 +1,145 @@ +// Filename: sceneSetup.I +// Created by: drose (27Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE SceneSetup:: +SceneSetup() { + _camera_transform = TransformState::make_identity(); + _render_transform = TransformState::make_identity(); +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::set_scene_root +// Access: Public +// Description: Specifies the root node of the scene. +//////////////////////////////////////////////////////////////////// +INLINE void SceneSetup:: +set_scene_root(const qpNodePath &scene_root) { + _scene_root = scene_root; +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::get_scene_root +// Access: Public +// Description: Returns the root node of the scene. +//////////////////////////////////////////////////////////////////// +INLINE const qpNodePath &SceneSetup:: +get_scene_root() const { + return _scene_root; +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::set_camera +// Access: Public +// Description: Specifies the camera used to render the scene. +//////////////////////////////////////////////////////////////////// +INLINE void SceneSetup:: +set_camera(const qpCamera *camera) { + _camera = camera; +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::get_camera +// Access: Public +// Description: Returns the camera used to render the scene. +//////////////////////////////////////////////////////////////////// +INLINE const qpCamera *SceneSetup:: +get_camera() const { + return _camera; +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::set_lens +// Access: Public +// Description: Indicates the particular Lens used for rendering. +//////////////////////////////////////////////////////////////////// +INLINE void SceneSetup:: +set_lens(const Lens *lens) { + _lens = lens; +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::get_lens +// Access: Public +// Description: Returns the particular Lens used for rendering. +//////////////////////////////////////////////////////////////////// +INLINE const Lens *SceneSetup:: +get_lens() const { + return _lens; +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::set_camera_transform +// Access: Public +// Description: Specifies the position of the camera relative to the +// starting node, without any compensating +// coordinate-system transforms that might have been +// introduced for the purposes of rendering. +//////////////////////////////////////////////////////////////////// +INLINE void SceneSetup:: +set_camera_transform(const TransformState *camera_transform) { + _camera_transform = camera_transform; +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::get_camera_transform +// Access: Public +// Description: Returns the position of the camera relative to the +// starting node, without any compensating +// coordinate-system transforms that might have been +// introduced for the purposes of rendering. +//////////////////////////////////////////////////////////////////// +INLINE const TransformState *SceneSetup:: +get_camera_transform() const { + return _camera_transform; +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::set_render_transform +// Access: Public +// Description: Specifies the position of the starting node relative +// to the camera, pretransformed as appropriate for +// rendering. +//////////////////////////////////////////////////////////////////// +INLINE void SceneSetup:: +set_render_transform(const TransformState *render_transform) { + _render_transform = render_transform; +} + +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::get_render_transform +// Access: Public +// Description: Returns the position of the starting node relative +// to the camera, pretransformed as appropriate for +// rendering. +// +// Note that this value is always the position of the +// starting node, not the current node, even if it is +// sampled during a traversal. To get the render +// transform of the current node check in the current +// CullTraverserData. +//////////////////////////////////////////////////////////////////// +INLINE const TransformState *SceneSetup:: +get_render_transform() const { + return _render_transform; +} diff --git a/panda/src/pgraph/sceneSetup.cxx b/panda/src/pgraph/sceneSetup.cxx new file mode 100644 index 0000000000..ac39a00dfc --- /dev/null +++ b/panda/src/pgraph/sceneSetup.cxx @@ -0,0 +1,20 @@ +// Filename: sceneSetup.cxx +// Created by: drose (27Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "sceneSetup.h" + diff --git a/panda/src/pgraph/sceneSetup.h b/panda/src/pgraph/sceneSetup.h new file mode 100644 index 0000000000..ce5d5bde21 --- /dev/null +++ b/panda/src/pgraph/sceneSetup.h @@ -0,0 +1,66 @@ +// Filename: sceneSetup.h +// Created by: drose (27Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef SCENESETUP_H +#define SCENESETUP_H + +#include "pandabase.h" + +#include "referenceCount.h" +#include "qpnodePath.h" +#include "qpcamera.h" +#include "transformState.h" +#include "lens.h" +#include "pointerTo.h" + +//////////////////////////////////////////////////////////////////// +// Class : SceneSetup +// Description : This object holds the camera position, etc., and +// other general setup information for rendering a +// particular scene. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA SceneSetup : public ReferenceCount { +public: + INLINE SceneSetup(); + + INLINE void set_scene_root(const qpNodePath &scene_root); + INLINE const qpNodePath &get_scene_root() const; + + INLINE void set_camera(const qpCamera *camera); + INLINE const qpCamera *get_camera() const; + + INLINE void set_lens(const Lens *lens); + INLINE const Lens *get_lens() const; + + INLINE void set_camera_transform(const TransformState *camera_transform); + INLINE const TransformState *get_camera_transform() const; + + INLINE void set_render_transform(const TransformState *render_transform); + INLINE const TransformState *get_render_transform() const; + +private: + qpNodePath _scene_root; + CPT(qpCamera) _camera; + CPT(Lens) _lens; + CPT(TransformState) _camera_transform; + CPT(TransformState) _render_transform; +}; + +#include "sceneSetup.I" + +#endif diff --git a/panda/src/testbed/demo.cxx b/panda/src/testbed/demo.cxx index 822705164e..391ce8124d 100644 --- a/panda/src/testbed/demo.cxx +++ b/panda/src/testbed/demo.cxx @@ -482,9 +482,6 @@ event_L(CPT_Event) { } void demo_keys(EventHandler&) { - new RenderRelation( lights, dlight ); - have_dlight = true; - /* event_handler.add_hook("mw-in-label2d", event_in_label2d); event_handler.add_hook("mw-out-label2d", event_out_label2d); diff --git a/panda/src/testbed/pview.cxx b/panda/src/testbed/pview.cxx index 3467071138..104bd3d1dc 100644 --- a/panda/src/testbed/pview.cxx +++ b/panda/src/testbed/pview.cxx @@ -49,6 +49,9 @@ #include "eventQueue.h" #include "eventHandler.h" #include "qpdataGraphTraverser.h" +#include "lightAttrib.h" +#include "ambientLight.h" +#include "directionalLight.h" // Use dconfig to read a few Configrc variables. Configure(config_pview); @@ -64,6 +67,7 @@ bool run_flag = true; // These are referenced in both event_w() and in event_b(). bool wireframe = false; bool two_sided = false; +bool lighting = false; // These are used by report_frame_rate(). @@ -76,6 +80,9 @@ static const int override_priority = 100; // This is the main scene graph. qpNodePath render; +// And this is the camera node. +qpNodePath camera_np; + void report_frame_rate() { double now = ClockObject::get_global_clock()->get_frame_time(); @@ -361,6 +368,37 @@ event_A(CPT_Event) { #endif } +void +event_l(CPT_Event) { + // 'l' : toggle lighting. + lighting = !lighting; + if (lighting) { + nout << "Enabling lighting.\n"; + static bool lights_created = false; + + static PT(AmbientLight) alight; + static PT(DirectionalLight) dlight; + + if (!lights_created) { + alight = new AmbientLight("ambient"); + alight->set_color(Colorf(0.2f, 0.2f, 0.2f, 1.0f)); + dlight = new DirectionalLight("directional"); + camera_np.attach_new_node(alight); + camera_np.attach_new_node(dlight); + + lights_created = true; + } + + // Enable lights on the top node. + render.node()->set_attrib(LightAttrib::make(LightAttrib::O_add, alight, dlight)); + + } else { + nout << "Disabling lighting.\n"; + // Remove the lights from the top node. + render.node()->clear_attrib(LightAttrib::get_class_type()); + } +} + int main(int argc, char *argv[]) { // First, we need a GraphicsPipe, before we can open a window. @@ -375,7 +413,7 @@ main(int argc, char *argv[]) { // Now we just need to make a scene graph for the camera to render. render = qpNodePath("render"); - render.attach_new_node(camera); + camera_np = render.attach_new_node(camera); camera->set_scene(render); // This is maybe here temporarily, and maybe not. @@ -398,6 +436,7 @@ main(int argc, char *argv[]) { event_handler.add_hook("s", event_s); event_handler.add_hook("shift-s", event_S); event_handler.add_hook("shift-a", event_A); + event_handler.add_hook("l", event_l); // Put something in the scene graph to look at.