From c0844239f1ac990a3da1b43f33868fb9adbb906f Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 29 Mar 2006 20:28:33 +0000 Subject: [PATCH] initial rough pass at hierarchical z-buffer visibility. experimental. --- panda/src/cull/Sources.pp | 29 +- panda/src/cull/config_cull.cxx | 16 + panda/src/cull/config_cull.h | 5 + panda/src/cull/cullBinBackToFront.cxx | 3 +- panda/src/cull/cullBinFrontToBack.cxx | 3 +- panda/src/cull/cullBinHierarchicalZBuffer.I | 111 +++ panda/src/cull/cullBinHierarchicalZBuffer.cxx | 779 ++++++++++++++++++ panda/src/cull/cullBinHierarchicalZBuffer.h | 163 ++++ panda/src/cull/cullBinStateSorted.cxx | 1 - panda/src/cull/cull_composite2.cxx | 1 + panda/src/display/graphicsStateGuardian.I | 11 - panda/src/display/graphicsStateGuardian.cxx | 65 ++ panda/src/display/graphicsStateGuardian.h | 10 +- panda/src/glstuff/Sources.pp | 53 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 109 ++- .../src/glstuff/glGraphicsStateGuardian_src.h | 20 +- panda/src/glstuff/glmisc_src.cxx | 16 +- panda/src/glstuff/glmisc_src.h | 1 + panda/src/glstuff/glstuff_src.cxx | 1 + panda/src/glstuff/glstuff_src.h | 1 + panda/src/gobj/Sources.pp | 9 +- panda/src/gobj/config_gobj.cxx | 4 + panda/src/gobj/gobj_composite2.cxx | 3 +- panda/src/gobj/occlusionQueryContext.I | 27 + panda/src/gobj/occlusionQueryContext.cxx | 36 + panda/src/gobj/occlusionQueryContext.h | 61 ++ panda/src/gobj/queryContext.I | 27 + panda/src/gobj/queryContext.cxx | 57 ++ panda/src/gobj/queryContext.h | 71 ++ panda/src/gsgbase/graphicsStateGuardianBase.h | 7 + panda/src/pgraph/colorWriteAttrib.h | 1 + panda/src/pgraph/cullBinManager.cxx | 13 +- panda/src/pgraph/cullBinManager.h | 1 + panda/src/pgraph/cullableObject.h | 4 + panda/src/pgraph/portalNode.cxx | 4 +- 35 files changed, 1646 insertions(+), 77 deletions(-) create mode 100644 panda/src/cull/cullBinHierarchicalZBuffer.I create mode 100644 panda/src/cull/cullBinHierarchicalZBuffer.cxx create mode 100644 panda/src/cull/cullBinHierarchicalZBuffer.h create mode 100644 panda/src/gobj/occlusionQueryContext.I create mode 100644 panda/src/gobj/occlusionQueryContext.cxx create mode 100644 panda/src/gobj/occlusionQueryContext.h create mode 100644 panda/src/gobj/queryContext.I create mode 100644 panda/src/gobj/queryContext.cxx create mode 100644 panda/src/gobj/queryContext.h diff --git a/panda/src/cull/Sources.pp b/panda/src/cull/Sources.pp index d0481b1394..95820d1513 100644 --- a/panda/src/cull/Sources.pp +++ b/panda/src/cull/Sources.pp @@ -9,13 +9,15 @@ #define TARGET cull #define SOURCES \ - binCullHandler.h \ + binCullHandler.h binCullHandler.I \ config_cull.h \ - cullBinBackToFront.h cullBinFixed.h \ - cullBinFrontToBack.h cullBinStateSorted.h cullBinUnsorted.h \ - drawCullHandler.h binCullHandler.I cullBinBackToFront.I \ - cullBinFixed.I cullBinFrontToBack.I cullBinStateSorted.I \ - cullBinUnsorted.I drawCullHandler.I + cullBinBackToFront.h cullBinBackToFront.I \ + cullBinFixed.h cullBinFixed.I \ + cullBinFrontToBack.h cullBinFrontToBack.I \ + cullBinHierarchicalZBuffer.h cullBinHierarchicalZBuffer.I \ + cullBinStateSorted.h cullBinStateSorted.I \ + cullBinUnsorted.h cullBinUnsorted.I \ + drawCullHandler.h drawCullHandler.I #define COMBINED_SOURCES \ $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx @@ -26,18 +28,21 @@ cullBinBackToFront.cxx \ cullBinFixed.cxx \ cullBinFrontToBack.cxx \ + cullBinHierarchicalZBuffer.cxx \ cullBinStateSorted.cxx \ cullBinUnsorted.cxx \ drawCullHandler.cxx #define INSTALL_HEADERS \ - binCullHandler.h \ + binCullHandler.h binCullHandler.I \ config_cull.h \ - cullBinBackToFront.h cullBinFixed.h \ - cullBinFrontToBack.h cullBinStateSorted.h cullBinUnsorted.h \ - drawCullHandler.h binCullHandler.I cullBinBackToFront.I \ - cullBinFixed.I cullBinFrontToBack.I cullBinStateSorted.I \ - cullBinUnsorted.I drawCullHandler.I + cullBinBackToFront.h cullBinBackToFront.I \ + cullBinFixed.h cullBinFixed.I \ + cullBinFrontToBack.h cullBinFrontToBack.I \ + cullBinHierarchicalZBuffer.h cullBinHierarchicalZBuffer.I \ + cullBinStateSorted.h cullBinStateSorted.I \ + cullBinUnsorted.h cullBinUnsorted.I \ + drawCullHandler.h drawCullHandler.I #define IGATESCAN all diff --git a/panda/src/cull/config_cull.cxx b/panda/src/cull/config_cull.cxx index d92049e8a2..c853818c1d 100644 --- a/panda/src/cull/config_cull.cxx +++ b/panda/src/cull/config_cull.cxx @@ -21,6 +21,7 @@ #include "cullBinBackToFront.h" #include "cullBinFixed.h" #include "cullBinFrontToBack.h" +#include "cullBinHierarchicalZBuffer.h" #include "cullBinStateSorted.h" #include "cullBinUnsorted.h" @@ -34,6 +35,18 @@ ConfigureFn(config_cull) { init_libcull(); } +ConfigVariableInt max_objects_per_octree_node +("max-objects-per-octree-node", 10, + PRC_DESC("Specifies the maximum number of objects collected per octree " + "node, by the hierarchical-z cull bin algorithm.")); + +ConfigVariableDouble octree_multiassign_ratio +("octree-multiassign-ratio", 0.1, + PRC_DESC("Objects that intersect a bisecting plane of an octree node must " + "be at least this fraction of the node's linear dimension in " + "order to be assigned to the node itself. If the object is smaller " + "than this, it will be multiply assigned to the node's children.")); + //////////////////////////////////////////////////////////////////// // Function: init_libcull // Description: Initializes the library. This must be called at @@ -53,6 +66,7 @@ init_libcull() { CullBinBackToFront::init_type(); CullBinFixed::init_type(); CullBinFrontToBack::init_type(); + CullBinHierarchicalZBuffer::init_type(); CullBinStateSorted::init_type(); CullBinUnsorted::init_type(); @@ -67,4 +81,6 @@ init_libcull() { CullBinFrontToBack::make_bin); bin_manager->register_bin_type(CullBinManager::BT_fixed, CullBinFixed::make_bin); + bin_manager->register_bin_type(CullBinManager::BT_hierarchical_z, + CullBinHierarchicalZBuffer::make_bin); } diff --git a/panda/src/cull/config_cull.h b/panda/src/cull/config_cull.h index 979bd322bc..12922cfd0c 100644 --- a/panda/src/cull/config_cull.h +++ b/panda/src/cull/config_cull.h @@ -22,12 +22,17 @@ #include "pandabase.h" #include "notifyCategoryProxy.h" #include "dconfig.h" +#include "configVariableInt.h" +#include "configVariableDouble.h" class DSearchPath; ConfigureDecl(config_cull, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(cull, EXPCL_PANDA, EXPTP_PANDA); +extern ConfigVariableInt max_objects_per_octree_node; +extern ConfigVariableDouble octree_multiassign_ratio; + extern EXPCL_PANDA void init_libcull(); #endif diff --git a/panda/src/cull/cullBinBackToFront.cxx b/panda/src/cull/cullBinBackToFront.cxx index bfc92be565..6dbb377556 100644 --- a/panda/src/cull/cullBinBackToFront.cxx +++ b/panda/src/cull/cullBinBackToFront.cxx @@ -63,8 +63,7 @@ add_object(CullableObject *object) { // Determine the center of the bounding volume. CPT(BoundingVolume) volume = object->_geom->get_bounds(); - if (!volume->is_empty() && - volume->is_of_type(GeometricBoundingVolume::get_class_type())) { + if (!volume->is_empty()) { const GeometricBoundingVolume *gbv; DCAST_INTO_V(gbv, volume); diff --git a/panda/src/cull/cullBinFrontToBack.cxx b/panda/src/cull/cullBinFrontToBack.cxx index beb591af29..79e7a2b30b 100644 --- a/panda/src/cull/cullBinFrontToBack.cxx +++ b/panda/src/cull/cullBinFrontToBack.cxx @@ -63,8 +63,7 @@ add_object(CullableObject *object) { // Determine the center of the bounding volume. CPT(BoundingVolume) volume = object->_geom->get_bounds(); - if (!volume->is_empty() && - volume->is_of_type(GeometricBoundingVolume::get_class_type())) { + if (!volume->is_empty()) { const GeometricBoundingVolume *gbv; DCAST_INTO_V(gbv, volume); diff --git a/panda/src/cull/cullBinHierarchicalZBuffer.I b/panda/src/cull/cullBinHierarchicalZBuffer.I new file mode 100644 index 0000000000..32f6d3fc5c --- /dev/null +++ b/panda/src/cull/cullBinHierarchicalZBuffer.I @@ -0,0 +1,111 @@ +// Filename: cullBinHierarchicalZBuffer.I +// Created by: drose (24Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::ObjectData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CullBinHierarchicalZBuffer::ObjectData:: +ObjectData(CullableObject *object, BoundingSphere *bounds) : + _object(object), + _bounds(bounds) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::ObjectData::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CullBinHierarchicalZBuffer::ObjectData:: +ObjectData(const CullBinHierarchicalZBuffer::ObjectData ©) : + _object(copy._object), + _bounds(copy._bounds) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::ObjectData::Copy Assignment +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void CullBinHierarchicalZBuffer::ObjectData:: +operator = (const CullBinHierarchicalZBuffer::ObjectData ©) { + _object = copy._object; + _bounds = copy._bounds; +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CullBinHierarchicalZBuffer:: +CullBinHierarchicalZBuffer(const string &name, GraphicsStateGuardianBase *gsg) : + CullBin(name, gsg) +{ + nassertv(_gsg->get_supports_occlusion_query()); +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::initial_assign +// Access: Public +// Description: Assigns the object to the node, in preparation for +// calling group_objects(). +//////////////////////////////////////////////////////////////////// +INLINE void CullBinHierarchicalZBuffer::OctreeNode:: +initial_assign(const CullBinHierarchicalZBuffer::ObjectData &object_data) { + _objects.push_back(object_data); +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::reassign +// Access: Public +// Description: After determining that the object bisects one of the +// major planes of the node, reassigns it back to the +// same node. +//////////////////////////////////////////////////////////////////// +INLINE void CullBinHierarchicalZBuffer::OctreeNode:: +reassign(const CullBinHierarchicalZBuffer::ObjectData &object_data) { + if (object_data._bounds->get_radius() / _half_side >= octree_multiassign_ratio) { + // The object is large enough to keep in this node. + //cerr << " reassigning.\n"; + _objects.push_back(object_data); + } else { + //cerr << " multidistributing.\n"; + multi_assign(object_data); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::assign_to_corner +// Access: Private +// Description: Assigns the object to the octree node in the +// indicated corner. +//////////////////////////////////////////////////////////////////// +INLINE void CullBinHierarchicalZBuffer::OctreeNode:: +assign_to_corner(int index, const CullBinHierarchicalZBuffer::ObjectData &object_data) { + //cerr << " Assigning to corner " << hex << index << dec << ".\n"; + nassertv(index >= 0 && index < 8); + if (_corners[index] == NULL) { + make_corner(index); + } + _corners[index]->initial_assign(object_data); +} diff --git a/panda/src/cull/cullBinHierarchicalZBuffer.cxx b/panda/src/cull/cullBinHierarchicalZBuffer.cxx new file mode 100644 index 0000000000..48a93cbeed --- /dev/null +++ b/panda/src/cull/cullBinHierarchicalZBuffer.cxx @@ -0,0 +1,779 @@ +// Filename: cullBinHierarchicalZBuffer.cxx +// Created by: drose (24Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "cullBinHierarchicalZBuffer.h" +#include "graphicsStateGuardianBase.h" +#include "geometricBoundingVolume.h" +#include "geomLines.h" +#include "geomTriangles.h" +#include "geomVertexWriter.h" +#include "depthWriteAttrib.h" +#include "depthTestAttrib.h" +#include "colorWriteAttrib.h" +#include "cullableObject.h" +#include "cullHandler.h" +#include "pStatTimer.h" +#include "config_cull.h" +#include "thread.h" + +PStatCollector CullBinHierarchicalZBuffer::_wait_occlusion_pcollector("Wait:Occlusion test"); + +PT(Geom) CullBinHierarchicalZBuffer::_octree_solid_test; +PT(Geom) CullBinHierarchicalZBuffer::_octree_wireframe_viz; +CPT(RenderState) CullBinHierarchicalZBuffer::_octree_solid_test_state; +TypeHandle CullBinHierarchicalZBuffer::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +CullBinHierarchicalZBuffer:: +~CullBinHierarchicalZBuffer() { + ObjectPointers::iterator pi; + for (pi = _object_pointers.begin(); pi != _object_pointers.end(); ++pi) { + delete (*pi); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::make_bin +// Access: Public, Static +// Description: Factory constructor for passing to the CullBinManager. +//////////////////////////////////////////////////////////////////// +CullBin *CullBinHierarchicalZBuffer:: +make_bin(const string &name, GraphicsStateGuardianBase *gsg) { + return new CullBinHierarchicalZBuffer(name, gsg); +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::make_next +// Access: Public, Virtual +// Description: Returns a newly-allocated CullBin object that +// contains a copy of just the subset of the data from +// this CullBin object that is worth keeping around +// for next frame. +// +// If a particular CullBin object has no data worth +// preserving till next frame, it is acceptable to +// return NULL (which is the default behavior of this +// method). +//////////////////////////////////////////////////////////////////// +PT(CullBin) CullBinHierarchicalZBuffer:: +make_next() const { + return (CullBin *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::add_object +// Access: Public, Virtual +// Description: Adds a geom, along with its associated state, to +// the bin for rendering. +//////////////////////////////////////////////////////////////////// +void CullBinHierarchicalZBuffer:: +add_object(CullableObject *object) { + // Determine the world-space bounding sphere for the object. + CPT(BoundingVolume) volume = object->_geom->get_bounds(); + if (volume->is_empty()) { + return; + } + + PT(BoundingSphere) sphere; + + if (volume->is_exact_type(BoundingSphere::get_class_type())) { + sphere = DCAST(BoundingSphere, volume->make_copy()); + } else { + const GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, volume); + PT(BoundingSphere) sphere = new BoundingSphere; + sphere->around(&gbv, &gbv + 1); + } + + object->_already_drawn = false; + sphere->xform(object->_net_transform->get_mat()); + _root.initial_assign(ObjectData(object, sphere)); + _object_pointers.push_back(object); +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::finish_cull +// Access: Public +// Description: Called after all the geoms have been added, this +// indicates that the cull process is finished for this +// frame and gives the bins a chance to do any +// post-processing (like sorting) before moving on to +// draw. +//////////////////////////////////////////////////////////////////// +void CullBinHierarchicalZBuffer:: +finish_cull() { + PStatTimer timer(_cull_this_pcollector); + + // Now we have a loose list of objects that are to be rendered. + // We'd rather have them in an octree, which has much better + // grouping properties for the purpose of this algorithm. + + // For now, we'll just build an octree here at runtime, a new one + // fresh for each frame. Maybe it won't be *too* bad. But later, + // we can optimize this to take advantage of temporal coherence by + // starting from the previous frame's octree. + _root.make_initial_bounds(); + _root.group_objects(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::draw +// Access: Public +// Description: Draws all the geoms in the bin, in the appropriate +// order. +//////////////////////////////////////////////////////////////////// +void CullBinHierarchicalZBuffer:: +draw() { + PStatTimer timer(_draw_this_pcollector); + _root.draw(*this); + + while (!_pending_nodes.empty()) { + PendingNode &pending = _pending_nodes.front(); + bool is_occluded; + if (!pending._query->is_answer_ready()) { + // The answer isn't ready yet. We have to wait. + PStatTimer timer(_wait_occlusion_pcollector); + is_occluded = (pending._query->get_num_fragments() == 0); + } else { + // The answer is ready right now. There will be no waiting. + is_occluded = (pending._query->get_num_fragments() == 0); + } + if (!is_occluded) { + // The octree cell is at least partially visible. Draw it, and + // continue recursion. + pending._octree_node->draw(*this); + } else { + pending._octree_node->draw_wireframe(*this); + } + _pending_nodes.pop_front(); + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +CullBinHierarchicalZBuffer::OctreeNode:: +OctreeNode() { + for (int i = 0; i < 8; ++i) { + _corners[i] = (OctreeNode *)NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +CullBinHierarchicalZBuffer::OctreeNode:: +OctreeNode(float mid_x, float mid_y, float mid_z, float half_side) : + _mid(mid_x, mid_y, mid_z), + _half_side(half_side) +{ + for (int i = 0; i < 8; ++i) { + _corners[i] = (OctreeNode *)NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +CullBinHierarchicalZBuffer::OctreeNode:: +~OctreeNode() { + for (int i = 0; i < 8; ++i) { + if (_corners[i] != (OctreeNode *)NULL) { + delete _corners[i]; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::make_initial_bounds +// Access: Public +// Description: Determines the minmax bounding volume of the root +// OctreeNode, based on the objects it contains. +//////////////////////////////////////////////////////////////////// +void CullBinHierarchicalZBuffer::OctreeNode:: +make_initial_bounds() { + if (_objects.empty()) { + return; + } + + LPoint3f scene_min = _objects[0]._bounds->get_center(); + LPoint3f scene_max = _objects[0]._bounds->get_center(); + + Objects::const_iterator oi; + for (oi = _objects.begin(); oi != _objects.end(); ++oi) { + LPoint3f object_min = (*oi)._bounds->get_min(); + LPoint3f object_max = (*oi)._bounds->get_max(); + scene_min[0] = min(scene_min[0], object_min[0]); + scene_min[1] = min(scene_min[1], object_min[1]); + scene_min[2] = min(scene_min[2], object_min[2]); + scene_max[0] = max(scene_max[0], object_max[0]); + scene_max[1] = max(scene_max[1], object_max[1]); + scene_max[2] = max(scene_max[2], object_max[2]); + } + + float side = max(max(scene_max[0] - scene_min[0], + scene_max[1] - scene_min[1]), + scene_max[2] - scene_min[2]); + + _mid.set((scene_min[0] + scene_max[0]) * 0.5f, + (scene_min[1] + scene_max[1]) * 0.5f, + (scene_min[2] + scene_max[2]) * 0.5f); + _half_side = side * 0.5f; +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::group_objects +// Access: Public +// Description: Recursively groups the objects assigned to this node +// into smaller octree nodes, as appropriate. +//////////////////////////////////////////////////////////////////// +void CullBinHierarchicalZBuffer::OctreeNode:: +group_objects() { + //cerr << "group_objects, " << _objects.size() << " objects.\n"; + if ((int)_objects.size() <= max_objects_per_octree_node) { + // No need to do any more subdividing. + //cerr << " small enough.\n"; + return; + } + + // Assign all objects to one or more corners. + + Objects old_objects; + old_objects.swap(_objects); + + Objects::const_iterator oi; + for (oi = old_objects.begin(); oi != old_objects.end(); ++oi) { + //cerr << " object " << (oi - old_objects.begin()) << "\n"; + const ObjectData &object_data = (*oi); + const LPoint3f &c = object_data._bounds->get_center(); + float r = object_data._bounds->get_radius(); + + if (c[0] + r <= _mid[0]) { + // -X + if (c[1] + r <= _mid[1]) { + // -X, -Y + if (c[2] + r <= _mid[2]) { + // -X, -Y, -Z + assign_to_corner(0, object_data); + } else if (c[2] - r >= _mid[2]) { + // -X, -Y, +Z + assign_to_corner(OC_z, object_data); + } else { + // -X, -Y, 0 + reassign(object_data); + } + } else if (c[1] - r >= _mid[1]) { + // -X, +Y + if (c[2] + r <= _mid[2]) { + // -X, +Y, -Z + assign_to_corner(OC_y, object_data); + } else if (c[2] - r >= _mid[2]) { + // -X, +Y, +Z + assign_to_corner(OC_y | OC_z, object_data); + } else { + // -X, +Y, 0 + reassign(object_data); + } + } else { + // -X, 0 + reassign(object_data); + } + } else if (c[0] - r >= _mid[0]) { + // +X + if (c[1] + r <= _mid[1]) { + // +X, -Y + if (c[2] + r <= _mid[2]) { + // +X, -Y, -Z + assign_to_corner(OC_x, object_data); + } else if (c[2] - r >= _mid[2]) { + // +X, -Y, +Z + assign_to_corner(OC_x | OC_z, object_data); + } else { + // +X, -Y, 0 + reassign(object_data); + } + } else if (c[1] - r >= _mid[1]) { + // +X, +Y + if (c[2] + r <= _mid[2]) { + // +X, +Y, -Z + assign_to_corner(OC_x | OC_y, object_data); + } else if (c[2] - r >= _mid[2]) { + // +X, +Y, +Z + assign_to_corner(OC_x | OC_y | OC_z, object_data); + } else { + // +X, +Y, 0 + reassign(object_data); + } + } else { + // +X, 0 + reassign(object_data); + } + } else { + // 0 + reassign(object_data); + } + } + + for (int i = 0; i < 8; ++i) { + if (_corners[i] != (OctreeNode *)NULL) { + _corners[i]->group_objects(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::occlusion_test +// Access: Public +// Description: Tests the octree node for visibility by rendering the +// octree cube, invisibly, with a query. Returns the +// occlusion query object representing this test. +//////////////////////////////////////////////////////////////////// +PT(OcclusionQueryContext) CullBinHierarchicalZBuffer::OctreeNode:: +occlusion_test(GraphicsStateGuardianBase *gsg) { + // Draw the bounding volume for visualization. This is + // complicated because we're doing this at such a low level, here + // in the middle of the draw task--we've already completed the + // cull traversal, so we can't just create a CullableObject or do + // anything else that requires a pointer to a CullTraverser. + // Instead, we have to do the relevant code by hand. + CPT(TransformState) net_transform = TransformState::make_pos_hpr_scale + (_mid, LVecBase3f(0.0f, 0.0f, 0.0f), + LVecBase3f(_half_side, _half_side, _half_side)); + CPT(TransformState) world_transform = gsg->get_scene()->get_world_transform(); + CPT(TransformState) modelview_transform = world_transform->compose(net_transform); + + CPT(RenderState) state = get_octree_solid_test_state(); + PT(GeomMunger) munger = gsg->get_geom_munger(state); + + CPT(Geom) viz = get_octree_solid_test(); + CPT(GeomVertexData) munged_data = viz->get_vertex_data(); + munger->munge_geom(viz, munged_data); + + gsg->set_state_and_transform(state, modelview_transform); + + gsg->begin_occlusion_query(); + viz->draw(gsg, munger, munged_data); + return gsg->end_occlusion_query(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::draw +// Access: Public +// Description: Draws all of the objects in this node, and +// recursively performs occlusion tests on all of the +// nested nodes. +//////////////////////////////////////////////////////////////////// +void CullBinHierarchicalZBuffer::OctreeNode:: +draw(CullBinHierarchicalZBuffer &bin) { + if (!_objects.empty()) { + // Now draw the objects within the octree node. + Objects::const_iterator oi; + for (oi = _objects.begin(); oi != _objects.end(); ++oi) { + CullableObject *object = (*oi)._object; + if (object->_already_drawn) { + //cerr << "skipping object.\n"; + } else { + //cerr << "drawing object.\n"; + CullHandler::draw(object, bin._gsg); + object->_already_drawn = true; + } + } + } + + for (int i = 0; i < 8; ++i) { + if (_corners[i] != (OctreeNode *)NULL) { + PendingNode pending; + pending._octree_node = _corners[i]; + pending._query = _corners[i]->occlusion_test(bin._gsg); + bin._pending_nodes.push_back(pending); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::draw_wireframe +// Access: Public +// Description: Draws a wireframe representation of the octree cube, +// for debugging and visualization purposes. +//////////////////////////////////////////////////////////////////// +void CullBinHierarchicalZBuffer::OctreeNode:: +draw_wireframe(CullBinHierarchicalZBuffer &bin) { + // As above, this is complicated because we're doing this at such a + // low level. + CPT(TransformState) net_transform = TransformState::make_pos_hpr_scale + (_mid, LVecBase3f(0.0f, 0.0f, 0.0f), + LVecBase3f(_half_side, _half_side, _half_side)); + CPT(TransformState) world_transform = bin._gsg->get_scene()->get_world_transform(); + CPT(TransformState) modelview_transform = world_transform->compose(net_transform); + + CPT(RenderState) state = RenderState::make_empty(); + PT(GeomMunger) munger = bin._gsg->get_geom_munger(state); + + CPT(Geom) viz = get_octree_wireframe_viz(); + CPT(GeomVertexData) munged_data = viz->get_vertex_data(); + munger->munge_geom(viz, munged_data); + + bin._gsg->set_state_and_transform(state, modelview_transform); + viz->draw(bin._gsg, munger, munged_data); +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::get_octree_solid_test +// Access: Private, Static +// Description: Returns a Geom that may be used to render the solid +// faces of octree cube, presumably invisibly. This +// returns a cube over the range (-1, -1, -1) - (1, 1, +// 1). +//////////////////////////////////////////////////////////////////// +CPT(Geom) CullBinHierarchicalZBuffer:: +get_octree_solid_test() { + if (_octree_solid_test == (Geom *)NULL) { + CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3(); + PT(GeomVertexData) vdata = + new GeomVertexData("octree", format, Geom::UH_static); + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + vertex.add_data3f(-1.0f, -1.0f, -1.0f); + vertex.add_data3f(1.0f, -1.0f, -1.0f); + vertex.add_data3f(-1.0f, -1.0f, 1.0f); + vertex.add_data3f(1.0f, -1.0f, 1.0f); + vertex.add_data3f(-1.0f, 1.0f, -1.0f); + vertex.add_data3f(1.0f, 1.0f, -1.0f); + vertex.add_data3f(-1.0f, 1.0f, 1.0f); + vertex.add_data3f(1.0f, 1.0f, 1.0f); + PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static); + tris->add_vertices(2, 0, 3); tris->close_primitive(); + tris->add_vertices(0, 1, 3); tris->close_primitive(); + tris->add_vertices(3, 1, 7); tris->close_primitive(); + tris->add_vertices(1, 5, 7); tris->close_primitive(); + tris->add_vertices(7, 5, 6); tris->close_primitive(); + tris->add_vertices(5, 4, 6); tris->close_primitive(); + tris->add_vertices(6, 4, 2); tris->close_primitive(); + tris->add_vertices(4, 0, 2); tris->close_primitive(); + tris->add_vertices(6, 2, 7); tris->close_primitive(); + tris->add_vertices(2, 3, 7); tris->close_primitive(); + tris->add_vertices(0, 4, 1); tris->close_primitive(); + tris->add_vertices(4, 5, 1); tris->close_primitive(); + + _octree_solid_test = new Geom(vdata); + _octree_solid_test->add_primitive(tris); + } + + return _octree_solid_test; +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::get_octree_wireframe_viz +// Access: Private, Static +// Description: Returns a Geom that may be used to render an +// OctreeNode in wireframe. This actually draws a +// wireframe cube in the range (-1, -1, -1) - (1, 1, 1). +//////////////////////////////////////////////////////////////////// +CPT(Geom) CullBinHierarchicalZBuffer:: +get_octree_wireframe_viz() { + if (_octree_wireframe_viz == (Geom *)NULL) { + CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3cp(); + PT(GeomVertexData) vdata = + new GeomVertexData("octree", format, Geom::UH_static); + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + vertex.add_data3f(-1.0f, -1.0f, -1.0f); + vertex.add_data3f(1.0f, -1.0f, -1.0f); + vertex.add_data3f(-1.0f, -1.0f, 1.0f); + vertex.add_data3f(1.0f, -1.0f, 1.0f); + vertex.add_data3f(-1.0f, 1.0f, -1.0f); + vertex.add_data3f(1.0f, 1.0f, -1.0f); + vertex.add_data3f(-1.0f, 1.0f, 1.0f); + vertex.add_data3f(1.0f, 1.0f, 1.0f); + CPT(GeomVertexData) cvdata = vdata->set_color(Colorf(1.0f, 0.5f, 0.0f, 1.0f)); + PT(GeomLines) lines = new GeomLines(Geom::UH_static); + lines->add_vertices(0, 1); lines->close_primitive(); + lines->add_vertices(1, 3); lines->close_primitive(); + lines->add_vertices(3, 2); lines->close_primitive(); + lines->add_vertices(2, 0); lines->close_primitive(); + lines->add_vertices(0, 4); lines->close_primitive(); + lines->add_vertices(4, 6); lines->close_primitive(); + lines->add_vertices(6, 7); lines->close_primitive(); + lines->add_vertices(7, 5); lines->close_primitive(); + lines->add_vertices(5, 4); lines->close_primitive(); + lines->add_vertices(1, 5); lines->close_primitive(); + lines->add_vertices(3, 7); lines->close_primitive(); + lines->add_vertices(2, 6); lines->close_primitive(); + + _octree_wireframe_viz = new Geom(cvdata); + _octree_wireframe_viz->add_primitive(lines); + } + + return _octree_wireframe_viz; +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::get_octree_solid_test_state +// Access: Private, Static +// Description: Returns the RenderState appropriate to rendering the +// octree test invisibly. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) CullBinHierarchicalZBuffer:: +get_octree_solid_test_state() { + if (_octree_solid_test_state == (RenderState *)NULL) { + _octree_solid_test_state = RenderState::make + (DepthWriteAttrib::make(DepthWriteAttrib::M_off), + DepthTestAttrib::make(DepthTestAttrib::M_less), + ColorWriteAttrib::make(ColorWriteAttrib::C_off)); + } + + return _octree_solid_test_state; +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::multi_assign +// Access: Public +// Description: The object intersects a center plane, but is too +// small to justify keeping within this big node. +// Duplicate it into the sub-nodes. +//////////////////////////////////////////////////////////////////// +void CullBinHierarchicalZBuffer::OctreeNode:: +multi_assign(const CullBinHierarchicalZBuffer::ObjectData &object_data) { + const LPoint3f &c = object_data._bounds->get_center(); + float r = object_data._bounds->get_radius(); + + //cerr << "multi_assigning " << c << " vs. " << _mid << "\n"; + + if (c[0] + r <= _mid[0]) { + // -X + if (c[1] + r <= _mid[1]) { + // -X, -Y + if (c[2] + r <= _mid[2]) { + // -X, -Y, -Z + nassertv(false); + } else if (c[2] - r >= _mid[2]) { + // -X, -Y, +Z + nassertv(false); + } else { + // -X, -Y, 0 + assign_to_corner(0, object_data); + assign_to_corner(OC_z, object_data); + } + } else if (c[1] - r >= _mid[1]) { + // -X, +Y + if (c[2] + r <= _mid[2]) { + // -X, +Y, -Z + nassertv(false); + } else if (c[2] - r >= _mid[2]) { + // -X, +Y, +Z + nassertv(false); + } else { + // -X, +Y, 0 + assign_to_corner(OC_y, object_data); + assign_to_corner(OC_y | OC_z, object_data); + } + } else { + // -X, 0 + if (c[2] + r <= _mid[2]) { + // -X, 0, -Z + assign_to_corner(0, object_data); + assign_to_corner(OC_y, object_data); + } else if (c[2] - r >= _mid[2]) { + // -X, 0, +Z + assign_to_corner(OC_z, object_data); + assign_to_corner(OC_y | OC_z, object_data); + } else { + // -X, 0, 0 + assign_to_corner(0, object_data); + assign_to_corner(OC_z, object_data); + assign_to_corner(OC_y, object_data); + assign_to_corner(OC_y | OC_z, object_data); + } + } + } else if (c[0] - r >= _mid[0]) { + // +X + if (c[1] + r <= _mid[1]) { + // +X, -Y + if (c[2] + r <= _mid[2]) { + // +X, -Y, -Z + nassertv(false); + } else if (c[2] - r >= _mid[2]) { + // +X, -Y, +Z + nassertv(false); + } else { + // +X, -Y, 0 + assign_to_corner(OC_x, object_data); + assign_to_corner(OC_x | OC_z, object_data); + } + } else if (c[1] - r >= _mid[1]) { + // +X, +Y + if (c[2] + r <= _mid[2]) { + // +X, +Y, -Z + nassertv(false); + } else if (c[2] - r >= _mid[2]) { + // +X, +Y, +Z + nassertv(false); + } else { + // +X, +Y, 0 + assign_to_corner(OC_x | OC_y, object_data); + assign_to_corner(OC_x | OC_y | OC_z, object_data); + } + } else { + // +X, 0 + if (c[2] + r <= _mid[2]) { + // +X, 0, -Z + assign_to_corner(OC_x, object_data); + assign_to_corner(OC_x | OC_y, object_data); + } else if (c[2] - r >= _mid[2]) { + // +X, 0, +Z + assign_to_corner(OC_x | OC_z, object_data); + assign_to_corner(OC_x | OC_y | OC_z, object_data); + } else { + // +X, 0, 0 + assign_to_corner(OC_x, object_data); + assign_to_corner(OC_x | OC_z, object_data); + assign_to_corner(OC_x | OC_y, object_data); + assign_to_corner(OC_x | OC_y | OC_z, object_data); + } + } + } else { + // 0 + if (c[1] + r <= _mid[1]) { + // 0, -Y + if (c[2] + r <= _mid[2]) { + // 0, -Y, -Z + assign_to_corner(0, object_data); + assign_to_corner(OC_x, object_data); + } else if (c[2] - r >= _mid[2]) { + // 0, -Y, +Z + assign_to_corner(OC_z, object_data); + assign_to_corner(OC_x | OC_z, object_data); + } else { + // 0, -Y, 0 + assign_to_corner(0, object_data); + assign_to_corner(OC_z, object_data); + assign_to_corner(OC_x, object_data); + assign_to_corner(OC_x | OC_z, object_data); + } + } else if (c[1] - r >= _mid[1]) { + // 0, +Y + if (c[2] + r <= _mid[2]) { + // 0, +Y, -Z + assign_to_corner(OC_y, object_data); + assign_to_corner(OC_x | OC_y, object_data); + } else if (c[2] - r >= _mid[2]) { + // 0, +Y, +Z + assign_to_corner(OC_y | OC_z, object_data); + assign_to_corner(OC_x | OC_y | OC_z, object_data); + } else { + // 0, +Y, 0 + assign_to_corner(OC_y, object_data); + assign_to_corner(OC_y | OC_z, object_data); + assign_to_corner(OC_x | OC_y, object_data); + assign_to_corner(OC_x | OC_y | OC_z, object_data); + } + } else { + // 0, 0 + if (c[2] + r <= _mid[2]) { + // 0, 0, -Z + assign_to_corner(0, object_data); + assign_to_corner(OC_y, object_data); + assign_to_corner(OC_x, object_data); + assign_to_corner(OC_x | OC_y, object_data); + } else if (c[2] - r >= _mid[2]) { + // 0, 0, +Z + assign_to_corner(OC_z, object_data); + assign_to_corner(OC_y | OC_z, object_data); + assign_to_corner(OC_x | OC_z, object_data); + assign_to_corner(OC_x | OC_y | OC_z, object_data); + } else { + // 0, 0, 0 + assign_to_corner(0, object_data); + assign_to_corner(OC_z, object_data); + assign_to_corner(OC_y, object_data); + assign_to_corner(OC_y | OC_z, object_data); + assign_to_corner(OC_x, object_data); + assign_to_corner(OC_x | OC_z, object_data); + assign_to_corner(OC_x | OC_y, object_data); + assign_to_corner(OC_x | OC_y | OC_z, object_data); + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CullBinHierarchicalZBuffer::OctreeNode::make_corner +// Access: Private +// Description: Makes a new octree node for the indicated corner. +//////////////////////////////////////////////////////////////////// +INLINE void CullBinHierarchicalZBuffer::OctreeNode:: +make_corner(int index) { + //cerr << "making corner " << hex << index << dec << "\n"; + nassertv(_corners[index] == NULL); + + OctreeNode *node = NULL; + + double q = _half_side * 0.5f; + + switch (index) { + case 0: + // -X, -Y, -Z + node = new OctreeNode(_mid[0] - q, _mid[1] - q, _mid[2] - q, q); + break; + + case OC_x: + // +X, -Y, -Z + node = new OctreeNode(_mid[0] + q, _mid[1] - q, _mid[2] - q, q); + break; + + case OC_y: + // -X, +Y, -Z + node = new OctreeNode(_mid[0] - q, _mid[1] + q, _mid[2] - q, q); + break; + + case OC_x | OC_y: + // +X, +Y, -Z + node = new OctreeNode(_mid[0] + q, _mid[1] + q, _mid[2] - q, q); + break; + + case OC_z: + // -X, -Y, +Z + node = new OctreeNode(_mid[0] - q, _mid[1] - q, _mid[2] + q, q); + break; + + case OC_x | OC_z: + // +X, -Y, +Z + node = new OctreeNode(_mid[0] + q, _mid[1] - q, _mid[2] + q, q); + break; + + case OC_y | OC_z: + // -X, +Y, +Z + node = new OctreeNode(_mid[0] - q, _mid[1] + q, _mid[2] + q, q); + break; + + case OC_x | OC_y | OC_z: + // +X, +Y, +Z + node = new OctreeNode(_mid[0] + q, _mid[1] + q, _mid[2] + q, q); + break; + } + nassertv(node != (OctreeNode *)NULL); + _corners[index] = node; +} diff --git a/panda/src/cull/cullBinHierarchicalZBuffer.h b/panda/src/cull/cullBinHierarchicalZBuffer.h new file mode 100644 index 0000000000..76c37dd03d --- /dev/null +++ b/panda/src/cull/cullBinHierarchicalZBuffer.h @@ -0,0 +1,163 @@ +// Filename: cullBinHierarchicalZBuffer.h +// Created by: drose (24Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CULLBINHIERARCHICALZBUFFER_H +#define CULLBINHIERARCHICALZBUFFER_H + +#include "pandabase.h" + +#include "cullBin.h" +#include "geom.h" +#include "transformState.h" +#include "renderState.h" +#include "pointerTo.h" +#include "boundingSphere.h" +#include "config_cull.h" +#include "occlusionQueryContext.h" +#include "pdeque.h" +#include "pStatCollector.h" + +//////////////////////////////////////////////////////////////////// +// Class : CullBinHierarchicalZBuffer +// Description : This cull bin uses a hierarchical Z-buffer algorithm +// to attempt to further eliminate geometry that is +// obscured behind walls, etc. It imposes some +// significant overhead over most of the other kinds of +// CullBins, and requires additional support from the +// graphics card, so it is most appropriate for scenes +// in which there might be a large amount of geometry, +// within the viewing frustum, but obscured behind large +// objects or walls. +// +// This code is still experimental. Use with caution. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA CullBinHierarchicalZBuffer : public CullBin { +public: + INLINE CullBinHierarchicalZBuffer(const string &name, GraphicsStateGuardianBase *gsg); + virtual ~CullBinHierarchicalZBuffer(); + + static CullBin *make_bin(const string &name, GraphicsStateGuardianBase *gsg); + virtual PT(CullBin) make_next() const; + + virtual void add_object(CullableObject *object); + virtual void finish_cull(); + virtual void draw(); + +private: + void draw_next(); + + static CPT(Geom) get_octree_solid_test(); + static CPT(Geom) get_octree_wireframe_viz(); + + static CPT(RenderState) get_octree_solid_test_state(); + + // We keep the original list of CullableObjects here in the bin + // class, so we can delete them on destruction. This allows us to + // duplicate pointers between different OctreeNodes. + typedef pvector ObjectPointers; + ObjectPointers _object_pointers; + + class ObjectData { + public: + INLINE ObjectData(CullableObject *object, BoundingSphere *bounds); + INLINE ObjectData(const ObjectData ©); + INLINE void operator = (const ObjectData ©); + + CullableObject *_object; + PT(BoundingSphere) _bounds; + }; + + typedef pvector Objects; + + enum OctreeCorners { + OC_x = 0x01, + OC_y = 0x02, + OC_z = 0x04, + }; + + class OctreeNode { + public: + OctreeNode(); + OctreeNode(float mid_x, float mid_y, float mid_z, float half_side); + ~OctreeNode(); + + void make_initial_bounds(); + void group_objects(); + PT(OcclusionQueryContext) occlusion_test(GraphicsStateGuardianBase *gsg); + void draw(CullBinHierarchicalZBuffer &bin); + void draw_wireframe(CullBinHierarchicalZBuffer &bin); + + INLINE void initial_assign(const ObjectData &object_data); + + private: + INLINE void reassign(const ObjectData &object_data); + INLINE void assign_to_corner(int index, const ObjectData &object_data); + void multi_assign(const ObjectData &object_data); + void make_corner(int index); + + Objects _objects; + OctreeNode *_corners[8]; + LPoint3f _mid; + float _half_side; + }; + + OctreeNode _root; + + // During draw(), we maintain a list of OctreeNodes that have been + // tested and have yet to pass the occlusion query and be drawn (or + // fail and be omitted). + class PendingNode { + public: + OctreeNode *_octree_node; + PT(OcclusionQueryContext) _query; + }; + typedef pdeque PendingNodes; + PendingNodes _pending_nodes; + + static PStatCollector _wait_occlusion_pcollector; + + static PT(Geom) _octree_solid_test; + static PT(Geom) _octree_wireframe_viz; + static CPT(RenderState) _octree_solid_test_state; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + CullBin::init_type(); + register_type(_type_handle, "CullBinHierarchicalZBuffer", + CullBin::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 OctreeNode; +}; + +#include "cullBinHierarchicalZBuffer.I" + +#endif + + + diff --git a/panda/src/cull/cullBinStateSorted.cxx b/panda/src/cull/cullBinStateSorted.cxx index 560d9cfb6c..5dc6b6efc7 100644 --- a/panda/src/cull/cullBinStateSorted.cxx +++ b/panda/src/cull/cullBinStateSorted.cxx @@ -18,7 +18,6 @@ #include "cullBinStateSorted.h" #include "graphicsStateGuardianBase.h" -#include "geometricBoundingVolume.h" #include "cullableObject.h" #include "cullHandler.h" #include "pStatTimer.h" diff --git a/panda/src/cull/cull_composite2.cxx b/panda/src/cull/cull_composite2.cxx index 4db9b57e2b..bcb7448e28 100644 --- a/panda/src/cull/cull_composite2.cxx +++ b/panda/src/cull/cull_composite2.cxx @@ -1,4 +1,5 @@ #include "cullBinFrontToBack.cxx" +#include "cullBinHierarchicalZBuffer.cxx" #include "cullBinStateSorted.cxx" #include "cullBinUnsorted.cxx" #include "drawCullHandler.cxx" diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index 233f6f200d..fa0ab258b3 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -593,17 +593,6 @@ get_global_gsg() { return _global_gsg; } - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::get_scene -// Access: Public -// Description: Returns the SceneSetup object. -//////////////////////////////////////////////////////////////////// -INLINE SceneSetup *GraphicsStateGuardian:: -get_scene() const { - return _scene_setup; -} - //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::reset_if_new // Access: Public diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index c489a67dbb..9067cd6e72 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -35,6 +35,7 @@ #include "geomLinestrips.h" #include "colorWriteAttrib.h" #include "shader.h" +#include "pnotify.h" #include #include @@ -137,6 +138,8 @@ GraphicsStateGuardian(const FrameBufferProperties &properties, _max_vertex_transforms = 0; _max_vertex_transform_indices = 0; + _supports_occlusion_query = false; + // Initially, we set this to false; a GSG that knows it has this // property should set it to true. _copy_texture_inverted = false; @@ -362,6 +365,16 @@ set_scene(SceneSetup *scene_setup) { return prepare_lens(); } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_scene +// Access: Public, Virtual +// Description: Returns the current SceneSetup object. +//////////////////////////////////////////////////////////////////// +SceneSetup *GraphicsStateGuardian:: +get_scene() const { + return _scene_setup; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::get_prepared_objects // Access: Public, Virtual @@ -511,6 +524,58 @@ void GraphicsStateGuardian:: release_index_buffer(IndexBufferContext *) { } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_supports_occlusion_query +// Access: Public, Virtual +// Description: Returns true if this GSG supports an occlusion query. +// If this is true, then begin_occlusion_query() and +// end_occlusion_query() may be called to bracket a +// sequence of draw_triangles() (or whatever) calls to +// measure pixels that pass the depth test. +//////////////////////////////////////////////////////////////////// +bool GraphicsStateGuardian:: +get_supports_occlusion_query() const { + return _supports_occlusion_query; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::begin_occlusion_query +// Access: Public, Virtual +// Description: Begins a new occlusion query. After this call, you +// may call begin_draw_primitives() and +// draw_triangles()/draw_whatever() repeatedly. +// Eventually, you should call end_occlusion_query() +// before the end of the frame; that will return a new +// OcclusionQueryContext object that will tell you how +// many pixels represented by the bracketed geometry +// passed the depth test. +// +// It is not valid to call begin_occlusion_query() +// between another begin_occlusion_query() +// .. end_occlusion_query() sequence. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +begin_occlusion_query() { + nassertv(_current_occlusion_query == (OcclusionQueryContext *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::end_occlusion_query +// Access: Public, Virtual +// Description: Ends a previous call to begin_occlusion_query(). +// This call returns the OcclusionQueryContext object +// that will (eventually) report the number of pixels +// that passed the depth test between the call to +// begin_occlusion_query() and end_occlusion_query(). +//////////////////////////////////////////////////////////////////// +PT(OcclusionQueryContext) GraphicsStateGuardian:: +end_occlusion_query() { + nassertr(_current_occlusion_query != (OcclusionQueryContext *)NULL, NULL); + PT(OcclusionQueryContext) result = _current_occlusion_query; + _current_occlusion_query = NULL; + return result; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::get_geom_munger // Access: Public diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 16dd44e6cd..cca5212306 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -45,6 +45,7 @@ #include "shaderContext.h" #include "bitMask.h" #include "texture.h" +#include "occlusionQueryContext.h" class DrawableRegion; class GraphicsEngine; @@ -132,7 +133,7 @@ PUBLISHED: public: bool set_scene(SceneSetup *scene_setup); - INLINE SceneSetup *get_scene() const; + virtual SceneSetup *get_scene() const; virtual PreparedGraphicsObjects *get_prepared_objects(); @@ -152,6 +153,10 @@ public: virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data); virtual void release_index_buffer(IndexBufferContext *ibc); + virtual bool get_supports_occlusion_query() const; + virtual void begin_occlusion_query(); + virtual PT(OcclusionQueryContext) end_occlusion_query(); + PT(GeomMunger) get_geom_munger(const RenderState *state); virtual PT(GeomMunger) make_geom_munger(const RenderState *state); @@ -338,6 +343,9 @@ protected: int _max_vertex_transforms; int _max_vertex_transform_indices; + bool _supports_occlusion_query; + PT(OcclusionQueryContext) _current_occlusion_query; + bool _copy_texture_inverted; bool _supports_multisample; bool _supports_generate_mipmap; diff --git a/panda/src/glstuff/Sources.pp b/panda/src/glstuff/Sources.pp index c71d13baf7..afe36d0021 100644 --- a/panda/src/glstuff/Sources.pp +++ b/panda/src/glstuff/Sources.pp @@ -13,36 +13,39 @@ #define INSTALL_HEADERS \ - panda_glext.h \ + glGeomContext_src.I \ + glGeomContext_src.cxx \ + glGeomContext_src.h \ + glGeomMunger_src.I \ + glGeomMunger_src.cxx \ + glGeomMunger_src.h \ + glGraphicsStateGuardian_src.I \ + glGraphicsStateGuardian_src.cxx \ + glGraphicsStateGuardian_src.h \ + glImmediateModeSender_src.I \ + glImmediateModeSender_src.cxx \ + glImmediateModeSender_src.h \ + glIndexBufferContext_src.I \ + glIndexBufferContext_src.cxx \ + glIndexBufferContext_src.h \ + glOcclusionQueryContext_src.I \ + glOcclusionQueryContext_src.cxx \ + glOcclusionQueryContext_src.h \ + glShaderContext_src.I \ + glShaderContext_src.cxx \ + glShaderContext_src.h \ + glTextureContext_src.I \ + glTextureContext_src.cxx \ + glTextureContext_src.h \ + glVertexBufferContext_src.I \ + glVertexBufferContext_src.cxx \ + glVertexBufferContext_src.h \ glmisc_src.cxx \ glmisc_src.h \ glstuff_src.cxx \ glstuff_src.h \ glstuff_undef_src.h \ - glVertexBufferContext_src.cxx \ - glVertexBufferContext_src.I \ - glVertexBufferContext_src.h \ - glImmediateModeSender_src.cxx \ - glImmediateModeSender_src.I \ - glImmediateModeSender_src.h \ - glIndexBufferContext_src.cxx \ - glIndexBufferContext_src.I \ - glIndexBufferContext_src.h \ - glGeomContext_src.cxx \ - glGeomContext_src.I \ - glGeomContext_src.h \ - glGeomMunger_src.cxx \ - glGeomMunger_src.I \ - glGeomMunger_src.h \ - glGraphicsStateGuardian_src.cxx \ - glGraphicsStateGuardian_src.I \ - glGraphicsStateGuardian_src.h \ - glTextureContext_src.cxx \ - glTextureContext_src.I \ - glTextureContext_src.h \ - glShaderContext_src.cxx \ - glShaderContext_src.h \ - glShaderContext_src.I \ + panda_glext.h #define SOURCES \ $[INSTALL_HEADERS] glpure.cxx diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 6cb2a3eefe..e4c5a2608c 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -721,11 +721,52 @@ reset() { } _glDrawBuffers = NULL; - if (has_extension("GL_ARB_draw_buffers")) { - _glDrawBuffers = (PFNGLDRAWBUFFERSARBPROC) + if (is_at_least_version(2, 0)) { + _glDrawBuffers = (PFNGLDRAWBUFFERSPROC) + get_extension_func(GLPREFIX_QUOTED, "DrawBuffers"); + } else if (has_extension("GL_ARB_draw_buffers")) { + _glDrawBuffers = (PFNGLDRAWBUFFERSPROC) get_extension_func(GLPREFIX_QUOTED, "DrawBuffersARB"); } + _supports_occlusion_query = false; + if (CLP(support_occlusion_query)) { + if (is_at_least_version(1, 5)) { + _supports_occlusion_query = true; + _glGenQueries = (PFNGLGENQUERIESPROC) + get_extension_func(GLPREFIX_QUOTED, "GenQueries"); + _glBeginQuery = (PFNGLBEGINQUERYPROC) + get_extension_func(GLPREFIX_QUOTED, "BeginQuery"); + _glEndQuery = (PFNGLENDQUERYPROC) + get_extension_func(GLPREFIX_QUOTED, "EndQuery"); + _glDeleteQueries = (PFNGLDELETEQUERIESPROC) + get_extension_func(GLPREFIX_QUOTED, "DeleteQueries"); + _glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) + get_extension_func(GLPREFIX_QUOTED, "GetQueryObjectuiv"); + } else if (has_extension("GL_ARB_occlusion_query")) { + _supports_occlusion_query = true; + _glGenQueries = (PFNGLGENQUERIESPROC) + get_extension_func(GLPREFIX_QUOTED, "GenQueriesARB"); + _glBeginQuery = (PFNGLBEGINQUERYPROC) + get_extension_func(GLPREFIX_QUOTED, "BeginQueryARB"); + _glEndQuery = (PFNGLENDQUERYPROC) + get_extension_func(GLPREFIX_QUOTED, "EndQueryARB"); + _glDeleteQueries = (PFNGLDELETEQUERIESPROC) + get_extension_func(GLPREFIX_QUOTED, "DeleteQueriesARB"); + _glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) + get_extension_func(GLPREFIX_QUOTED, "GetQueryObjectuivARB"); + } + } + + if (_supports_occlusion_query && + (_glGenQueries == NULL || _glBeginQuery == NULL || + _glEndQuery == NULL || _glDeleteQueries == NULL || + _glGetQueryObjectuiv == NULL)) { + GLCAT.warning() + << "Occlusion queries advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n"; + _supports_occlusion_query = false; + } + _glBlendEquation = NULL; bool supports_blend_equation = false; if (is_at_least_version(1, 2)) { @@ -1265,12 +1306,27 @@ end_frame() { ++ddli) { if (GLCAT.is_debug()) { GLCAT.debug() - << "releasing index " << (*ddli) << "\n"; + << "releasing display list index " << (*ddli) << "\n"; } GLP(DeleteLists)((*ddli), 1); } _deleted_display_lists.clear(); } + + // And deleted occlusion queries, too. + if (!_deleted_queries.empty()) { + DeletedDisplayLists::iterator ddli; + for (ddli = _deleted_queries.begin(); + ddli != _deleted_queries.end(); + ++ddli) { + if (GLCAT.is_debug()) { + GLCAT.debug() + << "releasing query index " << (*ddli) << "\n"; + } + _glDeleteQueries(1, &(*ddli)); + } + _deleted_queries.clear(); + } } { @@ -2845,6 +2901,53 @@ setup_primitive(const GeomPrimitive *data) { return NULL; } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::begin_occlusion_query +// Access: Public, Virtual +// Description: Begins a new occlusion query. After this call, you +// may call begin_draw_primitives() and +// draw_triangles()/draw_whatever() repeatedly. +// Eventually, you should call end_occlusion_query() +// before the end of the frame; that will return a new +// OcclusionQueryContext object that will tell you how +// many pixels represented by the bracketed geometry +// passed the depth test. +// +// It is not valid to call begin_occlusion_query() +// between another begin_occlusion_query() +// .. end_occlusion_query() sequence. +//////////////////////////////////////////////////////////////////// +void CLP(GraphicsStateGuardian):: +begin_occlusion_query() { + nassertv(_supports_occlusion_query); + nassertv(_current_occlusion_query == (OcclusionQueryContext *)NULL); + PT(CLP(OcclusionQueryContext)) query = new CLP(OcclusionQueryContext)(this); + + _glGenQueries(1, &query->_index); + _glBeginQuery(GL_SAMPLES_PASSED, query->_index); + + _current_occlusion_query = query; +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::end_occlusion_query +// Access: Public, Virtual +// Description: Ends a previous call to begin_occlusion_query(). +// This call returns the OcclusionQueryContext object +// that will (eventually) report the number of pixels +// that passed the depth test between the call to +// begin_occlusion_query() and end_occlusion_query(). +//////////////////////////////////////////////////////////////////// +PT(OcclusionQueryContext) CLP(GraphicsStateGuardian):: +end_occlusion_query() { + nassertr(_current_occlusion_query != (OcclusionQueryContext *)NULL, NULL); + PT(OcclusionQueryContext) result = _current_occlusion_query; + _current_occlusion_query = NULL; + _glEndQuery(GL_SAMPLES_PASSED); + + return result; +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::make_geom_munger // Access: Public, Virtual diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index ba0d66b237..c3a951e854 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -62,7 +62,7 @@ typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); -typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); @@ -82,8 +82,6 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { public: CLP(GraphicsStateGuardian)(const FrameBufferProperties &properties); virtual ~CLP(GraphicsStateGuardian)(); - friend class CLP(ShaderContext); - friend class CLP(GraphicsBuffer); virtual void reset(); @@ -131,6 +129,9 @@ public: virtual void release_index_buffer(IndexBufferContext *ibc); const unsigned char *setup_primitive(const GeomPrimitive *data); + virtual void begin_occlusion_query(); + virtual PT(OcclusionQueryContext) end_occlusion_query(); + virtual PT(GeomMunger) make_geom_munger(const RenderState *state); virtual void framebuffer_copy_to_texture @@ -424,7 +425,13 @@ public: PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC _glGetFramebufferAttachmentParameteriv; PFNGLGENERATEMIPMAPEXTPROC _glGenerateMipmap; - PFNGLDRAWBUFFERSARBPROC _glDrawBuffers; + PFNGLDRAWBUFFERSPROC _glDrawBuffers; + + PFNGLGENQUERIESPROC _glGenQueries; + PFNGLBEGINQUERYPROC _glBeginQuery; + PFNGLENDQUERYPROC _glEndQuery; + PFNGLDELETEQUERIESPROC _glDeleteQueries; + PFNGLGETQUERYOBJECTUIVPROC _glGetQueryObjectuiv; GLenum _edge_clamp; GLenum _border_clamp; @@ -436,6 +443,7 @@ public: Mutex _lock; typedef pvector DeletedDisplayLists; DeletedDisplayLists _deleted_display_lists; + DeletedDisplayLists _deleted_queries; static PStatCollector _load_display_list_pcollector; static PStatCollector _primitive_batches_display_list_pcollector; @@ -461,6 +469,10 @@ public: private: static TypeHandle _type_handle; + + friend class CLP(ShaderContext); + friend class CLP(GraphicsBuffer); + friend class CLP(OcclusionQueryContext); }; #include "glGraphicsStateGuardian_src.I" diff --git a/panda/src/glstuff/glmisc_src.cxx b/panda/src/glstuff/glmisc_src.cxx index e81e3cff34..084784142e 100644 --- a/panda/src/glstuff/glmisc_src.cxx +++ b/panda/src/glstuff/glmisc_src.cxx @@ -62,6 +62,13 @@ ConfigVariableBool CLP(color_mask) "is broken (some are). This will force the use of a (presumably) " "more expensive blending operation instead.")); +ConfigVariableBool CLP(support_occlusion_query) + ("gl-support-occlusion-query", true, + PRC_DESC("Configure this true to enable the use of the occlusion_query " + "extension if the GL claims to support it, or false not to " + "use it even if it appears to be available. (On some OpenGL " + "drivers, enabling this mode can force software rendering.)")); + ConfigVariableBool CLP(compile_and_execute) ("gl-compile-and-execute", false, PRC_DESC("Configure this true if you know your GL's implementation of " @@ -73,13 +80,14 @@ ConfigVariableBool CLP(compile_and_execute) "rendered at the same time it is being compiled.")); void CLP(init_classes)() { - CLP(GraphicsStateGuardian)::init_type(); - CLP(TextureContext)::init_type(); CLP(GeomContext)::init_type(); - CLP(VertexBufferContext)::init_type(); - CLP(IndexBufferContext)::init_type(); CLP(GeomMunger)::init_type(); + CLP(GraphicsStateGuardian)::init_type(); + CLP(IndexBufferContext)::init_type(); + CLP(OcclusionQueryContext)::init_type(); CLP(ShaderContext)::init_type(); + CLP(TextureContext)::init_type(); + CLP(VertexBufferContext)::init_type(); PandaSystem *ps = PandaSystem::get_global_ptr(); ps->add_system(GLSYSTEM_NAME); diff --git a/panda/src/glstuff/glmisc_src.h b/panda/src/glstuff/glmisc_src.h index c6c754b562..541f30daad 100644 --- a/panda/src/glstuff/glmisc_src.h +++ b/panda/src/glstuff/glmisc_src.h @@ -28,6 +28,7 @@ extern ConfigVariableBool CLP(ignore_filters); extern ConfigVariableBool CLP(ignore_mipmaps); extern ConfigVariableBool CLP(force_mipmaps); extern ConfigVariableBool CLP(color_mask); +extern ConfigVariableBool CLP(support_occlusion_query); extern ConfigVariableBool CLP(compile_and_execute); extern EXPCL_GL void CLP(init_classes)(); diff --git a/panda/src/glstuff/glstuff_src.cxx b/panda/src/glstuff/glstuff_src.cxx index 4f80933324..be36a927a8 100644 --- a/panda/src/glstuff/glstuff_src.cxx +++ b/panda/src/glstuff/glstuff_src.cxx @@ -25,6 +25,7 @@ #include "glTextureContext_src.cxx" #include "glVertexBufferContext_src.cxx" #include "glIndexBufferContext_src.cxx" +#include "glOcclusionQueryContext_src.cxx" #include "glGeomContext_src.cxx" #include "glGeomMunger_src.cxx" #include "glShaderContext_src.cxx" diff --git a/panda/src/glstuff/glstuff_src.h b/panda/src/glstuff/glstuff_src.h index 482ee5426f..5fb3c1871f 100644 --- a/panda/src/glstuff/glstuff_src.h +++ b/panda/src/glstuff/glstuff_src.h @@ -61,6 +61,7 @@ #include "glTextureContext_src.h" #include "glVertexBufferContext_src.h" #include "glIndexBufferContext_src.h" +#include "glOcclusionQueryContext_src.h" #include "glGeomContext_src.h" #include "glGeomMunger_src.h" #include "glShaderContext_src.h" diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index 4357fb678a..c21ac3bb19 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -41,10 +41,12 @@ internalName.I internalName.h \ material.I material.h materialPool.I materialPool.h \ matrixLens.I matrixLens.h \ + occlusionQueryContext.I occlusionQueryContext.h \ orthographicLens.I orthographicLens.h perspectiveLens.I \ perspectiveLens.h \ preparedGraphicsObjects.I preparedGraphicsObjects.h \ lens.h lens.I \ + queryContext.I queryContext.h \ savedContext.I savedContext.h \ shaderContext.h shaderContext.I \ shaderExpansion.h shaderExpansion.I \ @@ -93,10 +95,13 @@ indexBufferContext.cxx \ material.cxx \ internalName.cxx \ - materialPool.cxx matrixLens.cxx orthographicLens.cxx \ + materialPool.cxx matrixLens.cxx \ + occlusionQuery.cxx \ + orthographicLens.cxx \ perspectiveLens.cxx \ preparedGraphicsObjects.cxx \ lens.cxx \ + queryContext.cxx \ savedContext.cxx \ shaderContext.cxx \ shaderExpansion.cxx \ @@ -146,10 +151,12 @@ internalName.I internalName.h \ material.I material.h \ materialPool.I materialPool.h matrixLens.I matrixLens.h \ + occlusionQueryContext.I occlusionQueryContext.h \ orthographicLens.I orthographicLens.h perspectiveLens.I \ perspectiveLens.h \ preparedGraphicsObjects.I preparedGraphicsObjects.h \ lens.h lens.I \ + queryContext.I queryContext.h \ savedContext.I savedContext.h \ shaderContext.h shaderContext.I \ shaderExpansion.h shaderExpansion.I \ diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 0b515b7df5..489f1dca08 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -33,10 +33,12 @@ #include "geomVertexData.h" #include "geomVertexFormat.h" #include "material.h" +#include "occlusionQueryContext.h" #include "orthographicLens.h" #include "matrixLens.h" #include "perspectiveLens.h" #include "lens.h" +#include "queryContext.h" #include "sliderTable.h" #include "texture.h" #include "textureStage.h" @@ -263,10 +265,12 @@ ConfigureFn(config_gobj) { VertexBufferContext::init_type(); IndexBufferContext::init_type(); Material::init_type(); + OcclusionQueryContext::init_type(); OrthographicLens::init_type(); MatrixLens::init_type(); PerspectiveLens::init_type(); Lens::init_type(); + QueryContext::init_type(); SliderTable::init_type(); Texture::init_type(); TextureStage::init_type(); diff --git a/panda/src/gobj/gobj_composite2.cxx b/panda/src/gobj/gobj_composite2.cxx index 4a6b9dd52a..901fee2bda 100644 --- a/panda/src/gobj/gobj_composite2.cxx +++ b/panda/src/gobj/gobj_composite2.cxx @@ -1,4 +1,3 @@ - #include "config_gobj.cxx" #include "indexBufferContext.cxx" #include "internalName.cxx" @@ -6,9 +5,11 @@ #include "material.cxx" #include "materialPool.cxx" #include "matrixLens.cxx" +#include "occlusionQueryContext.cxx" #include "orthographicLens.cxx" #include "perspectiveLens.cxx" #include "preparedGraphicsObjects.cxx" +#include "queryContext.cxx" #include "savedContext.cxx" #include "sliderTable.cxx" #include "texture.cxx" diff --git a/panda/src/gobj/occlusionQueryContext.I b/panda/src/gobj/occlusionQueryContext.I new file mode 100644 index 0000000000..3907b8ca7d --- /dev/null +++ b/panda/src/gobj/occlusionQueryContext.I @@ -0,0 +1,27 @@ +// Filename: occlusionQueryContext.I +// Created by: drose (27Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: OcclusionQueryContext::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE OcclusionQueryContext:: +OcclusionQueryContext() { +} diff --git a/panda/src/gobj/occlusionQueryContext.cxx b/panda/src/gobj/occlusionQueryContext.cxx new file mode 100644 index 0000000000..5d603d5e8b --- /dev/null +++ b/panda/src/gobj/occlusionQueryContext.cxx @@ -0,0 +1,36 @@ +// Filename: occlusionQueryContext.cxx +// Created by: drose (27Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "occlusionQueryContext.h" + +TypeHandle OcclusionQueryContext::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: OcclusionQueryContext::get_num_fragments +// Access: Public, Virtual +// Description: Returns the number of fragments (pixels) of the +// specified geometry that passed the depth test. +// If is_answer_ready() did not return true, this +// function may block before it returns. +// +// It is only valid to call this from the draw thread. +//////////////////////////////////////////////////////////////////// +int OcclusionQueryContext:: +get_num_fragments() const { + return 0; +} diff --git a/panda/src/gobj/occlusionQueryContext.h b/panda/src/gobj/occlusionQueryContext.h new file mode 100644 index 0000000000..bce2360e76 --- /dev/null +++ b/panda/src/gobj/occlusionQueryContext.h @@ -0,0 +1,61 @@ +// Filename: occlusionQueryContext.h +// Created by: drose (27Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef OCCLUSIONQUERYCONTEXT_H +#define OCCLUSIONQUERYCONTEXT_H + +#include "pandabase.h" +#include "queryContext.h" + +//////////////////////////////////////////////////////////////////// +// Class : OcclusionQueryContext +// Description : Returned from a GSG in response to +// begin_occlusion_query() .. end_occlusion_query(), +// this records the number of fragments (pixels) that +// passed the depth test between the bracketing calls. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA OcclusionQueryContext : public QueryContext { +public: + INLINE OcclusionQueryContext(); + + virtual int get_num_fragments() const=0; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + QueryContext::init_type(); + register_type(_type_handle, "OcclusionQueryContext", + QueryContext::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 PreparedGraphicsObjects; +}; + +#include "occlusionQueryContext.I" + +#endif + diff --git a/panda/src/gobj/queryContext.I b/panda/src/gobj/queryContext.I new file mode 100644 index 0000000000..f85af51a3d --- /dev/null +++ b/panda/src/gobj/queryContext.I @@ -0,0 +1,27 @@ +// Filename: queryContext.I +// Created by: drose (27Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: QueryContext::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE QueryContext:: +QueryContext() { +} diff --git a/panda/src/gobj/queryContext.cxx b/panda/src/gobj/queryContext.cxx new file mode 100644 index 0000000000..42d72db12e --- /dev/null +++ b/panda/src/gobj/queryContext.cxx @@ -0,0 +1,57 @@ +// Filename: queryContext.cxx +// Created by: drose (27Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "queryContext.h" + +TypeHandle QueryContext::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: QueryContext::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +QueryContext:: +~QueryContext() { +} + +//////////////////////////////////////////////////////////////////// +// Function: QueryContext::is_answer_ready +// Access: Public, Virtual +// Description: Returns true if the query's answer is ready, false +// otherwise. If this returns false, the application +// must continue to poll until it returns true. +// +// It is only valid to call this from the draw thread. +//////////////////////////////////////////////////////////////////// +bool QueryContext:: +is_answer_ready() const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: QueryContext::waiting_for_answer +// Access: Public, Virtual +// Description: Requests the graphics engine to expedite the pending +// answer--the application is now waiting until the +// answer is ready. +// +// It is only valid to call this from the draw thread. +//////////////////////////////////////////////////////////////////// +void QueryContext:: +waiting_for_answer() { +} diff --git a/panda/src/gobj/queryContext.h b/panda/src/gobj/queryContext.h new file mode 100644 index 0000000000..fb5ae7a7d4 --- /dev/null +++ b/panda/src/gobj/queryContext.h @@ -0,0 +1,71 @@ +// Filename: queryContext.h +// Created by: drose (27Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef QUERYCONTEXT_H +#define QUERYCONTEXT_H + +#include "pandabase.h" +#include "typedReferenceCount.h" + +class PreparedGraphicsObjects; + +//////////////////////////////////////////////////////////////////// +// Class : QueryContext +// Description : This is a base class for queries that might require a +// round-trip to the graphics engine. The idea is that +// when you ask the GSG to make a particular query, it +// returns a QueryContext, which does not necessarily +// have the answer right away (but it will eventually). +// +// Unlike SavedContext, QueryContext is +// reference-counted. It removes itself from the GSG +// when the last reference goes away. You're +// responsible for keeping the pointer to the +// QueryContext as long as you are interested in the +// answer. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA QueryContext : public TypedReferenceCount { +public: + INLINE QueryContext(); + virtual ~QueryContext(); + + virtual bool is_answer_ready() const=0; + virtual void waiting_for_answer(); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedReferenceCount::init_type(); + register_type(_type_handle, "QueryContext", + TypedReferenceCount::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 "queryContext.I" + +#endif + diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index f1139d1fae..a160c21625 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -32,6 +32,7 @@ class NodePath; class VertexBufferContext; class IndexBufferContext; +class OcclusionQueryContext; class GeomContext; class GeomNode; class Geom; @@ -57,6 +58,7 @@ class GeomLinestrips; class GeomPoints; class GeomMunger; +class SceneSetup; class PreparedGraphicsObjects; class GraphicsOutput; class Texture; @@ -118,11 +120,13 @@ class EXPCL_PANDA GraphicsStateGuardianBase : public TypedWritableReferenceCount PUBLISHED: virtual bool get_supports_multisample() const=0; virtual int get_supported_geom_rendering() const=0; + virtual bool get_supports_occlusion_query() const=0; public: // These are some general interface functions; they're defined here // mainly to make it easy to call these from code in some directory // that display depends on. + virtual SceneSetup *get_scene() const=0; virtual PreparedGraphicsObjects *get_prepared_objects()=0; virtual TextureContext *prepare_texture(Texture *tex)=0; @@ -140,6 +144,9 @@ public: virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data)=0; virtual void release_index_buffer(IndexBufferContext *ibc)=0; + virtual void begin_occlusion_query()=0; + virtual PT(OcclusionQueryContext) end_occlusion_query()=0; + virtual PT(GeomMunger) get_geom_munger(const RenderState *state)=0; virtual void set_state_and_transform(const RenderState *state, diff --git a/panda/src/pgraph/colorWriteAttrib.h b/panda/src/pgraph/colorWriteAttrib.h index 57312a851a..809201afda 100644 --- a/panda/src/pgraph/colorWriteAttrib.h +++ b/panda/src/pgraph/colorWriteAttrib.h @@ -41,6 +41,7 @@ PUBLISHED: C_red = 0x001, C_green = 0x002, C_blue = 0x004, + C_rgb = 0x007, // == C_red | C_green | C_blue C_alpha = 0x008, C_all = 0x00f, }; diff --git a/panda/src/pgraph/cullBinManager.cxx b/panda/src/pgraph/cullBinManager.cxx index 20180a06dc..5aba1e412a 100644 --- a/panda/src/pgraph/cullBinManager.cxx +++ b/panda/src/pgraph/cullBinManager.cxx @@ -338,23 +338,17 @@ parse_bin_type(const string &bin_type) { } else if (cmp_nocase_uh(bin_type, "state_sorted") == 0) { return BT_state_sorted; - } else if (cmp_nocase_uh(bin_type, "statesorted") == 0) { - return BT_state_sorted; - } else if (cmp_nocase_uh(bin_type, "fixed") == 0) { return BT_fixed; } else if (cmp_nocase_uh(bin_type, "back_to_front") == 0) { return BT_back_to_front; - } else if (cmp_nocase_uh(bin_type, "backtofront") == 0) { - return BT_back_to_front; - } else if (cmp_nocase_uh(bin_type, "front_to_back") == 0) { return BT_front_to_back; - } else if (cmp_nocase_uh(bin_type, "fronttoback") == 0) { - return BT_front_to_back; + } else if (cmp_nocase_uh(bin_type, "hierarchical_z") == 0) { + return BT_hierarchical_z; } else { return BT_invalid; @@ -385,6 +379,9 @@ operator << (ostream &out, CullBinManager::BinType bin_type) { case CullBinManager::BT_fixed: return out << "fixed"; + + case CullBinManager::BT_hierarchical_z: + return out << "hierarchical_z"; } return out << "**invalid BinType(" << (int)bin_type << ")**"; diff --git a/panda/src/pgraph/cullBinManager.h b/panda/src/pgraph/cullBinManager.h index eb0de927e3..a5eb0352c7 100644 --- a/panda/src/pgraph/cullBinManager.h +++ b/panda/src/pgraph/cullBinManager.h @@ -47,6 +47,7 @@ PUBLISHED: BT_back_to_front, BT_front_to_back, BT_fixed, + BT_hierarchical_z, }; int add_bin(const string &name, BinType type, int sort); diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index d10eabf366..813dfce307 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -86,6 +86,10 @@ public: CPT(TransformState) _modelview_transform; CullableObject *_next; + // This flag is only used by certain CullBin types. In particular, + // it is used by CullBinHierarchicalZBuffer. + bool _already_drawn; + private: void munge_points_to_quads(const CullTraverser *traverser); void munge_texcoord_light_vector(const CullTraverser *traverser); diff --git a/panda/src/pgraph/portalNode.cxx b/panda/src/pgraph/portalNode.cxx index 93073e827a..4a6141975f 100755 --- a/panda/src/pgraph/portalNode.cxx +++ b/panda/src/pgraph/portalNode.cxx @@ -99,9 +99,9 @@ PortalNode(const PortalNode ©) : _vertices(copy._vertices), _cell_in(copy._cell_in), _cell_out(copy._cell_out), + _clip_plane(copy._clip_plane), _visible(copy._visible), - _open(copy._open), - _clip_plane(copy._clip_plane) + _open(copy._open) { }