From 2fc1dfb8a32c4e2f07707ed85ee989562576825c Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 14 May 2002 21:35:56 +0000 Subject: [PATCH] implement M_dual --- panda/src/glgsg/glGraphicsStateGuardian.cxx | 18 +--- panda/src/pgraph/alphaTestAttrib.I | 7 +- panda/src/pgraph/alphaTestAttrib.cxx | 8 +- panda/src/pgraph/alphaTestAttrib.h | 6 +- panda/src/pgraph/config_pgraph.cxx | 3 + panda/src/pgraph/cullResult.I | 15 --- panda/src/pgraph/cullResult.cxx | 110 ++++++++++++++++++++ panda/src/pgraph/cullResult.h | 6 +- panda/src/pgraph/cullTraverserData.cxx | 2 +- panda/src/pgraph/cullableObject.I | 21 ++-- panda/src/pgraph/cullableObject.h | 1 - panda/src/pgraph/renderState.I | 19 ++++ panda/src/pgraph/renderState.cxx | 42 ++++++-- panda/src/pgraph/renderState.h | 9 +- panda/src/pgraph/transparencyAttrib.cxx | 4 + panda/src/pgraph/transparencyAttrib.h | 1 + 16 files changed, 216 insertions(+), 56 deletions(-) diff --git a/panda/src/glgsg/glGraphicsStateGuardian.cxx b/panda/src/glgsg/glGraphicsStateGuardian.cxx index 71a680b583..81d39ac037 100644 --- a/panda/src/glgsg/glGraphicsStateGuardian.cxx +++ b/panda/src/glgsg/glGraphicsStateGuardian.cxx @@ -3480,7 +3480,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode, enable_multisample_alpha_one(false); enable_multisample_alpha_mask(false); enable_blend(true); - enable_alpha_test(false); call_glBlendFunc(GL_ZERO, GL_ONE); return; } @@ -3494,7 +3493,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode, enable_multisample_alpha_one(false); enable_multisample_alpha_mask(false); enable_blend(true); - enable_alpha_test(false); call_glBlendFunc(GL_DST_COLOR, GL_ZERO); return; @@ -3502,7 +3500,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode, enable_multisample_alpha_one(false); enable_multisample_alpha_mask(false); enable_blend(true); - enable_alpha_test(false); call_glBlendFunc(GL_ONE, GL_ONE); return; @@ -3510,7 +3507,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode, enable_multisample_alpha_one(false); enable_multisample_alpha_mask(false); enable_blend(true); - enable_alpha_test(false); call_glBlendFunc(GL_DST_COLOR, GL_ONE); return; @@ -3523,10 +3519,12 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode, // No color blend; is there a transparency set? switch (transparency_mode) { case TransparencyAttrib::M_none: + case TransparencyAttrib::M_binary: break; case TransparencyAttrib::M_alpha: case TransparencyAttrib::M_alpha_sorted: + case TransparencyAttrib::M_dual: // Should we really have an "alpha" and an "alpha_sorted" mode, // like Performer does? (The difference is that "alpha" is with // the write to the depth buffer disabled.) Or should we just use @@ -3537,30 +3535,19 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode, enable_multisample_alpha_one(false); enable_multisample_alpha_mask(false); enable_blend(true); - enable_alpha_test(false); call_glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); return; - - case TransparencyAttrib::M_binary: - enable_multisample_alpha_one(false); - enable_multisample_alpha_mask(false); - enable_blend(false); - enable_alpha_test(true); - call_glAlphaFunc(GL_EQUAL, 1); - return; case TransparencyAttrib::M_multisample: enable_multisample_alpha_one(true); enable_multisample_alpha_mask(true); enable_blend(false); - enable_alpha_test(false); return; case TransparencyAttrib::M_multisample_mask: enable_multisample_alpha_one(false); enable_multisample_alpha_mask(true); enable_blend(false); - enable_alpha_test(false); return; default: @@ -3573,7 +3560,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode, enable_multisample_alpha_one(false); enable_multisample_alpha_mask(false); enable_blend(false); - enable_alpha_test(false); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/alphaTestAttrib.I b/panda/src/pgraph/alphaTestAttrib.I index 430fbc977e..dc6364cafa 100644 --- a/panda/src/pgraph/alphaTestAttrib.I +++ b/panda/src/pgraph/alphaTestAttrib.I @@ -24,7 +24,8 @@ // AlphaTestAttrib object. //////////////////////////////////////////////////////////////////// INLINE AlphaTestAttrib:: -AlphaTestAttrib(AlphaTestAttrib::PandaCompareFunc mode,float reference_alpha) : +AlphaTestAttrib(AlphaTestAttrib::PandaCompareFunc mode, + float reference_alpha) : _mode(mode), _reference_alpha(reference_alpha) { } @@ -35,7 +36,7 @@ AlphaTestAttrib(AlphaTestAttrib::PandaCompareFunc mode,float reference_alpha) : // Description: Returns the alpha write mode. //////////////////////////////////////////////////////////////////// INLINE AlphaTestAttrib::PandaCompareFunc AlphaTestAttrib:: -get_mode(void) const { +get_mode() const { return _mode; } @@ -45,6 +46,6 @@ get_mode(void) const { // Description: Returns the alpha reference value. //////////////////////////////////////////////////////////////////// INLINE float AlphaTestAttrib:: -get_reference_alpha(void) const { +get_reference_alpha() const { return _reference_alpha; } diff --git a/panda/src/pgraph/alphaTestAttrib.cxx b/panda/src/pgraph/alphaTestAttrib.cxx index 98fd5b307c..08705b74b6 100644 --- a/panda/src/pgraph/alphaTestAttrib.cxx +++ b/panda/src/pgraph/alphaTestAttrib.cxx @@ -83,9 +83,11 @@ compare_to_impl(const RenderAttrib *other) const { const AlphaTestAttrib *ta; DCAST_INTO_R(ta, other, 0); int compare_result = ((int)_mode - (int)ta->_mode) ; - if(compare_result!=0) - return compare_result; - else return (int) (255.0f*(_reference_alpha - ta->_reference_alpha)); + if (compare_result!=0) { + return compare_result; + } else { + return (int) (255.0f*(_reference_alpha - ta->_reference_alpha)); + } } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/alphaTestAttrib.h b/panda/src/pgraph/alphaTestAttrib.h index d9d3ec272b..f76a7d5163 100644 --- a/panda/src/pgraph/alphaTestAttrib.h +++ b/panda/src/pgraph/alphaTestAttrib.h @@ -31,10 +31,12 @@ class FactoryParams; //////////////////////////////////////////////////////////////////// class EXPCL_PANDA AlphaTestAttrib : public RenderAttrib { private: - INLINE AlphaTestAttrib(PandaCompareFunc mode = M_always,float reference_alpha = 1.0f); + INLINE AlphaTestAttrib(PandaCompareFunc mode = M_always, + float reference_alpha = 1.0f); PUBLISHED: - static CPT(RenderAttrib) make(PandaCompareFunc mode,float reference_alpha); + static CPT(RenderAttrib) make(PandaCompareFunc mode, + float reference_alpha); INLINE float get_reference_alpha() const; INLINE PandaCompareFunc get_mode() const; diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 1ab6c53765..f63a5382a0 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -18,6 +18,7 @@ #include "config_pgraph.h" +#include "alphaTestAttrib.h" #include "ambientLight.h" #include "billboardEffect.h" #include "camera.h" @@ -104,6 +105,7 @@ init_libpgraph() { } initialized = true; + AlphaTestAttrib::init_type(); AmbientLight::init_type(); BillboardEffect::init_type(); Camera::init_type(); @@ -162,6 +164,7 @@ init_libpgraph() { ColorLerpFunctor::init_type(); ColorScaleLerpFunctor::init_type(); + AlphaTestAttrib::register_with_read_factory(); AmbientLight::register_with_read_factory(); BillboardEffect::register_with_read_factory(); Camera::register_with_read_factory(); diff --git a/panda/src/pgraph/cullResult.I b/panda/src/pgraph/cullResult.I index b44757d7ac..4beb210449 100644 --- a/panda/src/pgraph/cullResult.I +++ b/panda/src/pgraph/cullResult.I @@ -54,18 +54,3 @@ get_bin(int bin_index) { } return make_new_bin(bin_index); } - -//////////////////////////////////////////////////////////////////// -// Function: CullResult::add_object -// Access: Public -// Description: Adds the indicated CullableObject to the appropriate -// bin. The bin becomes the owner of the object -// pointer, and will eventually delete it. -//////////////////////////////////////////////////////////////////// -INLINE void CullResult:: -add_object(CullableObject *object) { - nassertv(object->_state != (const RenderState *)NULL); - CullBin *bin = get_bin(object->_state->get_bin_index()); - nassertv(bin != (CullBin *)NULL); - bin->add_object(object); -} diff --git a/panda/src/pgraph/cullResult.cxx b/panda/src/pgraph/cullResult.cxx index 1804f54333..dabd0921cc 100644 --- a/panda/src/pgraph/cullResult.cxx +++ b/panda/src/pgraph/cullResult.cxx @@ -18,6 +18,9 @@ #include "cullResult.h" #include "cullBinManager.h" +#include "alphaTestAttrib.h" +#include "transparencyAttrib.h" +#include "renderState.h" //////////////////////////////////////////////////////////////////// // Function: CullResult::make_next @@ -44,6 +47,64 @@ make_next() const { return new_result; } +//////////////////////////////////////////////////////////////////// +// Function: CullResult::add_object +// Access: Public +// Description: Adds the indicated CullableObject to the appropriate +// bin. The bin becomes the owner of the object +// pointer, and will eventually delete it. +//////////////////////////////////////////////////////////////////// +void CullResult:: +add_object(CullableObject *object) { + // Check to see if there's a special transparency setting. + const RenderState *state = object->_state; + nassertv(state != (const RenderState *)NULL); + + const TransparencyAttrib *trans = state->get_transparency(); + if (trans != (const TransparencyAttrib *)NULL) { + switch (trans->get_mode()) { + case TransparencyAttrib::M_binary: + // M_binary is implemented by explicitly setting the alpha test. + object->_state = state->compose(get_binary_state()); + break; + + case TransparencyAttrib::M_dual: + { + // M_dual is implemented by drawing the opaque parts first, + // without transparency, then drawing the transparent parts + // later. This means we must copy the object and add it to + // both bins. We can only do this if we do not have an + // explicit bin already applied; otherwise, M_dual falls back + // to M_alpha. + const CullBinAttrib *bin_attrib = state->get_bin(); + if (bin_attrib == (CullBinAttrib *)NULL || + bin_attrib->get_bin_name().empty()) { + // We make a copy of the object to draw the transparent part + // without decals; this gets placed in the transparent bin. + CullableObject *transparent_part = new CullableObject(*object); + transparent_part->_state = state->compose(get_dual_transparent_state()); + CullBin *bin = get_bin(transparent_part->_state->get_bin_index()); + nassertv(bin != (CullBin *)NULL); + bin->add_object(transparent_part); + + // Now we can draw the opaque part, with decals. This will + // end up in the opaque bin. + object->_state = state->compose(get_dual_opaque_state()); + } + } + break; + + default: + // Other kinds of transparency need no special handling. + break; + } + } + + CullBin *bin = get_bin(object->_state->get_bin_index()); + nassertv(bin != (CullBin *)NULL); + bin->add_object(object); +} + //////////////////////////////////////////////////////////////////// // Function: CullResult::finish_cull // Access: Public @@ -119,3 +180,52 @@ make_new_bin(int bin_index) { return bin; } + +//////////////////////////////////////////////////////////////////// +// Function: CullResult::get_binary_state +// Access: Private +// Description: Returns a RenderState that applies the effects of +// M_binary. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) CullResult:: +get_binary_state() { + static CPT(RenderState) state = NULL; + if (state == (const RenderState *)NULL) { + state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_equal, 1.0f), + RenderState::get_max_priority()); + } + return state; +} + +//////////////////////////////////////////////////////////////////// +// Function: CullResult::get_dual_transparent_state +// Access: Private +// Description: Returns a RenderState that renders only the +// transparent parts of an object, in support of M_dual. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) CullResult:: +get_dual_transparent_state() { + static CPT(RenderState) state = NULL; + if (state == (const RenderState *)NULL) { + state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_less, 1.0f), + RenderState::get_max_priority()); + } + return state; +} + +//////////////////////////////////////////////////////////////////// +// Function: CullResult::get_dual_opaque_state +// Access: Private +// Description: Returns a RenderState that renders only the +// opaque parts of an object, in support of M_dual. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) CullResult:: +get_dual_opaque_state() { + static CPT(RenderState) state = NULL; + if (state == (const RenderState *)NULL) { + state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_equal, 1.0f), + TransparencyAttrib::make(TransparencyAttrib::M_none), + RenderState::get_max_priority()); + } + return state; +} diff --git a/panda/src/pgraph/cullResult.h b/panda/src/pgraph/cullResult.h index 2e95e775cf..d5086333bf 100644 --- a/panda/src/pgraph/cullResult.h +++ b/panda/src/pgraph/cullResult.h @@ -53,7 +53,7 @@ public: INLINE CullBin *get_bin(int bin_index); - INLINE void add_object(CullableObject *object); + void add_object(CullableObject *object); void finish_cull(); void draw(); @@ -63,6 +63,10 @@ public: private: CullBin *make_new_bin(int bin_index); + static CPT(RenderState) get_binary_state(); + static CPT(RenderState) get_dual_transparent_state(); + static CPT(RenderState) get_dual_opaque_state(); + GraphicsStateGuardianBase *_gsg; typedef pvector< PT(CullBin) > Bins; diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index b2863bcc2d..e2e07f8fa1 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -156,7 +156,7 @@ get_fake_view_frustum_cull_state() { (ColorAttrib::make_flat(Colorf(1.0f, 0.0f, 0.0f, 1.0f)), TextureAttrib::make_off(), RenderModeAttrib::make(RenderModeAttrib::M_wireframe), - 1000); + RenderState::get_max_priority()); } return state; } diff --git a/panda/src/pgraph/cullableObject.I b/panda/src/pgraph/cullableObject.I index bfd9100c8c..129b666013 100644 --- a/panda/src/pgraph/cullableObject.I +++ b/panda/src/pgraph/cullableObject.I @@ -66,22 +66,31 @@ CullableObject(Geom *geom, const RenderState *state, //////////////////////////////////////////////////////////////////// // Function: CullableObject::Copy Constructor -// Access: Private -// Description: CullableObjects should not be copied. +// Access: Public +// Description: Copies the CullableObject, but does not copy its +// children (decals). //////////////////////////////////////////////////////////////////// INLINE CullableObject:: -CullableObject(const CullableObject ©) { - nassertv(false); +CullableObject(const CullableObject ©) : + _geom(copy._geom), + _state(copy._state), + _transform(copy._transform), + _next((CullableObject *)NULL) +{ } //////////////////////////////////////////////////////////////////// // Function: CullableObject::Copy Assignment Operator // Access: Private -// Description: CullableObjects should not be copied. +// Access: Public +// Description: Copies the CullableObject, but does not copy its +// children (decals). //////////////////////////////////////////////////////////////////// INLINE void CullableObject:: operator = (const CullableObject ©) { - nassertv(false); + _geom = copy._geom; + _state = copy._state; + _transform = copy._transform; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index 6f8a4b3987..e7c59c3435 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -46,7 +46,6 @@ public: const TransformState *transform, CullableObject *next = NULL); -private: INLINE CullableObject(const CullableObject ©); INLINE void operator = (const CullableObject ©); diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I index bd37c363ad..8cda909c54 100644 --- a/panda/src/pgraph/renderState.I +++ b/panda/src/pgraph/renderState.I @@ -237,6 +237,25 @@ get_fog() const { return _fog; } +//////////////////////////////////////////////////////////////////// +// Function: RenderState::get_bin +// Access: Public +// Description: This function is provided as an optimization, to +// speed up the render-time checking for the existance +// of a BinAttrib on this state. It returns a +// pointer to the BinAttrib, if there is one, or +// NULL if there is not. +//////////////////////////////////////////////////////////////////// +INLINE const CullBinAttrib *RenderState:: +get_bin() const { + if ((_flags & F_checked_bin) == 0) { + // We pretend this function is const, even though it transparently + // modifies the internal bin cache. + ((RenderState *)this)->determine_bin(); + } + return _bin; +} + //////////////////////////////////////////////////////////////////// // Function: RenderState::get_transparency // Access: Public diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index 4f474bd0b0..fafc691de3 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -608,6 +608,21 @@ write(ostream &out, int indent_level) const { } } +//////////////////////////////////////////////////////////////////// +// Function: RenderState::get_max_priority +// Access: Published, Static +// Description: Returns the maximum priority number (sometimes called +// override) that may be set on any node. This may or +// may not be enforced, but the scene graph code assumes +// that no priority numbers will be larger than this, +// and some effects may not work properly if you use a +// larger number. +//////////////////////////////////////////////////////////////////// +int RenderState:: +get_max_priority() { + return 1000000000; +} + //////////////////////////////////////////////////////////////////// // Function: RenderState::issue_delta_modify // Access: Public @@ -934,9 +949,8 @@ determine_bin_index() { string bin_name; _draw_order = 0; - const RenderAttrib *attrib = get_attrib(CullBinAttrib::get_class_type()); - if (attrib != (const RenderAttrib *)NULL) { - const CullBinAttrib *bin_attrib = DCAST(CullBinAttrib, attrib); + const CullBinAttrib *bin_attrib = get_bin(); + if (bin_attrib != (const CullBinAttrib *)NULL) { bin_name = bin_attrib->get_bin_name(); _draw_order = bin_attrib->get_draw_order(); } @@ -946,13 +960,12 @@ determine_bin_index() { // either opaque or transparent, based on the transparency // setting. bin_name = "opaque"; - const RenderAttrib *attrib = get_attrib(TransparencyAttrib::get_class_type()); - if (attrib != (const RenderAttrib *)NULL) { - const TransparencyAttrib *trans = DCAST(TransparencyAttrib, attrib); + const TransparencyAttrib *trans = get_transparency(); + if (trans != (const TransparencyAttrib *)NULL) { switch (trans->get_mode()) { case TransparencyAttrib::M_alpha: case TransparencyAttrib::M_alpha_sorted: - case TransparencyAttrib::M_binary: + case TransparencyAttrib::M_dual: // These transparency modes require special back-to-front sorting. bin_name = "transparent"; break; @@ -988,6 +1001,21 @@ determine_fog() { _flags |= F_checked_fog; } +//////////////////////////////////////////////////////////////////// +// Function: RenderState::determine_bin +// Access: Private +// Description: This is the private implementation of get_bin(). +//////////////////////////////////////////////////////////////////// +void RenderState:: +determine_bin() { + const RenderAttrib *attrib = get_attrib(CullBinAttrib::get_class_type()); + _bin = (const CullBinAttrib *)NULL; + if (attrib != (const RenderAttrib *)NULL) { + _bin = DCAST(CullBinAttrib, attrib); + } + _flags |= F_checked_bin; +} + //////////////////////////////////////////////////////////////////// // Function: RenderState::determine_transparency // Access: Private diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index 21a1b4fbdc..8c6d0d43dc 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -29,6 +29,7 @@ class GraphicsStateGuardianBase; class FogAttrib; +class CullBinAttrib; class TransparencyAttrib; class FactoryParams; @@ -92,10 +93,13 @@ PUBLISHED: void output(ostream &out) const; void write(ostream &out, int indent_level) const; + static int get_max_priority(); + public: INLINE int get_bin_index() const; INLINE int get_draw_order() const; INLINE const FogAttrib *get_fog() const; + INLINE const CullBinAttrib *get_bin() const; INLINE const TransparencyAttrib *get_transparency() const; CPT(RenderState) issue_delta_modify(const RenderState *other, @@ -111,6 +115,7 @@ private: CPT(RenderState) do_invert_compose(const RenderState *other) const; void determine_bin_index(); void determine_fog(); + void determine_bin(); void determine_transparency(); INLINE void set_destructing(); @@ -179,12 +184,14 @@ private: // We also cache the pointer to some critical attribs stored in the // state, if they exist. const FogAttrib *_fog; + const CullBinAttrib *_bin; const TransparencyAttrib *_transparency; enum Flags { F_checked_bin_index = 0x0001, F_checked_fog = 0x0002, - F_checked_transparency = 0x0004, + F_checked_bin = 0x0004, + F_checked_transparency = 0x0008, F_is_destructing = 0x8000, }; unsigned short _flags; diff --git a/panda/src/pgraph/transparencyAttrib.cxx b/panda/src/pgraph/transparencyAttrib.cxx index b6044cd28d..8f61f15065 100644 --- a/panda/src/pgraph/transparencyAttrib.cxx +++ b/panda/src/pgraph/transparencyAttrib.cxx @@ -83,6 +83,10 @@ output(ostream &out) const { case M_binary: out << "binary"; break; + + case M_dual: + out << "dual"; + break; } } diff --git a/panda/src/pgraph/transparencyAttrib.h b/panda/src/pgraph/transparencyAttrib.h index 285d72f817..e5844e53dc 100644 --- a/panda/src/pgraph/transparencyAttrib.h +++ b/panda/src/pgraph/transparencyAttrib.h @@ -44,6 +44,7 @@ PUBLISHED: M_multisample, // Source alpha values modified to 1.0 before writing M_multisample_mask, // Source alpha values not modified M_binary, // Only writes pixels with alpha = 1.0 + M_dual, // 2-pass: draws opaque, then draws transparent }; private: