higher-level ScissorEffect fixes

This commit is contained in:
David Rose 2008-08-01 21:54:20 +00:00
parent 89adb4d176
commit ab6e8bbc3c
11 changed files with 349 additions and 98 deletions

View File

@ -43,6 +43,7 @@
#include "antialiasAttrib.h"
#include "audioVolumeAttrib.h"
#include "texProjectorEffect.h"
#include "scissorEffect.h"
#include "texturePool.h"
#include "planeNode.h"
#include "lensNode.h"
@ -2796,6 +2797,113 @@ has_clip_plane_off(const NodePath &clip_plane) const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_scissor
// Access: Published
// Description: Sets up a scissor region on the nodes rendered at
// this level and below. The four coordinates are
// understood to define a rectangle in screen space.
// These numbers are relative to the current
// DisplayRegion, where (0,0) is the lower-left corner
// of the DisplayRegion, and (1,1) is the upper-right
// corner.
////////////////////////////////////////////////////////////////////
void NodePath::
set_scissor(float left, float right, float bottom, float top) {
set_effect(ScissorEffect::make_screen(LVecBase4f(left, right, bottom, top)));
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_scissor
// Access: Published
// Description: Sets up a scissor region on the nodes rendered at
// this level and below. The two points are understood
// to be relative to this node. When these points are
// projected into screen space, they define the
// diagonally-opposite points that determine the scissor
// region.
////////////////////////////////////////////////////////////////////
void NodePath::
set_scissor(const LPoint3f &a, const LPoint3f &b) {
set_effect(ScissorEffect::make_node(a, b));
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_scissor
// Access: Published
// Description: Sets up a scissor region on the nodes rendered at
// this level and below. The four points are understood
// to be relative to this node. When these points are
// projected into screen space, they define the
// bounding volume of the scissor region (the scissor
// region is the smallest onscreen rectangle that
// encloses all four points).
////////////////////////////////////////////////////////////////////
void NodePath::
set_scissor(const LPoint3f &a, const LPoint3f &b,
const LPoint3f &c, const LPoint3f &d) {
set_effect(ScissorEffect::make_node(a, b, c, d));
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_scissor
// Access: Published
// Description: Sets up a scissor region on the nodes rendered at
// this level and below. The two points are understood
// to be relative to the indicated other node. When
// these points are projected into screen space, they
// define the diagonally-opposite points that determine
// the scissor region.
////////////////////////////////////////////////////////////////////
void NodePath::
set_scissor(const NodePath &other, const LPoint3f &a, const LPoint3f &b) {
set_effect(ScissorEffect::make_node(a, b, other));
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_scissor
// Access: Published
// Description: Sets up a scissor region on the nodes rendered at
// this level and below. The four points are understood
// to be relative to the indicated other node. When
// these points are projected into screen space, they
// define the bounding volume of the scissor region (the
// scissor region is the smallest onscreen rectangle
// that encloses all four points).
////////////////////////////////////////////////////////////////////
void NodePath::
set_scissor(const NodePath &other,
const LPoint3f &a, const LPoint3f &b,
const LPoint3f &c, const LPoint3f &d) {
set_effect(ScissorEffect::make_node(a, b, c, d, other));
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::clear_scissor
// Access: Published
// Description: Removes the scissor region that was defined at this
// node level by a previous call to set_scissor().
////////////////////////////////////////////////////////////////////
void NodePath::
clear_scissor() {
clear_effect(ScissorEffect::get_class_type());
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::has_scissor
// Access: Published
// Description: Returns true if a scissor region was defined at this
// node by a previous call to set_scissor(). This does
// not check for scissor regions inherited from a parent
// class. It also does not check for the presence of a
// low-level ScissorAttrib, which is different from the
// ScissorEffect added by set_scissor.
////////////////////////////////////////////////////////////////////
bool NodePath::
has_scissor() const {
return has_effect(ScissorEffect::get_class_type());
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_bin
// Access: Published

View File

@ -547,6 +547,18 @@ PUBLISHED:
bool has_clip_plane_off() const;
bool has_clip_plane_off(const NodePath &clip_plane) const;
void set_scissor(float left, float right, float bottom, float top);
void set_scissor(const LPoint3f &a, const LPoint3f &b);
void set_scissor(const LPoint3f &a, const LPoint3f &b,
const LPoint3f &c, const LPoint3f &d);
void set_scissor(const NodePath &other,
const LPoint3f &a, const LPoint3f &b);
void set_scissor(const NodePath &other,
const LPoint3f &a, const LPoint3f &b,
const LPoint3f &c, const LPoint3f &d);
void clear_scissor();
bool has_scissor() const;
void set_bin(const string &bin_name, int draw_order, int priority = 0);
void clear_bin();
bool has_bin() const;

View File

@ -344,7 +344,16 @@ void PandaNode::
apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
GeomTransformer &transformer) {
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
xform(attribs._transform->get_mat());
const LMatrix4f &mat = attribs._transform->get_mat();
xform(mat);
Thread *current_thread = Thread::get_current_thread();
OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
cdata->_effects = cdata->_effects->xform(mat);
cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
}
}

View File

@ -103,6 +103,37 @@ compare_to_impl(const RenderAttrib *other) const {
return _frame.compare_to(ta->_frame);
}
////////////////////////////////////////////////////////////////////
// Function: ScissorAttrib::compose_impl
// Access: Protected, Virtual
// Description: Intended to be overridden by derived RenderAttrib
// types to specify how two consecutive RenderAttrib
// objects of the same type interact.
//
// This should return the result of applying the other
// RenderAttrib to a node in the scene graph below this
// RenderAttrib, which was already applied. In most
// cases, the result is the same as the other
// RenderAttrib (that is, a subsequent RenderAttrib
// completely replaces the preceding one). On the other
// hand, some kinds of RenderAttrib (for instance,
// ColorTransformAttrib) might combine in meaningful
// ways.
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ScissorAttrib::
compose_impl(const RenderAttrib *other) const {
const ScissorAttrib *ta;
DCAST_INTO_R(ta, other, 0);
LVecBase4f new_frame(max(ta->_frame[0], _frame[0]),
min(ta->_frame[1], _frame[1]),
max(ta->_frame[2], _frame[2]),
min(ta->_frame[3], _frame[3]));
ScissorAttrib *attrib = new ScissorAttrib(new_frame);
return return_new(attrib);
}
////////////////////////////////////////////////////////////////////
// Function: ScissorAttrib::make_default_impl
// Access: Protected, Virtual

View File

@ -55,6 +55,7 @@ public:
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:

View File

@ -63,7 +63,19 @@ get_num_points() const {
INLINE const LPoint3f &ScissorEffect::
get_point(int n) const {
nassertr(n >= 0 && n < (int)_points.size(), LPoint3f::zero());
return _points[n];
return _points[n]._p;
}
////////////////////////////////////////////////////////////////////
// Function: ScissorEffect::get_node
// Access: Published
// Description: Returns the node to which the nth point is relative,
// or empty NodePath to indicate the current node.
////////////////////////////////////////////////////////////////////
INLINE NodePath ScissorEffect::
get_node(int n) const {
nassertr(n >= 0 && n < (int)_points.size(), NodePath());
return _points[n]._node;
}
////////////////////////////////////////////////////////////////////

View File

@ -33,7 +33,7 @@ TypeHandle ScissorEffect::_type_handle;
////////////////////////////////////////////////////////////////////
ScissorEffect::
ScissorEffect(bool screen, const LVecBase4f &frame,
const LPoint3f *points, int num_points, bool clip) :
const PointDef *points, int num_points, bool clip) :
_screen(screen), _frame(frame), _clip(clip)
{
_points.reserve(num_points);
@ -42,6 +42,21 @@ ScissorEffect(bool screen, const LVecBase4f &frame,
}
}
////////////////////////////////////////////////////////////////////
// Function: ScissorEffect::Copy Constructor
// Access: Private
// Description: Use ScissorEffect::make() to construct a new
// ScissorEffect object.
////////////////////////////////////////////////////////////////////
ScissorEffect::
ScissorEffect(const ScissorEffect &copy) :
_screen(copy._screen),
_frame(copy._frame),
_points(copy._points),
_clip(copy._clip)
{
}
////////////////////////////////////////////////////////////////////
// Function: ScissorEffect::make_screen
// Access: Published, Static
@ -55,20 +70,37 @@ make_screen(const LVecBase4f &frame, bool clip) {
return return_new(effect);
}
////////////////////////////////////////////////////////////////////
// Function: ScissorEffect::make_node
// Access: Published, Static
// Description: Constructs a new node-relative ScissorEffect, with no
// points. This empty ScissorEffect does nothing. You
// must then call add_point a number of times to add the
// points you require.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) ScissorEffect::
make_node(bool clip) {
ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), NULL, 0, clip);
return return_new(effect);
}
////////////////////////////////////////////////////////////////////
// Function: ScissorEffect::make_node
// Access: Published, Static
// Description: Constructs a new node-relative ScissorEffect. The
// two points are understood to be relative to the
// current node, and determine the diagonally opposite
// indicated node, or the current node if the NodePath
// is empty, and determine the diagonally opposite
// corners of the scissor region.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) ScissorEffect::
make_node(const LPoint3f &a, const LPoint3f &b, bool clip) {
LPoint3f points[2];
points[0] = a;
points[1] = b;
ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), points, 2, clip);
make_node(const LPoint3f &a, const LPoint3f &b, const NodePath &node) {
PointDef points[2];
points[0]._p = a;
points[0]._node = node;
points[1]._p = b;
points[1]._node = node;
ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), points, 2, true);
return return_new(effect);
}
@ -77,30 +109,70 @@ make_node(const LPoint3f &a, const LPoint3f &b, bool clip) {
// Access: Published, Static
// Description: Constructs a new node-relative ScissorEffect. The
// four points are understood to be relative to the
// current node, and determine four points surrounding
// the scissor region.
// indicated node, or the current node if the indicated
// NodePath is empty, and determine four points
// surrounding the scissor region.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) ScissorEffect::
make_node(const LPoint3f &a, const LPoint3f &b, const LPoint3f &c, const LPoint3f &d, bool clip) {
LPoint3f points[4];
points[0] = a;
points[1] = b;
points[2] = c;
points[3] = d;
ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), points, 4, clip);
make_node(const LPoint3f &a, const LPoint3f &b, const LPoint3f &c, const LPoint3f &d, const NodePath &node) {
PointDef points[4];
points[0]._p = a;
points[0]._node = node;
points[1]._p = b;
points[1]._node = node;
points[2]._p = c;
points[2]._node = node;
points[3]._p = d;
points[3]._node = node;
ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), points, 4, true);
return return_new(effect);
}
////////////////////////////////////////////////////////////////////
// Function: ScissorEffect::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.
// Function: ScissorEffect::add_point
// Access: Published
// Description: Returns a new ScissorEffect with the indicated point
// added. It is only valid to call this on a "node"
// type ScissorEffect. The full set of points,
// projected into screen space, defines the bounding
// volume of the rectangular scissor region.
//
// Each point may be relative to a different node, if
// desired.
////////////////////////////////////////////////////////////////////
bool ScissorEffect::
safe_to_transform() const {
return false;
CPT(RenderEffect) ScissorEffect::
add_point(const LPoint3f &p, const NodePath &node) const {
nassertr(!is_screen(), this);
ScissorEffect *effect = new ScissorEffect(*this);
PointDef point;
point._p = p;
point._node = node;
effect->_points.push_back(point);
return return_new(effect);
}
////////////////////////////////////////////////////////////////////
// Function: ScissorEffect::xform
// Access: Public, Virtual
// Description: Returns a new RenderEffect transformed by the
// indicated matrix.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) ScissorEffect::
xform(const LMatrix4f &mat) const {
if (is_screen()) {
return this;
}
ScissorEffect *effect = new ScissorEffect(*this);
Points::iterator pi;
for (pi = effect->_points.begin();
pi != effect->_points.end();
++pi) {
PointDef &point = (*pi);
if (point._node.is_empty()) {
point._p = point._p * mat;
}
}
return return_new(effect);
}
////////////////////////////////////////////////////////////////////
@ -117,7 +189,12 @@ output(ostream &out) const {
out << "node";
Points::const_iterator pi;
for (pi = _points.begin(); pi != _points.end(); ++pi) {
out << " [" << (*pi) << "]";
const PointDef &point = (*pi);
if (point._node.is_empty()) {
out << " (" << point._p << ")";
} else {
out << " (" << point._node << ":" << point._p << ")";
}
}
}
if (!get_clip()) {
@ -162,8 +239,9 @@ cull_callback(CullTraverser *trav, CullTraverserData &data,
CPT(RenderState) &node_state) const {
LVecBase4f frame;
const Lens *lens = trav->get_scene()->get_lens();
CPT(TransformState) modelview_transform = data.get_modelview_transform(trav)->compose(node_transform);
if (modelview_transform->is_singular()) {
CPT(TransformState) modelview_transform = data.get_modelview_transform(trav);
CPT(TransformState) net_transform = modelview_transform->compose(node_transform);
if (net_transform->is_singular()) {
// If we're under a singular transform, never mind.
return;
}
@ -172,15 +250,24 @@ cull_callback(CullTraverser *trav, CullTraverserData &data,
frame = _frame;
} else {
const LMatrix4f &proj_mat = lens->get_projection_mat();
LMatrix4f net_mat = modelview_transform->get_mat() * proj_mat;
LMatrix4f net_mat = net_transform->get_mat() * proj_mat;
bool any_points = false;
Points::const_iterator pi;
for (pi = _points.begin(); pi != _points.end(); ++pi) {
const LPoint3f &p = (*pi);
LVecBase4f pv(p[0], p[1], p[2], 1.0f);
pv = pv * net_mat;
const PointDef &point = (*pi);
LVecBase4f pv(point._p[0], point._p[1], point._p[2], 1.0f);
if (point._node.is_empty()) {
// Relative to this node.
pv = pv * net_mat;
} else {
// Relative to some other node.
LMatrix4f other_mat = point._node.get_net_transform()->get_mat() * proj_mat;
pv = pv * other_mat;
}
if (pv[3] == 0) {
continue;
}
@ -264,7 +351,11 @@ compare_to_impl(const RenderEffect *other) const {
return compare;
}
for (size_t i = 0; i < _points.size(); ++i) {
compare = _points[i].compare_to(ta->_points[i]);
compare = _points[i]._p.compare_to(ta->_points[i]._p);
if (compare != 0) {
return compare;
}
compare = _points[i]._node.compare_to(ta->_points[i]._node);
if (compare != 0) {
return compare;
}
@ -301,7 +392,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
dg.add_uint16(_points.size());
Points::const_iterator pi;
for (pi = _points.begin(); pi != _points.end(); ++pi) {
(*pi).write_datagram(dg);
(*pi)._p.write_datagram(dg);
}
}
dg.add_bool(_clip);
@ -345,9 +436,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
int num_points = scan.get_uint16();
_points.reserve(num_points);
for (int i = 0; i < num_points; ++i) {
LPoint3f p;
p.read_datagram(scan);
_points.push_back(p);
PointDef point;
point._p.read_datagram(scan);
_points.push_back(point);
}
}
_clip = scan.get_bool();

View File

@ -31,24 +31,34 @@
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH ScissorEffect : public RenderEffect {
private:
class PointDef {
public:
LPoint3f _p;
NodePath _node;
};
ScissorEffect(bool screen, const LVecBase4f &frame,
const LPoint3f *points, int num_points, bool clip);
const PointDef *points, int num_points, bool clip);
ScissorEffect(const ScissorEffect &copy);
PUBLISHED:
static CPT(RenderEffect) make_screen(const LVecBase4f &frame, bool clip = true);
static CPT(RenderEffect) make_node(const LPoint3f &a, const LPoint3f &b, bool clip = true);
static CPT(RenderEffect) make_node(const LPoint3f &a, const LPoint3f &b, const LPoint3f &c, const LPoint3f &d, bool clip = true);
static CPT(RenderEffect) make_node(bool clip = true);
static CPT(RenderEffect) make_node(const LPoint3f &a, const LPoint3f &b, const NodePath &node = NodePath());
static CPT(RenderEffect) make_node(const LPoint3f &a, const LPoint3f &b, const LPoint3f &c, const LPoint3f &d, const NodePath &node = NodePath());
CPT(RenderEffect) add_point(const LPoint3f &point, const NodePath &node = NodePath()) const;
INLINE bool is_screen() const;
INLINE const LVecBase4f &get_frame() const;
INLINE int get_num_points() const;
INLINE const LPoint3f &get_point(int n) const;
INLINE NodePath get_node(int n) const;
INLINE bool get_clip() const;
public:
virtual bool safe_to_transform() const;
virtual CPT(RenderEffect) xform(const LMatrix4f &mat) const;
virtual void output(ostream &out) const;
virtual bool has_cull_callback() const;
@ -65,7 +75,7 @@ private:
private:
bool _screen;
LVecBase4f _frame;
typedef pvector<LPoint3f> Points;
typedef pvector<PointDef> Points;
Points _points;
bool _clip;

View File

@ -88,13 +88,11 @@ get_canvas_node() const {
}
////////////////////////////////////////////////////////////////////
// Function: PGVirtualFrame::get_clip_plane_node
// Function: PGVirtualFrame::get_canvas_parent
// Access: Published
// Description: Returns the special node that holds all of PlaneNodes
// that are used for applying the clip planes to the
// canvas_node.
// Description: Returns the parent node of the canvas_node.
////////////////////////////////////////////////////////////////////
INLINE PandaNode *PGVirtualFrame::
get_clip_plane_node() const {
return _clip_plane_node;
get_canvas_parent() const {
return _canvas_parent;
}

View File

@ -13,8 +13,7 @@
////////////////////////////////////////////////////////////////////
#include "pgVirtualFrame.h"
#include "clipPlaneAttrib.h"
#include "planeNode.h"
#include "scissorEffect.h"
#include "sceneGraphReducer.h"
TypeHandle PGVirtualFrame::_type_handle;
@ -99,7 +98,7 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
// Reassign the canvas_node to point to the new copy, if it's there.
const PGVirtualFrame *from_frame = DCAST(PGVirtualFrame, from);
PandaNode *from_canvas_node = from_frame->get_canvas_node();
PandaNode *from_clip_plane_node = from_frame->get_clip_plane_node();
PandaNode *from_canvas_parent = from_frame->get_canvas_parent();
InstanceMap::const_iterator ci;
ci = inst_map.find(from_canvas_node);
@ -108,10 +107,10 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
_canvas_node = DCAST(ModelNode, (*ci).second);
}
ci = inst_map.find(from_clip_plane_node);
ci = inst_map.find(from_canvas_parent);
if (ci != inst_map.end()) {
remove_child(_clip_plane_node);
_clip_plane_node = (*ci).second;
remove_child(_canvas_parent);
_canvas_parent = DCAST(ModelNode, (*ci).second);
}
// Reassign the clip planes according to the clip frame.
@ -163,33 +162,14 @@ set_clip_frame(const LVecBase4f &frame) {
if (!_has_clip_frame || _clip_frame != frame) {
_has_clip_frame = true;
_clip_frame = frame;
CPT(RenderEffect) scissor_effect = ScissorEffect::make_node
(LPoint3f(_clip_frame[0], _clip_frame[2], _clip_frame[2]),
LPoint3f(_clip_frame[1], _clip_frame[2], _clip_frame[2]),
LPoint3f(_clip_frame[1], _clip_frame[3], _clip_frame[3]),
LPoint3f(_clip_frame[0], _clip_frame[3], _clip_frame[3]));
const LVector3f r = LVector3f::right();
const LVector3f u = LVector3f::up();
PT(PlaneNode) left_clip =
new PlaneNode("left_clip", Planef(r, r * _clip_frame[0]));
PT(PlaneNode) right_clip =
new PlaneNode("right_clip", Planef(-r, r * _clip_frame[1]));
PT(PlaneNode) bottom_clip =
new PlaneNode("bottom_clip", Planef(u, u * _clip_frame[2]));
PT(PlaneNode) top_clip =
new PlaneNode("top_clip", Planef(-u, u * _clip_frame[3]));
_clip_plane_node->remove_all_children();
_clip_plane_node->add_child(left_clip);
_clip_plane_node->add_child(right_clip);
_clip_plane_node->add_child(bottom_clip);
_clip_plane_node->add_child(top_clip);
CPT(ClipPlaneAttrib) plane_attrib = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(left_clip)));
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(right_clip)));
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(bottom_clip)));
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(top_clip)));
_canvas_node->set_attrib(plane_attrib);
_canvas_parent->set_effect(scissor_effect);
clip_frame_changed();
}
}
@ -205,7 +185,7 @@ clear_clip_frame() {
if (_has_clip_frame) {
_has_clip_frame = false;
_canvas_node->clear_attrib(ClipPlaneAttrib::get_class_type());
_canvas_parent->clear_effect(ScissorEffect::get_class_type());
clip_frame_changed();
}
}
@ -222,17 +202,16 @@ clip_frame_changed() {
////////////////////////////////////////////////////////////////////
// Function: PGVirtualFrame::setup_child_nodes
// Access: Private
// Description: Creates the special canvas_node and clip_plane_node
// Description: Creates the special canvas_node and canvas_parent
// for this object.
////////////////////////////////////////////////////////////////////
void PGVirtualFrame::
setup_child_nodes() {
_canvas_parent = new ModelNode("canvas_parent");
_canvas_parent->set_preserve_transform(ModelNode::PT_local);
add_child(_canvas_parent);
_canvas_node = new ModelNode("canvas");
_canvas_node->set_preserve_transform(ModelNode::PT_local);
// We have to preserve the clip plane attribute.
_canvas_node->set_preserve_attributes(SceneGraphReducer::TT_other);
add_child(_canvas_node);
_clip_plane_node = new PandaNode("clip_planes");
add_child(_clip_plane_node);
_canvas_parent->add_child(_canvas_node);
}

View File

@ -29,19 +29,19 @@ class TransformState;
// only see the portion of the canvas that is below the
// window at any given time.
//
// This works simply by automatically defining clipping
// planes to be applied to a special child node, called
// This works simply by automatically defining a scissor
// effect to be applied to a special child node, called
// the canvas_node, of the PGVirtualFrame node. Every
// object that is parented to the canvas_node will be
// clipped by the clip_frame. Also, you can modify the
// canvas_transform through convenience methods here,
// which actually modifies the transform on the
// clipped by the scissor effect. Also, you can modify
// the canvas_transform through convenience methods
// here, which actually modifies the transform on the
// canvas_node.
//
// The net effect is that the virtual canvas is
// arbitrarily large, and we can peek at it through the
// clip_frame, and scroll through different parts of it
// by modifying the canvas_transform.
// scissor region, and scroll through different parts of
// it by modifying the canvas_transform.
//
// See PGScrollFrame for a specialization of this class
// that handles the traditional scrolling canvas, with
@ -71,7 +71,7 @@ PUBLISHED:
INLINE const TransformState *get_canvas_transform() const;
INLINE PandaNode *get_canvas_node() const;
INLINE PandaNode *get_clip_plane_node() const;
INLINE PandaNode *get_canvas_parent() const;
protected:
virtual void clip_frame_changed();
@ -84,7 +84,7 @@ private:
LVecBase4f _clip_frame;
PT(ModelNode) _canvas_node;
PT(PandaNode) _clip_plane_node;
PT(ModelNode) _canvas_parent;
public:
static TypeHandle get_class_type() {