diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index 8315a7e8c2..f790c9e9d7 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -158,6 +158,17 @@ ConfigVariableBool auto_generate_mipmaps "false by default because some drivers (Intel) seem to do a " "poor job of generating mipmaps when needed.")); +ConfigVariableBool color_scale_via_lighting +("color-scale-via-lighting", true, + PRC_DESC("When this is true, Panda will try to implement ColorAttribs and " + "ColorScaleAttribs using the lighting interface, by " + "creating a default material and/or an ambient light if " + "necessary, even if lighting is ostensibly disabled. This " + "avoids the need to munge the vertex data to change each vertex's " + "color. Set this false to avoid this trickery, so that lighting " + "is only enabled when the application specifically enables " + "it.")); + ConfigVariableInt win_size ("win-size", "640 480", PRC_DESC("This is the default size at which to open a new window. This " diff --git a/panda/src/display/config_display.h b/panda/src/display/config_display.h index d365b62f83..c1a0311845 100644 --- a/panda/src/display/config_display.h +++ b/panda/src/display/config_display.h @@ -57,6 +57,7 @@ extern EXPCL_PANDA ConfigVariableBool copy_texture_inverted; extern EXPCL_PANDA ConfigVariableBool window_inverted; extern EXPCL_PANDA ConfigVariableBool depth_offset_decals; extern EXPCL_PANDA ConfigVariableBool auto_generate_mipmaps; +extern EXPCL_PANDA ConfigVariableBool color_scale_via_lighting; extern EXPCL_PANDA ConfigVariableInt win_size; extern EXPCL_PANDA ConfigVariableInt win_origin; diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index 3972df3bad..0bd72f5efd 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -316,6 +316,19 @@ get_supports_render_texture() const { return _supports_render_texture; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_color_scale_via_lighting +// Access: Published +// Description: Returns true if this particular GSG can implement (or +// would prefer to implement) set color and/or color +// scale using materials and/or ambient lights, or +// false if we need to actually munge the color. +//////////////////////////////////////////////////////////////////// +INLINE bool GraphicsStateGuardian:: +get_color_scale_via_lighting() const { + return _color_scale_via_lighting; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::set_scene diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 5bf365d8ad..4dd6d3eedf 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -131,6 +131,17 @@ GraphicsStateGuardian(const FrameBufferProperties &properties, _supports_render_texture = false; _supported_geom_rendering = 0; + + // If this is true, then we can apply a color and/or color scale by + // twiddling the material and/or ambient light (which could mean + // enabling lighting even without a LightAttrib). + _color_scale_via_lighting = color_scale_via_lighting; + + if (!use_qpgeom) { + // The old Geom interface doesn't really work too well with the + // color_scale_via_lighting trick. + _color_scale_via_lighting = false; + } } //////////////////////////////////////////////////////////////////// @@ -223,6 +234,14 @@ reset() { _blend_mode_stale = false; _pending_texture = NULL; _texture_stale = false; + _pending_light = NULL; + _light_stale = false; + _pending_material = NULL; + _material_stale = false; + + _has_material_force_color = false; + _material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f); + _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f); } //////////////////////////////////////////////////////////////////// @@ -356,7 +375,7 @@ release_index_buffer(IndexBufferContext *) { // Description: Creates a new GeomMunger object to munge vertices // appropriate to this GSG for the indicated state. //////////////////////////////////////////////////////////////////// -CPT(qpGeomMunger) GraphicsStateGuardian:: +PT(qpGeomMunger) GraphicsStateGuardian:: get_geom_munger(const RenderState *state) { // The default implementation returns no munger at all, but // presumably, every kind of GSG needs some special munging action, @@ -886,6 +905,12 @@ issue_color_scale(const ColorScaleAttrib *attrib) { if (_texture_involves_color_scale) { _texture_stale = true; } + if (_color_scale_via_lighting) { + _light_stale = true; + _material_stale = true; + + determine_light_color_scale(); + } } //////////////////////////////////////////////////////////////////// @@ -929,153 +954,39 @@ issue_color(const ColorAttrib *attrib) { _vertex_colors_enabled = true; break; } + + if (_color_scale_via_lighting) { + _light_stale = true; + _material_stale = true; + + determine_light_color_scale(); + } } //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::issue_light // Access: Public, Virtual -// Description: The default implementation of issue_light() assumes -// we have a limited number of hardware lights -// available. This function assigns each light to a -// different hardware light id, trying to keep each -// 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. -// -// It will call apply_light() each time a light is -// assigned to a particular id for the first time in a -// given frame, and it will subsequently call -// enable_light() to enable or disable each light as the -// frame is rendered, as well as enable_lighting() to -// enable or disable overall lighting. -// -// If this model of hardware lights with id's does not -// apply to a particular graphics engine, it should -// override this function to do something more -// appropriate instead. +// Description: //////////////////////////////////////////////////////////////////// void GraphicsStateGuardian:: issue_light(const LightAttrib *attrib) { - // Initialize the current ambient light total and newly enabled - // light list - Colorf cur_ambient_light(0.0f, 0.0f, 0.0f, 1.0f); - int i; - int max_lights = (int)_light_info.size(); - for (i = 0; i < max_lights; i++) { - _light_info[i]._next_enabled = false; - } + // By default, we don't apply the light attrib right away, since + // it might have a dependency on the current ColorScaleAttrib. + _pending_light = attrib; + _light_stale = true; +} - bool any_bound = false; - - int num_enabled = 0; - int num_on_lights = attrib->get_num_on_lights(); - for (int li = 0; li < num_on_lights; li++) { - NodePath light = attrib->get_on_light(li); - nassertv(!light.is_empty() && light.node()->as_light() != (Light *)NULL); - Light *light_obj = light.node()->as_light(); - - num_enabled++; - - // Lighting should be enabled before we apply any lights. - enable_lighting(true); - _lighting_enabled = true; - _lighting_enabled_this_frame = true; - - if (light_obj->get_type() == AmbientLight::get_class_type()) { - // Ambient lights don't require specific light ids; simply add - // in the ambient contribution to the current total - cur_ambient_light += light_obj->get_color(); - - } 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++) { - if (_light_info[i]._light == light) { - // Light has already been bound to an id, we only need to - // enable the light, not reapply it. - cur_light_id = -2; - enable_light(i, true); - _light_info[i]._enabled = true; - _light_info[i]._next_enabled = true; - break; - } - } - - // See if there are any unbound light ids - if (cur_light_id == -1) { - for (i = 0; i < max_lights; i++) { - if (_light_info[i]._light.is_empty()) { - _light_info[i]._light = light; - cur_light_id = i; - break; - } - } - } - - // 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 (!attrib->has_on_light(_light_info[i]._light)) { - _light_info[i]._light = light; - cur_light_id = i; - break; - } - } - } - - // 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; - _light_info.push_back(LightInfo()); - max_lights++; - nassertv(max_lights == (int)_light_info.size()); - } - } - - if (cur_light_id >= 0) { - enable_light(cur_light_id, true); - _light_info[cur_light_id]._enabled = true; - _light_info[cur_light_id]._next_enabled = true; - - if (!any_bound) { - begin_bind_lights(); - any_bound = true; - } - - // This is the first time this frame that this light has been - // bound to this particular id. - light_obj->bind(this, light, cur_light_id); - - } else if (cur_light_id == -1) { - gsg_cat.warning() - << "Failed to bind " << light << " to id.\n"; - } - } - } - - // Disable all unused lights - for (i = 0; i < max_lights; i++) { - if (!_light_info[i]._next_enabled) { - enable_light(i, false); - _light_info[i]._enabled = false; - } - } - - // If no lights were enabled, disable lighting - if (num_enabled == 0) { - enable_lighting(false); - _lighting_enabled = false; - } else { - set_ambient_light(cur_ambient_light); - } - - if (any_bound) { - end_bind_lights(); - } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::issue_material +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +issue_material(const MaterialAttrib *attrib) { + // By default, we don't apply the material attrib right away, since + // it might have a dependency on the current ColorScaleAttrib. + _pending_material = attrib; + _material_stale = true; } //////////////////////////////////////////////////////////////////// @@ -1278,6 +1189,181 @@ void GraphicsStateGuardian:: bind_light(Spotlight *light_obj, const NodePath &light, int light_id) { } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::do_issue_light +// Access: Protected +// Description: This implementation of issue_light() assumes +// we have a limited number of hardware lights +// available. This function assigns each light to a +// different hardware light id, trying to keep each +// 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. +// +// It will call apply_light() each time a light is +// assigned to a particular id for the first time in a +// given frame, and it will subsequently call +// enable_light() to enable or disable each light as the +// frame is rendered, as well as enable_lighting() to +// enable or disable overall lighting. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +do_issue_light() { + // Initialize the current ambient light total and newly enabled + // 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++) { + _light_info[i]._next_enabled = false; + } + + bool any_bound = false; + + int num_enabled = 0; + if (_pending_light != (LightAttrib *)NULL) { + int num_on_lights = _pending_light->get_num_on_lights(); + for (int li = 0; li < num_on_lights; li++) { + NodePath light = _pending_light->get_on_light(li); + nassertv(!light.is_empty() && light.node()->as_light() != (Light *)NULL); + Light *light_obj = light.node()->as_light(); + + num_enabled++; + + // Lighting should be enabled before we apply any lights. + enable_lighting(true); + _lighting_enabled = true; + _lighting_enabled_this_frame = true; + + if (light_obj->get_type() == AmbientLight::get_class_type()) { + // Ambient lights don't require specific light ids; simply add + // in the ambient contribution to the current total + cur_ambient_light += light_obj->get_color(); + + } 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++) { + if (_light_info[i]._light == light) { + // Light has already been bound to an id; reuse the same id. + cur_light_id = -2; + enable_light(i, true); + _light_info[i]._enabled = true; + _light_info[i]._next_enabled = true; + light_obj->bind(this, light, i); + break; + } + } + + // See if there are any unbound light ids + if (cur_light_id == -1) { + for (i = 0; i < max_lights; i++) { + if (_light_info[i]._light.is_empty()) { + _light_info[i]._light = light; + cur_light_id = i; + break; + } + } + } + + // 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)) { + _light_info[i]._light = light; + cur_light_id = i; + break; + } + } + } + + // 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; + _light_info.push_back(LightInfo()); + max_lights++; + nassertv(max_lights == (int)_light_info.size()); + } + } + + if (cur_light_id >= 0) { + enable_light(cur_light_id, true); + _light_info[cur_light_id]._enabled = true; + _light_info[cur_light_id]._next_enabled = true; + + if (!any_bound) { + begin_bind_lights(); + any_bound = true; + } + + // This is the first time this frame that this light has been + // bound to this particular id. + light_obj->bind(this, light, cur_light_id); + + } else if (cur_light_id == -1) { + gsg_cat.warning() + << "Failed to bind " << light << " to id.\n"; + } + } + } + } + + // Disable all unused lights + for (i = 0; i < max_lights; i++) { + if (!_light_info[i]._next_enabled) { + enable_light(i, false); + _light_info[i]._enabled = false; + } + } + + // If no lights were enabled, disable lighting + if (num_enabled == 0) { + if (_color_scale_via_lighting && (_has_material_force_color || _light_color_scale != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f))) { + // Unless we need lighting anyway to apply a color or color + // scale. + enable_lighting(true); + _lighting_enabled = true; + _lighting_enabled_this_frame = true; + set_ambient_light(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); + + } else { + enable_lighting(false); + _lighting_enabled = false; + } + + } else { + set_ambient_light(cur_ambient_light); + } + + if (any_bound) { + end_bind_lights(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::do_issue_material +// Access: Protected, Virtual +// Description: Should be overridden by derived classes to actually +// apply the material saved in _pending_material. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +do_issue_material() { +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::do_issue_texture +// Access: Protected, Virtual +// Description: Should be overridden by derived classes to actually +// apply the texture saved in _pending_texture. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +do_issue_texture() { +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::slot_new_light // Access: Protected, Virtual @@ -1470,6 +1556,21 @@ finish_modify_state() { _blend_mode_stale = false; set_blend_mode(); } + + if (_texture_stale) { + _texture_stale = false; + do_issue_texture(); + } + + if (_material_stale) { + _material_stale = false; + do_issue_material(); + } + + if (_light_stale) { + _light_stale = false; + do_issue_light(); + } } //////////////////////////////////////////////////////////////////// @@ -1529,6 +1630,41 @@ panic_deactivate() { } } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::determine_light_color_scale +// Access: Protected +// Description: Called whenever the color or color scale is changed, +// if _color_scale_via_lighting is true. This will +// rederive _material_force_color and _light_color_scale +// appropriately. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +determine_light_color_scale() { + if (_has_scene_graph_color) { + // If we have a scene graph color, it, plus the color scale, goes + // directly into the material; we don't color scale the + // lights--this allows an alpha color scale to work properly. + _has_material_force_color = true; + _material_force_color = _scene_graph_color; + _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f); + if (!_color_blend_involves_color_scale && _color_scale_enabled) { + _material_force_color.set(_scene_graph_color[0] * _current_color_scale[0], + _scene_graph_color[1] * _current_color_scale[1], + _scene_graph_color[2] * _current_color_scale[2], + _scene_graph_color[3] * _current_color_scale[3]); + } + + } else { + // Otherise, leave the materials alone, but we might still scale + // the lights. + _has_material_force_color = false; + _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f); + if (!_color_blend_involves_color_scale && _color_scale_enabled) { + _light_color_scale = _current_color_scale; + } + } +} + #ifdef DO_PSTATS //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 553f1ba0b6..ea254768b2 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -41,6 +41,8 @@ #include "colorWriteAttrib.h" #include "colorBlendAttrib.h" #include "textureAttrib.h" +#include "materialAttrib.h" +#include "lightAttrib.h" #include "transparencyAttrib.h" #include "config_display.h" #include "qpgeomMunger.h" @@ -100,6 +102,8 @@ PUBLISHED: virtual int get_supported_geom_rendering() const; + INLINE bool get_color_scale_via_lighting() const; + public: INLINE bool set_scene(SceneSetup *scene_setup); INLINE SceneSetup *get_scene() const; @@ -118,7 +122,7 @@ public: virtual IndexBufferContext *prepare_index_buffer(qpGeomPrimitive *data); virtual void release_index_buffer(IndexBufferContext *ibc); - virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state); + virtual PT(qpGeomMunger) get_geom_munger(const RenderState *state); virtual void set_state_and_transform(const RenderState *state, const TransformState *transform); @@ -193,6 +197,7 @@ public: virtual void issue_color_scale(const ColorScaleAttrib *attrib); virtual void issue_color(const ColorAttrib *attrib); virtual void issue_light(const LightAttrib *attrib); + virtual void issue_material(const MaterialAttrib *attrib); virtual void issue_color_write(const ColorWriteAttrib *attrib); virtual void issue_transparency(const TransparencyAttrib *attrib); virtual void issue_color_blend(const ColorBlendAttrib *attrib); @@ -207,6 +212,10 @@ public: int light_id); protected: + void do_issue_light(); + virtual void do_issue_material(); + 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); @@ -231,6 +240,8 @@ protected: virtual void close_gsg(); void panic_deactivate(); + void determine_light_color_scale(); + INLINE void set_properties(const FrameBufferProperties &properties); #ifdef DO_PSTATS @@ -313,6 +324,14 @@ protected: CPT(TextureAttrib) _pending_texture; bool _texture_stale; + CPT(LightAttrib) _pending_light; + bool _light_stale; + CPT(MaterialAttrib) _pending_material; + bool _material_stale; + + bool _has_material_force_color; + Colorf _material_force_color; + LVecBase4f _light_color_scale; bool _needs_reset; bool _closing_gsg; @@ -332,6 +351,7 @@ protected: bool _supports_generate_mipmap; bool _supports_render_texture; int _supported_geom_rendering; + bool _color_scale_via_lighting; public: // Statistics diff --git a/panda/src/display/standardMunger.cxx b/panda/src/display/standardMunger.cxx index e7b67cc0ad..88debbe730 100644 --- a/panda/src/display/standardMunger.cxx +++ b/panda/src/display/standardMunger.cxx @@ -37,15 +37,56 @@ StandardMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state, int num_components, StandardMunger::NumericType numeric_type, StandardMunger::Contents contents) : - qpGeomMunger(gsg, state), _num_components(num_components), _numeric_type(numeric_type), _contents(contents) { _gsg = DCAST(GraphicsStateGuardian, gsg); - _color = state->get_color(); - _color_scale = state->get_color_scale(); _render_mode = state->get_render_mode(); + + _munge_color = false; + _munge_color_scale = false; + + CPT(ColorAttrib) color_attrib = state->get_color(); + CPT(ColorScaleAttrib) color_scale_attrib = state->get_color_scale(); + + if (color_attrib != (ColorAttrib *)NULL && + color_attrib->get_color_type() == ColorAttrib::T_flat) { + + if (!_gsg->get_color_scale_via_lighting()) { + // We only need to munge the color directly if the GSG says it + // can't cheat the color via lighting (presumably, in this case, + // by applying a material). + _color = color_attrib->get_color(); + if (color_scale_attrib != (ColorScaleAttrib *)NULL && + color_scale_attrib->has_scale()) { + const LVecBase4f &cs = color_scale_attrib->get_scale(); + _color.set(_color[0] * cs[0], + _color[1] * cs[1], + _color[2] * cs[2], + _color[3] * cs[3]); + } + _munge_color = true; + } + + } else if (color_scale_attrib != (ColorScaleAttrib *)NULL && + color_scale_attrib->has_scale()) { + _color_scale = color_scale_attrib->get_scale(); + if (!_gsg->get_color_scale_via_lighting() || _color_scale[3] != 1.0f) { + // We only need to apply the color scale by directly munging the + // color if the GSG says it can't cheat this via lighting (for + // instance, by applying an ambient light). Or, since we assume + // lighting can't scale the alpha component, if the color scale + // involves alpha. + + // Known bug: if there is a material on an object that would + // obscure the effect of color_scale, we scale the lighting + // anyway, thus applying the effect even if it should be + // obscured. It doesn't seem worth the effort to detect this + // contrived situation and handle it correctly. + _munge_color_scale = true; + } + } } //////////////////////////////////////////////////////////////////// @@ -67,25 +108,12 @@ CPT(qpGeomVertexData) StandardMunger:: munge_data_impl(const qpGeomVertexData *data) { CPT(qpGeomVertexData) new_data = data; - if (_color != (ColorAttrib *)NULL && - _color->get_color_type() == ColorAttrib::T_flat) { - Colorf color = _color->get_color(); - if (_color_scale != (ColorScaleAttrib *)NULL && - _color_scale->has_scale()) { - const LVecBase4f &cs = _color_scale->get_scale(); - color.set(color[0] * cs[0], - color[1] * cs[1], - color[2] * cs[2], - color[3] * cs[3]); - } - new_data = new_data->set_color(color, _num_components, _numeric_type, + if (_munge_color) { + new_data = new_data->set_color(_color, _num_components, _numeric_type, _contents); - - } else if (_color_scale != (ColorScaleAttrib *)NULL && - _color_scale->has_scale()) { - const LVecBase4f &cs = _color_scale->get_scale(); - new_data = new_data->scale_color(cs, _num_components, _numeric_type, - _contents); + } else if (_munge_color_scale) { + new_data = new_data->scale_color(_color_scale, _num_components, + _numeric_type, _contents); } qpGeomVertexAnimationSpec animation = new_data->get_format()->get_animation(); @@ -189,17 +217,30 @@ munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &vertex_data) { int StandardMunger:: compare_to_impl(const qpGeomMunger *other) const { const StandardMunger *om = DCAST(StandardMunger, other); - if (_color != om->_color) { - return _color < om->_color ? -1 : 1; - } - if (_color_scale != om->_color_scale) { - return _color_scale < om->_color_scale ? -1 : 1; - } if (_render_mode != om->_render_mode) { return _render_mode < om->_render_mode ? -1 : 1; } - return qpGeomMunger::compare_to_impl(other); + if (_munge_color != om->_munge_color) { + return (int)_munge_color - (int)om->_munge_color; + } + if (_munge_color_scale != om->_munge_color_scale) { + return (int)_munge_color_scale - (int)om->_munge_color_scale; + } + if (_munge_color) { + int compare = _color.compare_to(om->_color); + if (compare != 0) { + return compare; + } + } + if (_munge_color_scale) { + int compare = _color_scale.compare_to(om->_color_scale); + if (compare != 0) { + return compare; + } + } + + return StateMunger::compare_to_impl(other); } //////////////////////////////////////////////////////////////////// @@ -215,12 +256,43 @@ compare_to_impl(const qpGeomMunger *other) const { int StandardMunger:: geom_compare_to_impl(const qpGeomMunger *other) const { const StandardMunger *om = DCAST(StandardMunger, other); - if (_color != om->_color) { - return _color < om->_color ? -1 : 1; + if (_munge_color != om->_munge_color) { + return (int)_munge_color - (int)om->_munge_color; } - if (_color_scale != om->_color_scale) { - return _color_scale < om->_color_scale ? -1 : 1; + if (_munge_color_scale != om->_munge_color_scale) { + return (int)_munge_color_scale - (int)om->_munge_color_scale; + } + if (_munge_color) { + int compare = _color.compare_to(om->_color); + if (compare != 0) { + return compare; + } + } + if (_munge_color_scale) { + int compare = _color_scale.compare_to(om->_color_scale); + if (compare != 0) { + return compare; + } } - return qpGeomMunger::geom_compare_to_impl(other); + return StateMunger::geom_compare_to_impl(other); +} + +//////////////////////////////////////////////////////////////////// +// Function: StandardMunger::munge_state_impl +// Access: Protectes, Virtual +// Description: Given an input state, returns the munged state. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) StandardMunger:: +munge_state_impl(const RenderState *state) { + CPT(RenderState) munged_state = state; + + if (_munge_color) { + munged_state = munged_state->remove_attrib(ColorAttrib::get_class_type()); + munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_type()); + } else if (_munge_color_scale) { + munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_type()); + } + + return munged_state; } diff --git a/panda/src/display/standardMunger.h b/panda/src/display/standardMunger.h index 0496dc4cd0..bbb3f55081 100644 --- a/panda/src/display/standardMunger.h +++ b/panda/src/display/standardMunger.h @@ -20,7 +20,7 @@ #define STANDARDMUNGER_H #include "pandabase.h" -#include "qpgeomMunger.h" +#include "stateMunger.h" #include "graphicsStateGuardian.h" #include "colorAttrib.h" #include "colorScaleAttrib.h" @@ -36,7 +36,7 @@ // // This is part of the experimental Geom rewrite. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA StandardMunger : public qpGeomMunger { +class EXPCL_PANDA StandardMunger : public StateMunger { public: StandardMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state, int num_components, NumericType numeric_type, @@ -48,24 +48,29 @@ protected: virtual int compare_to_impl(const qpGeomMunger *other) const; virtual bool munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data); virtual int geom_compare_to_impl(const qpGeomMunger *other) const; + virtual CPT(RenderState) munge_state_impl(const RenderState *state); private: int _num_components; NumericType _numeric_type; Contents _contents; CPT(GraphicsStateGuardian) _gsg; - CPT(ColorAttrib) _color; - CPT(ColorScaleAttrib) _color_scale; CPT(RenderModeAttrib) _render_mode; + bool _munge_color; + bool _munge_color_scale; + + Colorf _color; + LVecBase4f _color_scale; + public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { - qpGeomMunger::init_type(); + StateMunger::init_type(); register_type(_type_handle, "StandardMunger", - qpGeomMunger::get_class_type()); + StateMunger::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index dd46bcee64..4fb9333f43 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -33,7 +33,6 @@ #include "spotlight.h" #include "textureAttrib.h" #include "texGenAttrib.h" -#include "lightAttrib.h" #include "shadeModelAttrib.h" #include "cullFaceAttrib.h" #include "transparencyAttrib.h" @@ -413,8 +412,8 @@ dx_init(void) { _has_scene_graph_color = false; // Apply a default material when materials are turned off. - Material empty; - apply_material(&empty); + _pending_material = NULL; + do_issue_material(); // GL stuff that hasnt been translated to DX // none of these are implemented @@ -3556,7 +3555,7 @@ release_index_buffer(IndexBufferContext *ibc) { // Description: Creates a new GeomMunger object to munge vertices // appropriate to this GSG for the indicated state. //////////////////////////////////////////////////////////////////// -CPT(qpGeomMunger) DXGraphicsStateGuardian8:: +PT(qpGeomMunger) DXGraphicsStateGuardian8:: get_geom_munger(const RenderState *state) { PT(DXGeomMunger8) munger = new DXGeomMunger8(this, state); return qpGeomMunger::register_munger(munger); @@ -3704,44 +3703,6 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const Rend return true; } -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian8::apply_material -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian8:: -apply_material(const Material *material) { - D3DMATERIAL8 cur_material; - cur_material.Diffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data()); - cur_material.Ambient = *(D3DCOLORVALUE *)(material->get_ambient().get_data()); - cur_material.Specular = *(D3DCOLORVALUE *)(material->get_specular().get_data()); - cur_material.Emissive = *(D3DCOLORVALUE *)(material->get_emission().get_data()); - cur_material.Power = material->get_shininess(); - - _pD3DDevice->SetMaterial(&cur_material); - - if (material->has_diffuse()) { - // If the material specifies an diffuse color, use it. - _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL); - } else { - // Otherwise, the diffuse color comes from the object color. - _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); - } - if (material->has_ambient()) { - // If the material specifies an ambient color, use it. - _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); - } else { - // Otherwise, the ambient color comes from the object color. - _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1); - } - - if (material->get_local()) { - _pD3DDevice->SetRenderState(D3DRS_LOCALVIEWER, TRUE); - } else { - _pD3DDevice->SetRenderState(D3DRS_LOCALVIEWER, FALSE); - } -} - //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::apply_fog // Access: Public, Virtual @@ -3977,42 +3938,6 @@ issue_shade_model(const ShadeModelAttrib *attrib) { } } -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian8::issue_texture -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian8:: -issue_texture(const TextureAttrib *attrib) { - DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1)); - if (attrib->is_off()) { - enable_texturing(false); - } else { - Texture *tex = attrib->get_texture(); - nassertv(tex != (Texture *)NULL); - - TextureContext *tc = tex->prepare_now(_prepared_objects, this); - apply_texture(tc); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian8::issue_material -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian8:: -issue_material(const MaterialAttrib *attrib) { - const Material *material = attrib->get_material(); - if (material != (const Material *)NULL) { - apply_material(material); - } else { - // Apply a default material when materials are turned off. - Material empty; - apply_material(&empty); - } -} - //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::issue_render_mode // Access: Public, Virtual @@ -4218,7 +4143,7 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) { black.r = black.g = black.b = black.a = 0.0f; D3DLIGHT8 alight; alight.Type = D3DLIGHT_POINT; - alight.Diffuse = *(D3DCOLORVALUE *)(light_obj->get_color().get_data()); + alight.Diffuse = get_light_color(light_obj); alight.Ambient = black ; alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data()); @@ -4267,7 +4192,7 @@ bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) { ZeroMemory(&alight, sizeof(D3DLIGHT8)); alight.Type = D3DLIGHT_DIRECTIONAL; - alight.Diffuse = *(D3DCOLORVALUE *)(light_obj->get_color().get_data()); + alight.Diffuse = get_light_color(light_obj); alight.Ambient = black ; alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data()); @@ -4318,7 +4243,7 @@ bind_light(Spotlight *light_obj, const NodePath &light, int light_id) { alight.Type = D3DLIGHT_SPOT; alight.Ambient = black ; - alight.Diffuse = *(D3DCOLORVALUE *)(light_obj->get_color().get_data()); + alight.Diffuse = get_light_color(light_obj); alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data()); alight.Position = *(D3DVECTOR *)pos.get_data(); @@ -4531,6 +4456,25 @@ get_index_type(qpGeom::NumericType numeric_type) { return D3DFMT_INDEX16; } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::get_light_color +// Access: Public +// Description: Returns the array of four floats that should be +// issued as the light's color, as scaled by the current +// value of _light_color_scale, in the case of +// color_scale_via_lighting. +//////////////////////////////////////////////////////////////////// +const D3DCOLORVALUE &DXGraphicsStateGuardian8:: +get_light_color(Light *light) const { + static Colorf c; + c = light->get_color(); + c.set(c[0] * _light_color_scale[0], + c[1] * _light_color_scale[1], + c[2] * _light_color_scale[2], + c[3] * _light_color_scale[3]); + return *(D3DCOLORVALUE *)c.get_data(); +} + //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::set_draw_buffer // Access: Protected @@ -4652,6 +4596,86 @@ do_auto_rescale_normal() { } } +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian8::do_issue_texture +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian8:: +do_issue_texture() { + DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1)); + + CPT(TextureAttrib) new_texture = _pending_texture->filter_to_max(_max_texture_stages); + + if (new_texture->is_off()) { + enable_texturing(false); + } else { + Texture *tex = new_texture->get_texture(); + nassertv(tex != (Texture *)NULL); + + TextureContext *tc = tex->prepare_now(_prepared_objects, this); + apply_texture(tc); + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian8::do_issue_material +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian8:: +do_issue_material() { + static Material empty; + const Material *material; + if (_pending_material == (MaterialAttrib *)NULL || + _pending_material->is_off()) { + material = ∅ + } else { + material = _pending_material->get_material(); + } + + D3DMATERIAL8 cur_material; + cur_material.Diffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data()); + cur_material.Ambient = *(D3DCOLORVALUE *)(material->get_ambient().get_data()); + cur_material.Specular = *(D3DCOLORVALUE *)(material->get_specular().get_data()); + cur_material.Emissive = *(D3DCOLORVALUE *)(material->get_emission().get_data()); + cur_material.Power = material->get_shininess(); + + if (material->has_diffuse()) { + // If the material specifies an diffuse color, use it. + _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL); + } else { + // Otherwise, the diffuse color comes from the object color. + if (_has_material_force_color) { + cur_material.Diffuse = *(D3DCOLORVALUE *)_material_force_color.get_data(); + _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL); + } else { + _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); + } + } + if (material->has_ambient()) { + // If the material specifies an ambient color, use it. + _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); + } else { + // Otherwise, the ambient color comes from the object color. + if (_has_material_force_color) { + cur_material.Ambient = *(D3DCOLORVALUE *)_material_force_color.get_data(); + _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL); + } else { + _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1); + } + } + + _pD3DDevice->SetMaterial(&cur_material); + + if (material->get_local()) { + _pD3DDevice->SetRenderState(D3DRS_LOCALVIEWER, TRUE); + } else { + _pD3DDevice->SetRenderState(D3DRS_LOCALVIEWER, FALSE); + } +} + //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::slot_new_light // Access: Protected, Virtual @@ -4693,7 +4717,13 @@ enable_lighting(bool enable) { //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian8:: set_ambient_light(const Colorf &color) { - _pD3DDevice->SetRenderState(D3DRS_AMBIENT, Colorf_to_D3DCOLOR(color)); + Colorf c = color; + c.set(c[0] * _light_color_scale[0], + c[1] * _light_color_scale[1], + c[2] * _light_color_scale[2], + c[3] * _light_color_scale[3]); + + _pD3DDevice->SetRenderState(D3DRS_AMBIENT, Colorf_to_D3DCOLOR(c)); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index c279fc24ea..453d1b887f 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -115,20 +115,17 @@ public: void apply_index_buffer(IndexBufferContext *ibc); virtual void release_index_buffer(IndexBufferContext *ibc); - virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state); + virtual PT(qpGeomMunger) get_geom_munger(const RenderState *state); virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); - virtual void apply_material(const Material *material); virtual void apply_fog(Fog *fog); virtual void issue_transform(const TransformState *transform); virtual void issue_tex_matrix(const TexMatrixAttrib *attrib); - virtual void issue_texture(const TextureAttrib *attrib); - virtual void issue_material(const MaterialAttrib *attrib); virtual void issue_render_mode(const RenderModeAttrib *attrib); virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib); virtual void issue_alpha_test(const AlphaTestAttrib *attrib); @@ -160,6 +157,8 @@ public: static D3DFORMAT get_index_type(qpGeom::NumericType numeric_type); + const D3DCOLORVALUE &get_light_color(Light *light) const; + public: // recreate_tex_callback needs these to be public DXScreenData *_pScrn; @@ -168,6 +167,8 @@ public: D3DPRESENT_PARAMETERS _PresReset; // This is built during reset device protected: + virtual void do_issue_material(); + virtual bool slot_new_light(int light_id); virtual void enable_lighting(bool enable); virtual void set_ambient_light(const Colorf &color); @@ -192,6 +193,7 @@ protected: static CPT(RenderState) get_flat_state(); void do_auto_rescale_normal(); + virtual void do_issue_texture(); bool _bDXisReady; HRESULT _last_testcooplevel_result; @@ -204,10 +206,10 @@ protected: bool _auto_rescale_normal; void GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize, - void *pIndexSpace,DWORD dwIndexSpaceByteSize, - D3DXVECTOR3 *pCenter, float fRadius, - DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz, - DWORD *pNumVertices,DWORD *pNumTris,DWORD fvfFlags,DWORD dwVertSize); + void *pIndexSpace,DWORD dwIndexSpaceByteSize, + D3DXVECTOR3 *pCenter, float fRadius, + DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz, + DWORD *pNumVertices,DWORD *pNumTris,DWORD fvfFlags,DWORD dwVertSize); HRESULT ReleaseAllDeviceObjects(void); HRESULT RecreateAllDeviceObjects(void); HRESULT DeleteAllDeviceObjects(void); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 7d517b1014..33fa4725f9 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -861,8 +861,8 @@ reset() { cfa->issue(this); ta->issue(this); - Material empty; - apply_material(&empty); + _pending_material = NULL; + do_issue_material(); if (CLP(cheap_textures)) { GLCAT.info() @@ -1157,7 +1157,8 @@ draw_point(GeomPoint *geom, GeomContext *gc) { GeomIssuer::IssueColor *issue_color; - if (_color_blend_involves_color_scale || !_color_scale_enabled) { + if (_color_blend_involves_color_scale || !_color_scale_enabled || + _color_scale_via_lighting) { issue_color = issue_color_gl; } else { issue_color = issue_scaled_color_gl; @@ -1227,7 +1228,8 @@ draw_line(GeomLine *geom, GeomContext *gc) { GeomIssuer::IssueColor *issue_color; - if (_color_blend_involves_color_scale || !_color_scale_enabled) { + if (_color_blend_involves_color_scale || !_color_scale_enabled || + _color_scale_via_lighting) { issue_color = issue_color_gl; } else { issue_color = issue_scaled_color_gl; @@ -1304,7 +1306,8 @@ draw_linestrip(GeomLinestrip *geom, GeomContext *gc) { GeomIssuer::IssueColor *issue_color; - if (_color_blend_involves_color_scale || !_color_scale_enabled) { + if (_color_blend_involves_color_scale || !_color_scale_enabled || + _color_scale_via_lighting) { issue_color = issue_color_gl; } else { issue_color = issue_scaled_color_gl; @@ -1677,7 +1680,8 @@ draw_polygon(GeomPolygon *geom, GeomContext *gc) { GeomIssuer::IssueColor *issue_color; - if (_color_blend_involves_color_scale || !_color_scale_enabled) { + if (_color_blend_involves_color_scale || !_color_scale_enabled || + _color_scale_via_lighting) { issue_color = issue_color_gl; } else { issue_color = issue_scaled_color_gl; @@ -1758,7 +1762,8 @@ draw_tri(GeomTri *geom, GeomContext *gc) { GeomIssuer::IssueColor *issue_color; - if (_color_blend_involves_color_scale || !_color_scale_enabled) { + if (_color_blend_involves_color_scale || !_color_scale_enabled || + _color_scale_via_lighting) { issue_color = issue_color_gl; } else { issue_color = issue_scaled_color_gl; @@ -1837,7 +1842,8 @@ draw_quad(GeomQuad *geom, GeomContext *gc) { GeomIssuer::IssueColor *issue_color; - if (_color_blend_involves_color_scale || !_color_scale_enabled) { + if (_color_blend_involves_color_scale || !_color_scale_enabled || + _color_scale_via_lighting) { issue_color = issue_color_gl; } else { issue_color = issue_scaled_color_gl; @@ -1920,7 +1926,8 @@ draw_tristrip(GeomTristrip *geom, GeomContext *gc) { GeomIssuer::IssueColor *issue_color; - if (_color_blend_involves_color_scale || !_color_scale_enabled) { + if (_color_blend_involves_color_scale || !_color_scale_enabled || + _color_scale_via_lighting) { issue_color = issue_color_gl; } else { issue_color = issue_scaled_color_gl; @@ -2021,7 +2028,8 @@ draw_trifan(GeomTrifan *geom, GeomContext *gc) { GeomIssuer::IssueColor *issue_color; - if (_color_blend_involves_color_scale || !_color_scale_enabled) { + if (_color_blend_involves_color_scale || !_color_scale_enabled || + _color_scale_via_lighting) { issue_color = issue_color_gl; } else { issue_color = issue_scaled_color_gl; @@ -2119,7 +2127,8 @@ draw_sphere(GeomSphere *geom, GeomContext *gc) { GeomIssuer::IssueColor *issue_color; - if (_color_blend_involves_color_scale || !_color_scale_enabled) { + if (_color_blend_involves_color_scale || !_color_scale_enabled || + _color_scale_via_lighting) { issue_color = issue_color_gl; } else { issue_color = issue_scaled_color_gl; @@ -3206,7 +3215,7 @@ setup_primitive(const qpGeomPrimitive *data) { // Description: Creates a new GeomMunger object to munge vertices // appropriate to this GSG for the indicated state. //////////////////////////////////////////////////////////////////// -CPT(qpGeomMunger) CLP(GraphicsStateGuardian):: +PT(qpGeomMunger) CLP(GraphicsStateGuardian):: get_geom_munger(const RenderState *state) { PT(CLP(GeomMunger)) munger = new CLP(GeomMunger)(this, state); return qpGeomMunger::register_munger(munger); @@ -3403,52 +3412,6 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, return true; } -//////////////////////////////////////////////////////////////////// -// Function: GLGraphicsStateGuardian::apply_material -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void CLP(GraphicsStateGuardian):: -apply_material(const Material *material) { - GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT; - - GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data()); - GLP(Materialfv)(face, GL_EMISSION, material->get_emission().get_data()); - GLP(Materialf)(face, GL_SHININESS, material->get_shininess()); - - if (material->has_ambient() && material->has_diffuse()) { - // The material has both an ambient and diffuse specified. This - // means we do not need glMaterialColor(). - GLP(Disable)(GL_COLOR_MATERIAL); - GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data()); - GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data()); - - } else if (material->has_ambient()) { - // The material specifies an ambient, but not a diffuse component. - // The diffuse component comes from the object's color. - GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data()); - GLP(ColorMaterial)(face, GL_DIFFUSE); - GLP(Enable)(GL_COLOR_MATERIAL); - - } else if (material->has_diffuse()) { - // The material specifies a diffuse, but not an ambient component. - // The ambient component comes from the object's color. - GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data()); - GLP(ColorMaterial)(face, GL_AMBIENT); - GLP(Enable)(GL_COLOR_MATERIAL); - - } else { - // The material specifies neither a diffuse nor an ambient - // component. Both components come from the object's color. - GLP(ColorMaterial)(face, GL_AMBIENT_AND_DIFFUSE); - GLP(Enable)(GL_COLOR_MATERIAL); - } - - GLP(LightModeli)(GL_LIGHT_MODEL_LOCAL_VIEWER, material->get_local()); - GLP(LightModeli)(GL_LIGHT_MODEL_TWO_SIDE, material->get_twoside()); - report_my_gl_errors(); -} - //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::apply_fog // Access: Public, Virtual @@ -3594,24 +3557,6 @@ issue_cg_shader_bind(const CgShaderAttrib *attrib) { } #endif -//////////////////////////////////////////////////////////////////// -// Function: GLGraphicsStateGuardian::issue_material -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void CLP(GraphicsStateGuardian):: -issue_material(const MaterialAttrib *attrib) { - const Material *material = attrib->get_material(); - if (material != (const Material *)NULL) { - apply_material(material); - } else { - // Apply a default material when materials are turned off. - Material empty; - apply_material(&empty); - } - report_my_gl_errors(); -} - //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::issue_render_mode // Access: Public, Virtual @@ -3903,6 +3848,77 @@ issue_depth_offset(const DepthOffsetAttrib *attrib) { report_my_gl_errors(); } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::do_issue_material +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void CLP(GraphicsStateGuardian):: +do_issue_material() { + static Material empty; + const Material *material; + if (_pending_material == (MaterialAttrib *)NULL || + _pending_material->is_off()) { + material = ∅ + } else { + material = _pending_material->get_material(); + } + + GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT; + + GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data()); + GLP(Materialfv)(face, GL_EMISSION, material->get_emission().get_data()); + GLP(Materialf)(face, GL_SHININESS, material->get_shininess()); + + if (material->has_ambient() && material->has_diffuse()) { + // The material has both an ambient and diffuse specified. This + // means we do not need glMaterialColor(). + GLP(Disable)(GL_COLOR_MATERIAL); + GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data()); + GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data()); + + } else if (material->has_ambient()) { + // The material specifies an ambient, but not a diffuse component. + // The diffuse component comes from the object's color. + GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data()); + if (_has_material_force_color) { + GLP(Disable)(GL_COLOR_MATERIAL); + GLP(Materialfv)(face, GL_DIFFUSE, _material_force_color.get_data()); + } else { + GLP(ColorMaterial)(face, GL_DIFFUSE); + GLP(Enable)(GL_COLOR_MATERIAL); + } + + } else if (material->has_diffuse()) { + // The material specifies a diffuse, but not an ambient component. + // The ambient component comes from the object's color. + GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data()); + if (_has_material_force_color) { + GLP(Disable)(GL_COLOR_MATERIAL); + GLP(Materialfv)(face, GL_AMBIENT, _material_force_color.get_data()); + } else { + GLP(ColorMaterial)(face, GL_AMBIENT); + GLP(Enable)(GL_COLOR_MATERIAL); + } + + } else { + // The material specifies neither a diffuse nor an ambient + // component. Both components come from the object's color. + if (_has_material_force_color) { + GLP(Disable)(GL_COLOR_MATERIAL); + GLP(Materialfv)(face, GL_AMBIENT, _material_force_color.get_data()); + GLP(Materialfv)(face, GL_DIFFUSE, _material_force_color.get_data()); + } else { + GLP(ColorMaterial)(face, GL_AMBIENT_AND_DIFFUSE); + GLP(Enable)(GL_COLOR_MATERIAL); + } + } + + GLP(LightModeli)(GL_LIGHT_MODEL_LOCAL_VIEWER, material->get_local()); + GLP(LightModeli)(GL_LIGHT_MODEL_TWO_SIDE, material->get_twoside()); + report_my_gl_errors(); +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::bind_light // Access: Public, Virtual @@ -3916,7 +3932,7 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) { GLenum id = get_light_id(light_id); static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f); GLP(Lightfv)(id, GL_AMBIENT, black.get_data()); - GLP(Lightfv)(id, GL_DIFFUSE, light_obj->get_color().get_data()); + GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_obj)); GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data()); // Position needs to specify x, y, z, and w @@ -3956,7 +3972,7 @@ bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) { GLenum id = get_light_id( light_id ); static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f); GLP(Lightfv)(id, GL_AMBIENT, black.get_data()); - GLP(Lightfv)(id, GL_DIFFUSE, light_obj->get_color().get_data()); + GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_obj)); GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data()); // Position needs to specify x, y, z, and w. @@ -4000,7 +4016,7 @@ bind_light(Spotlight *light_obj, const NodePath &light, int light_id) { GLenum id = get_light_id(light_id); static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f); GLP(Lightfv)(id, GL_AMBIENT, black.get_data()); - GLP(Lightfv)(id, GL_DIFFUSE, light_obj->get_color().get_data()); + GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_obj)); GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data()); // Position needs to specify x, y, z, and w @@ -4984,6 +5000,25 @@ issue_scaled_color(const Colorf &color) const { GLP(Color4fv)(transformed.get_data()); } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::get_light_color +// Access: Public +// Description: Returns the array of four floats that should be +// issued as the light's color, as scaled by the current +// value of _light_color_scale, in the case of +// color_scale_via_lighting. +//////////////////////////////////////////////////////////////////// +const float *CLP(GraphicsStateGuardian):: +get_light_color(Light *light) const { + static Colorf c; + c = light->get_color(); + c.set(c[0] * _light_color_scale[0], + c[1] * _light_color_scale[1], + c[2] * _light_color_scale[2], + c[3] * _light_color_scale[3]); + return c.get_data(); +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::slot_new_light // Access: Protected, Virtual @@ -5029,7 +5064,12 @@ enable_lighting(bool enable) { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: set_ambient_light(const Colorf &color) { - GLP(LightModelfv)(GL_LIGHT_MODEL_AMBIENT, color.get_data()); + Colorf c = color; + c.set(c[0] * _light_color_scale[0], + c[1] * _light_color_scale[1], + c[2] * _light_color_scale[2], + c[3] * _light_color_scale[3]); + GLP(LightModelfv)(GL_LIGHT_MODEL_AMBIENT, c.get_data()); } //////////////////////////////////////////////////////////////////// @@ -5306,12 +5346,6 @@ void CLP(GraphicsStateGuardian):: finish_modify_state() { GraphicsStateGuardian::finish_modify_state(); - // Apply the texture, if it needs to be reapplied. - if (_texture_stale) { - _texture_stale = false; - do_issue_texture(); - } - // If one of the previously-loaded TexGen modes modified the texture // matrix, then if either state changed, we have to change both of // them now. @@ -5656,7 +5690,7 @@ do_auto_rescale_normal() { //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::do_issue_texture -// Access: Protected +// Access: Protected, Virtual // Description: This is called by finish_modify_state() when the // texture state has changed. //////////////////////////////////////////////////////////////////// diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 38cb4d336c..3374aa4129 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -123,19 +123,17 @@ public: virtual void release_index_buffer(IndexBufferContext *ibc); const unsigned char *setup_primitive(const qpGeomPrimitive *data); - virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state); + virtual PT(qpGeomMunger) get_geom_munger(const RenderState *state); virtual void framebuffer_copy_to_texture (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); virtual bool framebuffer_copy_to_ram (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); - virtual void apply_material(const Material *material); void apply_fog(Fog *fog); virtual void issue_transform(const TransformState *transform); virtual void issue_tex_matrix(const TexMatrixAttrib *attrib); - virtual void issue_material(const MaterialAttrib *attrib); virtual void issue_render_mode(const RenderModeAttrib *attrib); virtual void issue_antialias(const AntialiasAttrib *); virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib); @@ -152,6 +150,8 @@ public: virtual void issue_cg_shader_bind(const CgShaderAttrib *attrib); #endif + virtual void do_issue_material(); + virtual void bind_light(PointLight *light_obj, const NodePath &light, int light_id); virtual void bind_light(DirectionalLight *light_obj, const NodePath &light, @@ -170,6 +170,7 @@ public: void dump_state(void); void issue_scaled_color(const Colorf &color) const; + const float *get_light_color(Light *light) const; INLINE static bool report_errors(int line, const char *source_file); INLINE void report_my_errors(int line, const char *source_file); @@ -256,7 +257,7 @@ protected: static CPT(RenderState) get_flat_state(); void do_auto_rescale_normal(); - void do_issue_texture(); + virtual void do_issue_texture(); void specify_texture(Texture *tex); void apply_texture(TextureContext *tc); bool upload_texture(CLP(TextureContext) *gtc); diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index d155dbca43..16b0e776bc 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -162,11 +162,11 @@ ConfigVariableBool display_list_animation ConfigVariableBool connect_triangle_strips ("connect-triangle-strips", true, - PRC_DESC("Set this true to set a batch of triangle strips to the graphics " + PRC_DESC("Set this true to send a batch of triangle strips to the graphics " "card as one long triangle strip, connected by degenerate " "triangles, or false to send them as separate triangle strips " - "with no degenerate triangles. In many cases, using one long " - "triangle strip can help performance by reducing the number " + "with no degenerate triangles. On PC hardware, using one long " + "triangle strip may help performance by reducing the number " "of separate graphics calls that have to be made.")); ConfigVariableBool use_qpgeom diff --git a/panda/src/gobj/material.I b/panda/src/gobj/material.I index 11427ad5a3..40ff5975ff 100644 --- a/panda/src/gobj/material.I +++ b/panda/src/gobj/material.I @@ -24,10 +24,10 @@ //////////////////////////////////////////////////////////////////// INLINE Material:: Material() { - _ambient.set(0.0f, 0.0f, 0.0f, 0.0f); + _ambient.set(1.0f, 1.0f, 1.0f, 1.0f); _diffuse.set(1.0f, 1.0f, 1.0f, 1.0f); - _specular.set(0.0f, 0.0f, 0.0f, 0.0f); - _emission.set(0.0f, 0.0f, 0.0f, 0.0f); + _specular.set(0.0f, 0.0f, 0.0f, 1.0f); + _emission.set(0.0f, 0.0f, 0.0f, 1.0f); _shininess = 0.0; _flags = 0; } diff --git a/panda/src/gobj/qpgeom.cxx b/panda/src/gobj/qpgeom.cxx index ceabfc3a1a..d2373cac39 100644 --- a/panda/src/gobj/qpgeom.cxx +++ b/panda/src/gobj/qpgeom.cxx @@ -633,81 +633,6 @@ transform_vertices(const LMatrix4f &mat) { } } -//////////////////////////////////////////////////////////////////// -// Function: qpGeom::munge_geom -// Access: Published -// Description: Applies the indicated munger to the geom and its -// data, and returns a (possibly different) geom and -// data, according to the munger's whim. -// -// The assumption is that for a particular geom and a -// particular munger, the result will always be the -// same; so this result may be cached. -//////////////////////////////////////////////////////////////////// -void qpGeom:: -munge_geom(const qpGeomMunger *munger, - CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const { - CPT(qpGeomVertexData) source_data = data; - - // Look up the munger in our cache--maybe we've recently applied it. - { - CDReader cdata(_cycler); - CacheEntry temp_entry(source_data, munger); - temp_entry.local_object(); - Cache::const_iterator ci = cdata->_cache.find(&temp_entry); - if (ci != cdata->_cache.end()) { - CacheEntry *entry = (*ci); - - if (get_modified() <= entry->_geom_result->get_modified() && - data->get_modified() <= entry->_data_result->get_modified()) { - // The cache entry is still good; use it. - - // Record a cache hit, so this element will stay in the cache a - // while longer. - entry->refresh(); - result = entry->_geom_result; - data = entry->_data_result; - return; - } - - // The cache entry is stale, remove it. - if (gobj_cat.is_debug()) { - gobj_cat.debug() - << "Cache entry " << *entry << " is stale, removing.\n"; - } - entry->erase(); - CDWriter cdataw(((qpGeom *)this)->_cycler, cdata); - cdataw->_cache.erase(entry); - } - } - - // Ok, invoke the munger. - PStatTimer timer(qpGeomMunger::_munge_pcollector); - - result = this; - if (munger != (qpGeomMunger *)NULL) { - data = munger->munge_data(data); - ((qpGeomMunger *)munger)->munge_geom_impl(result, data); - } - - { - // Record the new result in the cache. - CacheEntry *entry; - { - CDWriter cdata(((qpGeom *)this)->_cycler); - entry = new CacheEntry((qpGeom *)this, source_data, munger, - result, data); - bool inserted = cdata->_cache.insert(entry).second; - nassertv(inserted); - } - - // And tell the cache manager about the new entry. (It might - // immediately request a delete from the cache of the thing we - // just added.) - entry->record(); - } -} - //////////////////////////////////////////////////////////////////// // Function: qpGeom::check_valid // Access: Published diff --git a/panda/src/gobj/qpgeom.h b/panda/src/gobj/qpgeom.h index 62f7d27ef3..89dfe0b7ca 100644 --- a/panda/src/gobj/qpgeom.h +++ b/panda/src/gobj/qpgeom.h @@ -105,9 +105,6 @@ PUBLISHED: // Temporarily virtual. virtual void transform_vertices(const LMatrix4f &mat); - void munge_geom(const qpGeomMunger *munger, - CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const; - // Temporarily virtual. virtual bool check_valid() const; @@ -227,6 +224,7 @@ private: static TypeHandle _type_handle; friend class CacheEntry; + friend class qpGeomMunger; }; INLINE ostream &operator << (ostream &out, const qpGeom &obj); diff --git a/panda/src/gobj/qpgeomMunger.I b/panda/src/gobj/qpgeomMunger.I index e4fc4d8b5f..e3f9dc4112 100644 --- a/panda/src/gobj/qpgeomMunger.I +++ b/panda/src/gobj/qpgeomMunger.I @@ -45,7 +45,7 @@ is_registered() const { // normally; you should use only the returned value from // this point on. //////////////////////////////////////////////////////////////////// -INLINE CPT(qpGeomMunger) qpGeomMunger:: +INLINE PT(qpGeomMunger) qpGeomMunger:: register_munger(qpGeomMunger *munger) { return get_registry()->register_munger(munger); } diff --git a/panda/src/gobj/qpgeomMunger.cxx b/panda/src/gobj/qpgeomMunger.cxx index 0ccf51f981..181698a6d8 100644 --- a/panda/src/gobj/qpgeomMunger.cxx +++ b/panda/src/gobj/qpgeomMunger.cxx @@ -32,7 +32,7 @@ PStatCollector qpGeomMunger::_munge_pcollector("*:Munge"); // Description: //////////////////////////////////////////////////////////////////// qpGeomMunger:: -qpGeomMunger(const GraphicsStateGuardianBase *, const RenderState *) : +qpGeomMunger() : _is_registered(false) { #ifndef NDEBUG @@ -92,6 +92,79 @@ remove_data(const qpGeomVertexData *data) { nassertv(_is_registered); } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomMunger::munge_geom +// Access: Published +// Description: Applies the indicated munger to the geom and its +// data, and returns a (possibly different) geom and +// data, according to the munger's whim. +// +// The assumption is that for a particular geom and a +// particular munger, the result will always be the +// same; so this result may be cached. +//////////////////////////////////////////////////////////////////// +void qpGeomMunger:: +munge_geom(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data) { + CPT(qpGeomVertexData) source_data = data; + + // Look up the munger in the geom's cache--maybe we've recently + // applied it. + { + qpGeom::CDReader cdata(geom->_cycler); + qpGeom::CacheEntry temp_entry(source_data, this); + temp_entry.local_object(); + qpGeom::Cache::const_iterator ci = cdata->_cache.find(&temp_entry); + if (ci != cdata->_cache.end()) { + qpGeom::CacheEntry *entry = (*ci); + + if (geom->get_modified() <= entry->_geom_result->get_modified() && + data->get_modified() <= entry->_data_result->get_modified()) { + // The cache entry is still good; use it. + + // Record a cache hit, so this element will stay in the cache a + // while longer. + entry->refresh(); + geom = entry->_geom_result; + data = entry->_data_result; + return; + } + + // The cache entry is stale, remove it. + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Cache entry " << *entry << " is stale, removing.\n"; + } + entry->erase(); + qpGeom::CDWriter cdataw(((qpGeom *)geom.p())->_cycler, cdata); + cdataw->_cache.erase(entry); + } + } + + // Ok, invoke the munger. + PStatTimer timer(_munge_pcollector); + + CPT(qpGeom) orig_geom = geom; + data = munge_data(data); + munge_geom_impl(geom, data); + + { + // Record the new result in the cache. + qpGeom::CacheEntry *entry; + { + qpGeom::CDWriter cdata(((qpGeom *)orig_geom.p())->_cycler); + entry = new qpGeom::CacheEntry((qpGeom *)orig_geom.p(), source_data, this, + geom, data); + bool inserted = cdata->_cache.insert(entry).second; + nassertv(inserted); + } + + // And tell the cache manager about the new entry. (It might + // immediately request a delete from the cache of the thing we + // just added.) + entry->record(); + } +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomMunger::do_munge_format // Access: Protected @@ -286,7 +359,7 @@ Registry() { // normally; you should use only the returned value from // this point on. //////////////////////////////////////////////////////////////////// -CPT(qpGeomMunger) qpGeomMunger::Registry:: +PT(qpGeomMunger) qpGeomMunger::Registry:: register_munger(qpGeomMunger *munger) { if (munger->is_registered()) { return munger; diff --git a/panda/src/gobj/qpgeomMunger.h b/panda/src/gobj/qpgeomMunger.h index 2132683445..6a689adc8f 100644 --- a/panda/src/gobj/qpgeomMunger.h +++ b/panda/src/gobj/qpgeomMunger.h @@ -60,13 +60,13 @@ class qpGeom; //////////////////////////////////////////////////////////////////// class EXPCL_PANDA qpGeomMunger : public TypedReferenceCount, public qpGeomEnums { public: - qpGeomMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state); + qpGeomMunger(); qpGeomMunger(const qpGeomMunger ©); void operator = (const qpGeomMunger ©); virtual ~qpGeomMunger(); INLINE bool is_registered() const; - INLINE static CPT(qpGeomMunger) register_munger(qpGeomMunger *munger); + INLINE static PT(qpGeomMunger) register_munger(qpGeomMunger *munger); INLINE CPT(qpGeomVertexFormat) munge_format(const qpGeomVertexFormat *format, const qpGeomVertexAnimationSpec &animation) const; @@ -74,7 +74,7 @@ public: INLINE CPT(qpGeomVertexData) munge_data(const qpGeomVertexData *data) const; void remove_data(const qpGeomVertexData *data); - // Also see Geom::munge_geom() for the primary interface. + void munge_geom(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data); public: INLINE int compare_to(const qpGeomMunger &other) const; @@ -132,7 +132,7 @@ private: class EXPCL_PANDA Registry { public: Registry(); - CPT(qpGeomMunger) register_munger(qpGeomMunger *munger); + PT(qpGeomMunger) register_munger(qpGeomMunger *munger); void unregister_munger(qpGeomMunger *munger); Mungers _mungers; diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index c16bcfd0c3..95131166af 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -145,7 +145,7 @@ public: virtual IndexBufferContext *prepare_index_buffer(qpGeomPrimitive *data)=0; virtual void release_index_buffer(IndexBufferContext *ibc)=0; - virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state)=0; + virtual PT(qpGeomMunger) get_geom_munger(const RenderState *state)=0; virtual void set_state_and_transform(const RenderState *state, const TransformState *transform)=0; @@ -205,8 +205,6 @@ public: virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex)=0; virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex)=0; - virtual void apply_material(const Material *material)=0; - virtual CoordinateSystem get_internal_coordinate_system() const=0; virtual void issue_transform(const TransformState *) { } diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 45f7d88b27..a330fc1a4f 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -91,6 +91,7 @@ shadeModelAttrib.I shadeModelAttrib.h \ showBoundsEffect.I showBoundsEffect.h \ spotlight.I spotlight.h \ + stateMunger.I stateMunger.h \ switchNode.I switchNode.h \ texMatrixAttrib.I texMatrixAttrib.h \ texProjectorEffect.I texProjectorEffect.h \ @@ -188,6 +189,7 @@ shadeModelAttrib.cxx \ showBoundsEffect.cxx \ spotlight.cxx \ + stateMunger.cxx \ switchNode.cxx \ texMatrixAttrib.cxx \ texProjectorEffect.cxx \ @@ -281,6 +283,7 @@ shadeModelAttrib.I shadeModelAttrib.h \ showBoundsEffect.I showBoundsEffect.h \ spotlight.I spotlight.h \ + stateMunger.I stateMunger.h \ switchNode.I switchNode.h \ texMatrixAttrib.I texMatrixAttrib.h \ texProjectorEffect.I texProjectorEffect.h \ diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 8595c07010..5bc61f20f3 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -82,6 +82,7 @@ #include "shadeModelAttrib.h" #include "showBoundsEffect.h" #include "spotlight.h" +#include "stateMunger.h" #include "switchNode.h" #include "texMatrixAttrib.h" #include "texProjectorEffect.h" @@ -320,6 +321,7 @@ init_libpgraph() { ShadeModelAttrib::init_type(); ShowBoundsEffect::init_type(); Spotlight::init_type(); + StateMunger::init_type(); SwitchNode::init_type(); TexMatrixAttrib::init_type(); TexProjectorEffect::init_type(); diff --git a/panda/src/pgraph/cullResult.I b/panda/src/pgraph/cullResult.I index 37dbba7b04..dcd8ba9508 100644 --- a/panda/src/pgraph/cullResult.I +++ b/panda/src/pgraph/cullResult.I @@ -63,13 +63,13 @@ get_bin(int bin_index) { // if we haven't already created one for this state; // otherwise, it will return the existing one. //////////////////////////////////////////////////////////////////// -INLINE CPT(qpGeomMunger) CullResult:: +INLINE PT(qpGeomMunger) CullResult:: get_geom_munger(const RenderState *state) { Mungers::iterator mi = _mungers.find(state); if (mi != _mungers.end()) { return (*mi).second; } - CPT(qpGeomMunger) munger = _gsg->get_geom_munger(state); + PT(qpGeomMunger) munger = _gsg->get_geom_munger(state); _mungers.insert(Mungers::value_type(state, munger)); return munger; } diff --git a/panda/src/pgraph/cullResult.h b/panda/src/pgraph/cullResult.h index 6bb31cc04e..bbab24e9bb 100644 --- a/panda/src/pgraph/cullResult.h +++ b/panda/src/pgraph/cullResult.h @@ -66,7 +66,7 @@ public: private: CullBin *make_new_bin(int bin_index); - INLINE CPT(qpGeomMunger) get_geom_munger(const RenderState *state); + INLINE PT(qpGeomMunger) get_geom_munger(const RenderState *state); static CPT(RenderState) get_binary_state(); static CPT(RenderState) get_dual_transparent_state(); @@ -75,7 +75,7 @@ private: GraphicsStateGuardianBase *_gsg; - typedef pmap Mungers; + typedef pmap Mungers; Mungers _mungers; typedef pvector< PT(CullBin) > Bins; diff --git a/panda/src/pgraph/cullableObject.cxx b/panda/src/pgraph/cullableObject.cxx index b8b2e53c38..16983f4189 100644 --- a/panda/src/pgraph/cullableObject.cxx +++ b/panda/src/pgraph/cullableObject.cxx @@ -23,6 +23,7 @@ #include "cullTraverser.h" #include "sceneSetup.h" #include "lens.h" +#include "stateMunger.h" #include "pStatTimer.h" #include "qpgeomVertexWriter.h" #include "qpgeomVertexReader.h" @@ -42,7 +43,7 @@ TypeHandle CullableObject::_type_handle; //////////////////////////////////////////////////////////////////// void CullableObject:: munge_geom(GraphicsStateGuardianBase *gsg, - const qpGeomMunger *munger, const CullTraverser *traverser) { + qpGeomMunger *munger, const CullTraverser *traverser) { if (_geom != (Geom *)NULL) { // Temporary test and dcast until the experimental Geom rewrite // becomes the actual Geom rewrite. @@ -73,7 +74,12 @@ munge_geom(GraphicsStateGuardianBase *gsg, // Now invoke the munger to ensure the resulting geometry is in // a GSG-friendly form. - qpgeom->munge_geom(munger, qpgeom, _munged_data); + munger->munge_geom(qpgeom, _munged_data); + + StateMunger *state_munger; + DCAST_INTO_V(state_munger, munger); + _state = state_munger->munge_state(_state); + CPT(qpGeomVertexData) animated_vertices = _munged_data->animate_vertices(); #ifndef NDEBUG diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index e318f64d9d..caa228a8ed 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -58,7 +58,7 @@ public: INLINE bool has_decals() const; void munge_geom(GraphicsStateGuardianBase *gsg, - const qpGeomMunger *munger, const CullTraverser *traverser); + qpGeomMunger *munger, const CullTraverser *traverser); INLINE void draw(GraphicsStateGuardianBase *gsg); public: @@ -77,7 +77,7 @@ PUBLISHED: public: CPT(Geom) _geom; - CPT(qpGeomMunger) _munger; + PT(qpGeomMunger) _munger; CPT(qpGeomVertexData) _munged_data; CPT(RenderState) _state; CPT(TransformState) _transform; diff --git a/panda/src/pgraph/pgraph_composite4.cxx b/panda/src/pgraph/pgraph_composite4.cxx index 56353e8144..fd6c70bd4f 100644 --- a/panda/src/pgraph/pgraph_composite4.cxx +++ b/panda/src/pgraph/pgraph_composite4.cxx @@ -11,6 +11,7 @@ #include "shadeModelAttrib.cxx" #include "showBoundsEffect.cxx" #include "spotlight.cxx" +#include "stateMunger.cxx" #include "switchNode.cxx" #include "texMatrixAttrib.cxx" #include "texProjectorEffect.cxx" diff --git a/panda/src/pgraph/stateMunger.I b/panda/src/pgraph/stateMunger.I new file mode 100644 index 0000000000..d976176d69 --- /dev/null +++ b/panda/src/pgraph/stateMunger.I @@ -0,0 +1,18 @@ +// Filename: stateMunger.I +// Created by: drose (04May05) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/pgraph/stateMunger.cxx b/panda/src/pgraph/stateMunger.cxx new file mode 100644 index 0000000000..cf88e3a455 --- /dev/null +++ b/panda/src/pgraph/stateMunger.cxx @@ -0,0 +1,50 @@ +// Filename: stateMunger.cxx +// Created by: drose (04May05) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "stateMunger.h" + +TypeHandle StateMunger::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: StateMunger::munge_state +// Access: Public +// Description: Given an input state, returns the munged state. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) StateMunger:: +munge_state(const RenderState *state) { + CPT(RenderState) ptstate = state; + StateMap::iterator mi = _state_map.find(ptstate); + if (mi != _state_map.end()) { + return (*mi).second; + } + + CPT(RenderState) result = munge_state_impl(state); + _state_map[ptstate] = result; + + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: StateMunger::munge_state_impl +// Access: Protected, Virtual +// Description: Given an input state, returns the munged state. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) StateMunger:: +munge_state_impl(const RenderState *state) { + return state; +} diff --git a/panda/src/pgraph/stateMunger.h b/panda/src/pgraph/stateMunger.h new file mode 100644 index 0000000000..beadedf6d9 --- /dev/null +++ b/panda/src/pgraph/stateMunger.h @@ -0,0 +1,65 @@ +// Filename: stateMunger.h +// Created by: drose (04May05) +// +//////////////////////////////////////////////////////////////////// +// +// 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 STATEMUNGER_H +#define STATEMUNGER_H + +#include "pandabase.h" +#include "qpgeomMunger.h" + +//////////////////////////////////////////////////////////////////// +// Class : StateMunger +// Description : This is just a simple derivative of GeomMunger that +// adds the ability to munge states. That functionality +// can't be declared in the base class, since it doesn't +// really know about RenderState. +// +// This is part of the experimental Geom rewrite. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA StateMunger : public qpGeomMunger { +public: + CPT(RenderState) munge_state(const RenderState *state); + +protected: + CPT(RenderState) munge_state_impl(const RenderState *state); + + typedef pmap StateMap; + StateMap _state_map; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + qpGeomMunger::init_type(); + register_type(_type_handle, "StateMunger", + qpGeomMunger::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 "stateMunger.I" + +#endif +