diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 02534b3308..67c7f6d1ca 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -137,8 +137,8 @@ cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr) { return; } - PandaNode *scene = camera_node->get_scene(); - if (scene == (PandaNode *)NULL) { + NodeChain scene = camera_node->get_scene(); + if (scene.is_empty()) { // No scene, no draw. return; } @@ -161,20 +161,22 @@ cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr) { // The world transform is computed from the camera's position; we // then might need to adjust it into the GSG's internal coordinate // system. - CPT(TransformState) world_transform = camera.get_rel_transform(NodeChain()); + trav.set_camera_transform(scene.get_rel_transform(camera)); + + CPT(TransformState) render_transform = camera.get_rel_transform(scene); CoordinateSystem external_cs = gsg->get_coordinate_system(); CoordinateSystem internal_cs = gsg->get_internal_coordinate_system(); if (internal_cs != CS_default && internal_cs != external_cs) { CPT(TransformState) cs_transform = TransformState::make_mat(LMatrix4f::convert_mat(external_cs, internal_cs)); - world_transform = cs_transform->compose(world_transform); + render_transform = cs_transform->compose(render_transform); } - trav.set_world_transform(world_transform); + trav.set_render_transform(render_transform); DisplayRegionStack old_dr = gsg->push_display_region(dr); gsg->prepare_display_region(); - trav.traverse(scene); + trav.traverse(scene.node()); gsg->pop_display_region(old_dr); } diff --git a/panda/src/egg2pg/qpeggLoader.cxx b/panda/src/egg2pg/qpeggLoader.cxx index f0e31ea26b..fa8c15d1b0 100644 --- a/panda/src/egg2pg/qpeggLoader.cxx +++ b/panda/src/egg2pg/qpeggLoader.cxx @@ -24,6 +24,7 @@ #include "transformState.h" #include "textureAttrib.h" #include "texturePool.h" +#include "billboardAttrib.h" #include "qpgeomNode.h" #include "string_utils.h" #include "eggPrimitive.h" @@ -985,13 +986,13 @@ setup_bucket(BuilderBucket &bucket, PandaNode *parent, bin = render_mode->get_bin(); } - bucket._state = bucket._state->add(TextureAttrib::make_off()); + bucket._state = bucket._state->add_attrib(TextureAttrib::make_off()); if (egg_prim->has_texture()) { PT(EggTexture) egg_tex = egg_prim->get_texture(); const TextureDef &def = _textures[egg_tex]; if (def._texture != (const RenderAttrib *)NULL) { - bucket._state = bucket._state->add(def._texture); + bucket._state = bucket._state->add_attrib(def._texture); // bucket._trans.set_transition(def._apply); // If neither the primitive nor the texture specified an alpha @@ -1499,25 +1500,23 @@ create_group_arc(EggGroup *egg_group, PandaNode *parent, PandaNode *node) { node->set_transform(TransformState::make_mat(matf)); } - /* // If the group has a billboard flag, apply that. switch (egg_group->get_billboard_type()) { case EggGroup::BT_point_camera_relative: - arc->set_transition(new BillboardTransition(BillboardTransition::point_eye())); + node->set_attrib(BillboardAttrib::make_point_eye()); break; case EggGroup::BT_point_world_relative: - arc->set_transition(new BillboardTransition(BillboardTransition::point_world())); + node->set_attrib(BillboardAttrib::make_point_world()); break; case EggGroup::BT_axis: - arc->set_transition(new BillboardTransition(BillboardTransition::axis())); + node->set_attrib(BillboardAttrib::make_axis()); break; case EggGroup::BT_none: break; } - */ /* if (egg_group->get_decal_flag()) { diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index a337bd0f4c..6c6cce9e13 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -6,6 +6,7 @@ #define TARGET pgraph #define SOURCES \ + billboardAttrib.h billboardAttrib.I \ qpcamera.h qpcamera.I \ colorAttrib.h colorAttrib.I \ config_pgraph.h \ @@ -29,6 +30,7 @@ #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx #define INCLUDED_SOURCES \ + billboardAttrib.cxx \ qpcamera.cxx \ colorAttrib.cxx \ config_pgraph.cxx \ @@ -57,6 +59,7 @@ #endif #define INSTALL_HEADERS \ + billboardAttrib.h billboardAttrib.I \ qpcamera.h qpcamera.I \ colorAttrib.h colorAttrib.I \ config_pgraph.h \ diff --git a/panda/src/pgraph/billboardAttrib.I b/panda/src/pgraph/billboardAttrib.I new file mode 100644 index 0000000000..579a2b8285 --- /dev/null +++ b/panda/src/pgraph/billboardAttrib.I @@ -0,0 +1,153 @@ +// Filename: billboardAttrib.I +// Created by: drose (27Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// 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: BillboardAttrib::Constructor +// Access: Private +// Description: Use BillboardAttrib::make() to construct a new +// BillboardAttrib object. +//////////////////////////////////////////////////////////////////// +INLINE BillboardAttrib:: +BillboardAttrib() { + _off = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::make_axis +// Access: Published, Static +// Description: A convenience function to make a typical +// axis-rotating billboard. +//////////////////////////////////////////////////////////////////// +INLINE CPT(RenderAttrib) BillboardAttrib:: +make_axis() { + return make(LVector3f::up(), false, true, + 0.0f, NodeChain(), LPoint3f(0.0f, 0.0f, 0.0f)); +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::make_point_eye +// Access: Published, Static +// Description: A convenience function to make a typical +// eye-relative point-rotating billboard. +//////////////////////////////////////////////////////////////////// +INLINE CPT(RenderAttrib) BillboardAttrib:: +make_point_eye() { + return make(LVector3f::up(), true, false, + 0.0f, NodeChain(), LPoint3f(0.0f, 0.0f, 0.0f)); +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::make_point_world +// Access: Published, Static +// Description: A convenience function to make a typical +// world-relative point-rotating billboard. +//////////////////////////////////////////////////////////////////// +INLINE CPT(RenderAttrib) BillboardAttrib:: +make_point_world() { + return make(LVector3f::up(), false, false, + 0.0f, NodeChain(), LPoint3f(0.0f, 0.0f, 0.0f)); +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::is_off +// Access: Published +// Description: Returns true if the BillboardAttrib is an 'off' +// BillboardAttrib, indicating that it does not enable +// billboarding. This kind of BillboardAttrib isn't +// particularly useful and isn't normally created or +// stored in the graph; it might be implicitly +// discovered as the result of a +// NodeChain::get_rel_state(). +//////////////////////////////////////////////////////////////////// +INLINE bool BillboardAttrib:: +is_off() const { + return _off; +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::get_up_vector +// Access: Published +// Description: Returns the up vector in effect for this billboard. +//////////////////////////////////////////////////////////////////// +INLINE const LVector3f &BillboardAttrib:: +get_up_vector() const { + return _up_vector; +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::get_eye_relative +// Access: Published +// Description: Returns true if this billboard interprets the up +// vector relative to the camera, or false if it is +// relative to the world. +//////////////////////////////////////////////////////////////////// +INLINE bool BillboardAttrib:: +get_eye_relative() const { + return _eye_relative; +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::get_axial_rotate +// Access: Published +// Description: Returns true if this billboard rotates only around +// the axis of the up vector, or false if it rotates +// freely in three dimensions. +//////////////////////////////////////////////////////////////////// +INLINE bool BillboardAttrib:: +get_axial_rotate() const { + return _axial_rotate; +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::get_offset +// Access: Published +// Description: Returns the distance toward the camera (or the +// look_at_point) the billboard is moved towards, after +// rotating. This can be used to ensure the billboard +// is not obscured by nearby geometry. +//////////////////////////////////////////////////////////////////// +INLINE float BillboardAttrib:: +get_offset() const { + return _offset; +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::get_look_at +// Access: Published +// Description: Returns the node this billboard will rotate to look +// towards. If this is empty, it means the billboard +// will rotate towards the current camera node, wherever +// that might be. +//////////////////////////////////////////////////////////////////// +INLINE const NodeChain &BillboardAttrib:: +get_look_at() const { + return _look_at; +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::get_look_at_point +// Access: Published +// Description: Returns the point, relative to the look_at node, +// towards which the billboard will rotate. Normally +// this is (0, 0, 0). +//////////////////////////////////////////////////////////////////// +INLINE const LPoint3f &BillboardAttrib:: +get_look_at_point() const { + return _look_at_point; +} diff --git a/panda/src/pgraph/billboardAttrib.cxx b/panda/src/pgraph/billboardAttrib.cxx new file mode 100644 index 0000000000..3f5d8eb72e --- /dev/null +++ b/panda/src/pgraph/billboardAttrib.cxx @@ -0,0 +1,255 @@ +// Filename: billboardAttrib.cxx +// Created by: drose (27Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "billboardAttrib.h" +#include "look_at.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "datagram.h" +#include "datagramIterator.h" + +TypeHandle BillboardAttrib::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::make +// Access: Published, Static +// Description: Constructs a new BillboardAttrib object with the +// indicated properties. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) BillboardAttrib:: +make(const LVector3f &up_vector, bool eye_relative, + bool axial_rotate, float offset, const NodeChain &look_at, + const LPoint3f &look_at_point) { + BillboardAttrib *attrib = new BillboardAttrib; + attrib->_up_vector = up_vector; + attrib->_eye_relative = eye_relative; + attrib->_axial_rotate = axial_rotate; + attrib->_offset = offset; + attrib->_look_at = look_at; + attrib->_look_at_point = look_at_point; + attrib->_off = false; + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void BillboardAttrib:: +output(ostream &out) const { + out << get_type() << ":"; + if (is_off()) { + out << "(off)"; + } else { + if (_axial_rotate) { + out << "(axis"; + } else { + out << "(point"; + } + if (!_up_vector.almost_equal(LVector3f::up())) { + out << " up " << _up_vector; + } + if (_eye_relative) { + out << " eye"; + } + if (_offset != 0.0f) { + out << " offset " << _offset; + } + if (!_look_at.is_empty()) { + out << " look at " << _look_at; + } + if (!_look_at_point.almost_equal(LPoint3f(0.0f, 0.0f, 0.0f))) { + out << " look at point " << _look_at_point; + } + out << ")"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::do_billboard +// Access: Public +// Description: Computes the appropriate transform to apply to the +// billboarded geometry, given its current net +// transform, and the camera's inverse net transform. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) BillboardAttrib:: +do_billboard(const TransformState *net_transform, + const TransformState *camera_transform) const { + // Determine the relative transform to our camera (or other look_at + // coordinate space). + CPT(TransformState) rel_transform = + net_transform->invert_compose(camera_transform); + const LMatrix4f &rel_mat = rel_transform->get_mat(); + + // Determine the look_at point in the camera space. + LVector3f camera_pos, up; + + // If this is an eye-relative Billboard, then (a) the up vector is + // relative to the camera, not to the world, and (b) the look + // direction is towards the plane that contains the camera, + // perpendicular to the forward direction, not directly to the + // camera. + + if (_eye_relative) { + up = _up_vector * rel_mat; + camera_pos = LVector3f::forward() * rel_mat; + + } else { +// camera_pos= -rel_mat.get_row3(3); + + camera_pos[0] = -rel_mat(3,0); + camera_pos[1] = -rel_mat(3,1); + camera_pos[2] = -rel_mat(3,2); + + up = _up_vector; + } + + // Now determine the rotation matrix for the Billboard. + LMatrix4f rotate; + if (_axial_rotate) { + heads_up(rotate, camera_pos, up); + } else { + look_at(rotate, camera_pos, up); + } + + // Also slide the billboard geometry towards the camera according to + // the offset factor. + if (_offset != 0.0f) { + LVector3f translate(rel_mat(3, 0), rel_mat(3, 1), rel_mat(3, 2)); + translate.normalize(); + translate *= _offset; + rotate.set_row(3, translate); + } + + return TransformState::make_mat(rotate); +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::compare_to_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived BillboardAttrib +// types to return a unique number indicating whether +// this BillboardAttrib is equivalent to the other one. +// +// This should return 0 if the two BillboardAttrib 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 BillboardAttrib +// objects whose get_type() functions return the same. +//////////////////////////////////////////////////////////////////// +int BillboardAttrib:: +compare_to_impl(const RenderAttrib *other) const { + const BillboardAttrib *ta; + DCAST_INTO_R(ta, other, 0); + + if (_axial_rotate != ta->_axial_rotate) { + return _axial_rotate - ta->_axial_rotate; + } + if (_eye_relative != ta->_eye_relative) { + return _eye_relative - ta->_eye_relative; + } + if (_offset != ta->_offset) { + return _offset < ta->_offset ? -1 : 1; + } + int compare = _up_vector.compare_to(ta->_up_vector); + if (compare != 0) { + return compare; + } + compare = _look_at.compare_to(ta->_look_at); + if (compare != 0) { + return compare; + } + compare = _look_at_point.compare_to(ta->_look_at_point); + if (compare != 0) { + return compare; + } + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::make_default_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived BillboardAttrib +// types to specify what the default property for a +// BillboardAttrib of this type should be. +// +// This should return a newly-allocated BillboardAttrib of +// the same type that corresponds to whatever the +// standard default for this kind of BillboardAttrib is. +//////////////////////////////////////////////////////////////////// +RenderAttrib *BillboardAttrib:: +make_default_impl() const { + return new BillboardAttrib; +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// BillboardAttrib. +//////////////////////////////////////////////////////////////////// +void BillboardAttrib:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void BillboardAttrib:: +write_datagram(BamWriter *manager, Datagram &dg) { + RenderAttrib::write_datagram(manager, dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type BillboardAttrib is encountered +// in the Bam file. It should create the BillboardAttrib +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *BillboardAttrib:: +make_from_bam(const FactoryParams ¶ms) { + BillboardAttrib *attrib = new BillboardAttrib; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + attrib->fillin(scan, manager); + + return new_from_bam(attrib, manager); +} + +//////////////////////////////////////////////////////////////////// +// Function: BillboardAttrib::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 BillboardAttrib. +//////////////////////////////////////////////////////////////////// +void BillboardAttrib:: +fillin(DatagramIterator &scan, BamReader *manager) { + RenderAttrib::fillin(scan, manager); +} diff --git a/panda/src/pgraph/billboardAttrib.h b/panda/src/pgraph/billboardAttrib.h new file mode 100644 index 0000000000..c0f2077851 --- /dev/null +++ b/panda/src/pgraph/billboardAttrib.h @@ -0,0 +1,105 @@ +// Filename: billboardAttrib.h +// Created by: drose (27Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 BILLBOARDATTRIB_H +#define BILLBOARDATTRIB_H + +#include "pandabase.h" + +#include "renderAttrib.h" +#include "luse.h" +#include "nodeChain.h" + +//////////////////////////////////////////////////////////////////// +// Class : BillboardAttrib +// Description : Indicates that geometry at this node should +// automatically rotate to face the camera, or any other +// arbitrary node. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA BillboardAttrib : public RenderAttrib { +private: + INLINE BillboardAttrib(); + +PUBLISHED: + static CPT(RenderAttrib) make(const LVector3f &up_vector, + bool eye_relative, + bool axial_rotate, + float offset, + const NodeChain &look_at, + const LPoint3f &look_at_point); + INLINE static CPT(RenderAttrib) make_axis(); + INLINE static CPT(RenderAttrib) make_point_eye(); + INLINE static CPT(RenderAttrib) make_point_world(); + + INLINE bool is_off() const; + INLINE const LVector3f &get_up_vector() const; + INLINE bool get_eye_relative() const; + INLINE bool get_axial_rotate() const; + INLINE float get_offset() const; + INLINE const NodeChain &get_look_at() const; + INLINE const LPoint3f &get_look_at_point() const; + +public: + virtual void output(ostream &out) const; + + CPT(TransformState) do_billboard(const TransformState *net_transform, + const TransformState *camera_transform) const; + +protected: + virtual int compare_to_impl(const RenderAttrib *other) const; + virtual RenderAttrib *make_default_impl() const; + +private: + bool _off; + LVector3f _up_vector; + bool _eye_relative; + bool _axial_rotate; + float _offset; + NodeChain _look_at; + LPoint3f _look_at_point; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + +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, "BillboardAttrib", + 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 "billboardAttrib.I" + +#endif + diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index a53b2c739f..064553118a 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -18,6 +18,7 @@ #include "config_pgraph.h" +#include "billboardAttrib.h" #include "qpcamera.h" #include "colorAttrib.h" #include "qpgeomNode.h" @@ -57,6 +58,7 @@ init_libpgraph() { } initialized = true; + BillboardAttrib::init_type(); qpCamera::init_type(); ColorAttrib::init_type(); qpGeomNode::init_type(); @@ -70,6 +72,7 @@ init_libpgraph() { ColorAttrib::init_type(); TransformState::init_type(); + BillboardAttrib::register_with_read_factory(); ColorAttrib::register_with_read_factory(); qpGeomNode::register_with_read_factory(); PandaNode::register_with_read_factory(); diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index 015bad2f79..387236b7fc 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -249,7 +249,7 @@ get_child_sort(int n) const { INLINE void PandaNode:: set_attrib(const RenderAttrib *attrib, int override) { CDWriter cdata(_cycler); - cdata->_state = cdata->_state->add(attrib, override); + cdata->_state = cdata->_state->add_attrib(attrib, override); } //////////////////////////////////////////////////////////////////// @@ -282,7 +282,7 @@ get_attrib(TypeHandle type) const { INLINE void PandaNode:: clear_attrib(TypeHandle type) { CDWriter cdata(_cycler); - cdata->_state = cdata->_state->remove(type); + cdata->_state = cdata->_state->remove_attrib(type); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/qpcamera.I b/panda/src/pgraph/qpcamera.I index 0f3fc1d64b..f9bb292e10 100644 --- a/panda/src/pgraph/qpcamera.I +++ b/panda/src/pgraph/qpcamera.I @@ -48,7 +48,7 @@ is_active() const { // represent the root of any subgraph. //////////////////////////////////////////////////////////////////// INLINE void qpCamera:: -set_scene(PandaNode *scene) { +set_scene(const NodeChain &scene) { _scene = scene; } @@ -58,7 +58,7 @@ set_scene(PandaNode *scene) { // Description: Returns the scene that will be rendered by the // camera. See set_scene(). //////////////////////////////////////////////////////////////////// -INLINE PandaNode *qpCamera:: +INLINE const NodeChain &qpCamera:: get_scene() const { return _scene; } diff --git a/panda/src/pgraph/qpcamera.cxx b/panda/src/pgraph/qpcamera.cxx index 97b3f05835..0f9d0d21c3 100644 --- a/panda/src/pgraph/qpcamera.cxx +++ b/panda/src/pgraph/qpcamera.cxx @@ -31,8 +31,7 @@ TypeHandle qpCamera::_type_handle; qpCamera:: qpCamera(const string &name) : qpLensNode(name), - _active(true), - _scene((PandaNode *)NULL) + _active(true) { } diff --git a/panda/src/pgraph/qpcamera.h b/panda/src/pgraph/qpcamera.h index 3bff9a3697..ed0db4d84b 100644 --- a/panda/src/pgraph/qpcamera.h +++ b/panda/src/pgraph/qpcamera.h @@ -22,9 +22,9 @@ #include "pandabase.h" #include "qplensNode.h" +#include "nodeChain.h" class DisplayRegion; -class PandaNode; //////////////////////////////////////////////////////////////////// // Class : qpCamera @@ -49,8 +49,8 @@ PUBLISHED: INLINE void set_active(bool active); INLINE bool is_active() const; - INLINE void set_scene(PandaNode *scene); - INLINE PandaNode *get_scene() const; + INLINE void set_scene(const NodeChain &scene); + INLINE const NodeChain &get_scene() const; INLINE int get_num_display_regions() const; INLINE DisplayRegion *get_display_region(int n) const; @@ -60,7 +60,7 @@ private: void remove_display_region(DisplayRegion *display_region); bool _active; - PandaNode *_scene; + NodeChain _scene; typedef pvector DisplayRegions; DisplayRegions _display_regions; diff --git a/panda/src/pgraph/qpcullTraverser.cxx b/panda/src/pgraph/qpcullTraverser.cxx index 6e679f97d0..973bbe509a 100644 --- a/panda/src/pgraph/qpcullTraverser.cxx +++ b/panda/src/pgraph/qpcullTraverser.cxx @@ -19,6 +19,7 @@ #include "qpcullTraverser.h" #include "transformState.h" #include "renderState.h" +#include "billboardAttrib.h" #include "cullHandler.h" #include "dcast.h" #include "qpgeomNode.h" @@ -31,7 +32,8 @@ qpCullTraverser:: qpCullTraverser() { _initial_state = RenderState::make_empty(); - _world_transform = DCAST(TransformState, TransformState::make_identity()); + _camera_transform = DCAST(TransformState, TransformState::make_identity()); + _render_transform = DCAST(TransformState, TransformState::make_identity()); _cull_handler = (CullHandler *)NULL; } @@ -48,14 +50,28 @@ set_initial_state(const RenderState *initial_state) { } //////////////////////////////////////////////////////////////////// -// Function: qpCullTraverser::set_world_transform +// Function: qpCullTraverser::set_camera_transform // Access: Public -// Description: Specifies the position of the world relative to the -// camera. +// 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. //////////////////////////////////////////////////////////////////// void qpCullTraverser:: -set_world_transform(const TransformState *world_transform) { - _world_transform = world_transform; +set_camera_transform(const TransformState *camera_transform) { + _camera_transform = 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. +//////////////////////////////////////////////////////////////////// +void qpCullTraverser:: +set_render_transform(const TransformState *render_transform) { + _render_transform = render_transform; } //////////////////////////////////////////////////////////////////// @@ -78,7 +94,8 @@ void qpCullTraverser:: traverse(PandaNode *root) { nassertv(_cull_handler != (CullHandler *)NULL); - r_traverse(root, _world_transform, _initial_state, 0); + r_traverse(root, _render_transform, TransformState::make_identity(), + _initial_state, 0); } //////////////////////////////////////////////////////////////////// @@ -87,11 +104,25 @@ traverse(PandaNode *root) { // Description: The recursive traversal implementation. //////////////////////////////////////////////////////////////////// void qpCullTraverser:: -r_traverse(PandaNode *node, const TransformState *transform, +r_traverse(PandaNode *node, + const TransformState *render_transform, + const TransformState *net_transform, const RenderState *state, int flags) { - CPT(TransformState) next_transform = transform->compose(node->get_transform()); + CPT(TransformState) next_render_transform = + render_transform->compose(node->get_transform()); + CPT(TransformState) next_net_transform = + net_transform->compose(node->get_transform()); CPT(RenderState) next_state = state->compose(node->get_state()); + const BillboardAttrib *billboard = state->get_billboard(); + if (billboard != (const BillboardAttrib *)NULL) { + // Got to apply a billboard transform here. + CPT(TransformState) billboard_transform = + billboard->do_billboard(net_transform, _camera_transform); + next_render_transform = next_render_transform->compose(billboard_transform); + next_net_transform = next_net_transform->compose(billboard_transform); + } + if (node->is_geom_node()) { qpGeomNode *geom_node; DCAST_INTO_V(geom_node, node); @@ -101,7 +132,7 @@ r_traverse(PandaNode *node, const TransformState *transform, Geom *geom = geom_node->get_geom(i); CPT(RenderState) geom_state = next_state->compose(geom_node->get_geom_state(i)); - _cull_handler->record_geom(geom, next_transform, geom_state); + _cull_handler->record_geom(geom, next_render_transform, geom_state); } } @@ -109,6 +140,6 @@ r_traverse(PandaNode *node, const TransformState *transform, PandaNode::Children cr = node->get_children(); int num_children = cr.get_num_children(); for (int i = 0; i < num_children; i++) { - r_traverse(cr.get_child(i), next_transform, next_state, flags); + r_traverse(cr.get_child(i), next_render_transform, next_net_transform, next_state, flags); } } diff --git a/panda/src/pgraph/qpcullTraverser.h b/panda/src/pgraph/qpcullTraverser.h index 73c76b97f6..e5b5595912 100644 --- a/panda/src/pgraph/qpcullTraverser.h +++ b/panda/src/pgraph/qpcullTraverser.h @@ -41,17 +41,20 @@ public: qpCullTraverser(); void set_initial_state(const RenderState *initial_state); - void set_world_transform(const TransformState *world_transform); + void set_camera_transform(const TransformState *camera_transform); + void set_render_transform(const TransformState *render_transform); void set_cull_handler(CullHandler *cull_handler); void traverse(PandaNode *root); private: - void r_traverse(PandaNode *node, const TransformState *transform, + void r_traverse(PandaNode *node, const TransformState *render_transform, + const TransformState *net_transform, const RenderState *state, int flags); CPT(RenderState) _initial_state; - CPT(TransformState) _world_transform; + CPT(TransformState) _camera_transform; + CPT(TransformState) _render_transform; CullHandler *_cull_handler; }; diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I index 21020a97f1..fd0fe2bbb3 100644 --- a/panda/src/pgraph/renderState.I +++ b/panda/src/pgraph/renderState.I @@ -148,3 +148,22 @@ get_override(int n) const { nassertr(n >= 0 && n < (int)_attributes.size(), 0); return _attributes[n]._override; } + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::get_billboard +// Access: Public +// Description: This function is provided as an optimization, to +// speed up the render-time checking for the existance +// of a BillboardAttrib on this state. It returns a +// pointer to the BillboardAttrib, if there is one, or +// NULL if there is not. +//////////////////////////////////////////////////////////////////// +INLINE const BillboardAttrib *RenderState:: +get_billboard() const { + if ((_flags & F_checked_billboard) == 0) { + // We pretend this function is const, even though it transparently + // modifies the internal billboard cache. + ((RenderState *)this)->determine_billboard(); + } + return _billboard; +} diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index 12f97f352f..24bc305f06 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -17,6 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "renderState.h" +#include "billboardAttrib.h" #include "bamReader.h" #include "bamWriter.h" #include "datagramIterator.h" @@ -38,6 +39,7 @@ RenderState:: RenderState() { _saved_entry = _states.end(); _self_compose = (RenderState *)NULL; + _flags = 0; } //////////////////////////////////////////////////////////////////// @@ -399,7 +401,7 @@ invert_compose(const RenderState *other) const { } //////////////////////////////////////////////////////////////////// -// Function: RenderState::add +// Function: RenderState::add_attrib // Access: Published // Description: Returns a new RenderState object that represents the // same as the source state, with the new RenderAttrib @@ -407,7 +409,7 @@ invert_compose(const RenderState *other) const { // same type, it is replaced. //////////////////////////////////////////////////////////////////// CPT(RenderState) RenderState:: -add(const RenderAttrib *attrib, int override) const { +add_attrib(const RenderAttrib *attrib, int override) const { RenderState *new_state = new RenderState; back_insert_iterator result = back_inserter(new_state->_attributes); @@ -441,14 +443,14 @@ add(const RenderAttrib *attrib, int override) const { } //////////////////////////////////////////////////////////////////// -// Function: RenderState::remove +// Function: RenderState::remove_attrib // Access: Published // Description: Returns a new RenderState object that represents the // same as the source state, with the indicated // RenderAttrib removed //////////////////////////////////////////////////////////////////// CPT(RenderState) RenderState:: -remove(TypeHandle type) const { +remove_attrib(TypeHandle type) const { RenderState *new_state = new RenderState; back_insert_iterator result = back_inserter(new_state->_attributes); @@ -466,6 +468,23 @@ remove(TypeHandle type) const { return return_new(new_state); } +//////////////////////////////////////////////////////////////////// +// Function: RenderState::get_attrib +// Access: Published, Virtual +// Description: Looks for a RenderAttrib of the indicated type in the +// state, and returns it if it is found, or NULL if it +// is not. +//////////////////////////////////////////////////////////////////// +const RenderAttrib *RenderState:: +get_attrib(TypeHandle type) const { + Attributes::const_iterator ai; + ai = _attributes.find(Attribute(type)); + if (ai != _attributes.end()) { + return (*ai)._attrib; + } + return NULL; +} + //////////////////////////////////////////////////////////////////// // Function: RenderState::output // Access: Published, Virtual @@ -807,6 +826,21 @@ do_invert_compose(const RenderState *other) const { return return_new(new_state); } +//////////////////////////////////////////////////////////////////// +// Function: RenderState::determine_billboard +// Access: Private +// Description: This is the private implementation of +// get_billboard(). +//////////////////////////////////////////////////////////////////// +void RenderState:: +determine_billboard() { + const RenderAttrib *attrib = get_attrib(BillboardAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + _billboard = DCAST(BillboardAttrib, attrib); + } + _flags |= F_checked_billboard; +} + //////////////////////////////////////////////////////////////////// // Function: RenderState::register_with_read_factory // Access: Public, Static diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index 61cee2fc6c..5ea7200362 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -28,6 +28,7 @@ #include "ordered_vector.h" class GraphicsStateGuardianBase; +class BillboardAttrib; //////////////////////////////////////////////////////////////////// // Class : RenderState @@ -77,13 +78,17 @@ PUBLISHED: CPT(RenderState) compose(const RenderState *other) const; CPT(RenderState) invert_compose(const RenderState *other) const; - CPT(RenderState) add(const RenderAttrib *attrib, int override = 0) const; - CPT(RenderState) remove(TypeHandle type) const; + CPT(RenderState) add_attrib(const RenderAttrib *attrib, int override = 0) const; + CPT(RenderState) remove_attrib(TypeHandle type) const; + + const RenderAttrib *get_attrib(TypeHandle type) const; void output(ostream &out) const; void write(ostream &out, int indent_level) const; public: + INLINE const BillboardAttrib *get_billboard() const; + CPT(RenderState) issue_delta_modify(const RenderState *other, GraphicsStateGuardianBase *gsg) const; CPT(RenderState) issue_delta_set(const RenderState *other, @@ -93,6 +98,7 @@ private: static CPT(RenderState) return_new(RenderState *state); CPT(RenderState) do_compose(const RenderState *other) const; CPT(RenderState) do_invert_compose(const RenderState *other) const; + void determine_billboard(); private: typedef pset > States; @@ -145,6 +151,14 @@ private: typedef ov_set Attributes; Attributes _attributes; + // We cache the pointer to the BillboardAttrib stored in the state, + // if there is one. + const BillboardAttrib *_billboard; + enum Flags { + F_checked_billboard = 0x0001, + }; + short _flags; + public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); diff --git a/panda/src/testbed/pview.cxx b/panda/src/testbed/pview.cxx index b4f54bc3b9..652f516b1e 100644 --- a/panda/src/testbed/pview.cxx +++ b/panda/src/testbed/pview.cxx @@ -270,7 +270,7 @@ main(int argc, char *argv[]) { // Now we just need to make a scene graph for the camera to render. PT(PandaNode) render = new PandaNode("render"); render->add_child(camera); - camera->set_scene(render); + camera->set_scene(NodeChain(render)); // Set up a data graph for tracking user input. For now, this uses // the old-style graph interface.