diff --git a/panda/src/framework/pandaFramework.cxx b/panda/src/framework/pandaFramework.cxx index fc064a664e..2f886bae29 100644 --- a/panda/src/framework/pandaFramework.cxx +++ b/panda/src/framework/pandaFramework.cxx @@ -140,12 +140,6 @@ open_framework(int &argc, char **&argv) { _task_mgr.add(task); } - _highlight_wireframe = NodePath("wireframe"); - _highlight_wireframe.set_render_mode_wireframe(1); - _highlight_wireframe.set_texture_off(1); - _highlight_wireframe.set_color(1.0f, 0.0f, 0.0f, 1.0f, 1); - _highlight_wireframe.set_attrib(DepthOffsetAttrib::make()); - if (!playback_session.empty()) { // If the config file so indicates, create a recorder and start it // playing. @@ -784,13 +778,7 @@ set_highlight(const NodePath &node) { if (!_highlight.is_empty()) { framework_cat.info(false) << _highlight << "\n"; _highlight.show_bounds(); - - // Also create a new instance of the highlighted geometry, as a - // sibling of itself, under the special highlight property. - if (_highlight.has_parent()) { - _highlight_wireframe.reparent_to(_highlight.get_parent()); - _highlight.instance_to(_highlight_wireframe); - } + _highlight.set_render_mode_filled_wireframe(LColor(1.0f, 0.0f, 0.0f, 1.0f), 200); } } @@ -803,11 +791,8 @@ void PandaFramework:: clear_highlight() { if (!_highlight.is_empty()) { _highlight.hide_bounds(); + _highlight.clear_render_mode(); _highlight = NodePath(); - - // Clean up the special highlight instance. - _highlight_wireframe.detach_node(); - _highlight_wireframe.get_children().detach(); } } @@ -1012,7 +997,13 @@ event_w(const Event *event, void *) { WindowFramework *wf; DCAST_INTO_V(wf, param.get_ptr()); - wf->set_wireframe(!wf->get_wireframe()); + if (!wf->get_wireframe()) { + wf->set_wireframe(true, true); + } else if (wf->get_wireframe_filled()) { + wf->set_wireframe(true, false); + } else { + wf->set_wireframe(false, false); + } } } @@ -1286,13 +1277,6 @@ event_arrow_left(const Event *, void *data) { int index = parent.node()->find_child(node.node()); nassertv(index >= 0); int sibling = index - 1; - - if (sibling >= 0 && - parent.node()->get_child(sibling) == self->_highlight_wireframe.node()) { - // Skip over the special highlight node. - sibling--; - } - if (sibling >= 0) { self->set_highlight(NodePath(parent, parent.node()->get_child(sibling))); } @@ -1319,13 +1303,6 @@ event_arrow_right(const Event *, void *data) { nassertv(index >= 0); int num_children = parent.node()->get_num_children(); int sibling = index + 1; - - if (sibling < num_children && - parent.node()->get_child(sibling) == self->_highlight_wireframe.node()) { - // Skip over the special highlight node. - sibling++; - } - if (sibling < num_children) { self->set_highlight(NodePath(parent, parent.node()->get_child(sibling))); } diff --git a/panda/src/framework/windowFramework.I b/panda/src/framework/windowFramework.I index 6cb7b50a6f..d729cc0019 100644 --- a/panda/src/framework/windowFramework.I +++ b/panda/src/framework/windowFramework.I @@ -33,7 +33,7 @@ get_panda_framework() const { //////////////////////////////////////////////////////////////////// INLINE GraphicsWindow *WindowFramework:: get_graphics_window() const { - if (_window != (GraphicsOutput *)NULL && + if (_window != (GraphicsOutput *)NULL && _window->is_of_type(GraphicsWindow::get_class_type())) { return DCAST(GraphicsWindow, _window); } @@ -117,6 +117,17 @@ get_wireframe() const { return _wireframe_enabled; } +//////////////////////////////////////////////////////////////////// +// Function: WindowFramework::get_wireframe_filled +// Access: Public +// Description: Returns the current state of the wireframe_filled +// flag. +//////////////////////////////////////////////////////////////////// +INLINE bool WindowFramework:: +get_wireframe_filled() const { + return _wireframe_filled; +} + //////////////////////////////////////////////////////////////////// // Function: WindowFramework::get_texture // Access: Public diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index 5a8ca1b6b7..57505bb0d3 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -87,6 +87,7 @@ WindowFramework(PandaFramework *panda_framework) : _anim_controls_enabled = false; _anim_index = 0; _wireframe_enabled = false; + _wireframe_filled = false; _texture_enabled = true; _two_sided_enabled = false; _one_sided_reverse_enabled = false; @@ -362,7 +363,7 @@ get_pixel_2d() { PGTop *top = new PGTop("pixel_2d"); _pixel_2d = get_render_2d().attach_new_node(top); _pixel_2d.set_pos(-1, 0, 1); - + if (_window->has_size()) { int x_size = _window->get_sbs_left_x_size(); int y_size = _window->get_sbs_left_y_size(); @@ -653,7 +654,7 @@ load_model(const NodePath &parent, Filename filename) { // A texture object. Not exactly an image, but certainly a // texture. is_image = true; - + } else { TexturePool *texture_pool = TexturePool::get_global_ptr(); if (texture_pool->get_texture_type(extension) != NULL) { @@ -845,7 +846,7 @@ adjust_dimensions() { x_size = _window->get_sbs_left_x_size(); y_size = _window->get_sbs_left_y_size(); } - + if (this_aspect_ratio == 0.0f) { // An aspect ratio of 0.0 means to try to infer it. this_aspect_ratio = 1.0f; @@ -942,28 +943,42 @@ split_window(SplitType split_type) { // rendering (false). //////////////////////////////////////////////////////////////////// void WindowFramework:: -set_wireframe(bool enable) { - if (enable == _wireframe_enabled) { +set_wireframe(bool enable, bool filled) { + if (enable == _wireframe_enabled && filled == _wireframe_filled) { return; } NodePath render = get_render(); + if (!_two_sided_enabled) { + render.clear_two_sided(); + } + if (enable) { - render.set_render_mode_wireframe(override_priority); - render.set_two_sided(true, override_priority); + if (filled) { + render.set_attrib(RenderModeAttrib::make( + RenderModeAttrib::M_filled_wireframe, + 1.4f, false, LColor(1, 1, 1, .5f)), + override_priority); + // Darken the scene so that the wireframe is clearly visible, + // even when the scene is completely white. + render.set_color_scale(LColor(0.7f, 0.7f, 0.7f, 1), override_priority); + } else { + render.set_render_mode_wireframe(override_priority); + render.set_two_sided(true, override_priority); + render.clear_color_scale(); + } } else { render.clear_render_mode(); - if (!_two_sided_enabled) { - render.clear_two_sided(); - } if (_one_sided_reverse_enabled) { CPT(RenderAttrib) attrib = CullFaceAttrib::make_reverse(); render.node()->set_attrib(attrib); } + render.clear_color_scale(); } _wireframe_enabled = enable; + _wireframe_filled = filled; } //////////////////////////////////////////////////////////////////// @@ -1285,7 +1300,7 @@ load_image_as_model(const Filename &filename) { } else { framework_cat.warning() << "Texture size is 0 0: " << *tex << "\n"; - + left = -scale; right = scale; top = scale; @@ -1314,9 +1329,9 @@ load_image_as_model(const Filename &filename) { // Vertices and 3-d texture coordinates. vformat = GeomVertexFormat::register_format (new GeomVertexArrayFormat - (InternalName::get_vertex(), 3, + (InternalName::get_vertex(), 3, GeomEnums::NT_stdfloat, GeomEnums::C_point, - InternalName::get_texcoord(), 3, + InternalName::get_texcoord(), 3, GeomEnums::NT_stdfloat, GeomEnums::C_texcoord)); } @@ -1331,7 +1346,7 @@ load_image_as_model(const Filename &filename) { vertex.add_data3(LVertex::rfu(left, 0.02, bottom)); vertex.add_data3(LVertex::rfu(right, 0.02, top)); vertex.add_data3(LVertex::rfu(right, 0.02, bottom)); - + texcoord.add_data2(0.0f, tex_scale[1]); texcoord.add_data2(0.0f, 0.0f); texcoord.add_data2(tex_scale[0], tex_scale[1]); diff --git a/panda/src/framework/windowFramework.h b/panda/src/framework/windowFramework.h index 71520167e9..2ad042ed56 100644 --- a/panda/src/framework/windowFramework.h +++ b/panda/src/framework/windowFramework.h @@ -97,7 +97,7 @@ public: const pvector &files); NodePath load_model(const NodePath &parent, Filename filename); NodePath load_default_model(const NodePath &parent); - void loop_animations(int hierarchy_match_flags = + void loop_animations(int hierarchy_match_flags = PartGroup::HMF_ok_part_extra | PartGroup::HMF_ok_anim_extra); void stagger_animations(); @@ -122,7 +122,7 @@ public: }; WindowFramework *split_window(SplitType split_type = ST_default); - void set_wireframe(bool enable); + void set_wireframe(bool enable, bool filled=false); void set_texture(bool enable); void set_two_sided(bool enable); void set_one_sided_reverse(bool enable); @@ -131,6 +131,7 @@ public: void set_background_type(BackgroundType type); INLINE bool get_wireframe() const; + INLINE bool get_wireframe_filled() const; INLINE bool get_texture() const; INLINE bool get_two_sided() const; INLINE bool get_one_sided_reverse() const; @@ -150,7 +151,7 @@ private: void destroy_anim_controls(); void update_anim_controls(); - void setup_shuttle_button(const string &label, int index, + void setup_shuttle_button(const string &label, int index, EventHandler::EventCallbackFunction *func); void back_button(); void pause_button(); @@ -194,12 +195,13 @@ private: NodePath _alight; NodePath _dlight; - + bool _got_keyboard; bool _got_trackball; bool _got_lights; bool _wireframe_enabled; + bool _wireframe_filled; bool _texture_enabled; bool _two_sided_enabled; bool _one_sided_reverse_enabled; @@ -210,7 +212,7 @@ private: PT(SceneGraphAnalyzerMeter) _scene_graph_analyzer_meter; BackgroundType _background_type; - + static PT(TextFont) _shuttle_controls_font; public: diff --git a/panda/src/pgraph/cullResult.I b/panda/src/pgraph/cullResult.I index 50a4147b70..36a54b786e 100644 --- a/panda/src/pgraph/cullResult.I +++ b/panda/src/pgraph/cullResult.I @@ -39,3 +39,35 @@ get_bin(int bin_index) { } return make_new_bin(bin_index); } + +//////////////////////////////////////////////////////////////////// +// Function: CullResult::check_flash_bin +// Access: Private +// Description: If the user configured flash-bin-binname, then update +// the object's state to flash all the geometry in the +// bin. +//////////////////////////////////////////////////////////////////// +INLINE void CullResult:: +check_flash_bin(CPT(RenderState) &state, CullBinManager *bin_manager, int bin_index) { +#ifndef NDEBUG + if (bin_manager->get_bin_flash_active(bin_index)) { + apply_flash_color(state, bin_manager->get_bin_flash_color(bin_index)); + } +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: CullResult::check_flash_transparency +// Access: Private +// Description: If the user configured show-transparency, then +// update the object's state to flash the current +// geometry with the specified color. +//////////////////////////////////////////////////////////////////// +INLINE void CullResult:: +check_flash_transparency(CPT(RenderState) &state, const LColor &color) { +#ifndef NDEBUG + if (_show_transparency) { + apply_flash_color(state, color); + } +#endif +} diff --git a/panda/src/pgraph/cullResult.cxx b/panda/src/pgraph/cullResult.cxx index 65b05fd3fd..a7cab23a8b 100644 --- a/panda/src/pgraph/cullResult.cxx +++ b/panda/src/pgraph/cullResult.cxx @@ -27,27 +27,28 @@ #include "clockObject.h" #include "config_pgraph.h" #include "depthOffsetAttrib.h" +#include "colorBlendAttrib.h" TypeHandle CullResult::_type_handle; // This value is used instead of 1.0 to represent the alpha level of a // pixel that is to be considered "opaque" for the purposes of M_dual. - +// // Ideally, 1.0 is the only correct value for this. Realistically, we // have to fudge it lower for two reasons: - +// // (1) The modelers tend to paint textures with very slight // transparency levels in places that are not intended to be // transparent, without realizing it. These very faint transparency // regions are normally (almost) invisible, but when rendered with // M_dual they may be revealed as regions of poor alpha sorting. - +// // (2) There seems to be some problem in DX where, in certain // circumstances apparently related to automatic texture management, // it spontaneously drops out the bottom two bits of an eight-bit // alpha channel, causing a value of 255 to become a value of 252 // instead. - +// // We use 256 as the denominator here (instead of, say, 255) because a // fractional power of two will have a terminating representation in // base 2, and thus will be more likely to have a precise value in @@ -69,6 +70,10 @@ CullResult(GraphicsStateGuardianBase *gsg, #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); #endif + +#ifndef NDEBUG + _show_transparency = show_transparency.get_value(); +#endif } //////////////////////////////////////////////////////////////////// @@ -130,17 +135,13 @@ add_object(CullableObject *object, const CullTraverser *traverser) { // M_alpha implies an alpha-write test, so we don't waste time // writing 0-valued pixels. object->_state = state->compose(get_alpha_state()); -#ifndef NDEBUG check_flash_transparency(object->_state, flash_alpha_color); -#endif break; case TransparencyAttrib::M_binary: // M_binary is implemented by explicitly setting the alpha test. object->_state = state->compose(get_binary_state()); -#ifndef NDEBUG check_flash_transparency(object->_state, flash_binary_color); -#endif break; case TransparencyAttrib::M_multisample: @@ -150,9 +151,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) { if (!_gsg->get_supports_multisample()) { object->_state = state->compose(get_binary_state()); } -#ifndef NDEBUG check_flash_transparency(object->_state, flash_multisample_color); -#endif break; case TransparencyAttrib::M_dual: @@ -192,12 +191,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) { int transparent_bin_index = transparent_part->_state->get_bin_index(); CullBin *bin = get_bin(transparent_bin_index); nassertv(bin != (CullBin *)NULL); -#ifndef NDEBUG - if (bin_manager->get_bin_flash_active(transparent_bin_index)) { - do_flash_bin(transparent_part->_state, - bin_manager->get_bin_flash_color(transparent_bin_index)); - } -#endif + check_flash_bin(transparent_part->_state, bin_manager, transparent_bin_index); bin->add_object(transparent_part, current_thread); } else { delete transparent_part; @@ -225,16 +219,34 @@ add_object(CullableObject *object, const CullTraverser *traverser) { } } + // Check for a special wireframe setting. + const RenderModeAttrib *rmode = (const RenderModeAttrib *) + object->_state->get_attrib(RenderModeAttrib::get_class_slot()); + if (rmode != (const RenderModeAttrib *)NULL) { + if (rmode->get_mode() == RenderModeAttrib::M_filled_wireframe) { + CullableObject *wireframe_part = new CullableObject(*object); + wireframe_part->_state = get_wireframe_overlay_state(rmode); + + if (wireframe_part->munge_geom + (_gsg, _gsg->get_geom_munger(wireframe_part->_state, current_thread), + traverser, force)) { + int wireframe_bin_index = bin_manager->find_bin("fixed"); + CullBin *bin = get_bin(wireframe_bin_index); + nassertv(bin != (CullBin *)NULL); + check_flash_bin(wireframe_part->_state, bin_manager, wireframe_bin_index); + bin->add_object(wireframe_part, current_thread); + } else { + delete wireframe_part; + } + + object->_state = object->_state->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled)); + } + } + int bin_index = object->_state->get_bin_index(); CullBin *bin = get_bin(bin_index); nassertv(bin != (CullBin *)NULL); - -#ifndef NDEBUG - if (bin_manager->get_bin_flash_active(bin_index)) { - do_flash_bin(object->_state, - bin_manager->get_bin_flash_color(bin_index)); - } -#endif + check_flash_bin(object->_state, bin_manager, bin_index); // Munge vertices as needed for the GSG's requirements, and the // object's current state. @@ -410,16 +422,15 @@ get_binary_state() { return state; } +#ifndef NDEBUG //////////////////////////////////////////////////////////////////// -// Function: CullResult::do-flash_bin +// Function: CullResult::apply_flash_color // Access: Private -// Description: If the user configured flash-bin-binname, then update -// the object's state to flash all the geometry in the -// bin. +// Description: Update the object's state to flash the geometry +// with a solid color. //////////////////////////////////////////////////////////////////// void CullResult:: -do_flash_bin(CPT(RenderState) &state, const LColor &flash_color) { -#ifndef NDEBUG +apply_flash_color(CPT(RenderState) &state, const LColor &flash_color) { int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate); if ((cycle & 1) == 0) { state = state->remove_attrib(TextureAttrib::get_class_slot()); @@ -429,32 +440,8 @@ do_flash_bin(CPT(RenderState) &state, const LColor &flash_color) { state = state->add_attrib(ColorAttrib::make_flat(flash_color), RenderState::get_max_priority()); } +} #endif // NDEBUG -} - -//////////////////////////////////////////////////////////////////// -// Function: CullResult::check_flash_transparency -// Access: Private -// Description: If the user configured show-transparency, then -// update the object's state to flash the current -// geometry with the specified color. -//////////////////////////////////////////////////////////////////// -void CullResult:: -check_flash_transparency(CPT(RenderState) &state, const LColor &transparency) { -#ifndef NDEBUG - if (show_transparency) { - int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate); - if ((cycle & 1) == 0) { - state = state->remove_attrib(TextureAttrib::get_class_slot()); - state = state->remove_attrib(LightAttrib::get_class_slot()); - state = state->remove_attrib(ColorScaleAttrib::get_class_slot()); - state = state->remove_attrib(FogAttrib::get_class_slot()); - state = state->add_attrib(ColorAttrib::make_flat(transparency), - RenderState::get_max_priority()); - } - } -#endif -} //////////////////////////////////////////////////////////////////// // Function: CullResult::get_dual_transparent_state @@ -535,3 +522,22 @@ get_dual_opaque_state() { return state; } +//////////////////////////////////////////////////////////////////// +// Function: CullResult::get_wireframe_overlay_state +// Access: Private +// Description: Returns a RenderState that renders only the +// wireframe part of an M_filled_wireframe model. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) CullResult:: +get_wireframe_overlay_state(const RenderModeAttrib *rmode) { + return RenderState::make( + DepthOffsetAttrib::make(1, 0, 0.99999f), + ColorAttrib::make_flat(rmode->get_wireframe_color()), + ColorBlendAttrib::make(ColorBlendAttrib::M_add, + ColorBlendAttrib::O_incoming_alpha, + ColorBlendAttrib::O_one_minus_incoming_alpha), + RenderModeAttrib::make(RenderModeAttrib::M_wireframe, + rmode->get_thickness(), + rmode->get_perspective())); +} + diff --git a/panda/src/pgraph/cullResult.h b/panda/src/pgraph/cullResult.h index c6814dd3af..e24264e469 100644 --- a/panda/src/pgraph/cullResult.h +++ b/panda/src/pgraph/cullResult.h @@ -17,6 +17,7 @@ #include "pandabase.h" #include "cullBin.h" +#include "cullBinManager.h" #include "renderState.h" #include "cullableObject.h" #include "geomMunger.h" @@ -26,12 +27,11 @@ #include "pset.h" #include "pmap.h" - -class GraphicsStateGuardianBase; class CullTraverser; -class TransformState; +class GraphicsStateGuardianBase; class RenderState; class SceneSetup; +class TransformState; //////////////////////////////////////////////////////////////////// // Class : CullResult @@ -66,13 +66,19 @@ public: private: CullBin *make_new_bin(int bin_index); - void do_flash_bin(CPT(RenderState) &state, const LColor &flash_color); - void check_flash_transparency(CPT(RenderState) &state, const LColor &color); + + INLINE void check_flash_bin(CPT(RenderState) &state, CullBinManager *bin_manager, int bin_index); + INLINE void check_flash_transparency(CPT(RenderState) &state, const LColor &color); + +#ifndef NDEBUG + void apply_flash_color(CPT(RenderState) &state, const LColor &flash_color); +#endif static CPT(RenderState) get_alpha_state(); static CPT(RenderState) get_binary_state(); static CPT(RenderState) get_dual_transparent_state(); static CPT(RenderState) get_dual_opaque_state(); + static CPT(RenderState) get_wireframe_overlay_state(const RenderModeAttrib *rmode); GraphicsStateGuardianBase *_gsg; PStatCollector _draw_region_pcollector; @@ -80,6 +86,10 @@ private: typedef pvector< PT(CullBin) > Bins; Bins _bins; +#ifndef NDEBUG + bool _show_transparency; +#endif + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index ef6a626906..fdbfd02945 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -5213,6 +5213,22 @@ set_render_mode_filled(int priority) { node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, thickness, perspective), priority); } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_render_mode_filled_wireframe +// Access: Published +// Description: Sets up the geometry at this level and below (unless +// overridden) to render in filled, but overlay the +// wireframe on top with a fixed color. This is useful +// for debug visualizations. +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_render_mode_filled_wireframe(const LColor &wireframe_color, int priority) { + nassertv_always(!is_empty()); + PN_stdfloat thickness = get_render_mode_thickness(); + bool perspective = get_render_mode_perspective(); + node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled_wireframe, thickness, perspective, wireframe_color), priority); +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::set_render_mode_perspective // Access: Published diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index a5d8ecb26a..2cade4e55c 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -766,6 +766,7 @@ PUBLISHED: void set_render_mode_wireframe(int priority = 0); void set_render_mode_filled(int priority = 0); + void set_render_mode_filled_wireframe(const LColor &wireframe_color, int priority = 0); void set_render_mode_thickness(PN_stdfloat thickness, int priority = 0); void set_render_mode_perspective(bool perspective, int priority = 0); void set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority = 0); diff --git a/panda/src/pgraph/renderModeAttrib.I b/panda/src/pgraph/renderModeAttrib.I index b324663d9b..4a7bda8dc1 100644 --- a/panda/src/pgraph/renderModeAttrib.I +++ b/panda/src/pgraph/renderModeAttrib.I @@ -21,10 +21,11 @@ //////////////////////////////////////////////////////////////////// INLINE RenderModeAttrib:: RenderModeAttrib(RenderModeAttrib::Mode mode, PN_stdfloat thickness, - bool perspective) : + bool perspective, const LColor &wireframe_color) : _mode(mode), _thickness(thickness), - _perspective(perspective) + _perspective(perspective), + _wireframe_color(wireframe_color) { } @@ -68,6 +69,18 @@ get_perspective() const { return _perspective; } +//////////////////////////////////////////////////////////////////// +// Function: RenderModeAttrib::get_wireframe_color +// Access: Published +// Description: Returns the color that is used in M_filled_wireframe +// mode to distinguish the wireframe from the rest of +// the geometry. +//////////////////////////////////////////////////////////////////// +INLINE const LColor &RenderModeAttrib:: +get_wireframe_color() const { + return _wireframe_color; +} + //////////////////////////////////////////////////////////////////// // Function: RenderModeAttrib::get_geom_rendering // Access: Published diff --git a/panda/src/pgraph/renderModeAttrib.cxx b/panda/src/pgraph/renderModeAttrib.cxx index 9de256c811..cb91cdcf6e 100644 --- a/panda/src/pgraph/renderModeAttrib.cxx +++ b/panda/src/pgraph/renderModeAttrib.cxx @@ -44,10 +44,15 @@ int RenderModeAttrib::_attrib_slot; // it is false, the point thickness is actually a width // in pixels, and points are a uniform screen size // regardless of distance from the camera. +// +// In M_filled_wireframe mode, you should also specify +// the wireframe_color, indicating the flat color to +// assign to the overlayed wireframe. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) RenderModeAttrib:: -make(RenderModeAttrib::Mode mode, PN_stdfloat thickness, bool perspective) { - RenderModeAttrib *attrib = new RenderModeAttrib(mode, thickness, perspective); +make(RenderModeAttrib::Mode mode, PN_stdfloat thickness, + bool perspective, const LColor &wireframe_color) { + RenderModeAttrib *attrib = new RenderModeAttrib(mode, thickness, perspective, wireframe_color); return return_new(attrib); } @@ -66,7 +71,7 @@ make_default() { //////////////////////////////////////////////////////////////////// // Function: RenderModeAttrib::output // Access: Public, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// void RenderModeAttrib:: output(ostream &out) const { @@ -91,6 +96,10 @@ output(ostream &out) const { case M_filled_flat: out << "filled_flat"; break; + + case M_filled_wireframe: + out << "filled_wireframe(" << get_wireframe_color() << ")"; + break; } if (get_thickness() != 1.0f) { @@ -130,6 +139,9 @@ compare_to_impl(const RenderAttrib *other) const { if (_perspective != ta->_perspective) { return (int)_perspective - (int)ta->_perspective; } + if (_mode == M_filled_wireframe && _wireframe_color != ta->_wireframe_color) { + return _wireframe_color.compare_to(ta->_wireframe_color); + } return 0; } @@ -149,6 +161,9 @@ get_hash_impl() const { hash = int_hash::add_hash(hash, (int)_mode); hash = float_hash().add_hash(hash, _thickness); hash = int_hash::add_hash(hash, (int)_perspective); + if (_mode == M_filled_wireframe) { + hash = _wireframe_color.add_hash(hash); + } return hash; } @@ -180,7 +195,8 @@ compose_impl(const RenderAttrib *other) const { mode = get_mode(); } - return make(mode, ta->get_thickness(), ta->get_perspective()); + return make(mode, ta->get_thickness(), ta->get_perspective(), + ta->get_wireframe_color()); } //////////////////////////////////////////////////////////////////// @@ -207,6 +223,10 @@ write_datagram(BamWriter *manager, Datagram &dg) { dg.add_int8(_mode); dg.add_stdfloat(_thickness); dg.add_bool(_perspective); + + if (_mode == M_filled_wireframe) { + _wireframe_color.write_datagram(dg); + } } //////////////////////////////////////////////////////////////////// @@ -243,4 +263,8 @@ fillin(DatagramIterator &scan, BamReader *manager) { _mode = (Mode)scan.get_int8(); _thickness = scan.get_stdfloat(); _perspective = scan.get_bool(); + + if (_mode == M_filled_wireframe) { + _wireframe_color.read_datagram(scan); + } } diff --git a/panda/src/pgraph/renderModeAttrib.h b/panda/src/pgraph/renderModeAttrib.h index 8e0043f8e5..401b1d0152 100644 --- a/panda/src/pgraph/renderModeAttrib.h +++ b/panda/src/pgraph/renderModeAttrib.h @@ -44,20 +44,27 @@ PUBLISHED: // Filled polygons, without any particular emphasis on perspective // correctness (a particularly useful designation for software // rendering sprites). - M_filled_flat + M_filled_flat, + + // Filled polygons with wireframe rendered in front. + // The wireframe is given a solid color. + M_filled_wireframe }; private: - INLINE RenderModeAttrib(Mode mode, PN_stdfloat thickness, bool perspective); + INLINE RenderModeAttrib(Mode mode, PN_stdfloat thickness, bool perspective, + const LColor &wireframe_color = LColor::zero()); PUBLISHED: static CPT(RenderAttrib) make(Mode mode, PN_stdfloat thickness = 1.0f, - bool perspective = false); + bool perspective = false, + const LColor &wireframe_color = LColor::zero()); static CPT(RenderAttrib) make_default(); INLINE Mode get_mode() const; INLINE PN_stdfloat get_thickness() const; INLINE bool get_perspective() const; + INLINE const LColor &get_wireframe_color() const; INLINE int get_geom_rendering(int geom_rendering) const; @@ -73,6 +80,7 @@ private: Mode _mode; PN_stdfloat _thickness; bool _perspective; + LColor _wireframe_color; PUBLISHED: static int get_class_slot() { @@ -89,7 +97,7 @@ public: protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); - + public: static TypeHandle get_class_type() { return _type_handle;