361 lines
13 KiB
C++
361 lines
13 KiB
C++
// Filename: compassEffect.cxx
|
|
// Created by: drose (16Jul02)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "compassEffect.h"
|
|
#include "cullTraverserData.h"
|
|
#include "config_pgraph.h"
|
|
#include "nodePath.h"
|
|
#include "bamReader.h"
|
|
#include "bamWriter.h"
|
|
#include "datagram.h"
|
|
#include "datagramIterator.h"
|
|
|
|
TypeHandle CompassEffect::_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::make
|
|
// Access: Published, Static
|
|
// Description: Constructs a new CompassEffect object. If the
|
|
// reference is an empty NodePath, it means the
|
|
// CompassEffect is relative to the root of the scene
|
|
// graph; otherwise, it's relative to the indicated
|
|
// node. The properties bitmask specifies the set of
|
|
// properties that the compass node inherits from the
|
|
// reference instead of from its parent.
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderEffect) CompassEffect::
|
|
make(const NodePath &reference, int properties) {
|
|
CompassEffect *effect = new CompassEffect;
|
|
effect->_reference = reference;
|
|
effect->_properties = (properties & P_all);
|
|
return return_new(effect);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::safe_to_transform
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if it is generally safe to transform
|
|
// this particular kind of RenderEffect by calling the
|
|
// xform() method, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool CompassEffect::
|
|
safe_to_transform() const {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::output
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void CompassEffect::
|
|
output(ostream &out) const {
|
|
out << get_type() << ":";
|
|
if (_properties == 0) {
|
|
out << " none";
|
|
}
|
|
if ((_properties & P_pos) == P_pos) {
|
|
out << " xyz";
|
|
} else {
|
|
if ((_properties & P_x) != 0) {
|
|
out << " x";
|
|
}
|
|
if ((_properties & P_y) != 0) {
|
|
out << " y";
|
|
}
|
|
if ((_properties & P_z) != 0) {
|
|
out << " z";
|
|
}
|
|
}
|
|
if ((_properties & P_rot) != 0) {
|
|
out << " rot";
|
|
}
|
|
if ((_properties & P_scale) == P_scale) {
|
|
out << " scale";
|
|
} else {
|
|
if ((_properties & P_sx) != 0) {
|
|
out << " sx";
|
|
}
|
|
if ((_properties & P_sy) != 0) {
|
|
out << " sy";
|
|
}
|
|
if ((_properties & P_sz) != 0) {
|
|
out << " sz";
|
|
}
|
|
}
|
|
if (!_reference.is_empty()) {
|
|
out << " reference " << _reference;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::has_cull_callback
|
|
// Access: Public, Virtual
|
|
// Description: Should be overridden by derived classes to return
|
|
// true if cull_callback() has been defined. Otherwise,
|
|
// returns false to indicate cull_callback() does not
|
|
// need to be called for this effect during the cull
|
|
// traversal.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool CompassEffect::
|
|
has_cull_callback() const {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::cull_callback
|
|
// Access: Public, Virtual
|
|
// Description: If has_cull_callback() returns true, this function
|
|
// will be called during the cull traversal to perform
|
|
// any additional operations that should be performed at
|
|
// cull time. This may include additional manipulation
|
|
// of render state or additional visible/invisible
|
|
// decisions, or any other arbitrary operation.
|
|
//
|
|
// At the time this function is called, the current
|
|
// node's transform and state have not yet been applied
|
|
// to the net_transform and net_state. This callback
|
|
// may modify the node_transform and node_state to apply
|
|
// an effective change to the render state at this
|
|
// level.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CompassEffect::
|
|
cull_callback(CullTraverser *trav, CullTraverserData &data,
|
|
CPT(TransformState) &node_transform,
|
|
CPT(RenderState) &) const {
|
|
if (_properties == 0) {
|
|
// Nothing to do.
|
|
return;
|
|
}
|
|
|
|
CPT(TransformState) true_net_transform = data.get_net_transform(trav);
|
|
CPT(TransformState) want_net_transform = true_net_transform;
|
|
adjust_transform(want_net_transform, node_transform, data.node());
|
|
|
|
// Now compute the transform that will convert true_net_transform to
|
|
// want_transform. This is inv(true_net_transform) * want_transform.
|
|
CPT(TransformState) compass_transform =
|
|
true_net_transform->invert_compose(want_net_transform);
|
|
|
|
// And modify our local node's apparent transform so that
|
|
// true_net_transform->compose(new_node_transform) produces the same
|
|
// result we would have gotten had we actually computed
|
|
// want_transform->compose(orig_node_transform).
|
|
node_transform = compass_transform->compose(node_transform);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::has_adjust_transform
|
|
// Access: Public, Virtual
|
|
// Description: Should be overridden by derived classes to return
|
|
// true if adjust_transform() has been defined, and
|
|
// therefore the RenderEffect has some effect on the
|
|
// node's apparent local and net transforms.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool CompassEffect::
|
|
has_adjust_transform() const {
|
|
return (_properties != 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::adjust_transform
|
|
// Access: Public, Virtual
|
|
// Description: Performs some operation on the node's apparent net
|
|
// and/or local transforms. This will only be called if
|
|
// has_adjust_transform() is redefined to return true.
|
|
//
|
|
// Both parameters are in/out. The original transforms
|
|
// will be passed in, and they may (or may not) be
|
|
// modified in-place by the RenderEffect.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CompassEffect::
|
|
adjust_transform(CPT(TransformState) &net_transform,
|
|
CPT(TransformState) &node_transform,
|
|
PandaNode *) const {
|
|
if (_properties == 0) {
|
|
// Nothing to do.
|
|
return;
|
|
}
|
|
|
|
// The reference transform: where we are acting as if we inherit
|
|
// from. Either the root node (identity) or the specified reference
|
|
// node.
|
|
CPT(TransformState) ref_transform;
|
|
if (_reference.is_empty()) {
|
|
ref_transform = TransformState::make_identity();
|
|
} else {
|
|
ref_transform = _reference.get_net_transform();
|
|
}
|
|
|
|
// Now compute the net transform we actually want to achieve. This
|
|
// is all of the components from the net transform we want to
|
|
// inherit normally from our parent, with all of the components from
|
|
// the ref transform we want to inherit from our reference.
|
|
CPT(TransformState) want_net_transform;
|
|
if (_properties == P_all) {
|
|
// If we want to steal the whole transform, that's easy.
|
|
want_net_transform = ref_transform;
|
|
|
|
} else {
|
|
// How much of the pos do we want to steal? We can always
|
|
// determine a transform's pos, even if it's nondecomposable.
|
|
LVecBase3f want_pos = net_transform->get_pos();
|
|
const LVecBase3f &ref_pos = ref_transform->get_pos();
|
|
if ((_properties & P_x) != 0) {
|
|
want_pos[0] = ref_pos[0];
|
|
}
|
|
if ((_properties & P_y) != 0) {
|
|
want_pos[1] = ref_pos[1];
|
|
}
|
|
if ((_properties & P_z) != 0) {
|
|
want_pos[2] = ref_pos[2];
|
|
}
|
|
|
|
if ((_properties & ~P_pos) == 0) {
|
|
// If we only want to steal the pos, that's pretty easy.
|
|
want_net_transform = net_transform->set_pos(want_pos);
|
|
|
|
} else if ((_properties & (P_rot | P_scale)) == (P_rot | P_scale)) {
|
|
// If we want to steal everything *but* the pos, also easy.
|
|
want_net_transform = ref_transform->set_pos(want_pos);
|
|
|
|
} else {
|
|
// For any other combination, we have to be able to decompose both
|
|
// transforms.
|
|
if (!net_transform->has_components() ||
|
|
!ref_transform->has_components()) {
|
|
// If we can't decompose, just do the best we can: steal
|
|
// everything but the pos.
|
|
want_net_transform = ref_transform->set_pos(want_pos);
|
|
|
|
} else {
|
|
// If we can decompose, then take only the components we want.
|
|
LQuaternionf want_quat = net_transform->get_quat();
|
|
if ((_properties & P_rot) != 0) {
|
|
want_quat = ref_transform->get_quat();
|
|
}
|
|
|
|
LVecBase3f want_scale = net_transform->get_scale();
|
|
const LVecBase3f &ref_scale = ref_transform->get_scale();
|
|
if ((_properties & P_sx) != 0) {
|
|
want_scale[0] = ref_scale[0];
|
|
}
|
|
if ((_properties & P_sy) != 0) {
|
|
want_scale[1] = ref_scale[1];
|
|
}
|
|
if ((_properties & P_sz) != 0) {
|
|
want_scale[2] = ref_scale[2];
|
|
}
|
|
|
|
want_net_transform =
|
|
TransformState::make_pos_quat_scale(want_pos, want_quat, want_scale);
|
|
}
|
|
}
|
|
}
|
|
|
|
net_transform = want_net_transform;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::compare_to_impl
|
|
// Access: Protected, Virtual
|
|
// Description: Intended to be overridden by derived CompassEffect
|
|
// types to return a unique number indicating whether
|
|
// this CompassEffect is equivalent to the other one.
|
|
//
|
|
// This should return 0 if the two CompassEffect 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 CompassEffect
|
|
// objects whose get_type() functions return the same.
|
|
////////////////////////////////////////////////////////////////////
|
|
int CompassEffect::
|
|
compare_to_impl(const RenderEffect *other) const {
|
|
const CompassEffect *ta;
|
|
DCAST_INTO_R(ta, other, 0);
|
|
|
|
if (_properties != ta->_properties) {
|
|
return _properties - ta->_properties;
|
|
}
|
|
int compare = _reference.compare_to(ta->_reference);
|
|
if (compare != 0) {
|
|
return compare;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::register_with_read_factory
|
|
// Access: Public, Static
|
|
// Description: Tells the BamReader how to create objects of type
|
|
// CompassEffect.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CompassEffect::
|
|
register_with_read_factory() {
|
|
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::write_datagram
|
|
// Access: Public, Virtual
|
|
// Description: Writes the contents of this object to the datagram
|
|
// for shipping out to a Bam file.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CompassEffect::
|
|
write_datagram(BamWriter *manager, Datagram &dg) {
|
|
RenderEffect::write_datagram(manager, dg);
|
|
dg.add_uint16(_properties);
|
|
// *** We don't write out the _reference NodePath right now. Maybe
|
|
// we should.
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::make_from_bam
|
|
// Access: Protected, Static
|
|
// Description: This function is called by the BamReader's factory
|
|
// when a new object of type CompassEffect is encountered
|
|
// in the Bam file. It should create the CompassEffect
|
|
// and extract its information from the file.
|
|
////////////////////////////////////////////////////////////////////
|
|
TypedWritable *CompassEffect::
|
|
make_from_bam(const FactoryParams ¶ms) {
|
|
CompassEffect *effect = new CompassEffect;
|
|
DatagramIterator scan;
|
|
BamReader *manager;
|
|
|
|
parse_params(params, scan, manager);
|
|
effect->fillin(scan, manager);
|
|
|
|
return effect;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CompassEffect::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 CompassEffect.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CompassEffect::
|
|
fillin(DatagramIterator &scan, BamReader *manager) {
|
|
RenderEffect::fillin(scan, manager);
|
|
_properties = scan.get_uint16();
|
|
}
|