Remove old decal system to simplify cull/draw process a bit more

This commit is contained in:
rdb
2015-01-02 15:26:47 +01:00
parent e8905b840c
commit 5e5a04031f
10 changed files with 132 additions and 669 deletions

View File

@@ -257,12 +257,12 @@ ConfigVariableBool retransform_sprites
"necessary in order for fog to work correctly on the sprites."));
ConfigVariableBool depth_offset_decals
("depth-offset-decals", false,
("depth-offset-decals", true,
PRC_DESC("Set this true to allow decals to be implemented via the advanced "
"depth offset feature, if supported, instead of via the traditional "
"(and slower) two-pass approach. This is false by default "
"because it appears that many graphics drivers have issues with "
"their depth offset implementation."));
"(and slower) two-pass approach. This is currently the only method "
"by which decals are implemented in Panda3D, and as such, this "
"setting is ignored."));
ConfigVariableInt max_collect_vertices
("max-collect-vertices", 65534,

View File

@@ -27,7 +27,7 @@ TypeHandle CullBin::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: CullBin::Destructor
// Access: Public, Virtual
// Description:
// Description:
////////////////////////////////////////////////////////////////////
CullBin::
~CullBin() {
@@ -115,7 +115,7 @@ check_flash_color() {
} else {
_has_flash_color = false;
pgraph_cat.warning()
<< "Invalid value for flash-bin-" << _name << ": "
<< "Invalid value for flash-bin-" << _name << ": "
<< flash_bin.get_string_value() << "\n";
}
#endif // NDEBUG
@@ -124,7 +124,7 @@ check_flash_color() {
////////////////////////////////////////////////////////////////////
// Function: CullBin::ResultGraphBuilder::Constructor
// Access: Public
// Description:
// Description:
////////////////////////////////////////////////////////////////////
CullBin::ResultGraphBuilder::
ResultGraphBuilder(PandaNode *root_node) :
@@ -142,9 +142,8 @@ ResultGraphBuilder(PandaNode *root_node) :
////////////////////////////////////////////////////////////////////
void CullBin::ResultGraphBuilder::
add_object(CullableObject *object) {
if (_current_transform != object->_modelview_transform ||
_current_state != object->_state ||
object->is_fancy()) {
if (_current_transform != object->_modelview_transform ||
_current_state != object->_state) {
// Create a new GeomNode to hold the net transform and state. We
// choose to create a new GeomNode for each new state, to make it
// clearer to the observer when the state changes.
@@ -157,57 +156,13 @@ add_object(CullableObject *object) {
}
record_one_object(_current_node, object);
if (object->get_next() != (CullableObject *)NULL) {
// Collect the decal base pieces.
CullableObject *base = object->get_next();
while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) {
record_one_object(_current_node, base);
base = base->get_next();
}
if (base != (CullableObject *)NULL) {
// Now, collect all the decals.
_current_node->set_effect(DecalEffect::make());
int decal_index = 0;
CPT(TransformState) transform;
CPT(RenderState) state;
PT(GeomNode) decal_node;
CullableObject *decal = base->get_next();
while (decal != (CullableObject *)NULL) {
if (transform != decal->_modelview_transform ||
state != decal->_state ||
decal->get_next() != (CullableObject *)NULL) {
// Create a new GeomNode to hold the net transform.
transform = decal->_modelview_transform;
state = decal->_state;
decal_node = new GeomNode("decal_" + format_string(decal_index));
_current_node->add_child(decal_node);
decal_node->set_transform(transform);
decal_node->set_state(state);
}
record_one_object(decal_node, decal);
decal = decal->get_next();
++decal_index;
}
}
// Reset the current node pointer for next time so the decal root
// will remain in its own node.
_current_node.clear();
_current_transform.clear();
_current_state.clear();
}
++_object_index;
}
////////////////////////////////////////////////////////////////////
// Function: CullBin::ResultGraphBuilder::record_one_object
// Access: Private
// Description: Records a single object, without regard to decalling.
// Description: Records a single object.
////////////////////////////////////////////////////////////////////
void CullBin::ResultGraphBuilder::
record_one_object(GeomNode *node, CullableObject *object) {

View File

@@ -57,7 +57,7 @@ static const double bin_color_flash_rate = 1.0; // 1 state change per second
////////////////////////////////////////////////////////////////////
// Function: CullResult::Constructor
// Access: Public
// Description:
// Description:
////////////////////////////////////////////////////////////////////
CullResult::
CullResult(GraphicsStateGuardianBase *gsg,
@@ -87,7 +87,7 @@ make_next() const {
for (size_t i = 0; i < _bins.size(); ++i) {
CullBin *old_bin = _bins[i];
if (old_bin == (CullBin *)NULL ||
if (old_bin == (CullBin *)NULL ||
old_bin->get_bin_type() != bin_manager->get_bin_type(i)) {
new_result->_bins.push_back((CullBin *)NULL);
} else {
@@ -166,21 +166,19 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
// later. This means we must copy the object and add it to
// both bins. We can only do this if we do not have an
// explicit bin already applied; otherwise, M_dual falls back
// to M_alpha.
// to M_alpha.
{
const CullBinAttrib *bin_attrib = DCAST(CullBinAttrib, state->get_attrib(CullBinAttrib::get_class_slot()));
if (bin_attrib == (CullBinAttrib *)NULL ||
if (bin_attrib == (CullBinAttrib *)NULL ||
bin_attrib->get_bin_name().empty()) {
// We make a copy of the object to draw the transparent part
// without decals; this gets placed in the transparent bin.
// We make a copy of the object to draw the transparent part;
// this gets placed in the transparent bin.
#ifndef NDEBUG
if (m_dual_transparent)
if (m_dual_transparent)
#endif
{
CullableObject *transparent_part = new CullableObject(*object);
CPT(RenderState) transparent_state = object->has_decals() ?
get_dual_transparent_state_decals() :
get_dual_transparent_state();
CPT(RenderState) transparent_state = get_dual_transparent_state();
transparent_part->_state = state->compose(transparent_state);
if (transparent_part->munge_geom
(_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread),
@@ -195,9 +193,9 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
delete transparent_part;
}
}
// Now we can draw the opaque part, with decals. This will
// end up in the opaque bin.
// Now we can draw the opaque part. This will end up in
// the opaque bin.
object->_state = state->compose(get_dual_opaque_state());
#ifndef NDEBUG
if (!m_dual_opaque) {
@@ -210,7 +208,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
// M_alpha.
}
break;
default:
// Other kinds of transparency need no special handling.
break;
@@ -443,8 +441,6 @@ check_flash_transparency(CPT(RenderState) &state, const LColor &transparency) {
// Access: Private
// Description: Returns a RenderState that renders only the
// transparent parts of an object, in support of M_dual.
// This state is suitable only for objects that do not
// contain decals.
////////////////////////////////////////////////////////////////////
CPT(RenderState) CullResult::
get_dual_transparent_state() {
@@ -454,10 +450,7 @@ get_dual_transparent_state() {
// and hence filling up the depth buffer with large empty spaces
// that may obscure other things. However, this does mean we draw
// pixels twice where the alpha == 1.0 (since they were already
// drawn in the opaque pass). This is not normally a problem,
// except when we are using decals; in the case of decals, we
// don't want to draw the 1.0 pixels again, since these are the
// ones that may have been decaled onto.
// drawn in the opaque pass). This is not normally a problem.
state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_greater, 0.0f),
TransparencyAttrib::make(TransparencyAttrib::M_alpha),
DepthWriteAttrib::make(DepthWriteAttrib::M_off),
@@ -487,47 +480,6 @@ get_dual_transparent_state() {
return state;
}
////////////////////////////////////////////////////////////////////
// Function: CullResult::get_dual_transparent_state_decals
// Access: Private
// Description: Returns a RenderState that renders only the
// transparent parts of an object, but suitable for
// objects that contain decals.
////////////////////////////////////////////////////////////////////
CPT(RenderState) CullResult::
get_dual_transparent_state_decals() {
static CPT(RenderState) state = NULL;
if (state == (const RenderState *)NULL) {
// This is exactly the same as above except here we make the alpha
// test of < 1.0 instead of > 0.0. This makes us draw big empty
// pixels where the alpha values are 0.0, but we don't overwrite
// the decals where the pixels are 1.0.
state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_less, dual_opaque_level),
TransparencyAttrib::make(TransparencyAttrib::M_alpha),
DepthWriteAttrib::make(DepthWriteAttrib::M_off),
RenderState::get_max_priority());
}
#ifndef NDEBUG
if (m_dual_flash) {
int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
if ((cycle & 1) == 0) {
static CPT(RenderState) flash_state = NULL;
if (flash_state == (const RenderState *)NULL) {
flash_state = state->add_attrib(ColorAttrib::make_flat(LColor(0.8f, 0.2, 0.2, 1.0f)),
RenderState::get_max_priority());
flash_state = flash_state->add_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)),
RenderState::get_max_priority());
}
return flash_state;
}
}
#endif // NDEBUG
return state;
}
////////////////////////////////////////////////////////////////////
// Function: CullResult::get_dual_opaque_state
// Access: Private

View File

@@ -72,12 +72,11 @@ private:
static CPT(RenderState) get_alpha_state();
static CPT(RenderState) get_binary_state();
static CPT(RenderState) get_dual_transparent_state();
static CPT(RenderState) get_dual_transparent_state_decals();
static CPT(RenderState) get_dual_opaque_state();
GraphicsStateGuardianBase *_gsg;
PStatCollector _draw_region_pcollector;
typedef pvector< PT(CullBin) > Bins;
Bins _bins;
@@ -90,7 +89,7 @@ public:
register_type(_type_handle, "CullResult",
ReferenceCount::get_class_type());
}
private:
static TypeHandle _type_handle;
};
@@ -99,5 +98,3 @@ private:
#endif

View File

@@ -110,12 +110,12 @@ get_initial_state() const {
////////////////////////////////////////////////////////////////////
// Function: CullTraverser::get_depth_offset_decals
// Access: Published
// Description: Returns the depth_offset_decals flag. See
// set_depth_offset_decals().
// Description: Returns true, as depth offsets are the only way
// that we implement decals nowadays.
////////////////////////////////////////////////////////////////////
INLINE bool CullTraverser::
get_depth_offset_decals() const {
return _depth_offset_decals;
return true;
}
////////////////////////////////////////////////////////////////////
@@ -199,7 +199,7 @@ get_cull_handler() const {
////////////////////////////////////////////////////////////////////
// Function: CullTraverser::set_portal_clipper
// Access: Published
// Description: Specifies _portal_clipper object pointer that
// Description: Specifies _portal_clipper object pointer that
// subsequent traverse() or traverse_below may use.
////////////////////////////////////////////////////////////////////
INLINE void CullTraverser::

View File

@@ -47,7 +47,7 @@ TypeHandle CullTraverser::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: CullTraverser::Constructor
// Access: Published
// Description:
// Description:
////////////////////////////////////////////////////////////////////
CullTraverser::
CullTraverser() :
@@ -65,7 +65,7 @@ CullTraverser() :
////////////////////////////////////////////////////////////////////
// Function: CullTraverser::Copy Constructor
// Access: Published
// Description:
// Description:
////////////////////////////////////////////////////////////////////
CullTraverser::
CullTraverser(const CullTraverser &copy) :
@@ -76,7 +76,6 @@ CullTraverser(const CullTraverser &copy) :
_has_tag_state_key(copy._has_tag_state_key),
_tag_state_key(copy._tag_state_key),
_initial_state(copy._initial_state),
_depth_offset_decals(copy._depth_offset_decals),
_view_frustum(copy._view_frustum),
_cull_handler(copy._cull_handler),
_portal_clipper(copy._portal_clipper),
@@ -98,7 +97,6 @@ set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg,
_gsg = gsg;
_initial_state = scene_setup->get_initial_state();
_depth_offset_decals = _gsg->depth_offset_decals() && depth_offset_decals;
_current_thread = Thread::get_current_thread();
@@ -129,43 +127,43 @@ traverse(const NodePath &root) {
PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds();
if (bv != (BoundingVolume *)NULL &&
bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
local_frustum = DCAST(GeometricBoundingVolume, bv);
}
// This local_frustum is in camera space
PortalClipper portal_viewer(local_frustum, _scene_setup);
if (debug_portal_cull) {
portal_viewer.draw_camera_frustum();
}
// Store this pointer in this
set_portal_clipper(&portal_viewer);
CullTraverserData data(root, TransformState::make_identity(),
_initial_state, _view_frustum,
_initial_state, _view_frustum,
_current_thread);
traverse(data);
// Finally add the lines to be drawn
if (debug_portal_cull) {
portal_viewer.draw_lines();
}
// Render the frustum relative to the cull center.
NodePath cull_center = _scene_setup->get_cull_center();
CPT(TransformState) transform = cull_center.get_transform(root);
CullTraverserData my_data(data, portal_viewer._previous);
my_data._net_transform = my_data._net_transform->compose(transform);
traverse(my_data);
} else {
CullTraverserData data(root, TransformState::make_identity(),
_initial_state, _view_frustum,
_initial_state, _view_frustum,
_current_thread);
traverse(data);
}
}
@@ -181,7 +179,7 @@ void CullTraverser::
traverse(CullTraverserData &data) {
if (is_in_view(data)) {
if (pgraph_cat.is_spam()) {
pgraph_cat.spam()
pgraph_cat.spam()
<< "\n" << data._node_path
<< " " << data._draw_mask << "\n";
}
@@ -207,9 +205,9 @@ traverse(CullTraverserData &data) {
// up now.
show_bounds(data, node_effects->has_show_tight_bounds());
}
data.apply_transform_and_state(this);
const FogAttrib *fog = DCAST(FogAttrib, node_reader->get_state()->get_attrib(FogAttrib::get_class_slot()));
if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
// If we just introduced a FogAttrib here, call adjust_to_camera()
@@ -218,7 +216,7 @@ traverse(CullTraverserData &data) {
// need for it.
fog->get_fog()->adjust_to_camera(get_camera_transform());
}
if (fancy_bits & PandaNode::FB_cull_callback) {
PandaNode *node = data.node();
if (!node->cull_callback(this, data)) {
@@ -247,47 +245,41 @@ traverse_below(CullTraverserData &data) {
const RenderEffects *node_effects = node_reader->get_effects();
bool has_decal = !this_node_hidden && node_effects->has_decal();
if (has_decal && !_depth_offset_decals) {
// Start the three-pass decal rendering if we're not using
// DepthOffsetAttribs to implement decals.
start_decal(data);
} else {
if (!this_node_hidden) {
node->add_for_draw(this, data);
}
if (has_decal) {
// If we *are* implementing decals with DepthOffsetAttribs,
// apply it now, so that each child of this node gets offset by
// a tiny amount.
data._state = data._state->compose(get_depth_offset_state());
if (!this_node_hidden) {
node->add_for_draw(this, data);
}
if (has_decal) {
// If we *are* implementing decals with DepthOffsetAttribs,
// apply it now, so that each child of this node gets offset by
// a tiny amount.
data._state = data._state->compose(get_depth_offset_state());
#ifndef NDEBUG
// This is just a sanity check message.
if (!node->is_geom_node()) {
pgraph_cat.error()
<< "DecalEffect applied to " << *node << ", not a GeomNode.\n";
}
// This is just a sanity check message.
if (!node->is_geom_node()) {
pgraph_cat.error()
<< "DecalEffect applied to " << *node << ", not a GeomNode.\n";
}
#endif
}
// Now visit all the node's children.
PandaNode::Children children = node_reader->get_children();
node_reader->release();
int num_children = children.get_num_children();
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
while (i < num_children) {
CullTraverserData next_data(data, children.get_child(i));
traverse(next_data);
i = node->get_next_visible_child(i);
}
// Now visit all the node's children.
PandaNode::Children children = node_reader->get_children();
node_reader->release();
int num_children = children.get_num_children();
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
while (i < num_children) {
CullTraverserData next_data(data, children.get_child(i));
traverse(next_data);
i = node->get_next_visible_child(i);
}
} else {
for (int i = 0; i < num_children; i++) {
CullTraverserData next_data(data, children.get_child(i));
traverse(next_data);
}
} else {
for (int i = 0; i < num_children; i++) {
CullTraverserData next_data(data, children.get_child(i));
traverse(next_data);
}
}
}
@@ -311,20 +303,20 @@ end_traverse() {
// bounding volume.
////////////////////////////////////////////////////////////////////
void CullTraverser::
draw_bounding_volume(const BoundingVolume *vol,
draw_bounding_volume(const BoundingVolume *vol,
const TransformState *net_transform,
const TransformState *modelview_transform) const {
PT(Geom) bounds_viz = make_bounds_viz(vol);
if (bounds_viz != (Geom *)NULL) {
_geoms_pcollector.add_level(2);
CullableObject *outer_viz =
new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
CullableObject *outer_viz =
new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
net_transform, modelview_transform, get_scene());
_cull_handler->record_object(outer_viz, this);
CullableObject *inner_viz =
new CullableObject(bounds_viz, get_bounds_inner_viz_state(),
CullableObject *inner_viz =
new CullableObject(bounds_viz, get_bounds_inner_viz_state(),
net_transform, modelview_transform, get_scene());
_cull_handler->record_object(inner_viz, this);
}
@@ -360,13 +352,13 @@ show_bounds(CullTraverserData &data, bool tight) {
if (bounds_viz != (Geom *)NULL) {
_geoms_pcollector.add_level(1);
CullableObject *outer_viz =
new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
CullableObject *outer_viz =
new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
net_transform, modelview_transform,
get_scene());
_cull_handler->record_object(outer_viz, this);
}
} else {
draw_bounding_volume(node->get_bounds(),
net_transform, modelview_transform);
@@ -378,7 +370,7 @@ show_bounds(CullTraverserData &data, bool tight) {
GeomNode *gnode = DCAST(GeomNode, node);
int num_geoms = gnode->get_num_geoms();
for (int i = 0; i < num_geoms; ++i) {
draw_bounding_volume(gnode->get_geom(i)->get_bounds(),
draw_bounding_volume(gnode->get_geom(i)->get_bounds(),
net_transform, modelview_transform);
}
}
@@ -407,7 +399,7 @@ make_bounds_viz(const BoundingVolume *vol) {
("bounds", GeomVertexFormat::get_v3(),
Geom::UH_stream);
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
for (int sl = 0; sl < num_slices; ++sl) {
PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
@@ -419,11 +411,11 @@ make_bounds_viz(const BoundingVolume *vol) {
vertex.add_data3(compute_point(sphere, latitude, longitude1));
}
vertex.add_data3(compute_point(sphere, 1.0, longitude0));
strip->add_next_vertices(num_stacks * 2);
strip->close_primitive();
}
geom = new Geom(vdata);
geom->add_primitive(strip);
@@ -438,7 +430,7 @@ make_bounds_viz(const BoundingVolume *vol) {
for (int i = 0; i < 8; ++i ) {
vertex.add_data3(fvol->get_point(i));
}
PT(GeomLines) lines = new GeomLines(Geom::UH_stream);
lines->add_vertices(0, 1); lines->close_primitive();
lines->add_vertices(1, 2); lines->close_primitive();
@@ -472,7 +464,7 @@ make_bounds_viz(const BoundingVolume *vol) {
for (int i = 0; i < 8; ++i ) {
vertex.add_data3(box.get_point(i));
}
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_stream);
tris->add_vertices(0, 4, 5);
tris->close_primitive();
@@ -533,7 +525,7 @@ make_tight_bounds_viz(PandaNode *node) const {
Geom::UH_stream);
GeomVertexWriter vertex(vdata, InternalName::get_vertex(),
_current_thread);
vertex.add_data3(n[0], n[1], n[2]);
vertex.add_data3(n[0], n[1], x[2]);
vertex.add_data3(n[0], x[1], n[2]);
@@ -542,7 +534,7 @@ make_tight_bounds_viz(PandaNode *node) const {
vertex.add_data3(x[0], n[1], x[2]);
vertex.add_data3(x[0], x[1], n[2]);
vertex.add_data3(x[0], x[1], x[2]);
PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream);
// We wind one long linestrip around the wireframe cube. This
@@ -564,7 +556,7 @@ make_tight_bounds_viz(PandaNode *node) const {
strip->add_vertex(5);
strip->add_vertex(1);
strip->close_primitive();
geom = new Geom(vdata);
geom->add_primitive(strip);
}
@@ -576,10 +568,10 @@ make_tight_bounds_viz(PandaNode *node) const {
// Function: CullTraverser::compute_point
// Access: Private, Static
// Description: Returns a point on the surface of the sphere.
// latitude and longitude range from 0.0 to 1.0.
// latitude and longitude range from 0.0 to 1.0.
////////////////////////////////////////////////////////////////////
LVertex CullTraverser::
compute_point(const BoundingSphere *sphere,
compute_point(const BoundingSphere *sphere,
PN_stdfloat latitude, PN_stdfloat longitude) {
PN_stdfloat s1, c1;
csincos(latitude * MathNumbers::pi, &s1, &c1);
@@ -648,231 +640,3 @@ get_depth_offset_state() {
}
return state;
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverser::start_decal
// Access: Private
// Description: Collects a base node and all of the decals applied to
// it. This involves recursing below the base GeomNode
// to find all the decal geoms.
////////////////////////////////////////////////////////////////////
void CullTraverser::
start_decal(const CullTraverserData &data) {
PandaNode *node = data.node();
if (!node->is_geom_node()) {
pgraph_cat.error()
<< "DecalEffect applied to " << *node << ", not a GeomNode.\n";
return;
}
const PandaNodePipelineReader *node_reader = data.node_reader();
// Build a chain of CullableObjects. The head of the chain will be
// all of the base Geoms in order, followed by an empty
// CullableObject node, followed by all of the decal Geoms, in
// order.
// Since the CullableObject is a linked list which gets built in
// LIFO order, we start with the decals.
CullableObject *decals = (CullableObject *)NULL;
PandaNode::Children cr = node_reader->get_children();
int num_children = cr.get_num_children();
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
while (i < num_children) {
CullTraverserData next_data(data, cr.get_child(i));
decals = r_get_decals(next_data, decals);
i = node->get_next_visible_child(i);
}
} else {
for (int i = num_children - 1; i >= 0; i--) {
CullTraverserData next_data(data, cr.get_child(i));
decals = r_get_decals(next_data, decals);
}
}
// Now create a new, empty CullableObject to separate the decals
// from the non-decals.
CullableObject *separator = new CullableObject;
separator->set_next(decals);
// And now get the base Geoms, again in reverse order.
CullableObject *object = separator;
GeomNode *geom_node = DCAST(GeomNode, node);
GeomNode::Geoms geoms = geom_node->get_geoms();
int num_geoms = geoms.get_num_geoms();
_geoms_pcollector.add_level(num_geoms);
CPT(TransformState) net_transform = data.get_net_transform(this);
CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
CPT(TransformState) internal_transform = _scene_setup->get_cs_transform()->compose(modelview_transform);
for (int i = num_geoms - 1; i >= 0; i--) {
const Geom *geom = geoms.get_geom(i);
if (geom->is_empty()) {
continue;
}
CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
if (state->has_cull_callback() && !state->cull_callback(this, data)) {
// Cull.
continue;
}
// Cull the Geom bounding volume against the view frustum
// and/or the cull planes. Don't bother unless we've got more
// than one Geom, since otherwise the bounding volume of the
// GeomNode is (probably) the same as that of the one Geom,
// and we've already culled against that.
if (num_geoms > 1) {
if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
// Cull the individual Geom against the view frustum.
CPT(BoundingVolume) geom_volume = geom->get_bounds();
const GeometricBoundingVolume *geom_gbv =
DCAST(GeometricBoundingVolume, geom_volume);
int result = data._view_frustum->contains(geom_gbv);
if (result == BoundingVolume::IF_no_intersection) {
// Cull this Geom.
continue;
}
}
if (!data._cull_planes->is_empty()) {
// Also cull the Geom against the cull planes.
CPT(BoundingVolume) geom_volume = geom->get_bounds();
const GeometricBoundingVolume *geom_gbv =
DCAST(GeometricBoundingVolume, geom_volume);
int result;
data._cull_planes->do_cull(result, state, geom_gbv);
if (result == BoundingVolume::IF_no_intersection) {
// Cull.
continue;
}
}
}
CullableObject *next = object;
object =
new CullableObject(geom, state, net_transform,
modelview_transform, internal_transform);
object->set_next(next);
}
if (object != separator) {
// Finally, send the whole list down to the CullHandler for
// processing. The first Geom in the node now represents the
// overall state.
_cull_handler->record_object(object, this);
} else {
// Never mind; there's nothing to render.
delete object;
}
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverser::r_get_decals
// Access: Private
// Description: Recursively gets all the decals applied to a
// particular GeomNode. These are built into a
// CullableObject list in LIFO order (so that the
// traversing the list will extract them in the order
// they were encountered in the scene graph).
////////////////////////////////////////////////////////////////////
CullableObject *CullTraverser::
r_get_decals(CullTraverserData &data, CullableObject *decals) {
if (is_in_view(data)) {
PandaNodePipelineReader *node_reader = data.node_reader();
PandaNode *node = data.node();
const RenderEffects *node_effects = node_reader->get_effects();
if (node_effects->has_show_bounds()) {
// If we should show the bounding volume for this node, make it
// up now.
show_bounds(data, node_effects->has_show_tight_bounds());
}
data.apply_transform_and_state(this);
// First, visit all of the node's children.
int num_children = node_reader->get_num_children();
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
while (i < num_children) {
CullTraverserData next_data(data, node_reader->get_child(i));
decals = r_get_decals(next_data, decals);
i = node->get_next_visible_child(i);
}
} else {
for (int i = num_children - 1; i >= 0; i--) {
CullTraverserData next_data(data, node_reader->get_child(i));
decals = r_get_decals(next_data, decals);
}
}
// Now, tack on any geoms within the node.
if (node->is_geom_node()) {
GeomNode *geom_node = DCAST(GeomNode, node);
GeomNode::Geoms geoms = geom_node->get_geoms();
int num_geoms = geoms.get_num_geoms();
_geoms_pcollector.add_level(num_geoms);
CPT(TransformState) net_transform = data.get_net_transform(this);
CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
CPT(TransformState) internal_transform = _scene_setup->get_cs_transform()->compose(modelview_transform);
for (int i = num_geoms - 1; i >= 0; i--) {
const Geom *geom = geoms.get_geom(i);
if (geom->is_empty()) {
continue;
}
CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
if (state->has_cull_callback() && !state->cull_callback(this, data)) {
// Cull.
continue;
}
// Cull the Geom bounding volume against the view frustum
// and/or the cull planes. Don't bother unless we've got more
// than one Geom, since otherwise the bounding volume of the
// GeomNode is (probably) the same as that of the one Geom,
// and we've already culled against that.
if (num_geoms > 1) {
if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
// Cull the individual Geom against the view frustum.
CPT(BoundingVolume) geom_volume = geom->get_bounds();
const GeometricBoundingVolume *geom_gbv =
DCAST(GeometricBoundingVolume, geom_volume);
int result = data._view_frustum->contains(geom_gbv);
if (result == BoundingVolume::IF_no_intersection) {
// Cull this Geom.
continue;
}
}
if (!data._cull_planes->is_empty()) {
// Also cull the Geom against the cull planes.
CPT(BoundingVolume) geom_volume = geom->get_bounds();
const GeometricBoundingVolume *geom_gbv =
DCAST(GeometricBoundingVolume, geom_volume);
int result;
data._cull_planes->do_cull(result, state, geom_gbv);
if (result == BoundingVolume::IF_no_intersection) {
// Cull.
continue;
}
}
}
CullableObject *next = decals;
decals =
new CullableObject(geom, state, net_transform,
modelview_transform, internal_transform);
decals->set_next(next);
}
}
}
return decals;
}

View File

@@ -87,7 +87,7 @@ PUBLISHED:
INLINE static void flush_level();
void draw_bounding_volume(const BoundingVolume *vol,
void draw_bounding_volume(const BoundingVolume *vol,
const TransformState *net_transform,
const TransformState *modelview_transform) const;
@@ -105,7 +105,7 @@ private:
void show_bounds(CullTraverserData &data, bool tight);
static PT(Geom) make_bounds_viz(const BoundingVolume *vol);
PT(Geom) make_tight_bounds_viz(PandaNode *node) const;
static LVertex compute_point(const BoundingSphere *sphere,
static LVertex compute_point(const BoundingSphere *sphere,
PN_stdfloat latitude, PN_stdfloat longitude);
static CPT(RenderState) get_bounds_outer_viz_state();
static CPT(RenderState) get_bounds_inner_viz_state();
@@ -121,12 +121,11 @@ private:
bool _has_tag_state_key;
string _tag_state_key;
CPT(RenderState) _initial_state;
bool _depth_offset_decals;
PT(GeometricBoundingVolume) _view_frustum;
CullHandler *_cull_handler;
PortalClipper *_portal_clipper;
bool _effective_incomplete_render;
public:
static TypeHandle get_class_type() {
return _type_handle;
@@ -150,4 +149,4 @@ private:
#endif

View File

@@ -12,6 +12,7 @@
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CullableObject::Constructor
// Access: Public
@@ -19,9 +20,7 @@
// filled in later.
////////////////////////////////////////////////////////////////////
INLINE CullableObject::
CullableObject() :
_fancy(false)
{
CullableObject() {
#ifdef DO_MEMORY_USAGE
MemoryUsage::update_type(this, get_class_type());
#endif
@@ -42,8 +41,7 @@ CullableObject(const Geom *geom, const RenderState *state,
_state(state),
_net_transform(net_transform),
_modelview_transform(modelview_transform),
_internal_transform(scene_setup->get_cs_transform()->compose(modelview_transform)),
_fancy(false)
_internal_transform(scene_setup->get_cs_transform()->compose(modelview_transform))
{
#ifdef DO_MEMORY_USAGE
MemoryUsage::update_type(this, get_class_type());
@@ -65,20 +63,17 @@ CullableObject(const Geom *geom, const RenderState *state,
_state(state),
_net_transform(net_transform),
_modelview_transform(modelview_transform),
_internal_transform(internal_transform),
_fancy(false)
_internal_transform(internal_transform)
{
#ifdef DO_MEMORY_USAGE
MemoryUsage::update_type(this, get_class_type());
#endif
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::Copy Constructor
// Access: Public
// Description: Copies the CullableObject, but does not copy its
// children (decals).
// Description: Copies the CullableObject.
////////////////////////////////////////////////////////////////////
INLINE CullableObject::
CullableObject(const CullableObject &copy) :
@@ -88,8 +83,7 @@ CullableObject(const CullableObject &copy) :
_state(copy._state),
_net_transform(copy._net_transform),
_modelview_transform(copy._modelview_transform),
_internal_transform(copy._internal_transform),
_fancy(false)
_internal_transform(copy._internal_transform)
{
#ifdef DO_MEMORY_USAGE
MemoryUsage::update_type(this, get_class_type());
@@ -99,12 +93,10 @@ CullableObject(const CullableObject &copy) :
////////////////////////////////////////////////////////////////////
// Function: CullableObject::Copy Assignment Operator
// Access: Public
// Description: Copies the CullableObject, but does not copy its
// children (decals).
// Description: Copies the CullableObject.
////////////////////////////////////////////////////////////////////
INLINE void CullableObject::
operator = (const CullableObject &copy) {
nassertv(!_fancy);
_geom = copy._geom;
_munger = copy._munger;
_munged_data = copy._munged_data;
@@ -112,29 +104,7 @@ operator = (const CullableObject &copy) {
_net_transform = copy._net_transform;
_modelview_transform = copy._modelview_transform;
_internal_transform = copy._internal_transform;
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::is_fancy
// Access: Public
// Description: Returns true if the object has something fancy to it:
// decals, maybe, or a draw_callback, that prevents it
// from being rendered inline.
////////////////////////////////////////////////////////////////////
INLINE bool CullableObject::
is_fancy() const {
return _fancy;
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::has_decals
// Access: Public
// Description: Returns true if the object has decals associated with
// it.
////////////////////////////////////////////////////////////////////
INLINE bool CullableObject::
has_decals() const {
return _fancy && (_next != (CullableObject *)NULL);
_draw_callback = copy._draw_callback;
}
////////////////////////////////////////////////////////////////////
@@ -146,8 +116,17 @@ has_decals() const {
////////////////////////////////////////////////////////////////////
INLINE void CullableObject::
draw(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) {
if (_fancy) {
draw_fancy(gsg, force, current_thread);
if (_draw_callback != (CallbackObject *)NULL) {
// It has a callback associated.
gsg->clear_before_callback();
gsg->set_state_and_transform(_state, _internal_transform);
GeomDrawCallbackData cbdata(this, gsg, force);
_draw_callback->do_callback(&cbdata);
if (cbdata.get_lost_state()) {
// Tell the GSG to forget its state.
gsg->clear_state_and_transform();
}
// Now the callback has taken care of drawing.
} else {
nassertv(_geom != (Geom *)NULL);
gsg->set_state_and_transform(_state, _internal_transform);
@@ -184,43 +163,7 @@ request_resident() const {
////////////////////////////////////////////////////////////////////
INLINE void CullableObject::
set_draw_callback(CallbackObject *draw_callback) {
make_fancy();
if (draw_callback != _draw_callback) {
if (_draw_callback != (CallbackObject *)NULL) {
unref_delete(_draw_callback);
}
_draw_callback = draw_callback;
if (_draw_callback != (CallbackObject *)NULL) {
_draw_callback->ref();
}
}
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::set_next
// Access: Public
// Description: Sets the next object in the decal chain. This next
// object will be destructed when this object destructs.
////////////////////////////////////////////////////////////////////
INLINE void CullableObject::
set_next(CullableObject *next) {
make_fancy();
nassertv(_next == (CullableObject *)NULL);
_next = next;
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::get_next
// Access: Public
// Description: Returns the next object in the decal chain, or NULL
// for the end of the chain.
////////////////////////////////////////////////////////////////////
INLINE CullableObject *CullableObject::
get_next() const {
if (_fancy) {
return _next;
}
return NULL;
_draw_callback = draw_callback;
}
////////////////////////////////////////////////////////////////////
@@ -233,23 +176,6 @@ flush_level() {
_sw_sprites_pcollector.flush_level();
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::make_fancy
// Access: Private
// Description: Elevates this object to "fancy" status. This means
// that the additional pointers, like _next and
// _draw_callback, have meaningful values and should be
// examined.
////////////////////////////////////////////////////////////////////
INLINE void CullableObject::
make_fancy() {
if (!_fancy) {
_fancy = true;
_draw_callback = NULL;
_next = NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::draw_inline
// Access: Private
@@ -266,7 +192,7 @@ draw_inline(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread)
////////////////////////////////////////////////////////////////////
// Function: CullableObject::SortPoints::Constructor
// Access: Public
// Description:
// Description:
////////////////////////////////////////////////////////////////////
INLINE CullableObject::SortPoints::
SortPoints(const CullableObject::PointData *array) :
@@ -288,7 +214,7 @@ operator () (unsigned short a, unsigned short b) const {
////////////////////////////////////////////////////////////////////
// Function: CullableObject::SourceFormat::operator <
// Access: Public
// Description:
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool CullableObject::SourceFormat::
operator < (const CullableObject::SourceFormat &other) const {

View File

@@ -30,7 +30,6 @@
#include "geomTriangles.h"
#include "light.h"
#include "lightMutexHolder.h"
#include "geomDrawCallbackData.h"
CullableObject::FormatMap CullableObject::_format_map;
LightMutex CullableObject::_format_lock;
@@ -180,41 +179,13 @@ munge_geom(GraphicsStateGuardianBase *gsg,
#endif
}
if (_fancy) {
// Only check the _next pointer if the _fancy flag is set.
if (_next != (CullableObject *)NULL) {
if (_next->_state != (RenderState *)NULL) {
_next->munge_geom(gsg, gsg->get_geom_munger(_next->_state, current_thread),
traverser, force);
} else {
_next->munge_geom(gsg, munger, traverser, force);
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::Destructor
// Access: Public
// Description: Automatically deletes the whole chain of these things.
////////////////////////////////////////////////////////////////////
CullableObject::
~CullableObject() {
if (_fancy) {
// Only check the _next pointer if the _fancy flag is set.
if (_next != (CullableObject *)NULL) {
delete _next;
}
set_draw_callback(NULL);
}
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::output
// Access: Public
// Description:
// Description:
////////////////////////////////////////////////////////////////////
void CullableObject::
output(ostream &out) const {
@@ -225,7 +196,6 @@ output(ostream &out) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::munge_points_to_quads
// Access: Private
@@ -642,7 +612,7 @@ munge_texcoord_light_vector(const CullTraverser *traverser, bool force) {
return true;
}
if (!_munged_data->has_column(InternalName::get_vertex()) ||
if (!_munged_data->has_column(InternalName::get_vertex()) ||
!_munged_data->has_column(InternalName::get_normal())) {
// No vertex or normal; can't compute light vector.
return true;
@@ -775,97 +745,15 @@ get_flash_hardware_state() {
return flash_hardware_state;
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::draw_fancy
// Access: Private
// Description: Something fancy about this object. Draw it properly.
////////////////////////////////////////////////////////////////////
void CullableObject::
draw_fancy(GraphicsStateGuardianBase *gsg, bool force,
Thread *current_thread) {
nassertv(_fancy);
if (_draw_callback != (CallbackObject *)NULL) {
// It has a callback associated.
gsg->clear_before_callback();
gsg->set_state_and_transform(_state, _internal_transform);
GeomDrawCallbackData cbdata(this, gsg, force);
_draw_callback->do_callback(&cbdata);
if (cbdata.get_lost_state()) {
// Tell the GSG to forget its state.
gsg->clear_state_and_transform();
}
// Now the callback has taken care of drawing.
} else if (_next != (CullableObject *)NULL) {
// It has decals.
draw_with_decals(gsg, force, current_thread);
} else {
// Huh, nothing fancy after all. Somehow the _fancy flag got set
// incorrectly; that's a bug.
gsg->set_state_and_transform(_state, _internal_transform);
draw_inline(gsg, force, current_thread);
nassertv(false);
}
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::draw_with_decals
// Access: Private
// Description: Draws the current CullableObject, assuming it has
// attached decals.
////////////////////////////////////////////////////////////////////
void CullableObject::
draw_with_decals(GraphicsStateGuardianBase *gsg, bool force,
Thread *current_thread) {
nassertv(_fancy && _next != (CullableObject *)NULL);
// We draw with a three-step process.
// First, render all of the base geometry for the first pass.
CPT(RenderState) state = gsg->begin_decal_base_first();
CullableObject *base = this;
while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) {
gsg->set_state_and_transform(base->_state->compose(state), base->_internal_transform);
base->draw_inline(gsg, force, current_thread);
base = base->_next;
}
if (base != (CullableObject *)NULL) {
// Now, draw all the decals.
state = gsg->begin_decal_nested();
CullableObject *decal = base->_next;
while (decal != (CullableObject *)NULL) {
gsg->set_state_and_transform(decal->_state->compose(state), decal->_internal_transform);
decal->draw_inline(gsg, force, current_thread);
decal = decal->_next;
}
}
// And now, re-draw the base geometry, if required.
state = gsg->begin_decal_base_second();
if (state != (const RenderState *)NULL) {
base = this;
while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) {
gsg->set_state_and_transform(base->_state->compose(state), base->_internal_transform);
base->draw_inline(gsg, force, current_thread);
base = base->_next;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::SourceFormat::Constructor
// Access: Public
// Description:
// Description:
////////////////////////////////////////////////////////////////////
CullableObject::SourceFormat::
SourceFormat(const GeomVertexFormat *format, bool sprite_texcoord) :
_format(format),
_sprite_texcoord(sprite_texcoord)
_sprite_texcoord(sprite_texcoord)
{
_retransform_sprites = retransform_sprites;
}

View File

@@ -32,17 +32,17 @@
#include "sceneSetup.h"
#include "lightMutex.h"
#include "callbackObject.h"
#include "geomDrawCallbackData.h"
class CullTraverser;
////////////////////////////////////////////////////////////////////
// Class : CullableObject
// Description : The smallest atom of cull. This is normally just a
// Geom and its associated state, but it also represent
// a number of Geoms to be drawn together, with a number
// of Geoms decalled onto them.
// Geom and its associated state, but it also contain
// a draw callback.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH CullableObject
class EXPCL_PANDA_PGRAPH CullableObject
#ifdef DO_MEMORY_USAGE
: public ReferenceCount // We inherit from ReferenceCount just to get the memory type tracking that MemoryUsage provides.
#endif // DO_MEMORY_USAGE
@@ -57,13 +57,10 @@ public:
const TransformState *net_transform,
const TransformState *modelview_transform,
const TransformState *internal_transform);
INLINE CullableObject(const CullableObject &copy);
INLINE void operator = (const CullableObject &copy);
INLINE bool is_fancy() const;
INLINE bool has_decals() const;
bool munge_geom(GraphicsStateGuardianBase *gsg,
GeomMunger *munger, const CullTraverser *traverser,
bool force);
@@ -74,11 +71,8 @@ public:
INLINE static void flush_level();
INLINE void set_draw_callback(CallbackObject *draw_callback);
INLINE void set_next(CullableObject *next);
INLINE CullableObject *get_next() const;
public:
~CullableObject();
ALLOC_DELETED_CHAIN(CullableObject);
void output(ostream &out) const;
@@ -91,17 +85,9 @@ public:
CPT(TransformState) _net_transform;
CPT(TransformState) _modelview_transform;
CPT(TransformState) _internal_transform;
PT(CallbackObject) _draw_callback;
private:
bool _fancy;
// Fancy things below. These pointers are only meaningful if
// _fancy, above, is true.
CallbackObject *_draw_callback;
CullableObject *_next; // for decals
private:
INLINE void make_fancy();
bool munge_points_to_quads(const CullTraverser *traverser, bool force);
bool munge_texcoord_light_vector(const CullTraverser *traverser, bool force);
@@ -110,10 +96,6 @@ private:
INLINE void draw_inline(GraphicsStateGuardianBase *gsg,
bool force, Thread *current_thread);
void draw_fancy(GraphicsStateGuardianBase *gsg, bool force,
Thread *current_thread);
void draw_with_decals(GraphicsStateGuardianBase *gsg, bool force,
Thread *current_thread);
private:
// This class is used internally by munge_points_to_quads().