Add M_filled_wireframe render mode

This commit is contained in:
rdb 2015-02-06 12:15:25 +01:00
parent eaabc1bfa5
commit 78f8f65ef9
12 changed files with 236 additions and 121 deletions

View File

@ -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)));
}

View File

@ -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

View File

@ -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]);

View File

@ -97,7 +97,7 @@ public:
const pvector<Filename> &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:

View File

@ -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
}

View File

@ -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()));
}

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);
}
}

View File

@ -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 &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;