add set_priority() to Light, PlaneNode

This commit is contained in:
David Rose 2005-07-12 01:08:02 +00:00
parent 4589c7da34
commit 512acd4adf
30 changed files with 558 additions and 163 deletions

View File

@ -233,6 +233,38 @@ get_max_cube_map_dimension() const {
return _max_cube_map_dimension;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_max_lights
// Access: Published
// Description: Returns the maximum number of simultaneous lights
// that may be rendered on geometry, or -1 if there is
// no particular limit.
//
// The value returned may not be meaningful until after
// the graphics context has been fully created (e.g. the
// window has been opened).
////////////////////////////////////////////////////////////////////
INLINE int GraphicsStateGuardian::
get_max_lights() const {
return _max_lights;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_max_clip_planes
// Access: Published
// Description: Returns the maximum number of simultaneous clip planes
// that may be applied to geometry, or -1 if there is
// no particular limit.
//
// The value returned may not be meaningful until after
// the graphics context has been fully created (e.g. the
// window has been opened).
////////////////////////////////////////////////////////////////////
INLINE int GraphicsStateGuardian::
get_max_clip_planes() const {
return _max_clip_planes;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_max_vertex_transforms
// Access: Published

View File

@ -120,6 +120,10 @@ GraphicsStateGuardian(const FrameBufferProperties &properties,
_max_3d_texture_dimension = 0;
_max_cube_map_dimension = 0;
// Assume no limits on number of lights or clip planes.
_max_lights = -1;
_max_clip_planes = -1;
// Assume no vertex blending capability.
_max_vertex_transforms = 0;
_max_vertex_transform_indices = 0;
@ -1163,23 +1167,25 @@ issue_texture(const TextureAttrib *attrib) {
// Function: GraphicsStateGuardian::issue_clip_plane
// Access: Public, Virtual
// Description: This is fundametically similar to issue_light(), with
// calls to slot_new_clip_plane(), apply_clip_plane(),
// and enable_clip_planes(), as appropriate.
// calls to apply_clip_plane() and enable_clip_planes(),
// as appropriate.
////////////////////////////////////////////////////////////////////
void GraphicsStateGuardian::
issue_clip_plane(const ClipPlaneAttrib *attrib) {
int i;
int max_planes = (int)_clip_plane_info.size();
for (i = 0; i < max_planes; i++) {
int cur_max_planes = (int)_clip_plane_info.size();
for (i = 0; i < cur_max_planes; i++) {
_clip_plane_info[i]._next_enabled = false;
}
CPT(ClipPlaneAttrib) new_attrib = attrib->filter_to_max(_max_clip_planes);
bool any_bound = false;
int num_enabled = 0;
int num_on_planes = attrib->get_num_on_planes();
int num_on_planes = new_attrib->get_num_on_planes();
for (int li = 0; li < num_on_planes; li++) {
NodePath plane = attrib->get_on_plane(li);
NodePath plane = new_attrib->get_on_plane(li);
nassertv(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()));
num_enabled++;
@ -1191,7 +1197,7 @@ issue_clip_plane(const ClipPlaneAttrib *attrib) {
// Check to see if this plane has already been bound to an id
int cur_plane_id = -1;
for (i = 0; i < max_planes; i++) {
for (i = 0; i < cur_max_planes; i++) {
if (_clip_plane_info[i]._plane == plane) {
// Plane has already been bound to an id, we only need to
// enable the plane, not reapply it.
@ -1205,7 +1211,7 @@ issue_clip_plane(const ClipPlaneAttrib *attrib) {
// See if there are any unbound plane ids
if (cur_plane_id == -1) {
for (i = 0; i < max_planes; i++) {
for (i = 0; i < cur_max_planes; i++) {
if (_clip_plane_info[i]._plane.is_empty()) {
_clip_plane_info[i]._plane = plane;
cur_plane_id = i;
@ -1217,8 +1223,8 @@ issue_clip_plane(const ClipPlaneAttrib *attrib) {
// If there were no unbound plane ids, see if we can replace
// a currently unused but previously bound id
if (cur_plane_id == -1) {
for (i = 0; i < max_planes; i++) {
if (!attrib->has_on_plane(_clip_plane_info[i]._plane)) {
for (i = 0; i < cur_max_planes; i++) {
if (!new_attrib->has_on_plane(_clip_plane_info[i]._plane)) {
_clip_plane_info[i]._plane = plane;
cur_plane_id = i;
break;
@ -1228,11 +1234,11 @@ issue_clip_plane(const ClipPlaneAttrib *attrib) {
// If we *still* don't have a plane id, slot a new one.
if (cur_plane_id == -1) {
if (slot_new_clip_plane(max_planes)) {
cur_plane_id = max_planes;
if (_max_clip_planes < 0 || cur_max_planes < _max_clip_planes) {
cur_plane_id = cur_max_planes;
_clip_plane_info.push_back(ClipPlaneInfo());
max_planes++;
nassertv(max_planes == (int)_clip_plane_info.size());
cur_max_planes++;
nassertv(cur_max_planes == (int)_clip_plane_info.size());
}
}
@ -1257,7 +1263,7 @@ issue_clip_plane(const ClipPlaneAttrib *attrib) {
}
// Disable all unused planes
for (i = 0; i < max_planes; i++) {
for (i = 0; i < cur_max_planes; i++) {
if (!_clip_plane_info[i]._next_enabled) {
enable_clip_plane(i, false);
_clip_plane_info[i]._enabled = false;
@ -1321,8 +1327,8 @@ bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
// light associated with the same id where possible, but
// reusing id's when necessary. When it is no longer
// possible to reuse existing id's (e.g. all id's are in
// use), slot_new_light() is called to prepare the next
// sequential light id.
// use), the next sequential id is assigned (if
// available).
//
// It will call apply_light() each time a light is
// assigned to a particular id for the first time in a
@ -1337,8 +1343,8 @@ do_issue_light() {
// light list
Colorf cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
int i;
int max_lights = (int)_light_info.size();
for (i = 0; i < max_lights; i++) {
int cur_max_lights = (int)_light_info.size();
for (i = 0; i < cur_max_lights; i++) {
_light_info[i]._next_enabled = false;
}
@ -1346,9 +1352,11 @@ do_issue_light() {
int num_enabled = 0;
if (_pending_light != (LightAttrib *)NULL) {
int num_on_lights = _pending_light->get_num_on_lights();
CPT(LightAttrib) new_light = _pending_light->filter_to_max(_max_lights);
int num_on_lights = new_light->get_num_on_lights();
for (int li = 0; li < num_on_lights; li++) {
NodePath light = _pending_light->get_on_light(li);
NodePath light = new_light->get_on_light(li);
nassertv(!light.is_empty() && light.node()->as_light() != (Light *)NULL);
Light *light_obj = light.node()->as_light();
@ -1367,7 +1375,7 @@ do_issue_light() {
} else {
// Check to see if this light has already been bound to an id
int cur_light_id = -1;
for (i = 0; i < max_lights; i++) {
for (i = 0; i < cur_max_lights; i++) {
if (_light_info[i]._light == light) {
// Light has already been bound to an id; reuse the same id.
cur_light_id = -2;
@ -1386,7 +1394,7 @@ do_issue_light() {
// See if there are any unbound light ids
if (cur_light_id == -1) {
for (i = 0; i < max_lights; i++) {
for (i = 0; i < cur_max_lights; i++) {
if (_light_info[i]._light.is_empty()) {
_light_info[i]._light = light;
cur_light_id = i;
@ -1398,8 +1406,8 @@ do_issue_light() {
// If there were no unbound light ids, see if we can replace
// a currently unused but previously bound id
if (cur_light_id == -1) {
for (i = 0; i < max_lights; i++) {
if (!_pending_light->has_on_light(_light_info[i]._light)) {
for (i = 0; i < cur_max_lights; i++) {
if (!new_light->has_on_light(_light_info[i]._light)) {
_light_info[i]._light = light;
cur_light_id = i;
break;
@ -1409,11 +1417,11 @@ do_issue_light() {
// If we *still* don't have a light id, slot a new one.
if (cur_light_id == -1) {
if (slot_new_light(max_lights)) {
cur_light_id = max_lights;
if (_max_lights < 0 || cur_max_lights < _max_lights) {
cur_light_id = cur_max_lights;
_light_info.push_back(LightInfo());
max_lights++;
nassertv(max_lights == (int)_light_info.size());
cur_max_lights++;
nassertv(cur_max_lights == (int)_light_info.size());
}
}
@ -1440,7 +1448,7 @@ do_issue_light() {
}
// Disable all unused lights
for (i = 0; i < max_lights; i++) {
for (i = 0; i < cur_max_lights; i++) {
if (!_light_info[i]._next_enabled) {
enable_light(i, false);
_light_info[i]._enabled = false;
@ -1491,24 +1499,6 @@ void GraphicsStateGuardian::
do_issue_texture() {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::slot_new_light
// Access: Protected, Virtual
// Description: This will be called by the base class before a
// particular light id will be used for the first time.
// It is intended to allow the derived class to reserve
// any additional resources, if required, for the new
// light; and also to indicate whether the hardware
// supports this many simultaneous lights.
//
// The return value should be true if the additional
// light is supported, or false if it is not.
////////////////////////////////////////////////////////////////////
bool GraphicsStateGuardian::
slot_new_light(int light_id) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::enable_lighting
// Access: Protected, Virtual
@ -1573,25 +1563,6 @@ void GraphicsStateGuardian::
end_bind_lights() {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::slot_new_clip_plane
// Access: Protected, Virtual
// Description: This will be called by the base class before a
// particular clip plane id will be used for the first
// time. It is intended to allow the derived class to
// reserve any additional resources, if required, for
// the new clip plane; and also to indicate whether the
// hardware supports this many simultaneous clipping
// planes.
//
// The return value should be true if the additional
// plane is supported, or false if it is not.
////////////////////////////////////////////////////////////////////
bool GraphicsStateGuardian::
slot_new_clip_plane(int plane_id) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::enable_clip_planes
// Access: Protected, Virtual

View File

@ -94,6 +94,9 @@ PUBLISHED:
INLINE int get_max_3d_texture_dimension() const;
INLINE int get_max_cube_map_dimension() const;
INLINE int get_max_lights() const;
INLINE int get_max_clip_planes() const;
INLINE int get_max_vertex_transforms() const;
INLINE int get_max_vertex_transform_indices() const;
@ -225,7 +228,6 @@ protected:
virtual void do_issue_texture();
INLINE NodePath get_light(int light_id) const;
virtual bool slot_new_light(int light_id);
virtual void enable_lighting(bool enable);
virtual void set_ambient_light(const Colorf &color);
virtual void enable_light(int light_id, bool enable);
@ -233,7 +235,6 @@ protected:
virtual void end_bind_lights();
INLINE NodePath get_clip_plane(int plane_id) const;
virtual bool slot_new_clip_plane(int plane_id);
virtual void enable_clip_planes(bool enable);
virtual void enable_clip_plane(int plane_id, bool enable);
virtual void begin_bind_clip_planes();
@ -361,6 +362,9 @@ protected:
int _max_3d_texture_dimension;
int _max_cube_map_dimension;
int _max_lights;
int _max_clip_planes;
int _max_vertex_transforms;
int _max_vertex_transform_indices;

View File

@ -1509,8 +1509,8 @@ reset() {
}
_max_texture_stages = d3d_caps.MaxSimultaneousTextures;
_max_lights = d3d_caps.MaxActiveLights;
_max_clip_planes = d3d_caps.MaxUserClipPlanes;
_max_lights = (int)d3d_caps.MaxActiveLights;
_max_clip_planes = (int)d3d_caps.MaxUserClipPlanes;
_max_vertex_transforms = d3d_caps.MaxVertexBlendMatrices;
_max_vertex_transform_indices = d3d_caps.MaxVertexBlendMatrixIndex;
@ -2293,24 +2293,6 @@ do_issue_texture() {
_current_texture = new_texture;
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian8::slot_new_light
// Access: Protected, Virtual
// Description: This will be called by the base class before a
// particular light id will be used for the first time.
// It is intended to allow the derived class to reserve
// any additional resources, if required, for the new
// light; and also to indicate whether the hardware
// supports this many simultaneous lights.
//
// The return value should be true if the additional
// light is supported, or false if it is not.
////////////////////////////////////////////////////////////////////
bool DXGraphicsStateGuardian8::
slot_new_light(int light_id) {
return ((unsigned int)light_id < _max_lights);
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian8::enable_lighting
// Access: Protected, Virtual
@ -2361,25 +2343,6 @@ enable_light(int light_id, bool enable) {
}
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian8::slot_new_clip_plane
// Access: Protected, Virtual
// Description: This will be called by the base class before a
// particular clip plane id will be used for the first
// time. It is intended to allow the derived class to
// reserve any additional resources, if required, for
// the new clip plane; and also to indicate whether the
// hardware supports this many simultaneous clipping
// planes.
//
// The return value should be true if the additional
// plane is supported, or false if it is not.
////////////////////////////////////////////////////////////////////
bool DXGraphicsStateGuardian8::
slot_new_clip_plane(int plane_id) {
return ((unsigned int)plane_id < _max_clip_planes);
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian8::enable_clip_plane
// Access: Protected, Virtual

View File

@ -121,12 +121,10 @@ protected:
virtual void do_issue_material();
virtual void do_issue_texture();
virtual bool slot_new_light(int light_id);
virtual void enable_lighting(bool enable);
virtual void set_ambient_light(const Colorf &color);
virtual void enable_light(int light_id, bool enable);
virtual bool slot_new_clip_plane(int plane_id);
virtual void enable_clip_plane(int plane_id, bool enable);
virtual void bind_clip_plane(const NodePath &plane, int plane_id);
@ -223,9 +221,6 @@ protected:
D3DBLEND _blend_source_func;
D3DBLEND _blend_dest_func;
unsigned int _max_lights;
unsigned int _max_clip_planes;
bool _color_material_enabled;
bool _texturing_enabled;
bool _dither_enabled;

View File

@ -3795,24 +3795,6 @@ get_light_color(Light *light) const {
return c.get_data();
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::slot_new_light
// Access: Protected, Virtual
// Description: This will be called by the base class before a
// particular light id will be used for the first time.
// It is intended to allow the derived class to reserve
// any additional resources, if required, for the new
// light; and also to indicate whether the hardware
// supports this many simultaneous lights.
//
// The return value should be true if the additional
// light is supported, or false if it is not.
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
slot_new_light(int light_id) {
return (light_id < _max_lights);
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::enable_lighting
// Access: Protected, Virtual
@ -3908,25 +3890,6 @@ end_bind_lights() {
GLP(PopMatrix)();
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::slot_new_clip_plane
// Access: Protected, Virtual
// Description: This will be called by the base class before a
// particular clip plane id will be used for the first
// time. It is intended to allow the derived class to
// reserve any additional resources, if required, for
// the new clip plane; and also to indicate whether the
// hardware supports this many simultaneous clipping
// planes.
//
// The return value should be true if the additional
// plane is supported, or false if it is not.
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
slot_new_clip_plane(int plane_id) {
return (plane_id < _max_clip_planes);
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::enable_clip_plane
// Access: Protected, Virtual

View File

@ -170,14 +170,12 @@ protected:
bool is_at_least_version(int major_version, int minor_version, int release_version = 0) const;
virtual void *get_extension_func(const char *prefix, const char *name);
virtual bool slot_new_light(int light_id);
virtual void enable_lighting(bool enable);
virtual void set_ambient_light(const Colorf &color);
virtual void enable_light(int light_id, bool enable);
virtual void begin_bind_lights();
virtual void end_bind_lights();
virtual bool slot_new_clip_plane(int plane_id);
virtual void enable_clip_plane(int plane_id, bool enable);
virtual void begin_bind_clip_planes();
virtual void bind_clip_plane(const NodePath &plane, int plane_id);
@ -284,9 +282,6 @@ protected:
bool _dithering_enabled;
bool _texgen_forced_normal;
int _max_lights;
int _max_clip_planes;
LMatrix4f _projection_mat;
int _viewport_width;
int _viewport_height;

View File

@ -617,7 +617,7 @@ get_default() {
////////////////////////////////////////////////////////////////////
// Function: TextureStage::get_sort_seq
// Access: Published, Static
// Access: Public, Static
// Description: Returns a global sequence number that is incremented
// any time any TextureStage in the world changes sort
// or priority. This is used by TextureAttrib to

View File

@ -158,6 +158,8 @@ PUBLISHED:
void output(ostream &out) const;
INLINE static TextureStage *get_default();
public:
INLINE static UpdateSeq get_sort_seq();
private:

View File

@ -48,6 +48,21 @@ AmbientLight(const AmbientLight &copy) :
{
}
////////////////////////////////////////////////////////////////////
// Function: AmbientLight::get_class_priority
// Access: Published, Virtual
// Description: Returns the relative priority associated with all
// lights of this class. This priority is used to order
// lights whose instance priority (get_priority()) is
// the same--the idea is that other things being equal,
// AmbientLights (for instance) are less important than
// DirectionalLights.
////////////////////////////////////////////////////////////////////
int AmbientLight::
get_class_priority() const {
return (int)CP_ambient_priority;
}
////////////////////////////////////////////////////////////////////
// Function: AmbientLight::make_copy
// Access: Public, Virtual

View File

@ -40,6 +40,9 @@ protected:
public:
virtual PandaNode *make_copy() const;
virtual void write(ostream &out, int indent_level) const;
PUBLISHED:
virtual int get_class_priority() const;
public:
virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,

View File

@ -133,3 +133,20 @@ INLINE bool ClipPlaneAttrib::
is_identity() const {
return _on_planes.empty() && _off_planes.empty() && !_off_all_planes;
}
////////////////////////////////////////////////////////////////////
// Function: ClipPlaneAttrib::check_filtered
// Access: Private
// Description: Confirms whether the _filtered table is still valid.
// It may become invalid if someone calls
// PlaneNode::set_priority().
//
// If the table is invalid, transparently empties it
// before returning.
////////////////////////////////////////////////////////////////////
INLINE void ClipPlaneAttrib::
check_filtered() const {
if (_sort_seq != PlaneNode::get_sort_seq()) {
((ClipPlaneAttrib *)this)->sort_on_planes();
}
}

View File

@ -29,6 +29,20 @@ CPT(RenderAttrib) ClipPlaneAttrib::_empty_attrib;
CPT(RenderAttrib) ClipPlaneAttrib::_all_off_attrib;
TypeHandle ClipPlaneAttrib::_type_handle;
// This STL Function object is used in filter_to_max(), below, to sort
// a list of PlaneNodes in reverse order by priority.
class ComparePlaneNodePriorities {
public:
bool operator ()(const NodePath &a, const NodePath &b) const {
nassertr(!a.is_empty() && !b.is_empty(), a < b);
PlaneNode *pa = DCAST(PlaneNode, a.node());
PlaneNode *pb = DCAST(PlaneNode, b.node());
nassertr(pa != (PlaneNode *)NULL && pb != (PlaneNode *)NULL, a < b);
return pa->get_priority() > pb->get_priority();
}
};
////////////////////////////////////////////////////////////////////
// Function: ClipPlaneAttrib::make
// Access: Published, Static
@ -447,6 +461,61 @@ remove_off_plane(const NodePath &plane) const {
return return_new(attrib);
}
////////////////////////////////////////////////////////////////////
// Function: ClipPlaneAttrib::filter_to_max
// Access: Public
// Description: Returns a new ClipPlaneAttrib, very much like this one,
// but with the number of on_planes reduced to be no
// more than max_clip_planes. The number of off_planes in
// the new ClipPlaneAttrib is undefined.
////////////////////////////////////////////////////////////////////
CPT(ClipPlaneAttrib) ClipPlaneAttrib::
filter_to_max(int max_clip_planes) const {
if (max_clip_planes < 0 || (int)_on_planes.size() <= max_clip_planes) {
// Trivial case: this ClipPlaneAttrib qualifies.
return this;
}
// Since check_filtered() will clear the _filtered list if we are out
// of date, we should call it first.
check_filtered();
Filtered::const_iterator fi;
fi = _filtered.find(max_clip_planes);
if (fi != _filtered.end()) {
// Easy case: we have already computed this for this particular
// ClipPlaneAttrib.
return (*fi).second;
}
// Harder case: we have to compute it now. We must choose the n
// planeNodes with the highest priority in our list of planeNodes.
Planes priority_planes = _on_planes;
// This sort function uses the STL function object defined above.
sort(priority_planes.begin(), priority_planes.end(),
ComparePlaneNodePriorities());
// Now lop off all of the planeNodes after the first max_clip_planes.
priority_planes.erase(priority_planes.begin() + max_clip_planes,
priority_planes.end());
// And re-sort the ov_set into its proper order.
priority_planes.sort();
// Now create a new attrib reflecting these planeNodes.
PT(ClipPlaneAttrib) attrib = new ClipPlaneAttrib;
attrib->_on_planes.swap(priority_planes);
CPT(RenderAttrib) new_attrib = return_new(attrib);
// Finally, record this newly-created attrib in the map for next
// time.
CPT(ClipPlaneAttrib) planeNode_attrib = (const ClipPlaneAttrib *)new_attrib.p();
((ClipPlaneAttrib *)this)->_filtered[max_clip_planes] = planeNode_attrib;
return planeNode_attrib;
}
////////////////////////////////////////////////////////////////////
// Function: ClipPlaneAttrib::issue
// Access: Public, Virtual
@ -749,6 +818,20 @@ make_default_impl() const {
return new ClipPlaneAttrib;
}
////////////////////////////////////////////////////////////////////
// Function: ClipPlaneAttrib::sort_on_planes
// Access: Private
// Description: This is patterned after
// TextureAttrib::sort_on_stages(), but since planeNodes
// don't actually require sorting, this only empties the
// _filtered map.
////////////////////////////////////////////////////////////////////
void ClipPlaneAttrib::
sort_on_planes() {
_sort_seq = PlaneNode::get_sort_seq();
_filtered.clear();
}
////////////////////////////////////////////////////////////////////
// Function: ClipPlaneAttrib::register_with_read_factory
// Access: Public, Static

View File

@ -23,8 +23,9 @@
#include "planeNode.h"
#include "renderAttrib.h"
#include "ordered_vector.h"
#include "nodePath.h"
#include "ordered_vector.h"
#include "pmap.h"
////////////////////////////////////////////////////////////////////
// Class : ClipPlaneAttrib
@ -92,6 +93,8 @@ PUBLISHED:
CPT(RenderAttrib) add_off_plane(const NodePath &plane) const;
CPT(RenderAttrib) remove_off_plane(const NodePath &plane) const;
CPT(ClipPlaneAttrib) filter_to_max(int max_clip_planes) const;
public:
virtual void issue(GraphicsStateGuardianBase *gsg) const;
virtual void output(ostream &out) const;
@ -102,10 +105,19 @@ protected:
virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const;
virtual RenderAttrib *make_default_impl() const;
private:
INLINE void check_filtered() const;
void sort_on_planes();
private:
typedef ov_set<NodePath> Planes;
Planes _on_planes, _off_planes;
bool _off_all_planes;
typedef pmap< int, CPT(ClipPlaneAttrib) > Filtered;
Filtered _filtered;
UpdateSeq _sort_seq;
static CPT(RenderAttrib) _empty_attrib;
static CPT(RenderAttrib) _all_off_attrib;

View File

@ -159,6 +159,21 @@ get_vector_to_light(LVector3f &result, const LPoint3f &,
return true;
}
////////////////////////////////////////////////////////////////////
// Function: DirectionalLight::get_class_priority
// Access: Published, Virtual
// Description: Returns the relative priority associated with all
// lights of this class. This priority is used to order
// lights whose instance priority (get_priority()) is
// the same--the idea is that other things being equal,
// AmbientLights (for instance) are less important than
// DirectionalLights.
////////////////////////////////////////////////////////////////////
int DirectionalLight::
get_class_priority() const {
return (int)CP_directional_priority;
}
////////////////////////////////////////////////////////////////////
// Function: DirectionalLight::bind
// Access: Public, Virtual

View File

@ -53,6 +53,8 @@ PUBLISHED:
INLINE const LVector3f &get_direction() const;
INLINE void set_direction(const LVector3f &direction);
virtual int get_class_priority() const;
public:
virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,

View File

@ -48,7 +48,9 @@ CData(const Light::CData &copy) :
// Description:
////////////////////////////////////////////////////////////////////
INLINE Light::
Light() {
Light() :
_priority(0)
{
}
////////////////////////////////////////////////////////////////////
@ -58,6 +60,7 @@ Light() {
////////////////////////////////////////////////////////////////////
INLINE Light::
Light(const Light &copy) :
_priority(copy._priority),
_cycler(copy._cycler)
{
}
@ -85,9 +88,58 @@ set_color(const Colorf &color) {
mark_viz_stale();
}
////////////////////////////////////////////////////////////////////
// Function: Light::set_priority
// Access: Published
// Description: Changes the relative importance of this light
// relative to the other lights that are applied
// simultaneously.
//
// The priority number is used to decide which of the
// requested lights are to be selected for rendering
// when more lights are requested than the hardware will
// support. The highest-priority n lights are selected
// for rendering.
//
// This is similar to TextureStage::set_priority().
////////////////////////////////////////////////////////////////////
INLINE void Light::
set_priority(int priority) {
_priority = priority;
// Update the global flag to indicate that all LightAttribs in the
// world must now re-sort their lists.
_sort_seq++;
}
////////////////////////////////////////////////////////////////////
// Function: Light::get_priority
// Access: Published
// Description: Returns the priority associated with this light. See
// set_priority().
////////////////////////////////////////////////////////////////////
INLINE int Light::
get_priority() const {
return _priority;
}
////////////////////////////////////////////////////////////////////
// Function: Light::get_sort_seq
// Access: Public, Static
// Description: Returns a global sequence number that is incremented
// any time any Light in the world changes sort
// or priority. This is used by LightAttrib to
// determine when it is necessary to re-sort its
// internal array of stages.
////////////////////////////////////////////////////////////////////
INLINE UpdateSeq Light::
get_sort_seq() {
return _sort_seq;
}
////////////////////////////////////////////////////////////////////
// Function: Light::mark_viz_stale
// Access: Public
// Access: Protected
// Description: Indicates that the internal visualization object will
// need to be updated.
////////////////////////////////////////////////////////////////////

View File

@ -22,6 +22,8 @@
#include "datagram.h"
#include "datagramIterator.h"
UpdateSeq Light::_sort_seq;
TypeHandle Light::_type_handle;
@ -128,6 +130,7 @@ fill_viz_geom(GeomNode *) {
void Light::
write_datagram(BamWriter *manager, Datagram &dg) {
manager->write_cdata(dg, _cycler);
dg.add_int32(_priority);
}
////////////////////////////////////////////////////////////////////
@ -140,4 +143,5 @@ write_datagram(BamWriter *manager, Datagram &dg) {
void Light::
fillin(DatagramIterator &scan, BamReader *manager) {
manager->read_cdata(scan, _cycler);
_priority = scan.get_int32();
}

View File

@ -27,6 +27,7 @@
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "pipelineCycler.h"
#include "updateSeq.h"
#include "geomNode.h"
class NodePath;
@ -56,6 +57,10 @@ PUBLISHED:
INLINE const Colorf &get_color() const;
INLINE void set_color(const Colorf &color);
INLINE void set_priority(int priority);
INLINE int get_priority() const;
virtual int get_class_priority() const=0;
public:
virtual void output(ostream &out) const=0;
virtual void write(ostream &out, int indent_level) const=0;
@ -68,11 +73,31 @@ public:
GeomNode *get_viz();
INLINE static UpdateSeq get_sort_seq();
protected:
virtual void fill_viz_geom(GeomNode *viz_geom);
INLINE void mark_viz_stale();
// This enumerated class defines the relative class priority of
// different kinds of lights. This hierarchy is only used to
// resolve multiple lights of the same priority specified by
// set_priority(). In general, the first items in this list have a
// lesser priority than later items.
enum ClassPriority {
CP_ambient_priority,
CP_point_priority,
CP_directional_priority,
CP_spot_priority,
};
private:
// The priority is not cycled, because there's no real reason to do
// so, and cycling it makes it difficult to synchronize with the
// LightAttribs.
int _priority;
static UpdateSeq _sort_seq;
// This is the data that must be cycled between pipeline stages.
class EXPCL_PANDA CData : public CycleData {
public:

View File

@ -133,3 +133,20 @@ INLINE bool LightAttrib::
is_identity() const {
return _on_lights.empty() && _off_lights.empty() && !_off_all_lights;
}
////////////////////////////////////////////////////////////////////
// Function: LightAttrib::check_filtered
// Access: Private
// Description: Confirms whether the _filtered table is still valid.
// It may become invalid if someone calls
// Light::set_priority().
//
// If the table is invalid, transparently empties it
// before returning.
////////////////////////////////////////////////////////////////////
INLINE void LightAttrib::
check_filtered() const {
if (_sort_seq != Light::get_sort_seq()) {
((LightAttrib *)this)->sort_on_lights();
}
}

View File

@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////
#include "lightAttrib.h"
#include "ambientLight.h"
#include "pandaNode.h"
#include "nodePath.h"
#include "graphicsStateGuardianBase.h"
@ -30,6 +31,24 @@ CPT(RenderAttrib) LightAttrib::_empty_attrib;
CPT(RenderAttrib) LightAttrib::_all_off_attrib;
TypeHandle LightAttrib::_type_handle;
// This STL Function object is used in filter_to_max(), below, to sort
// a list of Lights in reverse order by priority. In the case of two
// lights with equal priority, the class priority is compared.
class CompareLightPriorities {
public:
bool operator ()(const NodePath &a, const NodePath &b) const {
nassertr(!a.is_empty() && !b.is_empty(), a < b);
Light *la = a.node()->as_light();
Light *lb = b.node()->as_light();
nassertr(la != (Light *)NULL && lb != (Light *)NULL, a < b);
if (la->get_priority() != lb->get_priority()) {
return la->get_priority() > lb->get_priority();
}
return la->get_class_priority() > lb->get_class_priority();
}
};
////////////////////////////////////////////////////////////////////
// Function: LightAttrib::make
// Access: Published, Static
@ -448,6 +467,83 @@ remove_off_light(const NodePath &light) const {
return return_new(attrib);
}
////////////////////////////////////////////////////////////////////
// Function: LightAttrib::filter_to_max
// Access: Public
// Description: Returns a new LightAttrib, very much like this one,
// but with the number of on_lights reduced to be no
// more than max_lights. The number of off_lights in
// the new LightAttrib is undefined.
//
// The number of AmbientLights is not included in the
// count. All AmbientLights in the original attrib are
// always included in the result, regardless of the
// value of max_lights.
////////////////////////////////////////////////////////////////////
CPT(LightAttrib) LightAttrib::
filter_to_max(int max_lights) const {
if (max_lights < 0 || (int)_on_lights.size() <= max_lights) {
// Trivial case: this LightAttrib qualifies.
return this;
}
// Since check_filtered() will clear the _filtered list if we are out
// of date, we should call it first.
check_filtered();
Filtered::const_iterator fi;
fi = _filtered.find(max_lights);
if (fi != _filtered.end()) {
// Easy case: we have already computed this for this particular
// LightAttrib.
return (*fi).second;
}
// Harder case: we have to compute it now. We must choose the n
// lights with the highest priority in our list of lights.
Lights priority_lights, ambient_lights;
// Separate the list of lights into ambient lights and other lights.
Lights::const_iterator li;
for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
const NodePath &np = (*li);
nassertr(!np.is_empty() && np.node()->as_light() != (Light *)NULL, this);
if (np.node()->is_exact_type(AmbientLight::get_class_type())) {
ambient_lights.push_back(np);
} else {
priority_lights.push_back(np);
}
}
// This sort function uses the STL function object defined above.
sort(priority_lights.begin(), priority_lights.end(),
CompareLightPriorities());
// Now lop off all of the lights after the first max_lights.
priority_lights.erase(priority_lights.begin() + max_lights,
priority_lights.end());
// Put the ambient lights back into the list.
for (li = ambient_lights.begin(); li != ambient_lights.end(); ++li) {
priority_lights.push_back(*li);
}
// And re-sort the ov_set into its proper order.
priority_lights.sort();
// Now create a new attrib reflecting these lights.
PT(LightAttrib) attrib = new LightAttrib;
attrib->_on_lights.swap(priority_lights);
CPT(RenderAttrib) new_attrib = return_new(attrib);
// Finally, record this newly-created attrib in the map for next
// time.
CPT(LightAttrib) light_attrib = (const LightAttrib *)new_attrib.p();
((LightAttrib *)this)->_filtered[max_lights] = light_attrib;
return light_attrib;
}
////////////////////////////////////////////////////////////////////
// Function: LightAttrib::issue
// Access: Public, Virtual
@ -750,6 +846,20 @@ make_default_impl() const {
return new LightAttrib;
}
////////////////////////////////////////////////////////////////////
// Function: LightAttrib::sort_on_lights
// Access: Private
// Description: This is patterned after
// TextureAttrib::sort_on_stages(), but since lights
// don't actually require sorting, this only empties the
// _filtered map.
////////////////////////////////////////////////////////////////////
void LightAttrib::
sort_on_lights() {
_sort_seq = Light::get_sort_seq();
_filtered.clear();
}
////////////////////////////////////////////////////////////////////
// Function: LightAttrib::register_with_read_factory
// Access: Public, Static

View File

@ -23,8 +23,9 @@
#include "light.h"
#include "renderAttrib.h"
#include "ordered_vector.h"
#include "nodePath.h"
#include "ordered_vector.h"
#include "pmap.h"
////////////////////////////////////////////////////////////////////
// Class : LightAttrib
@ -90,6 +91,8 @@ PUBLISHED:
CPT(RenderAttrib) add_off_light(const NodePath &light) const;
CPT(RenderAttrib) remove_off_light(const NodePath &light) const;
CPT(LightAttrib) filter_to_max(int max_lights) const;
public:
virtual void issue(GraphicsStateGuardianBase *gsg) const;
virtual void output(ostream &out) const;
@ -100,11 +103,20 @@ protected:
virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const;
virtual RenderAttrib *make_default_impl() const;
private:
INLINE void check_filtered() const;
void sort_on_lights();
private:
typedef ov_set<NodePath> Lights;
Lights _on_lights, _off_lights;
bool _off_all_lights;
typedef pmap< int, CPT(LightAttrib) > Filtered;
Filtered _filtered;
UpdateSeq _sort_seq;
static CPT(RenderAttrib) _empty_attrib;
static CPT(RenderAttrib) _all_off_attrib;

View File

@ -61,3 +61,53 @@ get_plane() const {
CDReader cdata(_cycler);
return cdata->_plane;
}
////////////////////////////////////////////////////////////////////
// Function: PlaneNode::set_priority
// Access: Published
// Description: Changes the relative importance of this PlaneNode
// (when it is used as a clip plane) relative to the
// other clip planes that are applied simultaneously.
//
// The priority number is used to decide which of the
// requested clip planes are to be activated when more
// clip planes are requested than the hardware will
// support. The highest-priority n planes are selected
// for rendering.
//
// This is similar to TextureStage::set_priority().
////////////////////////////////////////////////////////////////////
INLINE void PlaneNode::
set_priority(int priority) {
_priority = priority;
// Update the global flag to indicate that all ClipPlaneAttribs in
// the world must now re-sort their lists.
_sort_seq++;
}
////////////////////////////////////////////////////////////////////
// Function: PlaneNode::get_priority
// Access: Published
// Description: Returns the priority associated with this clip
// plane. See set_priority().
////////////////////////////////////////////////////////////////////
INLINE int PlaneNode::
get_priority() const {
return _priority;
}
////////////////////////////////////////////////////////////////////
// Function: PlaneNode::get_sort_seq
// Access: Public, Static
// Description: Returns a global sequence number that is incremented
// any time any PlaneNode in the world changes sort
// or priority. This is used by ClipPlaneAttrib to
// determine when it is necessary to re-sort its
// internal array of stages.
////////////////////////////////////////////////////////////////////
INLINE UpdateSeq PlaneNode::
get_sort_seq() {
return _sort_seq;
}

View File

@ -23,6 +23,8 @@
#include "datagram.h"
#include "datagramIterator.h"
UpdateSeq PlaneNode::_sort_seq;
TypeHandle PlaneNode::_type_handle;
////////////////////////////////////////////////////////////////////
@ -65,7 +67,8 @@ fillin(DatagramIterator &scan, BamReader *) {
////////////////////////////////////////////////////////////////////
PlaneNode::
PlaneNode(const string &name) :
PandaNode(name)
PandaNode(name),
_priority(0)
{
}
@ -77,6 +80,7 @@ PlaneNode(const string &name) :
PlaneNode::
PlaneNode(const PlaneNode &copy) :
PandaNode(copy),
_priority(copy._priority),
_cycler(copy._cycler)
{
}
@ -151,6 +155,7 @@ void PlaneNode::
write_datagram(BamWriter *manager, Datagram &dg) {
PandaNode::write_datagram(manager, dg);
manager->write_cdata(dg, _cycler);
dg.add_int32(_priority);
}
////////////////////////////////////////////////////////////////////
@ -184,4 +189,5 @@ void PlaneNode::
fillin(DatagramIterator &scan, BamReader *manager) {
PandaNode::fillin(scan, manager);
manager->read_cdata(scan, _cycler);
_priority = scan.get_int32();
}

View File

@ -23,6 +23,7 @@
#include "plane.h"
#include "pandaNode.h"
#include "updateSeq.h"
////////////////////////////////////////////////////////////////////
// Class : PlaneNode
@ -48,7 +49,19 @@ PUBLISHED:
INLINE void set_plane(const Planef &plane);
INLINE const Planef &get_plane() const;
INLINE void set_priority(int priority);
INLINE int get_priority() const;
public:
INLINE static UpdateSeq get_sort_seq();
private:
// The priority is not cycled, because there's no real reason to do
// so, and cycling it makes it difficult to synchronize with the
// ClipPlaneAttribs.
int _priority;
static UpdateSeq _sort_seq;
// This is the data that must be cycled between pipeline stages.
class EXPCL_PANDA CData : public CycleData {
public:

View File

@ -159,6 +159,21 @@ get_vector_to_light(LVector3f &result, const LPoint3f &from_object_point,
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PointLight::get_class_priority
// Access: Published, Virtual
// Description: Returns the relative priority associated with all
// lights of this class. This priority is used to order
// lights whose instance priority (get_priority()) is
// the same--the idea is that other things being equal,
// AmbientLights (for instance) are less important than
// DirectionalLights.
////////////////////////////////////////////////////////////////////
int PointLight::
get_class_priority() const {
return (int)CP_point_priority;
}
////////////////////////////////////////////////////////////////////
// Function: PointLight::bind
// Access: Public, Virtual

View File

@ -53,6 +53,8 @@ PUBLISHED:
INLINE const LPoint3f &get_point() const;
INLINE void set_point(const LPoint3f &point);
virtual int get_class_priority() const;
public:
virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,

View File

@ -212,6 +212,21 @@ make_spot(int pixel_width, float full_radius, Colorf &fg, Colorf &bg) {
return tex;
}
////////////////////////////////////////////////////////////////////
// Function: Spotlight::get_class_priority
// Access: Published, Virtual
// Description: Returns the relative priority associated with all
// lights of this class. This priority is used to order
// lights whose instance priority (get_priority()) is
// the same--the idea is that other things being equal,
// AmbientLights (for instance) are less important than
// DirectionalLights.
////////////////////////////////////////////////////////////////////
int Spotlight::
get_class_priority() const {
return (int)CP_spot_priority;
}
////////////////////////////////////////////////////////////////////
// Function: Spotlight::bind
// Access: Public, Virtual

View File

@ -65,6 +65,8 @@ PUBLISHED:
INLINE const LVecBase3f &get_attenuation() const;
INLINE void set_attenuation(const LVecBase3f &attenuation);
virtual int get_class_priority() const;
static PT(Texture) make_spot(int pixel_width, float full_radius,
Colorf &fg, Colorf &bg);

View File

@ -30,7 +30,7 @@ TypeHandle TextureAttrib::_type_handle;
// This STL Function object is used in filter_to_max(), below, to sort
// a list of TextureStages in reverse order by priority and, within
// prioirty, in order by sort.
// priority, in order by sort.
class CompareTextureStagePriorities {
public:
bool operator ()(const TextureStage *a, const TextureStage *b) const {
@ -778,7 +778,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
// Function: TextureAttrib::sort_on_stages
// Access: Private
// Description: Sorts the list of stages so that they are listed in
// render order.
// render order. Also clears the _filtered map.
////////////////////////////////////////////////////////////////////
void TextureAttrib::
sort_on_stages() {