new scene graph, transforms and cameras
This commit is contained in:
parent
5974c85efe
commit
063c2cafff
|
|
@ -102,6 +102,17 @@ get_camera() const {
|
|||
return _camera;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::get_qpcamera
|
||||
// Access: Public
|
||||
// Description: Returns the camera associated with this
|
||||
// DisplayRegion, or NULL if no camera is associated.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const NodeChain &DisplayRegion::
|
||||
get_qpcamera() const {
|
||||
return _qpcamera;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::set_cull_frustum
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "graphicsWindow.h"
|
||||
#include "config_display.h"
|
||||
#include "displayRegion.h"
|
||||
#include "qpcamera.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -33,6 +34,7 @@ DisplayRegion::
|
|||
DisplayRegion(GraphicsLayer *layer) :
|
||||
_l(0.), _r(1.), _b(0.), _t(1.),
|
||||
_layer(layer),
|
||||
_camera_node((qpCamera *)NULL),
|
||||
_active(true)
|
||||
{
|
||||
}
|
||||
|
|
@ -44,10 +46,11 @@ DisplayRegion(GraphicsLayer *layer) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
DisplayRegion::
|
||||
DisplayRegion(GraphicsLayer *layer, const float l,
|
||||
const float r, const float b, const float t)
|
||||
: _l(l), _r(r), _b(b), _t(t),
|
||||
_layer(layer),
|
||||
_active(true)
|
||||
const float r, const float b, const float t) :
|
||||
_l(l), _r(r), _b(b), _t(t),
|
||||
_layer(layer),
|
||||
_camera_node((qpCamera *)NULL),
|
||||
_active(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +65,8 @@ DisplayRegion::
|
|||
DisplayRegion(int xsize, int ysize) :
|
||||
_l(0.), _r(1.), _b(0.), _t(1.),
|
||||
_pl(0), _pr(xsize), _pb(0), _pt(ysize),
|
||||
_layer((GraphicsLayer *)0L),
|
||||
_layer((GraphicsLayer *)NULL),
|
||||
_camera_node((qpCamera *)NULL),
|
||||
_active(true)
|
||||
{
|
||||
}
|
||||
|
|
@ -74,8 +78,7 @@ DisplayRegion(int xsize, int ysize) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
DisplayRegion::
|
||||
DisplayRegion(const DisplayRegion&) {
|
||||
display_cat.error()
|
||||
<< "DisplayRegions should not be copied" << endl;
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -83,11 +86,9 @@ DisplayRegion(const DisplayRegion&) {
|
|||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DisplayRegion &DisplayRegion::
|
||||
operator=(const DisplayRegion&) {
|
||||
display_cat.error()
|
||||
<< "DisplayRegions should not be assigned" << endl;
|
||||
return *this;
|
||||
void DisplayRegion::
|
||||
operator = (const DisplayRegion&) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -97,6 +98,7 @@ operator=(const DisplayRegion&) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
DisplayRegion::
|
||||
~DisplayRegion() {
|
||||
set_qpcamera(NodeChain());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -182,6 +184,41 @@ set_camera(Camera *camera) {
|
|||
set_cull_frustum(camera);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::set_qpcamera
|
||||
// Access: Public
|
||||
// Description: Sets the camera that is associated with this
|
||||
// DisplayRegion. There is a one-to-one association
|
||||
// between cameras and DisplayRegions; if this camera
|
||||
// was already associated with a different
|
||||
// DisplayRegion, that association is removed.
|
||||
//
|
||||
// The camera is actually set via a NodeChain, which
|
||||
// clarifies which instance of the camera (if there
|
||||
// happen to be multiple instances) we should use.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
set_qpcamera(const NodeChain &camera) {
|
||||
qpCamera *camera_node = (qpCamera *)NULL;
|
||||
if (!camera.is_empty()) {
|
||||
DCAST_INTO_V(camera_node, camera.node());
|
||||
}
|
||||
|
||||
if (camera_node != _camera_node) {
|
||||
if (_camera_node != (qpCamera *)NULL) {
|
||||
// We need to tell the old camera we're not using him anymore.
|
||||
_camera_node->remove_display_region(this);
|
||||
}
|
||||
_camera_node = camera_node;
|
||||
if (_camera_node != (qpCamera *)NULL) {
|
||||
// Now tell the new camera we are using him.
|
||||
_camera_node->add_display_region(this);
|
||||
}
|
||||
}
|
||||
|
||||
_qpcamera = camera;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::output
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -17,25 +17,21 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
#ifndef DISPLAYREGION_H
|
||||
#define DISPLAYREGION_H
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Includes
|
||||
////////////////////////////////////////////////////////////////////
|
||||
#include <pandabase.h>
|
||||
|
||||
#include <referenceCount.h>
|
||||
#include <camera.h>
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "referenceCount.h"
|
||||
#include "camera.h"
|
||||
#include "nodeChain.h"
|
||||
|
||||
#include "plist.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Defines
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class GraphicsLayer;
|
||||
class GraphicsChannel;
|
||||
class GraphicsWindow;
|
||||
class GraphicsPipe;
|
||||
class CullHandler;
|
||||
class qpCamera;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : DisplayRegion
|
||||
|
|
@ -48,7 +44,12 @@ public:
|
|||
const float l, const float r,
|
||||
const float b, const float t);
|
||||
DisplayRegion(int xsize, int ysize);
|
||||
virtual ~DisplayRegion();
|
||||
private:
|
||||
DisplayRegion(const DisplayRegion &);
|
||||
void operator = (const DisplayRegion &);
|
||||
|
||||
public:
|
||||
~DisplayRegion();
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void get_dimensions(float &l, float &r, float &b, float &t) const;
|
||||
|
|
@ -66,6 +67,9 @@ PUBLISHED:
|
|||
void set_camera(Camera *camera);
|
||||
INLINE Camera *get_camera() const;
|
||||
|
||||
void set_qpcamera(const NodeChain &camera);
|
||||
INLINE const NodeChain &get_qpcamera() const;
|
||||
|
||||
INLINE void set_cull_frustum(LensNode *cull_frustum);
|
||||
INLINE LensNode *get_cull_frustum() const;
|
||||
|
||||
|
|
@ -98,14 +102,12 @@ protected:
|
|||
|
||||
GraphicsLayer *_layer;
|
||||
PT(Camera) _camera;
|
||||
NodeChain _qpcamera;
|
||||
qpCamera *_camera_node;
|
||||
PT(LensNode) _cull_frustum;
|
||||
|
||||
bool _active;
|
||||
|
||||
private:
|
||||
DisplayRegion(const DisplayRegion &);
|
||||
DisplayRegion& operator=(const DisplayRegion &);
|
||||
|
||||
friend class GraphicsLayer;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "drawCullHandler.h"
|
||||
#include "geom.h"
|
||||
#include "transformState.h"
|
||||
#include "renderState.h"
|
||||
#include "graphicsStateGuardian.h"
|
||||
|
||||
|
|
@ -30,7 +31,9 @@
|
|||
// discovered by the CullTraverser.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DrawCullHandler::
|
||||
record_geom(Geom *geom, const RenderState *state) {
|
||||
record_geom(Geom *geom, const TransformState *transform,
|
||||
const RenderState *state) {
|
||||
_gsg->set_transform(transform);
|
||||
_gsg->set_state(state);
|
||||
geom->draw(_gsg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ public:
|
|||
INLINE DrawCullHandler(GraphicsStateGuardian *gsg);
|
||||
|
||||
// virtual void begin_decal();
|
||||
virtual void record_geom(Geom *geom, const RenderState *state);
|
||||
virtual void record_geom(Geom *geom, const TransformState *transform,
|
||||
const RenderState *state);
|
||||
// virtual void push_decal();
|
||||
// virtual void pop_decal();
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ cull_and_draw_together() {
|
|||
cull_and_draw_together(win, dr);
|
||||
}
|
||||
win->flip();
|
||||
win->process_events();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,19 +112,27 @@ cull_and_draw_together() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr) {
|
||||
Camera *camera = dr->get_camera();
|
||||
if (camera == (Camera *)NULL || !camera->is_active()) {
|
||||
const NodeChain &camera = dr->get_qpcamera();
|
||||
if (camera.is_empty()) {
|
||||
// No camera, no draw.
|
||||
return;
|
||||
}
|
||||
|
||||
Lens *lens = camera->get_lens();
|
||||
qpCamera *camera_node;
|
||||
DCAST_INTO_V(camera_node, camera.node());
|
||||
|
||||
if (!camera_node->is_active()) {
|
||||
// Camera inactive, no draw.
|
||||
return;
|
||||
}
|
||||
|
||||
Lens *lens = camera_node->get_lens();
|
||||
if (lens == (Lens *)NULL) {
|
||||
// No lens, no draw.
|
||||
return;
|
||||
}
|
||||
|
||||
PandaNode *scene = camera->get_qpscene();
|
||||
PandaNode *scene = camera_node->get_scene();
|
||||
if (scene == (PandaNode *)NULL) {
|
||||
// No scene, no draw.
|
||||
return;
|
||||
|
|
@ -143,9 +152,7 @@ cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr) {
|
|||
DrawCullHandler cull_handler(gsg);
|
||||
qpCullTraverser trav;
|
||||
trav.set_cull_handler(&cull_handler);
|
||||
|
||||
// Here we should figure out the world transform: the camera's
|
||||
// inverse transform.
|
||||
trav.set_world_transform(camera.get_rel_transform(NodeChain()));
|
||||
|
||||
DisplayRegionStack old_dr = gsg->push_display_region(dr);
|
||||
gsg->prepare_display_region();
|
||||
|
|
|
|||
|
|
@ -144,6 +144,22 @@ set_state(const RenderState *state) {
|
|||
_qpstate = _qpstate->issue_delta_set(state, this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::set_transform
|
||||
// Access: Public
|
||||
// Description: Sets the world transform that will be applied to
|
||||
// subsequent geometry. This is normally called only
|
||||
// during the draw process, immediately before issuing
|
||||
// geometry commands.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void GraphicsStateGuardian::
|
||||
set_transform(const TransformState *transform) {
|
||||
if (transform != _transform) {
|
||||
_transform = transform;
|
||||
issue_transform(transform);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::get_state
|
||||
|
|
|
|||
|
|
@ -879,6 +879,16 @@ void GraphicsStateGuardian::
|
|||
end_decal(GeomNode *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::issue_transform
|
||||
// Access: Public, Virtual
|
||||
// Description: Sends the indicated transform matrix to the graphics
|
||||
// API to be applied to future vertices.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsStateGuardian::
|
||||
issue_transform(const TransformState *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::issue_color
|
||||
// Access: Public, Virtual
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "renderTraverser.h"
|
||||
#include "pStatCollector.h"
|
||||
#include "allTransitionsWrapper.h"
|
||||
#include "transformState.h"
|
||||
#include "renderState.h"
|
||||
|
||||
#include "notify.h"
|
||||
|
|
@ -142,6 +143,7 @@ public:
|
|||
|
||||
INLINE void modify_state(const RenderState *state);
|
||||
INLINE void set_state(const RenderState *state);
|
||||
INLINE void set_transform(const TransformState *transform);
|
||||
|
||||
RenderBuffer get_render_buffer(int buffer_type);
|
||||
|
||||
|
|
@ -173,6 +175,7 @@ public:
|
|||
|
||||
INLINE void clear_cached_state(void) { _state.clear(); };
|
||||
|
||||
virtual void issue_transform(const TransformState *transform);
|
||||
virtual void issue_color(const ColorAttrib *attrib);
|
||||
|
||||
protected:
|
||||
|
|
@ -224,6 +227,7 @@ protected:
|
|||
State _state;
|
||||
|
||||
CPT(RenderState) _qpstate;
|
||||
CPT(TransformState) _transform;
|
||||
|
||||
int _buffer_mask;
|
||||
Colorf _color_clear_value;
|
||||
|
|
|
|||
|
|
@ -3415,6 +3415,24 @@ issue_polygon_offset(const PolygonOffsetTransition *attrib) {
|
|||
report_errors();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GLGraphicsStateGuardian::issue_transform
|
||||
// Access: Public, Virtual
|
||||
// Description: Sends the indicated transform matrix to the graphics
|
||||
// API to be applied to future vertices.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GLGraphicsStateGuardian::
|
||||
issue_transform(const TransformState *transform) {
|
||||
#ifdef GSG_VERBOSE
|
||||
glgsg_cat.debug()
|
||||
<< "glLoadMatrix(GL_MODELVIEW): " << transform->get_mat() << endl;
|
||||
#endif
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadMatrixf(transform->get_mat().get_data());
|
||||
|
||||
report_errors();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GLGraphicsStateGuardian::issue_texture
|
||||
// Access: Public, Virtual
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ public:
|
|||
virtual void issue_point_shape(const PointShapeTransition *attrib);
|
||||
virtual void issue_polygon_offset(const PolygonOffsetTransition *attrib);
|
||||
|
||||
virtual void issue_transform(const TransformState *transform);
|
||||
virtual void issue_texture(const TextureAttrib *attrib);
|
||||
|
||||
virtual bool wants_normals(void) const;
|
||||
|
|
|
|||
|
|
@ -1217,6 +1217,9 @@ void glxGraphicsWindow::process_events(void)
|
|||
int got_event;
|
||||
glxGraphicsWindow* window;
|
||||
|
||||
if (_change_mask)
|
||||
handle_changes();
|
||||
|
||||
glxDisplay *glx = _pipe->get_glx_display();
|
||||
nassertv(glx != (glxDisplay *)NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
|
||||
dtoolutil:c dtoolbase:c dtool:m
|
||||
#define LOCAL_LIBS gsgbase gobj putil graph linmath express pandabase
|
||||
#define LOCAL_LIBS event gsgbase gobj putil graph linmath express pandabase
|
||||
|
||||
#begin lib_target
|
||||
#define TARGET pgraph
|
||||
|
||||
#define SOURCES \
|
||||
qpcamera.h qpcamera.I \
|
||||
colorAttrib.h colorAttrib.I \
|
||||
config_pgraph.h \
|
||||
cullHandler.h \
|
||||
|
|
@ -14,6 +15,9 @@
|
|||
cycleDataReader.h cycleDataReader.I \
|
||||
cycleDataWriter.h cycleDataWriter.I \
|
||||
qpgeomNode.h qpgeomNode.I \
|
||||
qplensNode.h qplensNode.I \
|
||||
nodeChain.h nodeChain.I \
|
||||
nodeChainComponent.h nodeChainComponent.I \
|
||||
pandaNode.h pandaNode.I \
|
||||
pipeline.h pipeline.I \
|
||||
pipelineCycler.h pipelineCycler.I \
|
||||
|
|
@ -21,10 +25,11 @@
|
|||
renderAttrib.h renderAttrib.I \
|
||||
renderState.h renderState.I \
|
||||
textureAttrib.h textureAttrib.I \
|
||||
transformAttrib.h transformAttrib.I
|
||||
transformState.h transformState.I
|
||||
|
||||
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
|
||||
#define INCLUDED_SOURCES \
|
||||
qpcamera.cxx \
|
||||
colorAttrib.cxx \
|
||||
config_pgraph.cxx \
|
||||
cullHandler.cxx \
|
||||
|
|
@ -33,6 +38,9 @@
|
|||
cycleDataReader.cxx \
|
||||
cycleDataWriter.cxx \
|
||||
qpgeomNode.cxx \
|
||||
qplensNode.cxx \
|
||||
nodeChain.cxx \
|
||||
nodeChainComponent.cxx \
|
||||
pandaNode.cxx \
|
||||
pipeline.cxx \
|
||||
pipelineCycler.cxx \
|
||||
|
|
@ -40,7 +48,7 @@
|
|||
renderAttrib.cxx \
|
||||
renderState.cxx \
|
||||
textureAttrib.cxx \
|
||||
transformAttrib.cxx
|
||||
transformState.cxx
|
||||
|
||||
#if $[DONT_COMBINE_PGRAPH]
|
||||
#define SOURCES $[SOURCES] $[INCLUDED_SOURCES]
|
||||
|
|
@ -49,6 +57,7 @@
|
|||
#endif
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
qpcamera.h qpcamera.I \
|
||||
colorAttrib.h colorAttrib.I \
|
||||
config_pgraph.h \
|
||||
cullHandler.h \
|
||||
|
|
@ -57,6 +66,9 @@
|
|||
cycleDataReader.h cycleDataReader.I \
|
||||
cycleDataWriter.h cycleDataWriter.I \
|
||||
qpgeomNode.h qpgeomNode.I \
|
||||
qplensNode.h qplensNode.I \
|
||||
nodeChain.h nodeChain.I \
|
||||
nodeChainComponent.h nodeChainComponent.I \
|
||||
pandaNode.h pandaNode.I \
|
||||
pipeline.h pipeline.I \
|
||||
pipelineCycler.h pipelineCycler.I \
|
||||
|
|
@ -64,7 +76,7 @@
|
|||
renderAttrib.h renderAttrib.I \
|
||||
renderState.h renderState.I \
|
||||
textureAttrib.h textureAttrib.I \
|
||||
transformAttrib.h transformAttrib.I
|
||||
transformState.h transformState.I
|
||||
|
||||
#define IGATESCAN all
|
||||
|
||||
|
|
|
|||
|
|
@ -18,13 +18,18 @@
|
|||
|
||||
#include "config_pgraph.h"
|
||||
|
||||
#include "qpcamera.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "qpgeomNode.h"
|
||||
#include "qplensNode.h"
|
||||
#include "nodeChain.h"
|
||||
#include "nodeChainComponent.h"
|
||||
#include "pandaNode.h"
|
||||
#include "renderAttrib.h"
|
||||
#include "renderState.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "transformAttrib.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "transformState.h"
|
||||
|
||||
#include "dconfig.h"
|
||||
|
||||
|
|
@ -52,18 +57,24 @@ init_libpgraph() {
|
|||
}
|
||||
initialized = true;
|
||||
|
||||
qpCamera::init_type();
|
||||
ColorAttrib::init_type();
|
||||
qpGeomNode::init_type();
|
||||
qpLensNode::init_type();
|
||||
NodeChain::init_type();
|
||||
NodeChainComponent::init_type();
|
||||
PandaNode::init_type();
|
||||
RenderAttrib::init_type();
|
||||
RenderState::init_type();
|
||||
TextureAttrib::init_type();
|
||||
TransformAttrib::init_type();
|
||||
ColorAttrib::init_type();
|
||||
TransformState::init_type();
|
||||
|
||||
ColorAttrib::register_with_read_factory();
|
||||
qpGeomNode::register_with_read_factory();
|
||||
PandaNode::register_with_read_factory();
|
||||
RenderState::register_with_read_factory();
|
||||
TextureAttrib::register_with_read_factory();
|
||||
TransformAttrib::register_with_read_factory();
|
||||
ColorAttrib::register_with_read_factory();
|
||||
TransformState::register_with_read_factory();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "cullHandler.h"
|
||||
#include "geom.h"
|
||||
#include "transformState.h"
|
||||
#include "renderState.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -31,6 +32,7 @@
|
|||
// it's not intended to be used except for debugging.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CullHandler::
|
||||
record_geom(Geom *geom, const RenderState *state) {
|
||||
cerr << *geom << " " << *state << "\n";
|
||||
record_geom(Geom *geom, const TransformState *transform,
|
||||
const RenderState *state) {
|
||||
cerr << *geom << " " << *transform << " " << *state << "\n";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "pandabase.h"
|
||||
|
||||
class Geom;
|
||||
class TransformState;
|
||||
class RenderState;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -34,7 +35,8 @@ class RenderState;
|
|||
class EXPCL_PANDA CullHandler {
|
||||
public:
|
||||
// virtual void begin_decal();
|
||||
virtual void record_geom(Geom *geom, const RenderState *state);
|
||||
virtual void record_geom(Geom *geom, const TransformState *transform,
|
||||
const RenderState *state);
|
||||
// virtual void push_decal();
|
||||
// virtual void pop_decal();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ INLINE CycleDataReader<CycleDataType>::
|
|||
CycleDataReader(const PipelineCycler<CycleDataType> &cycler) :
|
||||
_cycler(cycler)
|
||||
{
|
||||
_pointer = (const CycleDataType *)_cycler.read();
|
||||
_pointer = _cycler.read();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ INLINE CycleDataWriter<CycleDataType>::
|
|||
CycleDataWriter(PipelineCycler<CycleDataType> &cycler) :
|
||||
_cycler(cycler)
|
||||
{
|
||||
_pointer = (CycleDataType *)_cycler.write();
|
||||
_pointer = _cycler.write();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -0,0 +1,323 @@
|
|||
// Filename: nodeChain.I
|
||||
// Created by: drose (25Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: NodeChain::Default Constructor
|
||||
// Access: Published
|
||||
// Description: This constructs an empty NodeChain with no nodes. It
|
||||
// cannot be extended, since you cannot add nodes without
|
||||
// first specifying the top node. Use the constructor
|
||||
// that receives a node if you ever want to do anything
|
||||
// with this chain.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChain::
|
||||
NodeChain() :
|
||||
_error_type(ET_ok)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::Constructor
|
||||
// Access: Published
|
||||
// Description: This constructs an empty NodeChain with a single node.
|
||||
// This chain may now be extended by repeatedly calling
|
||||
// push_back() with each node below that node in
|
||||
// sequence.
|
||||
//
|
||||
// If the Node pointer is NULL, this quietly creates an
|
||||
// empty NodeChain.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChain::
|
||||
NodeChain(PandaNode *top_node) :
|
||||
_error_type(ET_ok)
|
||||
{
|
||||
if (top_node != (PandaNode *)NULL) {
|
||||
_head = top_node->get_generic_component();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::Copy Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChain::
|
||||
NodeChain(const NodeChain ©) :
|
||||
_head(copy._head),
|
||||
_error_type(copy._error_type)
|
||||
{
|
||||
uncollapse_head();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::Copy Assignment Operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void NodeChain::
|
||||
operator = (const NodeChain ©) {
|
||||
_head = copy._head;
|
||||
_error_type = copy._error_type;
|
||||
uncollapse_head();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::not_found named constructor
|
||||
// Access: Published, Static
|
||||
// Description: Creates a NodeChain with the ET_not_found error type
|
||||
// set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChain NodeChain::
|
||||
not_found() {
|
||||
NodeChain result;
|
||||
result._error_type = ET_not_found;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::removed named constructor
|
||||
// Access: Published, Static
|
||||
// Description: Creates a NodeChain with the ET_removed error type
|
||||
// set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChain NodeChain::
|
||||
removed() {
|
||||
NodeChain result;
|
||||
result._error_type = ET_removed;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::fail named constructor
|
||||
// Access: Published, Static
|
||||
// Description: Creates a NodeChain with the ET_fail error type
|
||||
// set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChain NodeChain::
|
||||
fail() {
|
||||
NodeChain result;
|
||||
result._error_type = ET_fail;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::is_empty
|
||||
// Access: Published
|
||||
// Description: Returns true if the NodeChain contains no nodes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool NodeChain::
|
||||
is_empty() const {
|
||||
return (_head == (NodeChainComponent *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::is_singleton
|
||||
// Access: Published
|
||||
// Description: Returns true if the NodeChain contains exactly one
|
||||
// node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool NodeChain::
|
||||
is_singleton() const {
|
||||
uncollapse_head();
|
||||
return (_head != (NodeChainComponent *)NULL && _head->is_top_node());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_error_type
|
||||
// Access: Published
|
||||
// Description: If is_empty() is true, this returns a code that
|
||||
// represents the reason why the NodeChain is empty.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChain::ErrorType NodeChain::
|
||||
get_error_type() const {
|
||||
return _error_type;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::node
|
||||
// Access: Published
|
||||
// Description: Returns the bottom node of the path, or NULL if the
|
||||
// path is empty.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *NodeChain::
|
||||
node() const {
|
||||
if (is_empty()) {
|
||||
return (PandaNode *)NULL;
|
||||
}
|
||||
return _head->get_node();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::has_parent
|
||||
// Access: Published
|
||||
// Description: Returns true if the node at the bottom of the
|
||||
// NodeChain has a parent; i.e. the NodeChain contains at
|
||||
// least two nodes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool NodeChain::
|
||||
has_parent() const {
|
||||
return !is_empty() && !is_singleton();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_parent
|
||||
// Access: Published
|
||||
// Description: Returns the NodeChain to the parent of the bottom
|
||||
// node: that is, this NodeChain, shortened by one node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChain NodeChain::
|
||||
get_parent() const {
|
||||
nassertr(has_parent(), NodeChain::fail());
|
||||
NodeChain parent(*this);
|
||||
parent._head = parent._head->get_next();
|
||||
return parent;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::attach_new_node
|
||||
// Access: Published
|
||||
// Description: Creates an ordinary PandaNode and attaches it below
|
||||
// the current NodeChain, returning a new NodeChain that
|
||||
// references it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChain NodeChain::
|
||||
attach_new_node(const string &name, int sort) const {
|
||||
nassertr(verify_complete(), NodeChain::fail());
|
||||
nassertr(!is_empty(), *this);
|
||||
|
||||
return attach_new_node(new PandaNode(name), sort);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_net_state
|
||||
// Access: Published
|
||||
// Description: Returns the net state on this node from the root.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPT(RenderState) NodeChain::
|
||||
get_net_state() const {
|
||||
uncollapse_head();
|
||||
return r_get_net_state(_head);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_net_transform
|
||||
// Access: Published
|
||||
// Description: Returns the net transform on this node from the root.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPT(TransformState) NodeChain::
|
||||
get_net_transform() const {
|
||||
uncollapse_head();
|
||||
return r_get_net_transform(_head);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_mat
|
||||
// Access: Published
|
||||
// Description: Returns the matrix that describes the coordinate
|
||||
// space of this node, relative to the other
|
||||
// node's coordinate space. If either NodeChain is
|
||||
// empty, it is taken to indicate the top of the graph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LMatrix4f &NodeChain::
|
||||
get_mat(const NodeChain &other) const {
|
||||
CPT(TransformState) transform = get_rel_transform(other);
|
||||
// We can safely assume the transform won't go away when the
|
||||
// function returns, since its reference count is also held in the
|
||||
// cache. This assumption allows us to return a reference to the
|
||||
// matrix, instead of having to return a matrix on the stack.
|
||||
nassertr(transform->get_ref_count() > 1, LMatrix4f::ident_mat());
|
||||
return transform->get_mat();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::operator ==
|
||||
// Access: Published
|
||||
// Description: Returns true if the two chains are equivalent; that
|
||||
// is, if they contain the same list of nodes in the same
|
||||
// order.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool NodeChain::
|
||||
operator == (const NodeChain &other) const {
|
||||
return (compare_to(other) == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::operator !=
|
||||
// Access: Published
|
||||
// Description: Returns true if the two chains are not equivalent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool NodeChain::
|
||||
operator != (const NodeChain &other) const {
|
||||
return (compare_to(other) != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::operator <
|
||||
// Access: Published
|
||||
// Description: Returns true if this NodeChain sorts before the other
|
||||
// one, false otherwise. The sorting order of two
|
||||
// nonequivalent NodeChains is consistent but undefined,
|
||||
// and is useful only for storing NodeChains in a sorted
|
||||
// container like an STL set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool NodeChain::
|
||||
operator < (const NodeChain &other) const {
|
||||
return (compare_to(other) < 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::compare_to
|
||||
// Access: Published
|
||||
// Description: Returns a number less than zero if this NodeChain
|
||||
// sorts before the other one, greater than zero if it
|
||||
// sorts after, or zero if they are equivalent.
|
||||
//
|
||||
// Two NodeChains are considered equivalent if they
|
||||
// consist of exactly the same list of nodes in the same
|
||||
// order. Otherwise, they are different; different
|
||||
// NodeChains will be ranked in a consistent but
|
||||
// undefined ordering; the ordering is useful only for
|
||||
// placing the NodeChains in a sorted container like an
|
||||
// STL set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int NodeChain::
|
||||
compare_to(const NodeChain &other) const {
|
||||
return r_compare_to(_head, other._head);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::output
|
||||
// Access: Published
|
||||
// Description: Writes a sensible description of the NodeChain to the
|
||||
// indicated output stream.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void NodeChain::
|
||||
output(ostream &out) const {
|
||||
if (_head == (NodeChainComponent *)NULL) {
|
||||
out << "(empty)";
|
||||
} else {
|
||||
r_output(out, _head);
|
||||
}
|
||||
}
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const NodeChain &node_chain) {
|
||||
node_chain.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,514 @@
|
|||
// Filename: nodeChain.cxx
|
||||
// Created by: drose (25Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "nodeChain.h"
|
||||
#include "node.h"
|
||||
#include "namedNode.h"
|
||||
#include "config_pgraph.h"
|
||||
#include "plist.h"
|
||||
|
||||
TypeHandle NodeChain::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_num_nodes
|
||||
// Access: Published
|
||||
// Description: Returns the number of nodes in the path.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int NodeChain::
|
||||
get_num_nodes() const {
|
||||
if (is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
uncollapse_head();
|
||||
return _head->get_length();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_node
|
||||
// Access: Published
|
||||
// Description: Returns the nth node of the path, where 0 is the
|
||||
// bottom node and get_num_nodes() - 1 is the top node.
|
||||
// This requires iterating through the path.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *NodeChain::
|
||||
get_node(int index) const {
|
||||
nassertr(index >= 0 && index < get_num_nodes(), NULL);
|
||||
|
||||
uncollapse_head();
|
||||
NodeChainComponent *comp = _head;
|
||||
while (index > 0) {
|
||||
// If this assertion fails, the index was out of range; the
|
||||
// component's length must have been invalid.
|
||||
nassertr(comp != (NodeChainComponent *)NULL, NULL);
|
||||
comp = comp->get_next();
|
||||
index--;
|
||||
}
|
||||
|
||||
// If this assertion fails, the index was out of range; the
|
||||
// component's length must have been invalid.
|
||||
nassertr(comp != (NodeChainComponent *)NULL, NULL);
|
||||
return comp->get_node();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_top_node
|
||||
// Access: Published
|
||||
// Description: Returns the top node of the path, or NULL if the path
|
||||
// is empty. This requires iterating through the path.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *NodeChain::
|
||||
get_top_node() const {
|
||||
if (is_empty()) {
|
||||
return (PandaNode *)NULL;
|
||||
}
|
||||
|
||||
uncollapse_head();
|
||||
NodeChainComponent *comp = _head;
|
||||
while (!comp->is_top_node()) {
|
||||
comp = comp->get_next();
|
||||
nassertr(comp != (NodeChainComponent *)NULL, NULL);
|
||||
}
|
||||
|
||||
return comp->get_node();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::reparent_to
|
||||
// Access: Published
|
||||
// Description: Removes the bottom node of the NodeChain from its
|
||||
// current parent and attaches it to the bottom node of
|
||||
// the indicated NodeChain.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NodeChain::
|
||||
reparent_to(const NodeChain &other, int sort) {
|
||||
nassertv(other.verify_complete());
|
||||
nassertv_always(!is_empty());
|
||||
nassertv_always(!other.is_empty());
|
||||
|
||||
uncollapse_head();
|
||||
other.uncollapse_head();
|
||||
PandaNode::reparent(other._head, _head, sort);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::wrt_reparent_to
|
||||
// Access: Published
|
||||
// Description: This functions identically to reparent_to(), except
|
||||
// the transform on this node is also adjusted so that
|
||||
// the node remains in the same place in world
|
||||
// coordinates, even if it is reparented into a
|
||||
// different coordinate system.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NodeChain::
|
||||
wrt_reparent_to(const NodeChain &other, int sort) {
|
||||
nassertv(other.verify_complete());
|
||||
nassertv_always(!is_empty());
|
||||
nassertv_always(!other.is_empty());
|
||||
|
||||
//****
|
||||
/*
|
||||
LMatrix4f mat = get_mat(other);
|
||||
set_mat(mat);
|
||||
*/
|
||||
|
||||
reparent_to(other, sort);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::instance_to
|
||||
// Access: Published
|
||||
// Description: Adds the bottom node of the NodeChain as a child of
|
||||
// the bottom node of the indicated other NodeChain. Any
|
||||
// other parent-child relations of the node are
|
||||
// unchanged; in particular, the node is not removed
|
||||
// from its existing parent, if any.
|
||||
//
|
||||
// If the node already had an existing parent, this
|
||||
// method will create a new instance of the node within
|
||||
// the scene graph.
|
||||
//
|
||||
// This does not change the NodeChain itself, but does
|
||||
// return a new NodeChain that reflects the new instance
|
||||
// node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
NodeChain NodeChain::
|
||||
instance_to(const NodeChain &other, int sort) const {
|
||||
nassertr(verify_complete(), NodeChain::fail());
|
||||
nassertr(!is_empty(), NodeChain::fail());
|
||||
nassertr(!other.is_empty(), NodeChain::fail());
|
||||
|
||||
uncollapse_head();
|
||||
other.uncollapse_head();
|
||||
|
||||
NodeChain new_instance;
|
||||
new_instance._head = PandaNode::attach(other._head, node(), sort);
|
||||
|
||||
return new_instance;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::copy_to
|
||||
// Access: Published
|
||||
// Description: Functions exactly like instance_to(), except a deep
|
||||
// copy is made of the bottom node and all of its
|
||||
// descendents, which is then parented to the indicated
|
||||
// node. A NodeChain to the newly created copy is
|
||||
// returned.
|
||||
//
|
||||
// Certain kinds of nodes may not be copied; if one of
|
||||
// these is encountered, the node will be "copied" as
|
||||
// the nearest copyable base class. For instance, a
|
||||
// Camera node in the graph will become a simple
|
||||
// NamedNode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
NodeChain NodeChain::
|
||||
copy_to(const NodeChain &other, int sort) const {
|
||||
//*****
|
||||
return instance_to(other, sort);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::attach_new_node
|
||||
// Access: Published
|
||||
// Description: Attaches a new node, with or without existing
|
||||
// parents, to the scene graph below the bottom node of
|
||||
// this NodeChain. This is the preferred way to add
|
||||
// nodes to the graph.
|
||||
//
|
||||
// This does *not* automatically extend the current
|
||||
// NodeChain to reflect the attachment; however, a
|
||||
// NodeChain that does reflect this extension is
|
||||
// returned.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
NodeChain NodeChain::
|
||||
attach_new_node(PandaNode *node, int sort) const {
|
||||
nassertr(verify_complete(), NodeChain::fail());
|
||||
nassertr(!is_empty(), NodeChain());
|
||||
nassertr(node != (PandaNode *)NULL, NodeChain());
|
||||
|
||||
uncollapse_head();
|
||||
NodeChain new_path(*this);
|
||||
new_path._head = PandaNode::attach(_head, node, sort);
|
||||
return new_path;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::remove_node
|
||||
// Access: Published
|
||||
// Description: Disconnects the bottom node from the scene graph.
|
||||
// This will also delete the node if there are no other
|
||||
// pointers to it.
|
||||
//
|
||||
// Normally, this should be called only when you are
|
||||
// really done with the node. If you want to remove a
|
||||
// node from the scene graph but keep it around for
|
||||
// later, you should probably use reparent_to() and put
|
||||
// it under a holding node instead.
|
||||
//
|
||||
// After the node is removed, the NodeChain will have
|
||||
// been cleared.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NodeChain::
|
||||
remove_node() {
|
||||
nassertv(_error_type != ET_not_found);
|
||||
if (is_empty()) {
|
||||
// If we have no arcs (maybe we were already removed), quietly do
|
||||
// nothing except to ensure the NodeChain is clear.
|
||||
(*this) = NodeChain::removed();
|
||||
return;
|
||||
}
|
||||
|
||||
uncollapse_head();
|
||||
PandaNode::detach(_head);
|
||||
|
||||
(*this) = NodeChain::removed();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_rel_state
|
||||
// Access: Published
|
||||
// Description: Returns the state changes that must be made to
|
||||
// transition from the render state of this node to the
|
||||
// render state of the other node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderState) NodeChain::
|
||||
get_rel_state(const NodeChain &other) const {
|
||||
if (is_empty()) {
|
||||
return other.get_net_state();
|
||||
}
|
||||
if (other.is_empty()) {
|
||||
return get_net_state()->invert_compose(RenderState::make_empty());
|
||||
}
|
||||
|
||||
nassertr(verify_complete(), RenderState::make_empty());
|
||||
nassertr(other.verify_complete(), RenderState::make_empty());
|
||||
|
||||
int a_count, b_count;
|
||||
find_common_ancestor(*this, other, a_count, b_count);
|
||||
|
||||
CPT(RenderState) a_state = r_get_partial_state(_head, a_count);
|
||||
CPT(RenderState) b_state = r_get_partial_state(other._head, b_count);
|
||||
return a_state->invert_compose(b_state);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::get_rel_transform
|
||||
// Access: Published
|
||||
// Description: Returns the relative transform from this node to the
|
||||
// other node; i.e. the transformation of the other node
|
||||
// as seen from this node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) NodeChain::
|
||||
get_rel_transform(const NodeChain &other) const {
|
||||
if (is_empty()) {
|
||||
return other.get_net_transform();
|
||||
}
|
||||
if (other.is_empty()) {
|
||||
return get_net_transform()->invert_compose(TransformState::make_identity());
|
||||
}
|
||||
|
||||
nassertr(verify_complete(), TransformState::make_identity());
|
||||
nassertr(other.verify_complete(), TransformState::make_identity());
|
||||
|
||||
int a_count, b_count;
|
||||
find_common_ancestor(*this, other, a_count, b_count);
|
||||
|
||||
CPT(TransformState) a_transform = r_get_partial_transform(_head, a_count);
|
||||
CPT(TransformState) b_transform = r_get_partial_transform(other._head, b_count);
|
||||
return a_transform->invert_compose(b_transform);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::verify_complete
|
||||
// Access: Published
|
||||
// Description: Returns true if all of the nodes described in the
|
||||
// NodeChain are connected *and* the top node is the top
|
||||
// of the graph, or false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool NodeChain::
|
||||
verify_complete() const {
|
||||
if (is_empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uncollapse_head();
|
||||
const NodeChainComponent *comp = _head;
|
||||
nassertr(comp != (const NodeChainComponent *)NULL, false);
|
||||
|
||||
PandaNode *node = comp->get_node();
|
||||
nassertr(node != (const PandaNode *)NULL, false);
|
||||
int length = comp->get_length();
|
||||
|
||||
comp = comp->get_next();
|
||||
length--;
|
||||
while (comp != (const NodeChainComponent *)NULL) {
|
||||
PandaNode *next_node = comp->get_node();
|
||||
nassertr(next_node != (const PandaNode *)NULL, false);
|
||||
|
||||
if (next_node->find_child(node) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (comp->get_length() != length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
node = next_node;
|
||||
comp = comp->get_next();
|
||||
length--;
|
||||
}
|
||||
|
||||
// Now that we've reached the top, we should have no parents.
|
||||
return length == 0 && node->get_num_parents() == 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::uncollapse_head
|
||||
// Access: Private
|
||||
// Description: Quietly and transparently uncollapses the _head
|
||||
// pointer if it needs it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NodeChain::
|
||||
uncollapse_head() const {
|
||||
if (_head != (NodeChainComponent *)NULL && _head->is_collapsed()) {
|
||||
((NodeChain *)this)->_head = _head->uncollapse();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::find_common_ancestor
|
||||
// Access: Private, Static
|
||||
// Description: Walks up from both NodeChains to find the first node
|
||||
// that both have in common, if any. Fills a_count and
|
||||
// b_count with the number of nodes below the common
|
||||
// node in each chain.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NodeChain::
|
||||
find_common_ancestor(const NodeChain &a, const NodeChain &b,
|
||||
int &a_count, int &b_count) {
|
||||
nassertv(!a.is_empty() && !b.is_empty());
|
||||
a.uncollapse_head();
|
||||
b.uncollapse_head();
|
||||
|
||||
NodeChainComponent *ac = a._head;
|
||||
NodeChainComponent *bc = b._head;
|
||||
a_count = 0;
|
||||
b_count = 0;
|
||||
|
||||
// Shorten up the longer one until they are the same length.
|
||||
while (ac->get_length() > bc->get_length()) {
|
||||
nassertv(ac != (NodeChainComponent *)NULL);
|
||||
ac = ac->get_next();
|
||||
a_count++;
|
||||
}
|
||||
while (bc->get_length() > ac->get_length()) {
|
||||
nassertv(bc != (NodeChainComponent *)NULL);
|
||||
bc = bc->get_next();
|
||||
b_count++;
|
||||
}
|
||||
|
||||
// Now shorten them both up until we reach the same component.
|
||||
while (ac != bc) {
|
||||
// These shouldn't go to NULL unless they both go there together.
|
||||
nassertv(ac != (NodeChainComponent *)NULL);
|
||||
nassertv(bc != (NodeChainComponent *)NULL);
|
||||
ac = ac->get_next();
|
||||
a_count++;
|
||||
bc = bc->get_next();
|
||||
b_count++;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::r_get_net_state
|
||||
// Access: Private
|
||||
// Description: Recursively determines the net state chnages to the
|
||||
// indicated component node from the root of the graph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderState) NodeChain::
|
||||
r_get_net_state(NodeChainComponent *comp) const {
|
||||
if (comp == (NodeChainComponent *)NULL) {
|
||||
return RenderState::make_empty();
|
||||
} else {
|
||||
CPT(RenderState) state = comp->get_node()->get_state();
|
||||
return r_get_net_state(comp->get_next())->compose(state);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::r_get_partial_state
|
||||
// Access: Private
|
||||
// Description: Recursively determines the net state changes to the
|
||||
// indicated component node from the nth node above it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderState) NodeChain::
|
||||
r_get_partial_state(NodeChainComponent *comp, int n) const {
|
||||
nassertr(comp != (NodeChainComponent *)NULL, RenderState::make_empty());
|
||||
if (n == 0) {
|
||||
return RenderState::make_empty();
|
||||
} else {
|
||||
CPT(RenderState) state = comp->get_node()->get_state();
|
||||
return r_get_partial_state(comp->get_next(), n - 1)->compose(state);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::r_get_net_transform
|
||||
// Access: Private
|
||||
// Description: Recursively determines the net transform to the
|
||||
// indicated component node from the root of the graph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) NodeChain::
|
||||
r_get_net_transform(NodeChainComponent *comp) const {
|
||||
if (comp == (NodeChainComponent *)NULL) {
|
||||
return TransformState::make_identity();
|
||||
} else {
|
||||
CPT(TransformState) transform = comp->get_node()->get_transform();
|
||||
return r_get_net_transform(comp->get_next())->compose(transform);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::r_get_partial_transform
|
||||
// Access: Private
|
||||
// Description: Recursively determines the net transform to the
|
||||
// indicated component node from the nth node above it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) NodeChain::
|
||||
r_get_partial_transform(NodeChainComponent *comp, int n) const {
|
||||
nassertr(comp != (NodeChainComponent *)NULL, TransformState::make_identity());
|
||||
if (n == 0) {
|
||||
return TransformState::make_identity();
|
||||
} else {
|
||||
CPT(TransformState) transform = comp->get_node()->get_transform();
|
||||
return r_get_partial_transform(comp->get_next(), n - 1)->compose(transform);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::r_output
|
||||
// Access: Private
|
||||
// Description: The recursive implementation of output(), this writes
|
||||
// the names of each node component in order from
|
||||
// beginning to end, by first walking to the end of the
|
||||
// linked list and then outputting from there.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NodeChain::
|
||||
r_output(ostream &out, NodeChainComponent *comp) const {
|
||||
NodeChainComponent *next = comp->get_next();
|
||||
if (next != (NodeChainComponent *)NULL) {
|
||||
// This is not the head of the list; keep going up.
|
||||
r_output(out, next);
|
||||
out << "/";
|
||||
}
|
||||
|
||||
// Now output this component.
|
||||
PandaNode *node = comp->get_node();
|
||||
if (node->has_name()) {
|
||||
out << node->get_name();
|
||||
} else {
|
||||
out << "+" << node->get_type();
|
||||
}
|
||||
out << "[" << comp->get_length() << "]";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChain::r_compare_to
|
||||
// Access: Private, Static
|
||||
// Description: The recursive implementation of compare_to(). Returns
|
||||
// < 0 if a sorts before b, > 0 if b sorts before a, or
|
||||
// == 0 if they are equivalent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int NodeChain::
|
||||
r_compare_to(const NodeChainComponent *a, const NodeChainComponent *b) {
|
||||
if (a == b) {
|
||||
return 0;
|
||||
|
||||
} else if (a == (const NodeChainComponent *)NULL) {
|
||||
return -1;
|
||||
|
||||
} else if (b == (const NodeChainComponent *)NULL) {
|
||||
return 1;
|
||||
|
||||
} else if (a->get_node() != b->get_node()) {
|
||||
return a->get_node() - b->get_node();
|
||||
|
||||
} else {
|
||||
return r_compare_to(a->get_next(), b->get_next());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
// Filename: nodeChain.h
|
||||
// Created by: drose (25Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 NODECHAIN_H
|
||||
#define NODECHAIN_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "renderState.h"
|
||||
#include "transformState.h"
|
||||
#include "nodeChainComponent.h"
|
||||
|
||||
#include "pointerTo.h"
|
||||
#include "referenceCount.h"
|
||||
#include "notify.h"
|
||||
#include "typedObject.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : NodeChain
|
||||
// Description : A NodeChain is the fundamental system for
|
||||
// disambiguating instances and manipulating the scene
|
||||
// graph. NodeChain is the base class of NodePath,
|
||||
// which adds a bit more high-level functionality, but
|
||||
// the fundamental scene graph manipulations are defined
|
||||
// at the NodeChain level.
|
||||
//
|
||||
// A NodeChain is a list of connected nodes from the
|
||||
// root of the graph to any sub-node. Each NodeChain
|
||||
// therefore unqiuely describes one instance of a node.
|
||||
//
|
||||
// NodeChains themselves are lightweight objects that
|
||||
// may easily be copied and passed by value. Their data
|
||||
// is stored as a series of NodeChainComponents that are
|
||||
// stored on the nodes. Holding a NodeChain will keep a
|
||||
// reference count to all the nodes in the chain.
|
||||
// However, if any node in the chain is removed or
|
||||
// reparented (perhaps through a different NodeChain),
|
||||
// the NodeChain will automatically be updated to
|
||||
// reflect the changes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA NodeChain {
|
||||
PUBLISHED:
|
||||
// This enumeration is returned by get_error_type() for an empty
|
||||
// NodeChain to report the reason it's empty.
|
||||
enum ErrorType {
|
||||
ET_ok = 0, // i.e. not empty, or never assigned to anything.
|
||||
ET_not_found, // returned from a failed find() or similar function.
|
||||
ET_removed, // remove_node() was previously called on this NodeChain.
|
||||
ET_fail, // general failure return from some function.
|
||||
};
|
||||
|
||||
INLINE NodeChain();
|
||||
INLINE NodeChain(PandaNode *top_node);
|
||||
INLINE NodeChain(const NodeChain ©);
|
||||
INLINE void operator = (const NodeChain ©);
|
||||
|
||||
INLINE static NodeChain not_found();
|
||||
INLINE static NodeChain removed();
|
||||
INLINE static NodeChain fail();
|
||||
|
||||
// Methods to query a NodeChain's contents.
|
||||
INLINE bool is_empty() const;
|
||||
INLINE bool is_singleton() const;
|
||||
int get_num_nodes() const;
|
||||
PandaNode *get_node(int index) const;
|
||||
|
||||
INLINE ErrorType get_error_type() const;
|
||||
|
||||
PandaNode *get_top_node() const;
|
||||
INLINE PandaNode *node() const;
|
||||
|
||||
// Methods that return collections of NodePaths derived from or
|
||||
// related to this one.
|
||||
|
||||
/*
|
||||
NodeChainCollection get_siblings() const;
|
||||
NodeChainCollection get_children() const;
|
||||
INLINE int get_num_children() const;
|
||||
INLINE NodeChain get_child(int n) const;
|
||||
*/
|
||||
|
||||
INLINE bool has_parent() const;
|
||||
INLINE NodeChain get_parent() const;
|
||||
|
||||
/*
|
||||
INLINE NodeChain find_path_down_to(Node *dnode) const;
|
||||
INLINE NodeChain find(const string &chain) const;
|
||||
|
||||
NodeChainCollection
|
||||
find_all_paths_down_to(Node *dnode) const;
|
||||
|
||||
NodeChainCollection
|
||||
find_all_matches(const string &chain) const;
|
||||
*/
|
||||
|
||||
// Methods that actually move nodes around in the scene graph. The
|
||||
// optional "sort" parameter can be used to force a particular
|
||||
// ordering between sibling nodes, useful when dealing with LOD's
|
||||
// and similar switch nodes. If the sort value is the same, nodes
|
||||
// will be arranged in the order they were added.
|
||||
void reparent_to(const NodeChain &other, int sort = 0);
|
||||
void wrt_reparent_to(const NodeChain &other, int sort = 0);
|
||||
NodeChain instance_to(const NodeChain &other, int sort = 0) const;
|
||||
NodeChain copy_to(const NodeChain &other, int sort = 0) const;
|
||||
NodeChain attach_new_node(PandaNode *node, int sort = 0) const;
|
||||
INLINE NodeChain attach_new_node(const string &name, int sort = 0) const;
|
||||
void remove_node();
|
||||
|
||||
|
||||
// Relative transform and state changes between nodes.
|
||||
CPT(RenderState) get_rel_state(const NodeChain &other) const;
|
||||
INLINE CPT(RenderState) get_net_state() const;
|
||||
|
||||
CPT(TransformState) get_rel_transform(const NodeChain &other) const;
|
||||
INLINE CPT(TransformState) get_net_transform() const;
|
||||
|
||||
INLINE const LMatrix4f &get_mat(const NodeChain &other) const;
|
||||
|
||||
bool verify_complete() const;
|
||||
|
||||
public:
|
||||
INLINE bool operator == (const NodeChain &other) const;
|
||||
INLINE bool operator != (const NodeChain &other) const;
|
||||
INLINE bool operator < (const NodeChain &other) const;
|
||||
INLINE int compare_to(const NodeChain &other) const;
|
||||
|
||||
INLINE void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
void uncollapse_head() const;
|
||||
static void find_common_ancestor(const NodeChain &a, const NodeChain &b,
|
||||
int &a_count, int &b_count);
|
||||
|
||||
CPT(RenderState) r_get_net_state(NodeChainComponent *comp) const;
|
||||
CPT(RenderState) r_get_partial_state(NodeChainComponent *comp, int n) const;
|
||||
CPT(TransformState) r_get_net_transform(NodeChainComponent *comp) const;
|
||||
CPT(TransformState) r_get_partial_transform(NodeChainComponent *comp, int n) const;
|
||||
void r_output(ostream &out, NodeChainComponent *comp) const;
|
||||
static int r_compare_to(const NodeChainComponent *a, const NodeChainComponent *v);
|
||||
|
||||
PT(NodeChainComponent) _head;
|
||||
ErrorType _error_type;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
register_type(_type_handle, "NodeChain");
|
||||
}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const NodeChain &node_chain);
|
||||
|
||||
#include "nodeChain.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
// Filename: nodeChainComponent.I
|
||||
// Created by: drose (25Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: NodeChainComponent::CData::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChainComponent::CData::
|
||||
CData() {
|
||||
_length = 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::CData::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChainComponent::CData::
|
||||
CData(const NodeChainComponent::CData ©) :
|
||||
_next(copy._next),
|
||||
_length(copy._length)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::Constructor
|
||||
// Access: Private
|
||||
// Description: Constructs a new NodeChainComponent from the
|
||||
// indicated node. Don't try to call this directly; ask
|
||||
// the PandaNode to do it for you.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChainComponent::
|
||||
NodeChainComponent(PandaNode *node, NodeChainComponent *next) :
|
||||
_node(node)
|
||||
{
|
||||
#ifdef DO_MEMORY_USAGE
|
||||
MemoryUsage::update_type(this, get_class_type());
|
||||
#endif
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_next = next;
|
||||
|
||||
if (next != (NodeChainComponent *)NULL) {
|
||||
cdata->_length = next->get_length() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: NodeChainComponents should not be copied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChainComponent::
|
||||
NodeChainComponent(const NodeChainComponent ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: NodeChainComponents should not be copied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void NodeChainComponent::
|
||||
operator = (const NodeChainComponent ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChainComponent::
|
||||
~NodeChainComponent() {
|
||||
nassertv(_node != (PandaNode *)NULL);
|
||||
_node->delete_component(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::get_node
|
||||
// Access: Public
|
||||
// Description: Returns the node referenced by this component.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *NodeChainComponent::
|
||||
get_node() const {
|
||||
return _node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::is_top_node
|
||||
// Access: Public
|
||||
// Description: Returns true if this component represents the top
|
||||
// node in the chain.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool NodeChainComponent::
|
||||
is_top_node() const {
|
||||
CDReader cdata(_cycler);
|
||||
return (cdata->_next == (NodeChainComponent *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::is_collapsed
|
||||
// Access: Public
|
||||
// Description: Returns true if this component has been collapsed
|
||||
// with another component. In this case, the component
|
||||
// itself is invalid, and the collapsed component should
|
||||
// be used instead.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool NodeChainComponent::
|
||||
is_collapsed() const {
|
||||
CDReader cdata(_cycler);
|
||||
return (cdata->_length == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::get_length
|
||||
// Access: Public
|
||||
// Description: Returns the length of the chain.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int NodeChainComponent::
|
||||
get_length() const {
|
||||
CDReader cdata(_cycler);
|
||||
nassertr(!is_collapsed(), 0);
|
||||
return cdata->_length;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::get_collapsed
|
||||
// Access: Public
|
||||
// Description: If is_collapsed() returns true, this is the component
|
||||
// that this one has been collapsed with, and should be
|
||||
// replaced with.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodeChainComponent *NodeChainComponent::
|
||||
get_collapsed() const {
|
||||
CDReader cdata(_cycler);
|
||||
nassertr(is_collapsed(), (NodeChainComponent *)NULL);
|
||||
return cdata->_next;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::set_next
|
||||
// Access: Private
|
||||
// Description: Sets the next pointer in the chain.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void NodeChainComponent::
|
||||
set_next(NodeChainComponent *next) {
|
||||
CDWriter cdata(_cycler);
|
||||
nassertv(!is_collapsed());
|
||||
nassertv(next != (NodeChainComponent *)NULL);
|
||||
cdata->_next = next;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::set_top_node
|
||||
// Access: Private
|
||||
// Description: Severs any connection to the next pointer in the
|
||||
// chain and makes this component a top node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void NodeChainComponent::
|
||||
set_top_node() {
|
||||
CDWriter cdata(_cycler);
|
||||
nassertv(!is_collapsed());
|
||||
cdata->_next = (NodeChainComponent *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::collapse_with
|
||||
// Access: Private
|
||||
// Description: Indicates that this component pointer is no longer
|
||||
// valid, and that the indicated component should be
|
||||
// used instead. This is done whenever two
|
||||
// NodeChainComponents have been collapsed together due
|
||||
// to an instance being removed higher up in the graph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void NodeChainComponent::
|
||||
collapse_with(NodeChainComponent *next) {
|
||||
CDWriter cdata(_cycler);
|
||||
nassertv(!is_collapsed());
|
||||
nassertv(next != (NodeChainComponent *)NULL);
|
||||
cdata->_next = next;
|
||||
cdata->_length = 0;
|
||||
|
||||
// We indicate a component has been collapsed by setting its length
|
||||
// to zero.
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// Filename: nodeChainComponent.cxx
|
||||
// Created by: drose (25Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "nodeChainComponent.h"
|
||||
|
||||
TypeHandle NodeChainComponent::_type_handle;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::CData::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CycleData *NodeChainComponent::CData::
|
||||
make_copy() const {
|
||||
return new CData(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::get_next
|
||||
// Access: Public
|
||||
// Description: Returns the next component in the chain.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
NodeChainComponent *NodeChainComponent::
|
||||
get_next() const {
|
||||
CDReader cdata(_cycler);
|
||||
nassertr(!is_collapsed(), (NodeChainComponent *)NULL);
|
||||
|
||||
NodeChainComponent *next = cdata->_next;
|
||||
|
||||
// If the next component has been collapsed, transparently update
|
||||
// the pointer to get the actual node, and store the new pointer,
|
||||
// before we return. Collapsing can happen at any time to any
|
||||
// component in the chain and we have to deal with it.
|
||||
if (next != (NodeChainComponent *)NULL && next->is_collapsed()) {
|
||||
next = next->uncollapse();
|
||||
((NodeChainComponent *)this)->set_next(next);
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::fix_length
|
||||
// Access: Public
|
||||
// Description: Checks that the length indicated by the component is
|
||||
// one more than the length of its predecessor. If this
|
||||
// is broken, fixes it and returns true indicating the
|
||||
// component has been changed; otherwise, returns false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool NodeChainComponent::
|
||||
fix_length() {
|
||||
int length_should_be = 1;
|
||||
if (!is_top_node()) {
|
||||
length_should_be = get_next()->get_length() + 1;
|
||||
}
|
||||
if (get_length() == length_should_be) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_length = length_should_be;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodeChainComponent::uncollapse
|
||||
// Access: Public
|
||||
// Description: Returns this component pointer if the component is
|
||||
// not collapsed; or if it has been collapsed, returns
|
||||
// the pointer it has been collapsed into.
|
||||
//
|
||||
// Collapsing can happen at any time to any component in
|
||||
// the chain and we have to deal with it. It happens
|
||||
// when a node is removed further up the chain that
|
||||
// results in two instances becoming the same thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
NodeChainComponent *NodeChainComponent::
|
||||
uncollapse() {
|
||||
NodeChainComponent *comp = this;
|
||||
|
||||
while (comp->is_collapsed()) {
|
||||
comp = comp->get_collapsed();
|
||||
}
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// Filename: nodeChainComponent.h
|
||||
// Created by: drose (25Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 NODECHAINCOMPONENT_H
|
||||
#define NODECHAINCOMPONENT_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "pointerTo.h"
|
||||
#include "referenceCount.h"
|
||||
#include "cycleData.h"
|
||||
#include "cycleDataReader.h"
|
||||
#include "cycleDataWriter.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : NodeChainComponent
|
||||
// Description : This is one component of a NodeChain. These are
|
||||
// stored on each PandaNode, as many as one for each of
|
||||
// the possible instances of the node (but they only
|
||||
// exist when they are requested, to minimize memory
|
||||
// waste). A NodeChain represents a singly-linked list
|
||||
// of these from an arbitrary component in the graph to
|
||||
// the root.
|
||||
//
|
||||
// This whole NodeChain system is used to disambiguate
|
||||
// instances in the scene graph, and the
|
||||
// NodeChainComponents are stored in the nodes
|
||||
// themselves to allow the nodes to keep these up to
|
||||
// date as the scene graph is manipulated.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA NodeChainComponent : public ReferenceCount {
|
||||
private:
|
||||
INLINE NodeChainComponent(PandaNode *node, NodeChainComponent *next = NULL);
|
||||
INLINE NodeChainComponent(const NodeChainComponent ©);
|
||||
INLINE void operator = (const NodeChainComponent ©);
|
||||
|
||||
public:
|
||||
INLINE ~NodeChainComponent();
|
||||
|
||||
INLINE PandaNode *get_node() const;
|
||||
INLINE bool is_top_node() const;
|
||||
INLINE bool is_collapsed() const;
|
||||
|
||||
NodeChainComponent *get_next() const;
|
||||
INLINE int get_length() const;
|
||||
INLINE NodeChainComponent *get_collapsed() const;
|
||||
|
||||
bool fix_length();
|
||||
NodeChainComponent *uncollapse();
|
||||
|
||||
private:
|
||||
INLINE void set_next(NodeChainComponent *next);
|
||||
INLINE void set_top_node();
|
||||
INLINE void collapse_with(NodeChainComponent *next);
|
||||
|
||||
PT(PandaNode) _node;
|
||||
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
public:
|
||||
INLINE CData();
|
||||
CData(const CData ©);
|
||||
virtual CycleData *make_copy() const;
|
||||
|
||||
PT(NodeChainComponent) _next;
|
||||
int _length;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
typedef CycleDataReader<CData> CDReader;
|
||||
typedef CycleDataWriter<CData> CDWriter;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
ReferenceCount::init_type();
|
||||
register_type(_type_handle, "NodeChainComponent",
|
||||
ReferenceCount::get_class_type());
|
||||
}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
friend class PandaNode;
|
||||
};
|
||||
|
||||
#include "nodeChainComponent.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -62,6 +62,42 @@ get_sort() const {
|
|||
return _sort;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::UpConnection::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode::UpConnection::
|
||||
UpConnection(PandaNode *parent) :
|
||||
_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::UpConnection::operator <
|
||||
// Access: Public
|
||||
// Description: Sorts the up connections of a node by pointer. This
|
||||
// is different from the down connections of a node,
|
||||
// which are sorted by the specified _sort number. This
|
||||
// makes it easy to locate a particular parent of a node
|
||||
// by pointer, or to test for a parent-child
|
||||
// relationship given two node pointers.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PandaNode::UpConnection::
|
||||
operator < (const UpConnection &other) const {
|
||||
return _parent < other._parent;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::UpConnection::get_parent
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *PandaNode::UpConnection::
|
||||
get_parent() const {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::CData::Constructor
|
||||
// Access: Public
|
||||
|
|
@ -69,7 +105,8 @@ get_sort() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode::CData::
|
||||
CData() {
|
||||
_state_changes = RenderState::make_empty();
|
||||
_state = RenderState::make_empty();
|
||||
_transform = TransformState::make_identity();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -140,7 +177,7 @@ INLINE PandaNode *PandaNode::
|
|||
get_parent(int n) const {
|
||||
CDReader cdata(_cycler);
|
||||
nassertr(n >= 0 && n < (int)cdata->_up.size(), NULL);
|
||||
return cdata->_up[n];
|
||||
return cdata->_up[n].get_parent();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -152,7 +189,7 @@ get_parent(int n) const {
|
|||
INLINE int PandaNode::
|
||||
find_parent(PandaNode *node) const {
|
||||
CDReader cdata(_cycler);
|
||||
Up::const_iterator ui = cdata->_up.find(node);
|
||||
Up::const_iterator ui = cdata->_up.find(UpConnection(node));
|
||||
if (ui == cdata->_up.end()) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -212,7 +249,7 @@ get_child_sort(int n) const {
|
|||
INLINE void PandaNode::
|
||||
set_attrib(const RenderAttrib *attrib, int override) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state_changes = cdata->_state_changes->add(attrib, override);
|
||||
cdata->_state = cdata->_state->add(attrib, override);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -227,9 +264,9 @@ set_attrib(const RenderAttrib *attrib, int override) {
|
|||
INLINE const RenderAttrib *PandaNode::
|
||||
get_attrib(TypeHandle type) const {
|
||||
CDReader cdata(_cycler);
|
||||
int index = cdata->_state_changes->find_attrib(type);
|
||||
int index = cdata->_state->find_attrib(type);
|
||||
if (index >= 0) {
|
||||
return cdata->_state_changes->get_attrib(index);
|
||||
return cdata->_state->get_attrib(index);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -245,7 +282,7 @@ get_attrib(TypeHandle type) const {
|
|||
INLINE void PandaNode::
|
||||
clear_attrib(TypeHandle type) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state_changes = cdata->_state_changes->remove(type);
|
||||
cdata->_state = cdata->_state->remove(type);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -261,7 +298,7 @@ clear_attrib(TypeHandle type) {
|
|||
INLINE void PandaNode::
|
||||
set_state(const RenderState *state) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state_changes = state;
|
||||
cdata->_state = state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -276,7 +313,7 @@ set_state(const RenderState *state) {
|
|||
INLINE const RenderState *PandaNode::
|
||||
get_state() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_state_changes;
|
||||
return cdata->_state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -290,7 +327,46 @@ get_state() const {
|
|||
INLINE void PandaNode::
|
||||
clear_state() {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state_changes = RenderState::make_empty();
|
||||
cdata->_state = RenderState::make_empty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::set_transform
|
||||
// Access: Published
|
||||
// Description: Sets the transform that will be applied to this node
|
||||
// and below. This defines a new coordinate space at
|
||||
// this point in the scene graph and below.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PandaNode::
|
||||
set_transform(const TransformState *transform) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_transform = transform;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_transform
|
||||
// Access: Published
|
||||
// Description: Returns the transform that has been set on this
|
||||
// particular node. This is not the net transform from
|
||||
// the root, but simply the transform on this particular
|
||||
// node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const TransformState *PandaNode::
|
||||
get_transform() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_transform;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::clear_transform
|
||||
// Access: Published
|
||||
// Description: Resets the transform on this node to the identity
|
||||
// transform.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PandaNode::
|
||||
clear_transform() {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_transform = TransformState::make_identity();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "config_pgraph.h"
|
||||
#include "nodeChainComponent.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
#include "indent.h"
|
||||
|
|
@ -34,9 +36,11 @@ PandaNode::CData::
|
|||
CData(const PandaNode::CData ©) :
|
||||
_down(copy._down),
|
||||
_up(copy._up),
|
||||
_chains(copy._chains),
|
||||
_node_bounds(copy._node_bounds),
|
||||
_subgraph_bounds(copy._subgraph_bounds),
|
||||
_state_changes(copy._state_changes)
|
||||
_state(copy._state),
|
||||
_transform(copy._transform)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -74,9 +78,11 @@ PandaNode(const PandaNode ©) :
|
|||
{
|
||||
// Copying a node does not copy its children.
|
||||
|
||||
// Copy the other node's bounding volume.
|
||||
// Copy the other node's state and bounding volume.
|
||||
CDReader copy_cdata(copy._cycler);
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state = copy_cdata->_state;
|
||||
cdata->_transform = copy_cdata->_transform;
|
||||
cdata->_node_bounds = copy_cdata->_node_bounds;
|
||||
}
|
||||
|
||||
|
|
@ -91,9 +97,11 @@ operator = (const PandaNode ©) {
|
|||
Namable::operator = (copy);
|
||||
ReferenceCount::operator = (copy);
|
||||
|
||||
// Copy the other node's bounding volume.
|
||||
// Copy the other node's state and bounding volume.
|
||||
CDReader copy_cdata(copy._cycler);
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state = copy_cdata->_state;
|
||||
cdata->_transform = copy_cdata->_transform;
|
||||
cdata->_node_bounds = copy_cdata->_node_bounds;
|
||||
}
|
||||
|
||||
|
|
@ -144,19 +152,32 @@ find_child(PandaNode *node) const {
|
|||
//
|
||||
// If the same child is added to a node more than once,
|
||||
// the previous instance is first removed.
|
||||
//
|
||||
// The return value is the index of the new child.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int PandaNode::
|
||||
add_child(PandaNode *child, int sort) {
|
||||
remove_child(child);
|
||||
void PandaNode::
|
||||
add_child(PandaNode *child_node, int sort) {
|
||||
// Ensure the child_node is not deleted while we do this.
|
||||
PT(PandaNode) keep_child = child_node;
|
||||
remove_child(child_node);
|
||||
CDWriter cdata(_cycler);
|
||||
CDWriter cdata_child(child->_cycler);
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
|
||||
cdata->_down.insert(DownConnection(child_node, sort));
|
||||
cdata_child->_up.insert(UpConnection(this));
|
||||
|
||||
Down::iterator ci = cdata->_down.insert(DownConnection(child, sort));
|
||||
cdata_child->_up.insert(this);
|
||||
// We also have to adjust any NodeChainComponents the child might
|
||||
// have that reference the child as a top node. Any other
|
||||
// components we can leave alone, because we are making a new
|
||||
// instance of the child.
|
||||
Chains::iterator ci;
|
||||
for (ci = cdata_child->_chains.begin();
|
||||
ci != cdata_child->_chains.end();
|
||||
++ci) {
|
||||
if ((*ci)->is_top_node()) {
|
||||
(*ci)->set_next(get_generic_component());
|
||||
}
|
||||
}
|
||||
|
||||
return ci - cdata->_down.begin();
|
||||
child_node->fix_chain_lengths();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -169,12 +190,41 @@ remove_child(int n) {
|
|||
CDWriter cdata(_cycler);
|
||||
nassertv(n >= 0 && n < (int)cdata->_down.size());
|
||||
|
||||
PandaNode *child = cdata->_down[n].get_child();
|
||||
CDWriter cdata_child(child->_cycler);
|
||||
PT(PandaNode) child_node = cdata->_down[n].get_child();
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
|
||||
cdata->_down.erase(cdata->_down.begin() + n);
|
||||
int num_erased = cdata_child->_up.erase(this);
|
||||
int num_erased = cdata_child->_up.erase(UpConnection(this));
|
||||
nassertv(num_erased == 1);
|
||||
|
||||
// Now sever any NodeChainComponents on the child that reference
|
||||
// this node. If we have multiple of these, we have to collapse
|
||||
// them together.
|
||||
NodeChainComponent *collapsed = (NodeChainComponent *)NULL;
|
||||
Chains::iterator ci;
|
||||
ci = cdata_child->_chains.begin();
|
||||
while (ci != cdata_child->_chains.end()) {
|
||||
Chains::iterator cnext = ci;
|
||||
++cnext;
|
||||
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
|
||||
if (collapsed == (NodeChainComponent *)NULL) {
|
||||
(*ci)->set_top_node();
|
||||
collapsed = (*ci);
|
||||
} else {
|
||||
// This is a different component that used to reference a
|
||||
// different instance, but now it's all just the same topnode.
|
||||
// We have to collapse this and the previous one together.
|
||||
// However, there might be some NodeChains out there that
|
||||
// still keep a pointer to this one, so we can't remove it
|
||||
// altogether.
|
||||
(*ci)->collapse_with(collapsed);
|
||||
cdata_child->_chains.erase(ci);
|
||||
}
|
||||
}
|
||||
ci = cnext;
|
||||
}
|
||||
|
||||
child_node->fix_chain_lengths();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -185,24 +235,49 @@ remove_child(int n) {
|
|||
// already a child of the node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PandaNode::
|
||||
remove_child(PandaNode *child) {
|
||||
CDWriter cdata_child(child->_cycler);
|
||||
remove_child(PandaNode *child_node) {
|
||||
// Ensure the child_node is not deleted while we do this.
|
||||
PT(PandaNode) keep_child = child_node;
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
|
||||
// First, look for and remove this node from the child's parent
|
||||
// list.
|
||||
int num_erased = cdata_child->_up.erase(this);
|
||||
int num_erased = cdata_child->_up.erase(UpConnection(this));
|
||||
if (num_erased == 0) {
|
||||
// No such node; it wasn't our child to begin with.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now sever any NodeChainComponents on the child that reference
|
||||
// this node. If we have multiple of these, we have to collapse
|
||||
// them together (see above).
|
||||
NodeChainComponent *collapsed = (NodeChainComponent *)NULL;
|
||||
Chains::iterator ci;
|
||||
ci = cdata_child->_chains.begin();
|
||||
while (ci != cdata_child->_chains.end()) {
|
||||
Chains::iterator cnext = ci;
|
||||
++cnext;
|
||||
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
|
||||
if (collapsed == (NodeChainComponent *)NULL) {
|
||||
(*ci)->set_top_node();
|
||||
collapsed = (*ci);
|
||||
} else {
|
||||
(*ci)->collapse_with(collapsed);
|
||||
cdata_child->_chains.erase(ci);
|
||||
}
|
||||
}
|
||||
ci = cnext;
|
||||
}
|
||||
|
||||
child_node->fix_chain_lengths();
|
||||
|
||||
CDWriter cdata(_cycler);
|
||||
|
||||
// Now, look for and remove the child node from our down list.
|
||||
Down::iterator ci;
|
||||
for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
|
||||
if ((*ci).get_child() == child) {
|
||||
cdata->_down.erase(ci);
|
||||
Down::iterator di;
|
||||
for (di = cdata->_down.begin(); di != cdata->_down.end(); ++di) {
|
||||
if ((*di).get_child() == child_node) {
|
||||
cdata->_down.erase(di);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -222,9 +297,32 @@ remove_all_children() {
|
|||
CDWriter cdata(_cycler);
|
||||
Down::iterator ci;
|
||||
for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
|
||||
PandaNode *child = (*ci).get_child();
|
||||
CDWriter child_cdata(child->_cycler);
|
||||
child_cdata->_up.erase(this);
|
||||
PT(PandaNode) child_node = (*ci).get_child();
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
cdata_child->_up.erase(UpConnection(this));
|
||||
|
||||
// Now sever any NodeChainComponents on the child that reference
|
||||
// this node. If we have multiple of these, we have to collapse
|
||||
// them together (see above).
|
||||
NodeChainComponent *collapsed = (NodeChainComponent *)NULL;
|
||||
Chains::iterator ci;
|
||||
ci = cdata_child->_chains.begin();
|
||||
while (ci != cdata_child->_chains.end()) {
|
||||
Chains::iterator cnext = ci;
|
||||
++cnext;
|
||||
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
|
||||
if (collapsed == (NodeChainComponent *)NULL) {
|
||||
(*ci)->set_top_node();
|
||||
collapsed = (*ci);
|
||||
} else {
|
||||
(*ci)->collapse_with(collapsed);
|
||||
cdata_child->_chains.erase(ci);
|
||||
}
|
||||
}
|
||||
ci = cnext;
|
||||
}
|
||||
|
||||
child_node->fix_chain_lengths();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -247,8 +345,11 @@ void PandaNode::
|
|||
write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level) << *this;
|
||||
CDReader cdata(_cycler);
|
||||
if (!cdata->_state_changes->is_empty()) {
|
||||
out << " (" << *cdata->_state_changes << ")";
|
||||
if (!cdata->_transform->is_identity()) {
|
||||
out << " T";
|
||||
}
|
||||
if (!cdata->_state->is_empty()) {
|
||||
out << " (" << *cdata->_state << ")";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
|
|
@ -269,6 +370,286 @@ is_geom_node() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::attach
|
||||
// Access: Private, Static
|
||||
// Description: Creates a new parent-child relationship, and returns
|
||||
// the new NodeChainComponent. If the child was already
|
||||
// attached to the indicated parent, repositions it and
|
||||
// returns the original NodeChainComponent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(NodeChainComponent) PandaNode::
|
||||
attach(NodeChainComponent *parent, PandaNode *child_node, int sort) {
|
||||
nassertr(parent != (NodeChainComponent *)NULL, (NodeChainComponent *)NULL);
|
||||
|
||||
// See if the child was already attached to the parent. If it was,
|
||||
// we'll use that same NodeChainComponent.
|
||||
PT(NodeChainComponent) child = get_component(parent, child_node);
|
||||
|
||||
if (child == (NodeChainComponent *)NULL) {
|
||||
// The child was not already attached to the parent, so get a new
|
||||
// component.
|
||||
child = get_top_component(child_node);
|
||||
}
|
||||
|
||||
reparent(parent, child, sort);
|
||||
return child;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::detach
|
||||
// Access: Private, Static
|
||||
// Description: Breaks a parent-child relationship.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
detach(NodeChainComponent *child) {
|
||||
nassertv(child != (NodeChainComponent *)NULL);
|
||||
nassertv(!child->is_top_node());
|
||||
PandaNode *child_node = child->get_node();
|
||||
PandaNode *parent_node = child->get_next()->get_node();
|
||||
|
||||
// Break the NodeChainComponent connection.
|
||||
child->set_top_node();
|
||||
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
|
||||
// Any other components in the same child_node that previously
|
||||
// referenced the same parent has now become invalid and must be
|
||||
// collapsed into this one and removed from the chains set.
|
||||
Chains::iterator ci;
|
||||
ci = cdata_child->_chains.begin();
|
||||
while (ci != cdata_child->_chains.end()) {
|
||||
Chains::iterator cnext = ci;
|
||||
++cnext;
|
||||
if ((*ci) != child && !(*ci)->is_top_node() &&
|
||||
(*ci)->get_next()->get_node() == parent_node) {
|
||||
(*ci)->collapse_with(child);
|
||||
cdata_child->_chains.erase(ci);
|
||||
}
|
||||
ci = cnext;
|
||||
}
|
||||
|
||||
child_node->fix_chain_lengths();
|
||||
|
||||
// Now look for the child and break the actual connection.
|
||||
|
||||
// First, look for and remove the parent node from the child's up
|
||||
// list.
|
||||
int num_erased = cdata_child->_up.erase(UpConnection(parent_node));
|
||||
nassertv(num_erased == 1);
|
||||
|
||||
CDWriter cdata_parent(parent_node->_cycler);
|
||||
|
||||
// Now, look for and remove the child node from the parent's down list.
|
||||
Down::iterator di;
|
||||
for (di = cdata_parent->_down.begin();
|
||||
di != cdata_parent->_down.end();
|
||||
++di) {
|
||||
if ((*di).get_child() == child_node) {
|
||||
cdata_parent->_down.erase(di);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We shouldn't get here unless there was a parent-child mismatch.
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::reparent
|
||||
// Access: Private, Static
|
||||
// Description: Switches a node from one parent to another.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
reparent(NodeChainComponent *new_parent, NodeChainComponent *child, int sort) {
|
||||
nassertv(new_parent != (NodeChainComponent *)NULL);
|
||||
nassertv(child != (NodeChainComponent *)NULL);
|
||||
|
||||
if (!child->is_top_node()) {
|
||||
detach(child);
|
||||
}
|
||||
|
||||
// Adjust the NodeChainComponents.
|
||||
child->set_next(new_parent);
|
||||
|
||||
PandaNode *child_node = child->get_node();
|
||||
PandaNode *parent_node = new_parent->get_node();
|
||||
|
||||
// Now reattach at the indicated sort position.
|
||||
CDWriter cdata_parent(parent_node->_cycler);
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
|
||||
cdata_parent->_down.insert(DownConnection(child_node, sort));
|
||||
cdata_child->_up.insert(UpConnection(parent_node));
|
||||
|
||||
cdata_child->_chains.insert(child);
|
||||
child_node->fix_chain_lengths();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_component
|
||||
// Access: Private, Static
|
||||
// Description: Returns the NodeChainComponent based on the indicated
|
||||
// child of the given parent, or NULL if there is no
|
||||
// such parent-child relationship.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(NodeChainComponent) PandaNode::
|
||||
get_component(NodeChainComponent *parent, PandaNode *child_node) {
|
||||
nassertr(parent != (NodeChainComponent *)NULL, (NodeChainComponent *)NULL);
|
||||
PandaNode *parent_node = parent->get_node();
|
||||
|
||||
{
|
||||
CDReader cdata_child(child_node->_cycler);
|
||||
|
||||
// First, walk through the list of NodeChainComponents we already
|
||||
// have on the child, looking for one that already exists,
|
||||
// referencing the indicated parent component.
|
||||
Chains::iterator ci;
|
||||
for (ci = cdata_child->_chains.begin();
|
||||
ci != cdata_child->_chains.end();
|
||||
++ci) {
|
||||
if ((*ci)->get_next() == parent) {
|
||||
// If we already have such a component, just return it.
|
||||
return (*ci);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We don't already have a NodeChainComponent referring to this
|
||||
// parent-child relationship. Are they actually related?
|
||||
int child_index = child_node->find_parent(parent_node);
|
||||
if (child_index >= 0) {
|
||||
// They are. Create and return a new one.
|
||||
PT(NodeChainComponent) child =
|
||||
new NodeChainComponent(child_node, parent);
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
cdata_child->_chains.insert(child);
|
||||
return child;
|
||||
} else {
|
||||
// They aren't related. Return NULL.
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_top_component
|
||||
// Access: Private, Static
|
||||
// Description: Returns a NodeChainComponent referencing the
|
||||
// indicated node as a singleton. It is invalid to call
|
||||
// this for a node that has parents, unless you are
|
||||
// about to create a new instance (and immediately
|
||||
// reconnect the NodeChainComponent elsewhere).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(NodeChainComponent) PandaNode::
|
||||
get_top_component(PandaNode *child_node) {
|
||||
{
|
||||
CDReader cdata_child(child_node->_cycler);
|
||||
|
||||
// Walk through the list of NodeChainComponents we already have on
|
||||
// the child, looking for one that already exists as a top node.
|
||||
Chains::const_iterator ci;
|
||||
for (ci = cdata_child->_chains.begin();
|
||||
ci != cdata_child->_chains.end();
|
||||
++ci) {
|
||||
if ((*ci)->is_top_node()) {
|
||||
// If we already have such a component, just return it.
|
||||
return (*ci);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We don't already have such a NodeChainComponent; create and
|
||||
// return a new one.
|
||||
PT(NodeChainComponent) child =
|
||||
new NodeChainComponent(child_node, (NodeChainComponent *)NULL);
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
cdata_child->_chains.insert(child);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_generic_component
|
||||
// Access: Private
|
||||
// Description: Returns a NodeChainComponent referencing this node as
|
||||
// a chain from the root. It is only valid to call this
|
||||
// if there is an unambiguous path from the root;
|
||||
// otherwise, a warning will be issued and one path will
|
||||
// be chosen arbitrarily.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(NodeChainComponent) PandaNode::
|
||||
get_generic_component() {
|
||||
int num_parents = get_num_parents();
|
||||
if (num_parents == 0) {
|
||||
return get_top_component(this);
|
||||
|
||||
} else {
|
||||
if (num_parents != 1) {
|
||||
pgraph_cat.warning()
|
||||
<< *this << " has " << num_parents
|
||||
<< " parents; choosing arbitrary path to root.\n";
|
||||
}
|
||||
PT(NodeChainComponent) parent = get_parent(0)->get_generic_component();
|
||||
return get_component(parent, this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::delete_component
|
||||
// Access: Private
|
||||
// Description: Removes a NodeChainComponent from the set prior to
|
||||
// its deletion. This should only be called by the
|
||||
// NodeChainComponent destructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
delete_component(NodeChainComponent *component) {
|
||||
// We have to remove the component from all of the pipeline stages,
|
||||
// not just the current one.
|
||||
int max_num_erased = 0;
|
||||
|
||||
int num_stages = _cycler.get_num_stages();
|
||||
for (int i = 0; i < num_stages; i++) {
|
||||
if (_cycler.is_stage_unique(i)) {
|
||||
CData *cdata = _cycler.write_stage(i);
|
||||
int num_erased = cdata->_chains.erase(component);
|
||||
max_num_erased = max(max_num_erased, num_erased);
|
||||
_cycler.release_write_stage(i, cdata);
|
||||
}
|
||||
}
|
||||
nassertv(max_num_erased == 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::fix_chain_lengths
|
||||
// Access: Private
|
||||
// Description: Recursively fixes the _length member of each
|
||||
// NodeChainComponent at this level and below, after an
|
||||
// add or delete child operation that might have messed
|
||||
// these up.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
fix_chain_lengths() {
|
||||
CDReader cdata(_cycler);
|
||||
bool any_wrong = false;
|
||||
|
||||
Chains::const_iterator ci;
|
||||
for (ci = cdata->_chains.begin(); ci != cdata->_chains.end(); ++ci) {
|
||||
if ((*ci)->fix_length()) {
|
||||
any_wrong = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If any chains were updated, we have to recurse on all of our
|
||||
// children, since any one of those chains might be shared by any of
|
||||
// our child nodes.
|
||||
if (any_wrong) {
|
||||
Down::const_iterator di;
|
||||
for (di = cdata->_down.begin(); di != cdata->_down.end(); ++di) {
|
||||
(*di).get_child()->fix_chain_lengths();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "cycleDataWriter.h"
|
||||
#include "pipelineCycler.h"
|
||||
#include "renderState.h"
|
||||
#include "transformState.h"
|
||||
|
||||
#include "typedWritable.h"
|
||||
#include "boundedObject.h"
|
||||
|
|
@ -35,6 +36,8 @@
|
|||
#include "ordered_vector.h"
|
||||
#include "pointerTo.h"
|
||||
|
||||
class NodeChainComponent;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PandaNode
|
||||
// Description : A basic node of the scene graph or data graph. This
|
||||
|
|
@ -58,9 +61,9 @@ PUBLISHED:
|
|||
INLINE int get_child_sort(int n) const;
|
||||
int find_child(PandaNode *node) const;
|
||||
|
||||
int add_child(PandaNode *child, int sort = 0);
|
||||
void add_child(PandaNode *child_node, int sort = 0);
|
||||
void remove_child(int n);
|
||||
bool remove_child(PandaNode *child);
|
||||
bool remove_child(PandaNode *child_node);
|
||||
|
||||
/*
|
||||
bool stash_child(PandaNode *child);
|
||||
|
|
@ -80,12 +83,31 @@ PUBLISHED:
|
|||
INLINE const RenderState *get_state() const;
|
||||
INLINE void clear_state();
|
||||
|
||||
INLINE void set_transform(const TransformState *transform);
|
||||
INLINE const TransformState *get_transform() const;
|
||||
INLINE void clear_transform();
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
||||
public:
|
||||
virtual bool is_geom_node() const;
|
||||
|
||||
private:
|
||||
// parent-child manipulation for NodeChain support. Don't try to
|
||||
// call these directly.
|
||||
static PT(NodeChainComponent) attach(NodeChainComponent *parent,
|
||||
PandaNode *child, int sort);
|
||||
static void detach(NodeChainComponent *child);
|
||||
static void reparent(NodeChainComponent *new_parent,
|
||||
NodeChainComponent *child, int sort);
|
||||
static PT(NodeChainComponent) get_component(NodeChainComponent *parent,
|
||||
PandaNode *child);
|
||||
static PT(NodeChainComponent) get_top_component(PandaNode *child);
|
||||
PT(NodeChainComponent) get_generic_component();
|
||||
void delete_component(NodeChainComponent *component);
|
||||
void fix_chain_lengths();
|
||||
|
||||
private:
|
||||
class EXPCL_PANDA DownConnection {
|
||||
public:
|
||||
|
|
@ -102,13 +124,27 @@ private:
|
|||
int _sort;
|
||||
};
|
||||
typedef ov_multiset<DownConnection> Down;
|
||||
// Parent pointers are not reference counted. That way, parents and
|
||||
// children do not circularly reference each other. In fact, parent
|
||||
// pointers are just simple pointers, with no additional data. We
|
||||
// don't really need to keep the parent pointers around, but it's
|
||||
// nice to be able to walk up the graph.
|
||||
typedef ov_set<PandaNode *> Up;
|
||||
|
||||
class EXPCL_PANDA UpConnection {
|
||||
public:
|
||||
INLINE UpConnection(PandaNode *child);
|
||||
INLINE bool operator < (const UpConnection &other) const;
|
||||
INLINE PandaNode *get_parent() const;
|
||||
|
||||
private:
|
||||
// Parent pointers are not reference counted. That way, parents and
|
||||
// children do not circularly reference each other.
|
||||
PandaNode *_parent;
|
||||
};
|
||||
typedef ov_set<UpConnection> Up;
|
||||
|
||||
// We also maintain a set of NodeChainComponents in the node. This
|
||||
// represents the set of instances of this node that we have
|
||||
// requested a NodeChain for. We don't keep reference counts; when
|
||||
// each NodeChainComponent destructs, it removes itself from this
|
||||
// set.
|
||||
typedef pset<NodeChainComponent *> Chains;
|
||||
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
public:
|
||||
|
|
@ -118,10 +154,12 @@ private:
|
|||
|
||||
Down _down;
|
||||
Up _up;
|
||||
Chains _chains;
|
||||
|
||||
BoundedObject _node_bounds;
|
||||
BoundedObject _subgraph_bounds;
|
||||
CPT(RenderState) _state_changes;
|
||||
CPT(RenderState) _state;
|
||||
CPT(TransformState) _transform;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
|
|
@ -175,6 +213,8 @@ private:
|
|||
static TypeHandle _type_handle;
|
||||
|
||||
friend class PandaNode::Children;
|
||||
friend class NodeChain;
|
||||
friend class NodeChainComponent;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const PandaNode &node) {
|
||||
|
|
|
|||
|
|
@ -6,4 +6,6 @@
|
|||
#include "cycleDataReader.cxx"
|
||||
#include "cycleDataWriter.cxx"
|
||||
#include "qpgeomNode.cxx"
|
||||
#include "pandaNode.cxx"
|
||||
#include "qplensNode.cxx"
|
||||
#include "nodeChain.cxx"
|
||||
#include "nodeChainComponent.cxx"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include "pandaNode.cxx"
|
||||
#include "pipeline.cxx"
|
||||
#include "pipelineCycler.cxx"
|
||||
#include "pipelineCyclerBase.cxx"
|
||||
|
|
@ -5,5 +6,4 @@
|
|||
#include "renderState.cxx"
|
||||
#include "test_pgraph.cxx"
|
||||
#include "textureAttrib.cxx"
|
||||
#include "transformAttrib.cxx"
|
||||
|
||||
#include "transformState.cxx"
|
||||
|
|
|
|||
|
|
@ -28,3 +28,36 @@ PipelineCycler(Pipeline *pipeline) :
|
|||
PipelineCyclerBase(new CycleDataType, pipeline)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipelineCycler::read
|
||||
// Access: Public
|
||||
// Description: See PipelineCyclerBase::read().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class CycleDataType>
|
||||
INLINE const CycleDataType *PipelineCycler<CycleDataType>::
|
||||
read() const {
|
||||
return (const CycleDataType *)PipelineCyclerBase::read();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipelineCycler::write
|
||||
// Access: Public
|
||||
// Description: See PipelineCyclerBase::write().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class CycleDataType>
|
||||
INLINE CycleDataType *PipelineCycler<CycleDataType>::
|
||||
write() {
|
||||
return (CycleDataType *)PipelineCyclerBase::write();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipelineCycler::write_stage
|
||||
// Access: Public
|
||||
// Description: See PipelineCyclerBase::write_stage().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class CycleDataType>
|
||||
INLINE CycleDataType *PipelineCycler<CycleDataType>::
|
||||
write_stage(int n) {
|
||||
return (CycleDataType *)PipelineCyclerBase::write_stage(n);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,10 @@ template<class CycleDataType>
|
|||
class PipelineCycler : public PipelineCyclerBase {
|
||||
public:
|
||||
INLINE PipelineCycler(Pipeline *pipeline = NULL);
|
||||
|
||||
INLINE const CycleDataType *read() const;
|
||||
INLINE CycleDataType *write();
|
||||
INLINE CycleDataType *write_stage(int n);
|
||||
};
|
||||
|
||||
#include "pipelineCycler.I"
|
||||
|
|
|
|||
|
|
@ -107,3 +107,56 @@ release_write(CycleData *pointer) {
|
|||
nassertv(_write_count > 0);
|
||||
_write_count--;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipelineCyclerBase::get_num_stages
|
||||
// Access: Public
|
||||
// Description: Returns the number of stages in the pipeline.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int PipelineCyclerBase::
|
||||
get_num_stages() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipelineCyclerBase::is_stage_unique
|
||||
// Access: Public
|
||||
// Description: Returns true if the nth stage is a different pointer
|
||||
// than the previous stage, or false if its pointer is
|
||||
// shared with the previous one.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PipelineCyclerBase::
|
||||
is_stage_unique(int n) const {
|
||||
nassertr(n == 0, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipelineCyclerBase::write_stage
|
||||
// Access: Public
|
||||
// Description: Returns a pointer suitable for writing to the nth
|
||||
// stage of the pipeline. This is for special
|
||||
// applications that need to update the entire pipeline
|
||||
// at once (for instance, to remove an invalid pointer).
|
||||
// This pointer should later be released with
|
||||
// release_write_stage().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CycleData *PipelineCyclerBase::
|
||||
write_stage(int n) {
|
||||
nassertr(n == 0, (CycleData *)NULL);
|
||||
_stage_count++;
|
||||
return _data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipelineCyclerBase::release_write_stage
|
||||
// Access: Public
|
||||
// Description: Releases a pointer previously obtained via a call to
|
||||
// write_stage().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PipelineCyclerBase::
|
||||
release_write_stage(int n, CycleData *pointer) {
|
||||
nassertv(n == 0 && pointer == _data);
|
||||
nassertv(_stage_count > 0);
|
||||
_stage_count--;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline) :
|
|||
_data(initial_data),
|
||||
_pipeline(pipeline),
|
||||
_read_count(0),
|
||||
_write_count(0)
|
||||
_write_count(0),
|
||||
_stage_count(0)
|
||||
{
|
||||
if (_pipeline == (Pipeline *)NULL) {
|
||||
_pipeline = Pipeline::get_render_pipeline();
|
||||
|
|
@ -43,6 +44,6 @@ PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PipelineCyclerBase::
|
||||
~PipelineCyclerBase() {
|
||||
nassertv(_read_count == 0 && _write_count == 0);
|
||||
nassertv(_read_count == 0 && _write_count == 0 && _stage_count == 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,10 +43,15 @@ public:
|
|||
INLINE void increment_write(CycleData *pointer);
|
||||
INLINE void release_write(CycleData *pointer);
|
||||
|
||||
INLINE int get_num_stages();
|
||||
INLINE bool is_stage_unique(int n) const;
|
||||
INLINE CycleData *write_stage(int n);
|
||||
INLINE void release_write_stage(int n, CycleData *pointer);
|
||||
|
||||
private:
|
||||
PT(CycleData) _data;
|
||||
Pipeline *_pipeline;
|
||||
short _read_count, _write_count;
|
||||
short _read_count, _write_count, _stage_count;
|
||||
};
|
||||
|
||||
#include "pipelineCyclerBase.I"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
// Filename: qpcamera.I
|
||||
// Created by: drose (26Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: qpCamera::set_active
|
||||
// Access: Published
|
||||
// Description: Sets the active flag on the camera. When the camera
|
||||
// is not active, nothing will be rendered.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpCamera::
|
||||
set_active(bool active) {
|
||||
_active = active;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::is_active
|
||||
// Access: Published
|
||||
// Description: Returns the current setting of the active flag on the
|
||||
// camera.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpCamera::
|
||||
is_active() const {
|
||||
return _active;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::set_scene
|
||||
// Access: Published
|
||||
// Description: Sets the scene that will be rendered by the camera.
|
||||
// This is normally the root node of a scene graph,
|
||||
// typically a node called 'render', although it could
|
||||
// represent the root of any subgraph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpCamera::
|
||||
set_scene(PandaNode *scene) {
|
||||
_scene = scene;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::get_scene
|
||||
// Access: Published
|
||||
// Description: Returns the scene that will be rendered by the
|
||||
// camera. See set_scene().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *qpCamera::
|
||||
get_scene() const {
|
||||
return _scene;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::get_num_display_regions
|
||||
// Access: Published
|
||||
// Description: Returns the number of display regions associated with
|
||||
// the camera.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpCamera::
|
||||
get_num_display_regions() const {
|
||||
return _display_regions.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::get_display_region
|
||||
// Access: Published
|
||||
// Description: Returns the nth display region associated with the
|
||||
// camera.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE DisplayRegion *qpCamera::
|
||||
get_display_region(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_display_regions.size(), (DisplayRegion *)NULL);
|
||||
return _display_regions[n];
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
// Filename: qpcamera.cxx
|
||||
// Created by: drose (26Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "pandabase.h"
|
||||
#include "qpcamera.h"
|
||||
#include "lens.h"
|
||||
#include "throw_event.h"
|
||||
|
||||
TypeHandle qpCamera::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpCamera::
|
||||
qpCamera(const string &name) :
|
||||
qpLensNode(name),
|
||||
_active(true),
|
||||
_scene((PandaNode *)NULL)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpCamera::
|
||||
qpCamera(const qpCamera ©) :
|
||||
qpLensNode(copy),
|
||||
_active(copy._active),
|
||||
_scene(copy._scene)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpCamera::
|
||||
operator = (const qpCamera ©) {
|
||||
qpLensNode::operator = (copy);
|
||||
_active = copy._active;
|
||||
_scene = copy._scene;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpCamera::
|
||||
~qpCamera() {
|
||||
// We don't have to destroy the display region(s) associated with
|
||||
// the camera; they're responsible for themselves. However, they
|
||||
// should have removed themselves before we destruct, or something
|
||||
// went wrong.
|
||||
nassertv(_display_regions.empty());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *qpCamera::
|
||||
make_copy() const {
|
||||
return new qpCamera(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::safe_to_flatten
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if it is generally safe to flatten out
|
||||
// this particular kind of Node by duplicating
|
||||
// instances, false otherwise (for instance, a qpCamera
|
||||
// cannot be safely flattened, because the qpCamera
|
||||
// pointer itself is meaningful).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpCamera::
|
||||
safe_to_flatten() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::safe_to_transform
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if it is generally safe to transform
|
||||
// this particular kind of Node by calling the xform()
|
||||
// method, false otherwise. For instance, it's usually
|
||||
// a bad idea to attempt to xform a Character.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpCamera::
|
||||
safe_to_transform() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::add_display_region
|
||||
// Access: Private
|
||||
// Description: Adds the indicated DisplayRegion to the set of
|
||||
// DisplayRegions shared by the camera. This is only
|
||||
// intended to be called from the DisplayRegion.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpCamera::
|
||||
add_display_region(DisplayRegion *display_region) {
|
||||
_display_regions.push_back(display_region);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCamera::remove_display_region
|
||||
// Access: Private
|
||||
// Description: Removes the indicated DisplayRegion from the set of
|
||||
// DisplayRegions shared by the camera. This is only
|
||||
// intended to be called from the DisplayRegion.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpCamera::
|
||||
remove_display_region(DisplayRegion *display_region) {
|
||||
DisplayRegions::iterator dri =
|
||||
find(_display_regions.begin(), _display_regions.end(), display_region);
|
||||
if (dri != _display_regions.end()) {
|
||||
_display_regions.erase(dri);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// Filename: qpcamera.h
|
||||
// Created by: drose (26Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 QPCAMERA_H
|
||||
#define QPCAMERA_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "qplensNode.h"
|
||||
|
||||
class DisplayRegion;
|
||||
class PandaNode;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpCamera
|
||||
// Description : A node that can be positioned around in the scene
|
||||
// graph to represent a point of view for rendering a
|
||||
// scene.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpCamera : public qpLensNode {
|
||||
PUBLISHED:
|
||||
qpCamera(const string &name);
|
||||
|
||||
public:
|
||||
qpCamera(const qpCamera ©);
|
||||
void operator = (const qpCamera ©);
|
||||
virtual ~qpCamera();
|
||||
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual bool safe_to_flatten() const;
|
||||
virtual bool safe_to_transform() const;
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void set_active(bool active);
|
||||
INLINE bool is_active() const;
|
||||
|
||||
INLINE void set_scene(PandaNode *scene);
|
||||
INLINE PandaNode *get_scene() const;
|
||||
|
||||
INLINE int get_num_display_regions() const;
|
||||
INLINE DisplayRegion *get_display_region(int n) const;
|
||||
|
||||
private:
|
||||
void add_display_region(DisplayRegion *display_region);
|
||||
void remove_display_region(DisplayRegion *display_region);
|
||||
|
||||
bool _active;
|
||||
PandaNode *_scene;
|
||||
|
||||
typedef pvector<DisplayRegion *> DisplayRegions;
|
||||
DisplayRegions _display_regions;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
qpLensNode::init_type();
|
||||
register_type(_type_handle, "qpCamera",
|
||||
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;
|
||||
|
||||
friend class DisplayRegion;
|
||||
};
|
||||
|
||||
#include "qpcamera.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpcullTraverser.h"
|
||||
#include "transformState.h"
|
||||
#include "renderState.h"
|
||||
#include "cullHandler.h"
|
||||
#include "dcast.h"
|
||||
|
|
@ -30,7 +31,7 @@
|
|||
qpCullTraverser::
|
||||
qpCullTraverser() {
|
||||
_initial_state = RenderState::make_empty();
|
||||
_world_transform = DCAST(TransformAttrib, TransformAttrib::make_identity());
|
||||
_world_transform = DCAST(TransformState, TransformState::make_identity());
|
||||
_cull_handler = (CullHandler *)NULL;
|
||||
}
|
||||
|
||||
|
|
@ -49,17 +50,11 @@ set_initial_state(const RenderState *initial_state) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCullTraverser::set_world_transform
|
||||
// Access: Public
|
||||
// Description: Specifies the net inverse transform of the camera
|
||||
// viewing the scene. Normally, this is the same as the
|
||||
// transform specified in the initial state, but it
|
||||
// might be different if we are culling a subgraph,
|
||||
// for instance.
|
||||
//
|
||||
// This is used to evaluate camera-dependent attributes
|
||||
// like billboards and LOD nodes.
|
||||
// Description: Specifies the position of the world relative to the
|
||||
// camera.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpCullTraverser::
|
||||
set_world_transform(const TransformAttrib *world_transform) {
|
||||
set_world_transform(const TransformState *world_transform) {
|
||||
_world_transform = world_transform;
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +62,7 @@ set_world_transform(const TransformAttrib *world_transform) {
|
|||
// Function: qpCullTraverser::set_cull_handler
|
||||
// Access: Public
|
||||
// Description: Specifies the object that will receive the culled
|
||||
// Geoms. This must be called before traverse().
|
||||
// Geoms. This must be set before calling traverse().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpCullTraverser::
|
||||
set_cull_handler(CullHandler *cull_handler) {
|
||||
|
|
@ -83,7 +78,7 @@ void qpCullTraverser::
|
|||
traverse(PandaNode *root) {
|
||||
nassertv(_cull_handler != (CullHandler *)NULL);
|
||||
|
||||
r_traverse(root, _initial_state, 0);
|
||||
r_traverse(root, _world_transform, _initial_state, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -92,7 +87,9 @@ traverse(PandaNode *root) {
|
|||
// Description: The recursive traversal implementation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpCullTraverser::
|
||||
r_traverse(PandaNode *node, const RenderState *state, int flags) {
|
||||
r_traverse(PandaNode *node, const TransformState *transform,
|
||||
const RenderState *state, int flags) {
|
||||
CPT(TransformState) next_transform = transform->compose(node->get_transform());
|
||||
CPT(RenderState) next_state = state->compose(node->get_state());
|
||||
|
||||
if (node->is_geom_node()) {
|
||||
|
|
@ -104,7 +101,7 @@ r_traverse(PandaNode *node, const RenderState *state, int flags) {
|
|||
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, geom_state);
|
||||
_cull_handler->record_geom(geom, next_transform, geom_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +109,6 @@ r_traverse(PandaNode *node, const RenderState *state, int flags) {
|
|||
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_state, flags);
|
||||
r_traverse(cr.get_child(i), next_transform, next_state, flags);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include "pandabase.h"
|
||||
|
||||
#include "renderState.h"
|
||||
#include "transformAttrib.h"
|
||||
#include "transformState.h"
|
||||
#include "pointerTo.h"
|
||||
|
||||
class PandaNode;
|
||||
|
|
@ -41,16 +41,17 @@ public:
|
|||
qpCullTraverser();
|
||||
|
||||
void set_initial_state(const RenderState *initial_state);
|
||||
void set_world_transform(const TransformAttrib *world_transform);
|
||||
void set_world_transform(const TransformState *world_transform);
|
||||
void set_cull_handler(CullHandler *cull_handler);
|
||||
|
||||
void traverse(PandaNode *root);
|
||||
|
||||
private:
|
||||
void r_traverse(PandaNode *node, const RenderState *state, int flags);
|
||||
void r_traverse(PandaNode *node, const TransformState *transform,
|
||||
const RenderState *state, int flags);
|
||||
|
||||
CPT(RenderState) _initial_state;
|
||||
CPT(TransformAttrib) _world_transform;
|
||||
CPT(TransformState) _world_transform;
|
||||
CullHandler *_cull_handler;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
// Filename: qplensNode.I
|
||||
// Created by: drose (26Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: qpLensNode::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpLensNode::
|
||||
qpLensNode(const string &name) :
|
||||
PandaNode(name)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpLensNode::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpLensNode::
|
||||
qpLensNode(const qpLensNode ©) :
|
||||
PandaNode(copy),
|
||||
_lens(copy._lens)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpLensNode::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpLensNode::
|
||||
operator = (const qpLensNode ©) {
|
||||
PandaNode::operator = (copy);
|
||||
_lens = copy._lens;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: copy_lens
|
||||
// Access: Public
|
||||
// Description: Sets up the qpLensNode using a copy of the
|
||||
// indicated Lens. If the original Lens is
|
||||
// changed or destroyed, this qpLensNode is not
|
||||
// affected.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpLensNode::
|
||||
copy_lens(const Lens &lens) {
|
||||
_lens = lens.make_copy();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: set_lens
|
||||
// Access: Public
|
||||
// Description: Sets up the qpLensNode using this particular Lens
|
||||
// pointer. If the lens is subsequently modified, the
|
||||
// qpLensNode properties immediately reflect the change.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpLensNode::
|
||||
set_lens(Lens *lens) {
|
||||
_lens = lens;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: get_lens
|
||||
// Access: Public
|
||||
// Description: Returns a pointer to the particular Lens
|
||||
// associated with this qpLensNode, or NULL if there is
|
||||
// not yet a Lens associated.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE Lens *qpLensNode::
|
||||
get_lens() {
|
||||
return _lens;
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
// Filename: qplensNode.cxx
|
||||
// Created by: drose (26Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "qplensNode.h"
|
||||
#include "geometricBoundingVolume.h"
|
||||
|
||||
TypeHandle qpLensNode::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpLensNode::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *qpLensNode::
|
||||
make_copy() const {
|
||||
return new qpLensNode(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpLensNode::is_in_view
|
||||
// Access: Public
|
||||
// Description: Returns true if the given point is within the bounds
|
||||
// of the lens of the qpLensNode (i.e. if the camera can
|
||||
// see the point).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpLensNode::
|
||||
is_in_view(const LPoint3f &pos) {
|
||||
PT(BoundingVolume) bv = _lens->make_bounds();
|
||||
if (bv == NULL) {
|
||||
return false;
|
||||
}
|
||||
GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bv);
|
||||
int ret = gbv->contains(pos);
|
||||
return (ret != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpLensNode::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpLensNode::
|
||||
output(ostream &out) const {
|
||||
PandaNode::output(out);
|
||||
if (_lens != (Lens *)NULL) {
|
||||
out << " (";
|
||||
_lens->output(out);
|
||||
out << ")";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpLensNode::write
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpLensNode::
|
||||
write(ostream &out, int indent_level) const {
|
||||
PandaNode::write(out, indent_level);
|
||||
if (_lens != (Lens *)NULL) {
|
||||
_lens->write(out, indent_level + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// Filename: qplensNode.h
|
||||
// Created by: drose (26Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 QPLENSNODE_H
|
||||
#define QPLENSNODE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "lens.h"
|
||||
#include "pointerTo.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpLensNode
|
||||
// Description : A node that contains a Lens. The most important
|
||||
// example of this kind of node is a Camera, but other
|
||||
// kinds of nodes also contain a lens (for instance, a
|
||||
// Spotlight).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpLensNode : public PandaNode {
|
||||
PUBLISHED:
|
||||
INLINE qpLensNode(const string &name);
|
||||
|
||||
public:
|
||||
INLINE qpLensNode(const qpLensNode ©);
|
||||
INLINE void operator = (const qpLensNode ©);
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
virtual PandaNode *make_copy() const;
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void copy_lens(const Lens &lens);
|
||||
INLINE void set_lens(Lens *lens);
|
||||
INLINE Lens *get_lens();
|
||||
|
||||
bool is_in_view(const LPoint3f &pos);
|
||||
|
||||
protected:
|
||||
PT(Lens) _lens;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
PandaNode::init_type();
|
||||
register_type(_type_handle, "qpLensNode",
|
||||
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;
|
||||
};
|
||||
|
||||
#include "qplensNode.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -173,7 +173,8 @@ compare_to_impl(const RenderAttrib *other) const {
|
|||
// RenderAttrib (that is, a subsequent RenderAttrib
|
||||
// completely replaces the preceding one). On the other
|
||||
// hand, some kinds of RenderAttrib (for instance,
|
||||
// TransformAttrib) might combine in meaningful ways.
|
||||
// ColorTransformAttrib) might combine in meaningful
|
||||
// ways.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) RenderAttrib::
|
||||
compose_impl(const RenderAttrib *other) const {
|
||||
|
|
|
|||
|
|
@ -72,9 +72,6 @@ RenderState::
|
|||
if (_saved_entry != _states.end()) {
|
||||
_states.erase(_saved_entry);
|
||||
_saved_entry = _states.end();
|
||||
|
||||
cerr << "Removing " << (void *)this << ", " << _states.size()
|
||||
<< " remaining.\n";
|
||||
}
|
||||
|
||||
// Now make sure we clean up all other floating pointers to the
|
||||
|
|
@ -359,8 +356,6 @@ invert_compose(const RenderState *other) const {
|
|||
// but we pretend that it is because it's only a cache which is
|
||||
// transparent to the rest of the interface.
|
||||
|
||||
cerr << "invert composing " << *this << " with " << *other << "\n";
|
||||
|
||||
// We handle empty state (identity) as a trivial special case.
|
||||
if (is_empty()) {
|
||||
return other;
|
||||
|
|
@ -384,7 +379,6 @@ invert_compose(const RenderState *other) const {
|
|||
((Composition &)comp)._result = do_invert_compose(other);
|
||||
}
|
||||
// Here's the cache!
|
||||
cerr << " returning cached result " << (void *)comp._result.p() << "\n";
|
||||
return comp._result;
|
||||
}
|
||||
|
||||
|
|
@ -401,7 +395,6 @@ invert_compose(const RenderState *other) const {
|
|||
((RenderState *)other)->_invert_composition_cache[this]._result = NULL;
|
||||
((RenderState *)this)->_invert_composition_cache[other]._result = result;
|
||||
|
||||
cerr << " returning new result " << (void *)result.p() << "\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -472,17 +465,19 @@ remove(TypeHandle type) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void RenderState::
|
||||
output(ostream &out) const {
|
||||
out << get_type() << ":";
|
||||
if (_attributes.empty()) {
|
||||
out << "empty";
|
||||
out << "(empty)";
|
||||
|
||||
} else {
|
||||
Attributes::const_iterator ai = _attributes.begin();
|
||||
out << (*ai)._type;
|
||||
out << "(" << (*ai)._type;
|
||||
++ai;
|
||||
while (ai != _attributes.end()) {
|
||||
out << " " << (*ai)._type;
|
||||
++ai;
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,8 @@ private:
|
|||
// should be).
|
||||
const RenderState *_self_compose;
|
||||
|
||||
// This is the actual set of data within the RenderState: a set of
|
||||
private:
|
||||
// This is the actual data within the RenderState: a set of
|
||||
// RenderAttribs.
|
||||
class Attribute {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "nodeChain.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "transformAttrib.h"
|
||||
#include "transformState.h"
|
||||
#include "texture.h"
|
||||
#include "qpgeomNode.h"
|
||||
#include "geomTristrip.h"
|
||||
|
|
@ -68,19 +69,25 @@ main(int argc, char *argv[]) {
|
|||
qpGeomNode *g2 = new qpGeomNode("g2");
|
||||
b->add_child(g2);
|
||||
g2->add_geom(geom1, b->get_state());
|
||||
g2->set_attrib(TransformAttrib::make_mat(LMatrix4f::translate_mat(10, 0, 0)));
|
||||
g2->set_transform(TransformState::make_mat(LMatrix4f::translate_mat(10, 0, 0)));
|
||||
|
||||
cerr << "\n";
|
||||
list_hierarchy(root, 0);
|
||||
|
||||
qpCullTraverser trav;
|
||||
CullHandler cull_handler;
|
||||
trav.set_cull_handler(&cull_handler);
|
||||
cerr << "\n";
|
||||
trav.traverse(root);
|
||||
NodeChain ch_g1(g1);
|
||||
cerr << ch_g1 << "\n";
|
||||
|
||||
cerr << "\n";
|
||||
trav.traverse(root);
|
||||
NodeChain ch_g2(g2);
|
||||
cerr << ch_g2 << "\n";
|
||||
|
||||
cerr << *ch_g1.get_rel_transform(ch_g2) << "\n";
|
||||
cerr << *ch_g2.get_rel_transform(ch_g1) << "\n";
|
||||
|
||||
cerr << *ch_g1.get_rel_state(ch_g2) << "\n";
|
||||
cerr << *ch_g2.get_rel_state(ch_g1) << "\n";
|
||||
|
||||
cerr << *ch_g2.get_rel_transform(ch_g2) << "\n";
|
||||
cerr << *ch_g2.get_rel_state(ch_g2) << "\n";
|
||||
|
||||
cerr << "\n";
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,308 +0,0 @@
|
|||
// Filename: transformAttrib.cxx
|
||||
// Created by: drose (23Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "transformAttrib.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
#include "datagram.h"
|
||||
#include "datagramIterator.h"
|
||||
#include "compose_matrix.h"
|
||||
|
||||
TypeHandle TransformAttrib::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::make_identity
|
||||
// Access: Published, Static
|
||||
// Description: Constructs an identity transform.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) TransformAttrib::
|
||||
make_identity() {
|
||||
TransformAttrib *attrib = new TransformAttrib;
|
||||
return return_new(attrib);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::make_components
|
||||
// Access: Published, Static
|
||||
// Description: Makes a new TransformAttrib with the specified
|
||||
// components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) TransformAttrib::
|
||||
make_components(const LVecBase3f &pos, const LVecBase3f &hpr,
|
||||
const LVecBase3f &scale) {
|
||||
// Make a special-case check for the identity transform.
|
||||
if (pos == LVecBase3f(0.0f, 0.0f, 0.0f) &&
|
||||
hpr == LVecBase3f(0.0f, 0.0f, 0.0f) &&
|
||||
scale == LVecBase3f(1.0f, 1.0f, 1.0f)) {
|
||||
return make_identity();
|
||||
}
|
||||
|
||||
TransformAttrib *attrib = new TransformAttrib;
|
||||
attrib->_pos = pos;
|
||||
attrib->_hpr = hpr;
|
||||
attrib->_scale = scale;
|
||||
attrib->_flags = F_components_given | F_components_known | F_has_components;
|
||||
return return_new(attrib);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::make_components
|
||||
// Access: Published, Static
|
||||
// Description: Makes a new TransformAttrib with the specified
|
||||
// transformation matrix.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) TransformAttrib::
|
||||
make_mat(const LMatrix4f &mat) {
|
||||
// Make a special-case check for the identity matrix.
|
||||
if (mat == LMatrix4f::ident_mat()) {
|
||||
return make_identity();
|
||||
}
|
||||
|
||||
TransformAttrib *attrib = new TransformAttrib;
|
||||
attrib->_mat = mat;
|
||||
attrib->_flags = F_mat_known;
|
||||
return return_new(attrib);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformAttrib::
|
||||
output(ostream &out) const {
|
||||
out << get_type() << ":";
|
||||
if (is_identity()) {
|
||||
out << "(identity)";
|
||||
|
||||
} else if (has_components()) {
|
||||
out << "(";
|
||||
if (get_pos() != LVecBase3f(0.0f, 0.0f, 0.0f)) {
|
||||
out << "pos " << get_pos();
|
||||
}
|
||||
if (get_hpr() != LVecBase3f(0.0f, 0.0f, 0.0f)) {
|
||||
out << "hpr " << get_hpr();
|
||||
}
|
||||
if (get_scale() != LVecBase3f(1.0f, 1.0f, 1.0f)) {
|
||||
out << "scale " << get_scale();
|
||||
}
|
||||
out << ")";
|
||||
|
||||
} else {
|
||||
out << get_mat();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::compare_to_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: Intended to be overridden by derived TransformAttrib
|
||||
// types to return a unique number indicating whether
|
||||
// this TransformAttrib is equivalent to the other one.
|
||||
//
|
||||
// This should return 0 if the two TransformAttrib 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 TransformAttrib
|
||||
// objects whose get_type() functions return the same.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int TransformAttrib::
|
||||
compare_to_impl(const RenderAttrib *other) const {
|
||||
const TransformAttrib *ta;
|
||||
DCAST_INTO_R(ta, other, 0);
|
||||
|
||||
if (is_identity() != ta->is_identity()) {
|
||||
return is_identity() < ta->is_identity();
|
||||
}
|
||||
if (is_identity()) {
|
||||
// All identity transforms are equivalent to each other.
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool components_given = (_flags & F_components_given) != 0;
|
||||
bool ta_components_given = (ta->_flags & F_components_given) != 0;
|
||||
if (components_given != ta_components_given) {
|
||||
return components_given < ta_components_given;
|
||||
}
|
||||
if (components_given) {
|
||||
// If the transform was specified componentwise, compare them
|
||||
// componentwise.
|
||||
int c = _pos.compare_to(ta->_pos);
|
||||
if (c != 0) {
|
||||
return c;
|
||||
}
|
||||
c = _hpr.compare_to(ta->_hpr);
|
||||
if (c != 0) {
|
||||
return c;
|
||||
}
|
||||
c = _scale.compare_to(ta->_hpr);
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
// Otherwise, compare the matrices.
|
||||
return get_mat().compare_to(ta->get_mat());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) TransformAttrib::
|
||||
compose_impl(const RenderAttrib *other) const {
|
||||
const TransformAttrib *ta;
|
||||
DCAST_INTO_R(ta, other, other);
|
||||
|
||||
// Identity times anything, duh.
|
||||
if (is_identity()) {
|
||||
return ta;
|
||||
} else if (ta->is_identity()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// Perhaps we should be smarter here if both transforms are
|
||||
// componentwise, and multiply them componentwise.
|
||||
LMatrix4f new_mat = get_mat() * ta->get_mat();
|
||||
return make_mat(new_mat);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::make_default_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: Intended to be overridden by derived TransformAttrib
|
||||
// types to specify what the default property for a
|
||||
// TransformAttrib of this type should be.
|
||||
//
|
||||
// This should return a newly-allocated TransformAttrib of
|
||||
// the same type that corresponds to whatever the
|
||||
// standard default for this kind of TransformAttrib is.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
RenderAttrib *TransformAttrib::
|
||||
make_default_impl() const {
|
||||
return new TransformAttrib;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::calc_singular
|
||||
// Access: Private
|
||||
// Description: Determines whether the transform is singular (i.e. it
|
||||
// scales to zero, and has no inverse).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformAttrib::
|
||||
calc_singular() {
|
||||
bool singular = false;
|
||||
|
||||
if (has_components()) {
|
||||
// The matrix is singular if any component of its scale is 0.
|
||||
singular = (_scale[0] == 0.0f || _scale[1] == 0.0f || _scale[2] == 0.0f);
|
||||
} else {
|
||||
// The matrix is singular if its determinant is zero.
|
||||
const LMatrix4f &mat = get_mat();
|
||||
singular = (mat.get_upper_3().determinant() == 0.0f);
|
||||
}
|
||||
|
||||
if (singular) {
|
||||
_flags |= F_is_singular;
|
||||
}
|
||||
_flags |= F_singular_known;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::calc_components
|
||||
// Access: Private
|
||||
// Description: Derives the components from the matrix, if possible.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformAttrib::
|
||||
calc_components() {
|
||||
bool possible = decompose_matrix(get_mat(), _scale, _hpr, _pos);
|
||||
if (possible) {
|
||||
// Some matrices can't be decomposed into scale, hpr, pos.
|
||||
_flags |= F_has_components;
|
||||
}
|
||||
_flags |= F_components_known;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::calc_mat
|
||||
// Access: Private
|
||||
// Description: Computes the matrix from the components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformAttrib::
|
||||
calc_mat() {
|
||||
compose_matrix(_mat, _scale, _hpr, _pos);
|
||||
_flags |= F_mat_known;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
// Description: Tells the BamReader how to create objects of type
|
||||
// TransformAttrib.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformAttrib::
|
||||
register_with_read_factory() {
|
||||
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::write_datagram
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes the contents of this object to the datagram
|
||||
// for shipping out to a Bam file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformAttrib::
|
||||
write_datagram(BamWriter *manager, Datagram &dg) {
|
||||
RenderAttrib::write_datagram(manager, dg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::make_from_bam
|
||||
// Access: Protected, Static
|
||||
// Description: This function is called by the BamReader's factory
|
||||
// when a new object of type TransformAttrib is encountered
|
||||
// in the Bam file. It should create the TransformAttrib
|
||||
// and extract its information from the file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TypedWritable *TransformAttrib::
|
||||
make_from_bam(const FactoryParams ¶ms) {
|
||||
TransformAttrib *attrib = new TransformAttrib;
|
||||
DatagramIterator scan;
|
||||
BamReader *manager;
|
||||
|
||||
parse_params(params, scan, manager);
|
||||
attrib->fillin(scan, manager);
|
||||
|
||||
return new_from_bam(attrib, manager);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::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 TransformAttrib.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformAttrib::
|
||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
RenderAttrib::fillin(scan, manager);
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
// Filename: transformAttrib.h
|
||||
// Created by: drose (23Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 TRANSFORMATTRIB_H
|
||||
#define TRANSFORMATTRIB_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "renderAttrib.h"
|
||||
#include "luse.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : TransformAttrib
|
||||
// Description : Indicates a coordinate-system transform on vertices.
|
||||
// TransformAttribs are the primary means for storing
|
||||
// transformations on the scene graph.
|
||||
//
|
||||
// Transforms may be specified in one of two ways:
|
||||
// componentwise, with a pos-hpr-scale, or with an
|
||||
// arbitrary transform matrix. If you specify a
|
||||
// transform componentwise, it will remember its
|
||||
// original components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA TransformAttrib : public RenderAttrib {
|
||||
private:
|
||||
INLINE TransformAttrib();
|
||||
|
||||
PUBLISHED:
|
||||
static CPT(RenderAttrib) make_identity();
|
||||
static CPT(RenderAttrib) make_components(const LVecBase3f &pos,
|
||||
const LVecBase3f &hpr,
|
||||
const LVecBase3f &scale);
|
||||
static CPT(RenderAttrib) make_mat(const LMatrix4f &mat);
|
||||
|
||||
INLINE bool is_identity() const;
|
||||
INLINE bool is_singular() const;
|
||||
INLINE bool has_components() const;
|
||||
INLINE const LVecBase3f &get_pos() const;
|
||||
INLINE const LVecBase3f &get_hpr() const;
|
||||
INLINE const LVecBase3f &get_scale() const;
|
||||
INLINE const LMatrix4f &get_mat() const;
|
||||
|
||||
public:
|
||||
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 RenderAttrib *make_default_impl() const;
|
||||
|
||||
private:
|
||||
INLINE void check_singular() const;
|
||||
INLINE void check_components() const;
|
||||
INLINE void check_mat() const;
|
||||
void calc_singular();
|
||||
void calc_components();
|
||||
void calc_mat();
|
||||
|
||||
enum Flags {
|
||||
F_is_identity = 0x0001,
|
||||
F_is_singular = 0x0002,
|
||||
F_singular_known = 0x0004,
|
||||
F_components_given = 0x0008,
|
||||
F_components_known = 0x0010,
|
||||
F_has_components = 0x0020,
|
||||
F_mat_known = 0x0040,
|
||||
};
|
||||
LVecBase3f _pos, _hpr, _scale;
|
||||
LMatrix4f _mat;
|
||||
|
||||
short _flags;
|
||||
|
||||
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, "TransformAttrib",
|
||||
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 "transformAttrib.I"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// Filename: transformAttrib.I
|
||||
// Created by: drose (23Feb02)
|
||||
// Filename: transformState.I
|
||||
// Created by: drose (25Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
@ -18,42 +18,95 @@
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::Constructor
|
||||
// Access: Private
|
||||
// Description: Use TransformAttrib::make() to construct a new
|
||||
// TransformAttrib object.
|
||||
// Function: TransformState::make_pos
|
||||
// Access: Published, Static
|
||||
// Description: Makes a new TransformState with the specified
|
||||
// components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE TransformAttrib::
|
||||
TransformAttrib() {
|
||||
_flags = F_is_identity | F_singular_known;
|
||||
INLINE CPT(TransformState) TransformState::
|
||||
make_pos(const LVecBase3f &pos) {
|
||||
return make_pos_hpr_scale(pos,
|
||||
LVecBase3f(0.0f, 0.0f, 0.0f),
|
||||
LVecBase3f(1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::is_identity
|
||||
// Function: TransformState::make_hpr
|
||||
// Access: Published, Static
|
||||
// Description: Makes a new TransformState with the specified
|
||||
// components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPT(TransformState) TransformState::
|
||||
make_hpr(const LVecBase3f &hpr) {
|
||||
return make_pos_hpr_scale(LVecBase3f(0.0f, 0.0f, 0.0f),
|
||||
hpr,
|
||||
LVecBase3f(1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::make_pos_hpr
|
||||
// Access: Published, Static
|
||||
// Description: Makes a new TransformState with the specified
|
||||
// components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPT(TransformState) TransformState::
|
||||
make_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) {
|
||||
return make_pos_hpr_scale(pos, hpr,
|
||||
LVecBase3f(1.0, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::make_scale
|
||||
// Access: Published, Static
|
||||
// Description: Makes a new TransformState with the specified
|
||||
// components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPT(TransformState) TransformState::
|
||||
make_scale(float scale) {
|
||||
return make_pos_hpr_scale(LVecBase3f(0.0f, 0.0f, 0.0f),
|
||||
LVecBase3f(0.0f, 0.0f, 0.0f),
|
||||
LVecBase3f(scale, scale, scale));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::make_scale
|
||||
// Access: Published, Static
|
||||
// Description: Makes a new TransformState with the specified
|
||||
// components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPT(TransformState) TransformState::
|
||||
make_scale(const LVecBase3f &scale) {
|
||||
return make_pos_hpr_scale(LVecBase3f(0.0f, 0.0f, 0.0f),
|
||||
LVecBase3f(0.0f, 0.0f, 0.0f),
|
||||
scale);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::is_identity
|
||||
// Access: Published
|
||||
// Description: Returns true if the transform represents the identity
|
||||
// matrix, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool TransformAttrib::
|
||||
INLINE bool TransformState::
|
||||
is_identity() const {
|
||||
return ((_flags & F_is_identity) != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::is_singular
|
||||
// Function: TransformState::is_singular
|
||||
// Access: Published
|
||||
// Description: Returns true if the transform represents a singular
|
||||
// transform (that is, it has a zero scale, and it
|
||||
// cannot be inverted), or false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool TransformAttrib::
|
||||
INLINE bool TransformState::
|
||||
is_singular() const {
|
||||
check_singular();
|
||||
return ((_flags & F_is_singular) != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::has_components
|
||||
// Function: TransformState::has_components
|
||||
// Access: Published
|
||||
// Description: Returns true if the transform can be described by
|
||||
// separate pos, hpr, and scale components. Most
|
||||
|
|
@ -69,20 +122,20 @@ is_singular() const {
|
|||
// If this returns true, you may safely call get_pos(),
|
||||
// etc., to retrieve the components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool TransformAttrib::
|
||||
INLINE bool TransformState::
|
||||
has_components() const {
|
||||
check_components();
|
||||
return ((_flags & F_has_components) != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::get_pos
|
||||
// Function: TransformState::get_pos
|
||||
// Access: Published
|
||||
// Description: Returns the pos component of the transform. It is an
|
||||
// error to call this if has_components() returned
|
||||
// false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase3f &TransformAttrib::
|
||||
INLINE const LVecBase3f &TransformState::
|
||||
get_pos() const {
|
||||
check_components();
|
||||
nassertr(has_components(), _pos);
|
||||
|
|
@ -90,13 +143,13 @@ get_pos() const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::get_hpr
|
||||
// Function: TransformState::get_hpr
|
||||
// Access: Published
|
||||
// Description: Returns the hpr component of the transform. It is an
|
||||
// error to call this if has_components() returned
|
||||
// false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase3f &TransformAttrib::
|
||||
INLINE const LVecBase3f &TransformState::
|
||||
get_hpr() const {
|
||||
check_components();
|
||||
nassertr(has_components(), _hpr);
|
||||
|
|
@ -104,13 +157,13 @@ get_hpr() const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::get_scale
|
||||
// Function: TransformState::get_scale
|
||||
// Access: Published
|
||||
// Description: Returns the scale component of the transform. It is an
|
||||
// error to call this if has_components() returned
|
||||
// false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase3f &TransformAttrib::
|
||||
INLINE const LVecBase3f &TransformState::
|
||||
get_scale() const {
|
||||
check_components();
|
||||
nassertr(has_components(), _scale);
|
||||
|
|
@ -118,55 +171,55 @@ get_scale() const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::get_mat
|
||||
// Function: TransformState::get_mat
|
||||
// Access: Published
|
||||
// Description: Returns the matrix that describes the transform.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LMatrix4f &TransformAttrib::
|
||||
INLINE const LMatrix4f &TransformState::
|
||||
get_mat() const {
|
||||
check_mat();
|
||||
return _mat;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::check_singular
|
||||
// Function: TransformState::check_singular
|
||||
// Access: Private
|
||||
// Description: Ensures that we know whether the matrix is singular.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void TransformAttrib::
|
||||
INLINE void TransformState::
|
||||
check_singular() const {
|
||||
// This pretends to be a const function, even though it's not,
|
||||
// because it only updates a transparent cache value.
|
||||
if ((_flags & F_singular_known) == 0) {
|
||||
((TransformAttrib *)this)->calc_singular();
|
||||
((TransformState *)this)->calc_singular();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::check_components
|
||||
// Function: TransformState::check_components
|
||||
// Access: Private
|
||||
// Description: Ensures that we know the components of the transform
|
||||
// (or that we know they cannot be derived).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void TransformAttrib::
|
||||
INLINE void TransformState::
|
||||
check_components() const {
|
||||
// This pretends to be a const function, even though it's not,
|
||||
// because it only updates a transparent cache value.
|
||||
if ((_flags & F_components_known) == 0) {
|
||||
((TransformAttrib *)this)->calc_components();
|
||||
((TransformState *)this)->calc_components();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformAttrib::check_mat
|
||||
// Function: TransformState::check_mat
|
||||
// Access: Private
|
||||
// Description: Ensures that we know the overall matrix.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void TransformAttrib::
|
||||
INLINE void TransformState::
|
||||
check_mat() const {
|
||||
// This pretends to be a const function, even though it's not,
|
||||
// because it only updates a transparent cache value.
|
||||
if ((_flags & F_mat_known) == 0) {
|
||||
((TransformAttrib *)this)->calc_mat();
|
||||
((TransformState *)this)->calc_mat();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,650 @@
|
|||
// Filename: transformState.cxx
|
||||
// Created by: drose (25Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "transformState.h"
|
||||
#include "compose_matrix.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
#include "datagramIterator.h"
|
||||
#include "indent.h"
|
||||
#include "compareTo.h"
|
||||
|
||||
TransformState::States TransformState::_states;
|
||||
CPT(TransformState) TransformState::_identity_state;
|
||||
TypeHandle TransformState::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::Constructor
|
||||
// Access: Protected
|
||||
// Description: Actually, this could be a private constructor, since
|
||||
// no one inherits from TransformState, but gcc gives us a
|
||||
// spurious warning if all constructors are private.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TransformState::
|
||||
TransformState() {
|
||||
_saved_entry = _states.end();
|
||||
_self_compose = (TransformState *)NULL;
|
||||
_flags = F_is_identity | F_singular_known;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: TransformStates are not meant to be copied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TransformState::
|
||||
TransformState(const TransformState &) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: TransformStates are not meant to be copied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
operator = (const TransformState &) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description: The destructor is responsible for removing the
|
||||
// TransformState from the global set if it is there.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TransformState::
|
||||
~TransformState() {
|
||||
// Remove the deleted TransformState object from the global pool.
|
||||
if (_saved_entry != _states.end()) {
|
||||
_states.erase(_saved_entry);
|
||||
_saved_entry = _states.end();
|
||||
}
|
||||
|
||||
// Now make sure we clean up all other floating pointers to the
|
||||
// TransformState. These may be scattered around in the various
|
||||
// CompositionCaches from other TransformState objects.
|
||||
|
||||
// Fortunately, since we added CompositionCache records in pairs, we
|
||||
// know exactly the set of TransformState objects that have us in their
|
||||
// cache: it's the same set of TransformState objects that we have in
|
||||
// our own cache.
|
||||
|
||||
// We do need to put some thought into this loop, because as we
|
||||
// clear out cache entries we'll cause other TransformState objects to
|
||||
// destruct, which could cause things to get pulled out of our own
|
||||
// _composition_cache map. We don't want to get bitten by this
|
||||
// cascading effect.
|
||||
CompositionCache::iterator ci;
|
||||
ci = _composition_cache.begin();
|
||||
while (ci != _composition_cache.end()) {
|
||||
{
|
||||
PT(TransformState) other = (TransformState *)(*ci).first;
|
||||
Composition comp = (*ci).second;
|
||||
|
||||
// We should never have a reflexive entry in this map. If we
|
||||
// do, something got screwed up elsewhere.
|
||||
nassertv(other != (const TransformState *)this);
|
||||
|
||||
// Now we're holding a reference count to the other state, as well
|
||||
// as to the computed result (if any), so neither object will be
|
||||
// tempted to destruct. Go ahead and remove ourselves from the
|
||||
// other cache.
|
||||
other->_composition_cache.erase(this);
|
||||
|
||||
// It's all right if the other state destructs now, since it
|
||||
// won't try to remove itself from our own composition cache any
|
||||
// more. Someone might conceivably delete the *next* entry,
|
||||
// though, so we should be sure to let all that deleting finish
|
||||
// up before we attempt to increment ci, by closing the scope
|
||||
// here.
|
||||
}
|
||||
// Now it's safe to increment ci, because the current cache entry
|
||||
// has not gone away, and if the next one has, by now it's safely
|
||||
// gone.
|
||||
++ci;
|
||||
}
|
||||
|
||||
// A similar bit of code for the invert cache.
|
||||
ci = _invert_composition_cache.begin();
|
||||
while (ci != _invert_composition_cache.end()) {
|
||||
{
|
||||
PT(TransformState) other = (TransformState *)(*ci).first;
|
||||
Composition comp = (*ci).second;
|
||||
nassertv(other != (const TransformState *)this);
|
||||
other->_invert_composition_cache.erase(this);
|
||||
}
|
||||
++ci;
|
||||
}
|
||||
|
||||
// Also, if we called compose(this) at some point and the return
|
||||
// value was something other than this, we need to decrement the
|
||||
// associated reference count.
|
||||
if (_self_compose != (TransformState *)NULL && _self_compose != this) {
|
||||
unref_delete((TransformState *)_self_compose);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::operator <
|
||||
// Access: Public
|
||||
// Description: Provides an arbitrary ordering among all unique
|
||||
// TransformStates, so we can store the essentially
|
||||
// different ones in a big set and throw away the rest.
|
||||
//
|
||||
// This method is not needed outside of the TransformState
|
||||
// class because all equivalent TransformState objects are
|
||||
// guaranteed to share the same pointer; thus, a pointer
|
||||
// comparison is always sufficient.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TransformState::
|
||||
operator < (const TransformState &other) const {
|
||||
bool components_given = (_flags & F_components_given) != 0;
|
||||
bool other_components_given = (other._flags & F_components_given) != 0;
|
||||
if (components_given != other_components_given) {
|
||||
return components_given < other_components_given;
|
||||
}
|
||||
if (components_given) {
|
||||
// If the transform was specified componentwise, compare them
|
||||
// componentwise.
|
||||
int c = _pos.compare_to(other._pos);
|
||||
if (c != 0) {
|
||||
return c < 0;
|
||||
}
|
||||
c = _hpr.compare_to(other._hpr);
|
||||
if (c != 0) {
|
||||
return c < 0;
|
||||
}
|
||||
c = _scale.compare_to(other._hpr);
|
||||
return c < 0;
|
||||
}
|
||||
|
||||
// Otherwise, compare the matrices.
|
||||
return get_mat() < other.get_mat();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::make_identity
|
||||
// Access: Published, Static
|
||||
// Description: Constructs an identity transform.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) TransformState::
|
||||
make_identity() {
|
||||
// The identity state is asked for so often, we make it a special case
|
||||
// and store a pointer forever once we find it the first time.
|
||||
if (_identity_state == (TransformState *)NULL) {
|
||||
TransformState *state = new TransformState;
|
||||
_identity_state = return_new(state);
|
||||
}
|
||||
|
||||
return _identity_state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::make_pos_hpr_scale
|
||||
// Access: Published, Static
|
||||
// Description: Makes a new TransformState with the specified
|
||||
// components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) TransformState::
|
||||
make_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr,
|
||||
const LVecBase3f &scale) {
|
||||
// Make a special-case check for the identity transform.
|
||||
if (pos == LVecBase3f(0.0f, 0.0f, 0.0f) &&
|
||||
hpr == LVecBase3f(0.0f, 0.0f, 0.0f) &&
|
||||
scale == LVecBase3f(1.0f, 1.0f, 1.0f)) {
|
||||
return make_identity();
|
||||
}
|
||||
|
||||
TransformState *attrib = new TransformState;
|
||||
attrib->_pos = pos;
|
||||
attrib->_hpr = hpr;
|
||||
attrib->_scale = scale;
|
||||
attrib->_flags = F_components_given | F_components_known | F_has_components;
|
||||
return return_new(attrib);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::make_mat
|
||||
// Access: Published, Static
|
||||
// Description: Makes a new TransformState with the specified
|
||||
// transformation matrix.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) TransformState::
|
||||
make_mat(const LMatrix4f &mat) {
|
||||
// Make a special-case check for the identity matrix.
|
||||
if (mat == LMatrix4f::ident_mat()) {
|
||||
return make_identity();
|
||||
}
|
||||
|
||||
TransformState *attrib = new TransformState;
|
||||
attrib->_mat = mat;
|
||||
attrib->_flags = F_mat_known;
|
||||
return return_new(attrib);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::compose
|
||||
// Access: Published
|
||||
// Description: Returns a new TransformState object that represents the
|
||||
// composition of this state with the other state.
|
||||
//
|
||||
// The result of this operation is cached, and will be
|
||||
// retained as long as both this TransformState object and
|
||||
// the other TransformState object continue to exist.
|
||||
// Should one of them destruct, the cached entry will be
|
||||
// removed, and its pointer will be allowed to destruct
|
||||
// as well.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) TransformState::
|
||||
compose(const TransformState *other) const {
|
||||
// This method isn't strictly const, because it updates the cache,
|
||||
// but we pretend that it is because it's only a cache which is
|
||||
// transparent to the rest of the interface.
|
||||
|
||||
// We handle identity as a trivial special case.
|
||||
if (is_identity()) {
|
||||
return other;
|
||||
}
|
||||
if (other->is_identity()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (other == this) {
|
||||
// compose(this) has to be handled as a special case, because the
|
||||
// caching problem is so different.
|
||||
if (_self_compose != (TransformState *)NULL) {
|
||||
return _self_compose;
|
||||
}
|
||||
CPT(TransformState) result = do_compose(this);
|
||||
((TransformState *)this)->_self_compose = result;
|
||||
|
||||
if (result != (const TransformState *)this) {
|
||||
// If the result of compose(this) is something other than this,
|
||||
// explicitly increment the reference count. We have to be sure
|
||||
// to decrement it again later, in our destructor.
|
||||
_self_compose->ref();
|
||||
|
||||
// (If the result was just this again, we still store the
|
||||
// result, but we don't increment the reference count, since
|
||||
// that would be a self-referential leak. What a mess this is.)
|
||||
}
|
||||
return _self_compose;
|
||||
}
|
||||
|
||||
// Is this composition already cached?
|
||||
CompositionCache::const_iterator ci = _composition_cache.find(other);
|
||||
if (ci != _composition_cache.end()) {
|
||||
const Composition &comp = (*ci).second;
|
||||
if (comp._result == (const TransformState *)NULL) {
|
||||
// Well, it wasn't cached already, but we already had an entry
|
||||
// (probably created for the reverse direction), so use the same
|
||||
// entry to store the new result.
|
||||
((Composition &)comp)._result = do_compose(other);
|
||||
}
|
||||
// Here's the cache!
|
||||
return comp._result;
|
||||
}
|
||||
|
||||
// We need to make a new cache entry, both in this object and in the
|
||||
// other object. We make both records so the other TransformState
|
||||
// object will know to delete the entry from this object when it
|
||||
// destructs, and vice-versa.
|
||||
|
||||
// The cache entry in this object is the only one that indicates the
|
||||
// result; the other will be NULL for now.
|
||||
CPT(TransformState) result = do_compose(other);
|
||||
// We store them in this order, on the off-chance that other is the
|
||||
// same as this, a degenerate case which is still worth supporting.
|
||||
((TransformState *)other)->_composition_cache[this]._result = NULL;
|
||||
((TransformState *)this)->_composition_cache[other]._result = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::invert_compose
|
||||
// Access: Published
|
||||
// Description: Returns a new TransformState object that represents the
|
||||
// composition of this state's inverse with the other
|
||||
// state.
|
||||
//
|
||||
// This is similar to compose(), but is particularly
|
||||
// useful for computing the relative state of a node as
|
||||
// viewed from some other node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) TransformState::
|
||||
invert_compose(const TransformState *other) const {
|
||||
// This method isn't strictly const, because it updates the cache,
|
||||
// but we pretend that it is because it's only a cache which is
|
||||
// transparent to the rest of the interface.
|
||||
|
||||
// We handle identity as a trivial special case.
|
||||
if (is_identity()) {
|
||||
return other;
|
||||
}
|
||||
// Unlike compose(), the case of other->is_identity() is not quite as
|
||||
// trivial for invert_compose().
|
||||
|
||||
if (other == this) {
|
||||
// a->invert_compose(a) always produces identity.
|
||||
return make_identity();
|
||||
}
|
||||
|
||||
// Is this composition already cached?
|
||||
CompositionCache::const_iterator ci = _invert_composition_cache.find(other);
|
||||
if (ci != _invert_composition_cache.end()) {
|
||||
const Composition &comp = (*ci).second;
|
||||
if (comp._result == (const TransformState *)NULL) {
|
||||
// Well, it wasn't cached already, but we already had an entry
|
||||
// (probably created for the reverse direction), so use the same
|
||||
// entry to store the new result.
|
||||
((Composition &)comp)._result = do_invert_compose(other);
|
||||
}
|
||||
// Here's the cache!
|
||||
return comp._result;
|
||||
}
|
||||
|
||||
// We need to make a new cache entry, both in this object and in the
|
||||
// other object. We make both records so the other TransformState
|
||||
// object will know to delete the entry from this object when it
|
||||
// destructs, and vice-versa.
|
||||
|
||||
// The cache entry in this object is the only one that indicates the
|
||||
// result; the other will be NULL for now.
|
||||
CPT(TransformState) result = do_invert_compose(other);
|
||||
// We store them in this order, on the off-chance that other is the
|
||||
// same as this, a degenerate case which is still worth supporting.
|
||||
((TransformState *)other)->_invert_composition_cache[this]._result = NULL;
|
||||
((TransformState *)this)->_invert_composition_cache[other]._result = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::output
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
output(ostream &out) const {
|
||||
out << get_type() << ":";
|
||||
if (is_identity()) {
|
||||
out << "(identity)";
|
||||
|
||||
} else if (has_components()) {
|
||||
out << "(";
|
||||
if (get_pos() != LVecBase3f(0.0f, 0.0f, 0.0f)) {
|
||||
out << "pos " << get_pos();
|
||||
}
|
||||
if (get_hpr() != LVecBase3f(0.0f, 0.0f, 0.0f)) {
|
||||
out << "hpr " << get_hpr();
|
||||
}
|
||||
if (get_scale() != LVecBase3f(1.0f, 1.0f, 1.0f)) {
|
||||
out << "scale " << get_scale();
|
||||
}
|
||||
out << ")";
|
||||
|
||||
} else {
|
||||
out << get_mat();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::write
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level) << *this << "\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::return_new
|
||||
// Access: Private, Static
|
||||
// Description: This function is used to share a common TransformState
|
||||
// pointer for all equivalent TransformState objects.
|
||||
//
|
||||
// See the similar logic in RenderAttrib. The idea is
|
||||
// to create a new TransformState object and pass it
|
||||
// through this function, which will share the pointer
|
||||
// with a previously-created TransformState object if it is
|
||||
// equivalent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) TransformState::
|
||||
return_new(TransformState *state) {
|
||||
nassertr(state != (TransformState *)NULL, state);
|
||||
|
||||
// This should be a newly allocated pointer, not one that was used
|
||||
// for anything else.
|
||||
nassertr(state->_saved_entry == _states.end(), state);
|
||||
|
||||
// Save the state in a local PointerTo so that it will be freed at
|
||||
// the end of this function if no one else uses it.
|
||||
CPT(TransformState) pt_state = state;
|
||||
|
||||
pair<States::iterator, bool> result = _states.insert(state);
|
||||
if (result.second) {
|
||||
// The state was inserted; save the iterator and return the
|
||||
// input state.
|
||||
state->_saved_entry = result.first;
|
||||
return pt_state;
|
||||
}
|
||||
|
||||
// The state was not inserted; there must be an equivalent one
|
||||
// already in the set. Return that one.
|
||||
return *(result.first);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::do_compose
|
||||
// Access: Private
|
||||
// Description: The private implemention of compose(); this actually
|
||||
// composes two TransformStates, without bothering with the
|
||||
// cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) TransformState::
|
||||
do_compose(const TransformState *other) const {
|
||||
LMatrix4f new_mat = get_mat() * other->get_mat();
|
||||
return make_mat(new_mat);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::do_invert_compose
|
||||
// Access: Private
|
||||
// Description: The private implemention of invert_compose().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(TransformState) TransformState::
|
||||
do_invert_compose(const TransformState *other) const {
|
||||
LMatrix4f new_mat;
|
||||
new_mat.invert_from(get_mat());
|
||||
new_mat = new_mat * other->get_mat();
|
||||
return make_mat(new_mat);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::calc_singular
|
||||
// Access: Private
|
||||
// Description: Determines whether the transform is singular (i.e. it
|
||||
// scales to zero, and has no inverse).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
calc_singular() {
|
||||
bool singular = false;
|
||||
|
||||
if (has_components()) {
|
||||
// The matrix is singular if any component of its scale is 0.
|
||||
singular = (_scale[0] == 0.0f || _scale[1] == 0.0f || _scale[2] == 0.0f);
|
||||
} else {
|
||||
// The matrix is singular if its determinant is zero.
|
||||
const LMatrix4f &mat = get_mat();
|
||||
singular = (mat.get_upper_3().determinant() == 0.0f);
|
||||
}
|
||||
|
||||
if (singular) {
|
||||
_flags |= F_is_singular;
|
||||
}
|
||||
_flags |= F_singular_known;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::calc_components
|
||||
// Access: Private
|
||||
// Description: Derives the components from the matrix, if possible.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
calc_components() {
|
||||
if ((_flags & F_is_identity) != 0) {
|
||||
_scale.set(1.0f, 1.0f, 1.0f);
|
||||
_hpr.set(0.0f, 0.0f, 0.0f);
|
||||
_pos.set(0.0f, 0.0f, 0.0f);
|
||||
_flags |= F_has_components;
|
||||
|
||||
} else {
|
||||
// If we don't have components and we're not identity, the only
|
||||
// other explanation is that we were constructed via a matrix.
|
||||
nassertv((_flags & F_mat_known) != 0);
|
||||
|
||||
bool possible = decompose_matrix(get_mat(), _scale, _hpr, _pos);
|
||||
if (possible) {
|
||||
// Some matrices can't be decomposed into scale, hpr, pos.
|
||||
_flags |= F_has_components;
|
||||
}
|
||||
}
|
||||
|
||||
_flags |= F_components_known;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::calc_mat
|
||||
// Access: Private
|
||||
// Description: Computes the matrix from the components.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
calc_mat() {
|
||||
if ((_flags & F_is_identity) != 0) {
|
||||
_mat = LMatrix4f::ident_mat();
|
||||
|
||||
} else {
|
||||
// If we don't have a matrix and we're not identity, the only
|
||||
// other explanation is that we were constructed via components.
|
||||
nassertv((_flags & F_components_known) != 0);
|
||||
compose_matrix(_mat, _scale, _hpr, _pos);
|
||||
}
|
||||
_flags |= F_mat_known;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
// Description: Tells the BamReader how to create objects of type
|
||||
// TransformState.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
register_with_read_factory() {
|
||||
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::write_datagram
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes the contents of this object to the datagram
|
||||
// for shipping out to a Bam file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
write_datagram(BamWriter *manager, Datagram &dg) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::finalize
|
||||
// Access: Public, Virtual
|
||||
// Description: Method to ensure that any necessary clean up tasks
|
||||
// that have to be performed by this object are performed
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
finalize() {
|
||||
// Unref the pointer that we explicitly reffed in make_from_bam().
|
||||
unref();
|
||||
|
||||
// We should never get back to zero after unreffing our own count,
|
||||
// because we expect to have been stored in a pointer somewhere. If
|
||||
// we do get to zero, it's a memory leak; the way to avoid this is
|
||||
// to call unref_delete() above instead of unref(), but this is
|
||||
// dangerous to do from within a virtual function.
|
||||
nassertv(get_ref_count() != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::make_from_bam
|
||||
// Access: Protected, Static
|
||||
// Description: This function is called by the BamReader's factory
|
||||
// when a new object of type TransformState is encountered
|
||||
// in the Bam file. It should create the TransformState
|
||||
// and extract its information from the file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TypedWritable *TransformState::
|
||||
make_from_bam(const FactoryParams ¶ms) {
|
||||
TransformState *state = new TransformState;
|
||||
DatagramIterator scan;
|
||||
BamReader *manager;
|
||||
|
||||
parse_params(params, scan, manager);
|
||||
state->fillin(scan, manager);
|
||||
|
||||
return new_from_bam(state, manager);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::new_from_bam
|
||||
// Access: Protected, Static
|
||||
// Description: Uniquifies the pointer for a TransformState object just
|
||||
// created from a bam file, and preserves its reference
|
||||
// count correctly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TypedWritable *TransformState::
|
||||
new_from_bam(TransformState *state, BamReader *manager) {
|
||||
// First, uniquify the pointer.
|
||||
CPT(TransformState) pointer = return_new(state);
|
||||
|
||||
// But now we have a problem, since we have to hold the reference
|
||||
// count and there's no way to return a TypedWritable while still
|
||||
// holding the reference count! We work around this by explicitly
|
||||
// upping the count, and also setting a finalize() callback to down
|
||||
// it later.
|
||||
if (pointer == state) {
|
||||
pointer->ref();
|
||||
manager->register_finalize(state);
|
||||
}
|
||||
|
||||
// We have to cast the pointer back to non-const, because the bam
|
||||
// reader expects that.
|
||||
return (TransformState *)pointer.p();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformState::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 TransformState.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformState::
|
||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
// Filename: transformState.h
|
||||
// Created by: drose (25Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 TRANSFORMSTATE_H
|
||||
#define TRANSFORMSTATE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "typedWritableReferenceCount.h"
|
||||
#include "pointerTo.h"
|
||||
#include "indirectLess.h"
|
||||
#include "luse.h"
|
||||
#include "pset.h"
|
||||
|
||||
class GraphicsStateGuardianBase;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : TransformState
|
||||
// Description : Indicates a coordinate-system transform on vertices.
|
||||
// TransformStates are the primary means for storing
|
||||
// transformations on the scene graph.
|
||||
//
|
||||
// Transforms may be specified in one of two ways:
|
||||
// componentwise, with a pos-hpr-scale, or with an
|
||||
// arbitrary transform matrix. If you specify a
|
||||
// transform componentwise, it will remember its
|
||||
// original components.
|
||||
//
|
||||
// TransformState objects are managed very much like
|
||||
// RenderState objects. They are immutable and
|
||||
// reference-counted automatically.
|
||||
//
|
||||
// You should not attempt to create or modify a
|
||||
// TransformState object directly. Instead, call one of
|
||||
// the make() functions to create one for you. And
|
||||
// instead of modifying a TransformState object, create a
|
||||
// new one.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA TransformState : public TypedWritableReferenceCount {
|
||||
protected:
|
||||
TransformState();
|
||||
|
||||
private:
|
||||
TransformState(const TransformState ©);
|
||||
void operator = (const TransformState ©);
|
||||
|
||||
public:
|
||||
virtual ~TransformState();
|
||||
|
||||
bool operator < (const TransformState &other) const;
|
||||
|
||||
PUBLISHED:
|
||||
static CPT(TransformState) make_identity();
|
||||
INLINE static CPT(TransformState) make_pos(const LVecBase3f &pos);
|
||||
INLINE static CPT(TransformState) make_hpr(const LVecBase3f &hpr);
|
||||
INLINE static CPT(TransformState) make_pos_hpr(const LVecBase3f &pos,
|
||||
const LVecBase3f &hpr);
|
||||
INLINE static CPT(TransformState) make_scale(float scale);
|
||||
INLINE static CPT(TransformState) make_scale(const LVecBase3f &scale);
|
||||
static CPT(TransformState) make_pos_hpr_scale(const LVecBase3f &pos,
|
||||
const LVecBase3f &hpr,
|
||||
const LVecBase3f &scale);
|
||||
static CPT(TransformState) make_mat(const LMatrix4f &mat);
|
||||
|
||||
INLINE bool is_identity() const;
|
||||
INLINE bool is_singular() const;
|
||||
INLINE bool has_components() const;
|
||||
INLINE const LVecBase3f &get_pos() const;
|
||||
INLINE const LVecBase3f &get_hpr() const;
|
||||
INLINE const LVecBase3f &get_scale() const;
|
||||
INLINE const LMatrix4f &get_mat() const;
|
||||
|
||||
CPT(TransformState) compose(const TransformState *other) const;
|
||||
CPT(TransformState) invert_compose(const TransformState *other) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level) const;
|
||||
|
||||
private:
|
||||
static CPT(TransformState) return_new(TransformState *state);
|
||||
CPT(TransformState) do_compose(const TransformState *other) const;
|
||||
CPT(TransformState) do_invert_compose(const TransformState *other) const;
|
||||
|
||||
private:
|
||||
typedef pset<const TransformState *, IndirectLess<TransformState> > States;
|
||||
static States _states;
|
||||
static CPT(TransformState) _identity_state;
|
||||
|
||||
// This iterator records the entry corresponding to this TransformState
|
||||
// object in the above global set. We keep the iterator around so
|
||||
// we can remove it when the TransformState destructs.
|
||||
States::iterator _saved_entry;
|
||||
|
||||
// This data structure manages the job of caching the composition of
|
||||
// two TransformStates. It's complicated because we have to be sure to
|
||||
// remove the entry if *either* of the input TransformStates destructs.
|
||||
// To implement this, we always record Composition entries in pairs,
|
||||
// one in each of the two involved TransformState objects.
|
||||
class Composition {
|
||||
public:
|
||||
CPT(TransformState) _result;
|
||||
};
|
||||
|
||||
typedef pmap<const TransformState *, Composition> CompositionCache;
|
||||
CompositionCache _composition_cache;
|
||||
CompositionCache _invert_composition_cache;
|
||||
|
||||
// Thise pointer is used to cache the result of compose(this). This
|
||||
// has to be a special case, because we have to handle the reference
|
||||
// counts carefully so that we don't leak.
|
||||
const TransformState *_self_compose;
|
||||
|
||||
private:
|
||||
// This is the actual data within the TransformState.
|
||||
INLINE void check_singular() const;
|
||||
INLINE void check_components() const;
|
||||
INLINE void check_mat() const;
|
||||
void calc_singular();
|
||||
void calc_components();
|
||||
void calc_mat();
|
||||
|
||||
enum Flags {
|
||||
F_is_identity = 0x0001,
|
||||
F_is_singular = 0x0002,
|
||||
F_singular_known = 0x0004,
|
||||
F_components_given = 0x0008,
|
||||
F_components_known = 0x0010,
|
||||
F_has_components = 0x0020,
|
||||
F_mat_known = 0x0040,
|
||||
};
|
||||
LVecBase3f _pos, _hpr, _scale;
|
||||
LMatrix4f _mat;
|
||||
|
||||
short _flags;
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||
virtual void finalize();
|
||||
|
||||
protected:
|
||||
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
||||
static TypedWritable *new_from_bam(TransformState *state, BamReader *manager);
|
||||
void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
TypedWritableReferenceCount::init_type();
|
||||
register_type(_type_handle, "TransformState",
|
||||
TypedWritableReferenceCount::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 TransformState &state) {
|
||||
state.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "transformState.I"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
#include "graphicsPipe.h"
|
||||
#include "interactiveGraphicsPipe.h"
|
||||
#include "displayRegion.h"
|
||||
#include "camera.h"
|
||||
#include "qpcamera.h"
|
||||
#include "perspectiveLens.h"
|
||||
#include "pandaNode.h"
|
||||
#include "textureAttrib.h"
|
||||
|
|
@ -33,6 +33,32 @@
|
|||
#include "texture.h"
|
||||
#include "texturePool.h"
|
||||
|
||||
// These are in support of legacy data graph operations.
|
||||
#include "namedNode.h"
|
||||
#include "mouse.h"
|
||||
#include "mouseWatcher.h"
|
||||
#include "trackball.h"
|
||||
#include "transform2sg.h"
|
||||
#include "dataRelation.h"
|
||||
#include "dataGraphTraversal.h"
|
||||
#include "buttonThrower.h"
|
||||
#include "modifierButtons.h"
|
||||
#include "keyboardButton.h"
|
||||
#include "event.h"
|
||||
#include "eventQueue.h"
|
||||
#include "eventHandler.h"
|
||||
|
||||
// Use dconfig to read a few Configrc variables.
|
||||
Configure(config_pview);
|
||||
ConfigureFn(config_pview) {
|
||||
}
|
||||
|
||||
static const int win_width = config_pview.GetInt("win-width", 640);
|
||||
static const int win_height = config_pview.GetInt("win-height", 480);
|
||||
|
||||
// As long as this is true, the main loop will continue running.
|
||||
bool run_flag = true;
|
||||
|
||||
PT(GraphicsPipe)
|
||||
make_pipe() {
|
||||
// We use the GraphicsPipe factory to make us a renderable pipe
|
||||
|
|
@ -59,20 +85,25 @@ make_pipe() {
|
|||
return pipe;
|
||||
}
|
||||
|
||||
PT(Camera)
|
||||
setup_window(GraphicsPipe *pipe, GraphicsEngine *engine) {
|
||||
PT(GraphicsWindow)
|
||||
make_window(GraphicsPipe *pipe, GraphicsEngine *engine) {
|
||||
// Now create a window on that pipe.
|
||||
GraphicsWindow::Properties window_prop;
|
||||
window_prop._xorg = 0;
|
||||
window_prop._yorg = 0;
|
||||
window_prop._xsize = 640;
|
||||
window_prop._ysize = 480;
|
||||
window_prop._xsize = win_width;
|
||||
window_prop._ysize = win_height;
|
||||
window_prop._title = "Panda Viewer";
|
||||
// window_prop._fullscreen = true;
|
||||
|
||||
PT(GraphicsWindow) window = pipe->make_window(window_prop);
|
||||
engine->add_window(window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
PT(qpCamera)
|
||||
make_camera(GraphicsWindow *window) {
|
||||
// Get the first channel on the window. This will be the only
|
||||
// channel on non-SGI hardware.
|
||||
PT(GraphicsChannel) channel = window->get_channel(0);
|
||||
|
|
@ -84,11 +115,11 @@ setup_window(GraphicsPipe *pipe, GraphicsEngine *engine) {
|
|||
PT(DisplayRegion) dr = layer->make_display_region();
|
||||
|
||||
// Finally, we need a camera to associate with the display region.
|
||||
PT(Camera) camera = new Camera;
|
||||
PT(qpCamera) camera = new qpCamera("camera");
|
||||
PT(Lens) lens = new PerspectiveLens;
|
||||
lens->set_film_size(640, 480);
|
||||
lens->set_film_size(win_width, win_height);
|
||||
camera->set_lens(lens);
|
||||
dr->set_camera(camera);
|
||||
dr->set_qpcamera(NodeChain(camera));
|
||||
|
||||
return camera;
|
||||
}
|
||||
|
|
@ -102,9 +133,9 @@ make_default_geometry(PandaNode *parent) {
|
|||
PTA_Colorf colors;
|
||||
PTA_ushort cindex;
|
||||
|
||||
coords.push_back(Vertexf::rfu(0.0, 20.0, 0.0));
|
||||
coords.push_back(Vertexf::rfu(1.0, 20.0, 0.0));
|
||||
coords.push_back(Vertexf::rfu(0.0, 20.0, 1.0));
|
||||
coords.push_back(Vertexf::rfu(0.0, 0.0, 0.0));
|
||||
coords.push_back(Vertexf::rfu(1.0, 0.0, 0.0));
|
||||
coords.push_back(Vertexf::rfu(0.0, 0.0, 1.0));
|
||||
uvs.push_back(TexCoordf(0.0, 0.0));
|
||||
uvs.push_back(TexCoordf(1.0, 0.0));
|
||||
uvs.push_back(TexCoordf(0.0, 1.0));
|
||||
|
|
@ -153,6 +184,39 @@ get_models(PandaNode *parent, int argc, char *argv[]) {
|
|||
*/
|
||||
}
|
||||
|
||||
NamedNode *
|
||||
setup_mouse(NamedNode *data_root, GraphicsWindow *window) {
|
||||
MouseAndKeyboard *mouse = new MouseAndKeyboard(window, 0);
|
||||
new DataRelation(data_root, mouse);
|
||||
|
||||
// Create a ButtonThrower to throw events from the keyboard.
|
||||
PT(ButtonThrower) bt = new ButtonThrower("kb-events");
|
||||
ModifierButtons mods;
|
||||
mods.add_button(KeyboardButton::shift());
|
||||
mods.add_button(KeyboardButton::control());
|
||||
mods.add_button(KeyboardButton::alt());
|
||||
bt->set_modifier_buttons(mods);
|
||||
new DataRelation(mouse, bt);
|
||||
|
||||
return mouse;
|
||||
}
|
||||
|
||||
void
|
||||
setup_trackball(NamedNode *mouse, qpCamera *camera) {
|
||||
PT(Trackball) trackball = new Trackball("trackball");
|
||||
trackball->set_pos(LVector3f::forward() * 50.0);
|
||||
new DataRelation(mouse, trackball);
|
||||
|
||||
PT(Transform2SG) tball2cam = new Transform2SG("tball2cam");
|
||||
tball2cam->set_node(camera);
|
||||
new DataRelation(trackball, tball2cam);
|
||||
}
|
||||
|
||||
void
|
||||
event_esc(CPT_Event) {
|
||||
// The Escape or q key was pressed. Exit the application.
|
||||
run_flag = false;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
|
|
@ -163,33 +227,40 @@ main(int argc, char *argv[]) {
|
|||
GraphicsEngine *engine = new GraphicsEngine;
|
||||
|
||||
// Now open a window and get a camera.
|
||||
PT(Camera) camera = setup_window(pipe, engine);
|
||||
PT(GraphicsWindow) window = make_window(pipe, engine);
|
||||
PT(qpCamera) camera = make_camera(window);
|
||||
|
||||
// Now we just need to make a scene graph for the camera to render.
|
||||
PT(PandaNode) render = new PandaNode("render");
|
||||
camera->set_qpscene(render);
|
||||
render->add_child(camera);
|
||||
camera->set_scene(render);
|
||||
|
||||
// Set up a data graph for tracking user input. For now, this uses
|
||||
// the old-style graph interface.
|
||||
PT(NamedNode) data_root = new NamedNode("data_root");
|
||||
NamedNode *mouse = setup_mouse(data_root, window);
|
||||
setup_trackball(mouse, camera);
|
||||
|
||||
// Use an event handler to manage keyboard events.
|
||||
EventHandler event_handler(EventQueue::get_global_event_queue());
|
||||
event_handler.add_hook("escape", event_esc);
|
||||
event_handler.add_hook("q", event_esc);
|
||||
|
||||
|
||||
// Put something in the scene graph to look at.
|
||||
get_models(render, argc, argv);
|
||||
|
||||
/*
|
||||
// Put the scene a distance in front of our face so we can see it.
|
||||
LMatrix4f mat = LMatrix4f::translate_mat(0, 20, 0);
|
||||
TransformTransition *tt = new TransformTransition(mat);
|
||||
render_arc->set_transition(tt);
|
||||
*/
|
||||
|
||||
|
||||
// This is our main update loop. Run for 5 seconds, then shut down.
|
||||
// This is our main update loop. Loop here until someone
|
||||
// (e.g. event_esc) sets run_flag to false.
|
||||
ClockObject *clock = ClockObject::get_global_clock();
|
||||
clock->tick();
|
||||
double now = clock->get_frame_time();
|
||||
while (clock->get_frame_time() - now < 5.0) {
|
||||
while (run_flag) {
|
||||
clock->tick();
|
||||
traverse_data_graph(data_root);
|
||||
event_handler.process_events();
|
||||
engine->render_frame();
|
||||
}
|
||||
|
||||
cerr << "Exiting.\n";
|
||||
delete engine;
|
||||
return (0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#begin lib_target
|
||||
#define TARGET tform
|
||||
#define LOCAL_LIBS \
|
||||
dgraph graph linmath sgattrib display event putil gobj gsgbase \
|
||||
dgraph pgraph graph linmath sgattrib display event putil gobj gsgbase \
|
||||
mathutil sgraph device sgraphutil
|
||||
|
||||
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "nodeRelation.h"
|
||||
#include "transformTransition.h"
|
||||
#include "transformState.h"
|
||||
#include "matrixDataTransition.h"
|
||||
#include "allTransitionsWrapper.h"
|
||||
|
||||
|
|
@ -36,6 +37,7 @@ TypeHandle Transform2SG::_transform_type;
|
|||
Transform2SG::
|
||||
Transform2SG(const string &name) : DataNode(name) {
|
||||
_arc = NULL;
|
||||
_node = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -60,6 +62,27 @@ get_arc() const {
|
|||
return _arc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Transform2SG::set_node
|
||||
// Access: Public
|
||||
// Description: Sets the node that this node will adjust.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Transform2SG::
|
||||
set_node(PandaNode *node) {
|
||||
_node = node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Transform2SG::get_node
|
||||
// Access: Public
|
||||
// Description: Returns the node that this node will adjust, or NULL
|
||||
// if the node has not yet been set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *Transform2SG::
|
||||
get_node() const {
|
||||
return _node;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Transform2SG::transmit_data
|
||||
|
|
@ -70,9 +93,14 @@ void Transform2SG::
|
|||
transmit_data(AllTransitionsWrapper &data) {
|
||||
const NodeTransition *transform = data.get_transition(_transform_type);
|
||||
|
||||
if (transform != (NodeTransition *)NULL && _arc != (NodeRelation *)NULL) {
|
||||
if (transform != (NodeTransition *)NULL) {
|
||||
const LMatrix4f &mat = DCAST(MatrixDataTransition, transform)->get_value();
|
||||
_arc->set_transition(new TransformTransition(mat));
|
||||
if (_arc != (NodeRelation *)NULL) {
|
||||
_arc->set_transition(new TransformTransition(mat));
|
||||
}
|
||||
if (_node != (PandaNode *)NULL) {
|
||||
_node->set_transform(TransformState::make_mat(mat));
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the data below us.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "pandabase.h"
|
||||
|
||||
#include "dataNode.h"
|
||||
#include "pandaNode.h"
|
||||
|
||||
class NodeRelation;
|
||||
|
||||
|
|
@ -39,8 +40,12 @@ PUBLISHED:
|
|||
void set_arc(NodeRelation *arc);
|
||||
NodeRelation *get_arc() const;
|
||||
|
||||
void set_node(PandaNode *node);
|
||||
PandaNode *get_node() const;
|
||||
|
||||
private:
|
||||
NodeRelation *_arc;
|
||||
PandaNode *_node;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// From parent class DataNode
|
||||
|
|
|
|||
Loading…
Reference in New Issue