Panda3D
standardMunger.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file standardMunger.cxx
10  * @author drose
11  * @date 2005-03-21
12  */
13 
14 #include "standardMunger.h"
15 
16 #include "config_gobj.h"
17 
18 #include "displayRegion.h"
19 #include "graphicsStateGuardian.h"
20 #include "lightAttrib.h"
21 #include "materialAttrib.h"
22 #include "renderState.h"
23 
24 TypeHandle StandardMunger::_type_handle;
25 
26 /**
27  * The StandardMunger constructor accepts additional parameters that specify
28  * the GSG's preferred color format (since we might be munging the color
29  * anyway, we might as well convert it as we munge).
30  */
33  int num_components,
34  StandardMunger::NumericType numeric_type,
35  StandardMunger::Contents contents) :
36  StateMunger(gsg),
37  _num_components(num_components),
38  _numeric_type(numeric_type),
39  _contents(contents),
40  _munge_color(false),
41  _munge_color_scale(false),
42  _auto_shader(false),
43  _shader_skinning(false),
44  _remove_material(false)
45 {
46  const ShaderAttrib *shader_attrib;
47  state->get_attrib_def(shader_attrib);
48 #ifdef HAVE_CG
49  _auto_shader = shader_attrib->auto_shader();
50 #endif
51  if (shader_attrib->get_flag(ShaderAttrib::F_hardware_skinning)) {
52  _shader_skinning = true;
53  }
54 
55  if (!get_gsg()->get_runtime_color_scale() && !_auto_shader &&
56  shader_attrib->get_shader() == nullptr) {
57  // We might need to munge the colors.
58  const ColorAttrib *color_attrib;
59  const ColorScaleAttrib *color_scale_attrib;
60 
61  if (state->get_attrib(color_attrib) &&
62  color_attrib->get_color_type() != ColorAttrib::T_vertex) {
63 
64  // In this case, we don't need to munge anything as we can apply the
65  // color and color scale via glColor4f.
66 
67  } else if (state->get_attrib(color_scale_attrib) &&
68  color_scale_attrib->has_scale()) {
69  _color_scale = color_scale_attrib->get_scale();
70 
71  const TextureAttrib *tex_attrib = (const TextureAttrib *)
72  state->get_attrib(TextureAttrib::get_class_slot());
73 
74  // If the GSG says it can't cheat this RGB or alpha scale, we have to
75  // apply the color scale directly.
76  if ((color_scale_attrib->has_rgb_scale() && !get_gsg()->get_color_scale_via_lighting()) ||
77  (color_scale_attrib->has_alpha_scale() && !get_gsg()->get_alpha_scale_via_texture(tex_attrib))) {
78  _munge_color_scale = true;
79  _should_munge_state = true;
80  }
81 
82  // Known bug: if there is a material on an object that would obscure the
83  // effect of color_scale, we scale the lighting anyway, thus applying
84  // the effect even if it should be obscured. It doesn't seem worth the
85  // effort to detect this contrived situation and handle it correctly.
86  }
87  }
88 
89  // If we have no lights but do have a material, we will need to remove it so
90  // that it won't appear when we enable color scale via lighting.
91  const LightAttrib *light_attrib;
92  const MaterialAttrib *material_attrib;
94  (!state->get_attrib(light_attrib) || !light_attrib->has_any_on_light()) &&
95  state->get_attrib(material_attrib) &&
96  material_attrib->get_material() != nullptr &&
97  shader_attrib->get_shader() == nullptr) {
98  _remove_material = true;
99  _should_munge_state = true;
100  }
101 }
102 
103 /**
104  *
105  */
106 StandardMunger::
107 ~StandardMunger() {
108 }
109 
110 /**
111  * Given a source GeomVertexData, converts it as necessary for rendering.
112  */
113 CPT(GeomVertexData) StandardMunger::
114 munge_data_impl(const GeomVertexData *data) {
115  CPT(GeomVertexData) new_data = data;
116 
117  if (_munge_color) {
118  new_data = new_data->set_color(_color, _num_components, _numeric_type,
119  _contents);
120  } else if (_munge_color_scale) {
121  new_data = new_data->scale_color(_color_scale, _num_components,
122  _numeric_type, _contents);
123  }
124 
125  GeomVertexAnimationSpec animation = new_data->get_format()->get_animation();
126  if ((_shader_skinning && animation.get_animation_type() != AT_none) ||
127  (_auto_shader && hardware_animated_vertices &&
128  !basic_shaders_only && animation.get_animation_type() == AT_panda)) {
129  animation.set_hardware(4, true);
130 
131  } else if (hardware_animated_vertices &&
132  animation.get_animation_type() == AT_panda &&
133  new_data->get_slider_table() == nullptr) {
134  // Maybe we can animate the vertices with hardware.
135  const TransformBlendTable *table = new_data->get_transform_blend_table();
136  if (table != nullptr &&
137  table->get_num_transforms() != 0 &&
139  get_gsg()->get_max_vertex_transforms()) {
140  if (matrix_palette &&
141  table->get_num_transforms() <= get_gsg()->get_max_vertex_transform_indices()) {
142 
143  if (table->get_num_transforms() == table->get_max_simultaneous_transforms()) {
144  // We can support an indexed palette, but since that won't save us
145  // any per-vertex blends, go ahead and do a plain old nonindexed
146  // table instead.
147  animation.set_hardware(table->get_num_transforms(), false);
148 
149  } else {
150  // We can support an indexed palette, and that means we can reduce
151  // the number of blends we have to specify for each vertex.
152  animation.set_hardware(table->get_max_simultaneous_transforms(), true);
153  }
154 
155  } else if (table->get_num_transforms() <=
156  get_gsg()->get_max_vertex_transforms()) {
157  // We can't support an indexed palette, but we have few enough
158  // transforms that we can do a nonindexed table.
159  animation.set_hardware(table->get_num_transforms(), false);
160  }
161  }
162  }
163 
164  CPT(GeomVertexFormat) orig_format = new_data->get_format();
165  CPT(GeomVertexFormat) new_format = munge_format(orig_format, animation);
166 
167  if (new_format == orig_format) {
168  // Trivial case.
169  return new_data;
170  }
171 
172  return new_data->convert_to(new_format);
173 }
174 
175 /**
176  * Converts a Geom and/or its data as necessary.
177  */
178 void StandardMunger::
179 munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data,
180  Thread *) {
181  int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
182 
183  int unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
184  if (unsupported_bits != 0) {
185  // Even beyond munging the vertex format, we have to convert the Geom
186  // itself into a new primitive type the GSG can render directly. If we
187  // don't support a strip cut index, it might be faster to just decompose
188  // it rather than draw them one by one.
189  if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
190  (unsupported_bits & Geom::GR_strip_cut_index) != 0) {
191 
192  // This decomposes everything in the primitive, so that if (for
193  // instance) the primitive contained both strips and fans, but the GSG
194  // didn't support fans, it would decompose the strips too. To handle
195  // this correctly, we'd need a separate decompose_fans() and
196  // decompose_strips() call; but for now, we'll just say it's good
197  // enough. In practice, we don't have any GSG's that can support strips
198  // without also supporting fans.
199  geom = geom->decompose();
200 
201  // Decomposing might produce an indexed Geom, so re-check the
202  // unsupported bits.
203  unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
204  }
205  if ((unsupported_bits & Geom::GR_shade_model_bits) != 0) {
206  // Rotate the vertices to account for different shade-model expectations
207  // (e.g. SM_flat_last_vertex to SM_flat_first_vertex)
208  geom = geom->rotate();
209  }
210  if ((unsupported_bits & Geom::GR_indexed_bits) != 0) {
211  // Convert indexed geometry to nonindexed geometry.
212  PT(Geom) new_geom = geom->make_copy();
213  new_geom->set_vertex_data(vertex_data);
214  new_geom->make_nonindexed(false);
215  geom = new_geom;
216  vertex_data = new_geom->get_vertex_data();
217  }
218  }
219 }
220 
221 /**
222  * Converts a Geom and/or its data as necessary.
223  */
224 void StandardMunger::
225 premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
226  int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
227 
228  int unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
229  if (unsupported_bits != 0) {
230  // Even beyond munging the vertex format, we have to convert the Geom
231  // itself into a new primitive type the GSG can render directly. If we
232  // don't support a strip cut index, it might be faster to just decompose
233  // it rather than draw them one by one.
234  if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
235  (unsupported_bits & Geom::GR_strip_cut_index) != 0) {
236 
237  // This decomposes everything in the primitive, so that if (for
238  // instance) the primitive contained both strips and fans, but the GSG
239  // didn't support fans, it would decompose the strips too. To handle
240  // this correctly, we'd need a separate decompose_fans() and
241  // decompose_strips() call; but for now, we'll just say it's good
242  // enough. In practice, we don't have any GSG's that can support strips
243  // without also supporting fans.
244  geom = geom->decompose();
245 
246  // Decomposing might produce an indexed Geom, so re-check the
247  // unsupported bits.
248  unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
249  }
250  if ((unsupported_bits & Geom::GR_shade_model_bits) != 0) {
251  // Rotate the vertices to account for different shade-model expectations
252  // (e.g. SM_flat_last_vertex to SM_flat_first_vertex)
253  geom = geom->rotate();
254  }
255  if ((unsupported_bits & Geom::GR_indexed_bits) != 0) {
256  // Convert indexed geometry to nonindexed geometry.
257  PT(Geom) new_geom = geom->make_copy();
258  new_geom->set_vertex_data(vertex_data);
259  new_geom->make_nonindexed(false);
260  geom = new_geom;
261  vertex_data = new_geom->get_vertex_data();
262  }
263  }
264 }
265 
266 /**
267  * Called to compare two GeomMungers who are known to be of the same type, for
268  * an apples-to-apples comparison. This will never be called on two pointers
269  * of a different type.
270  */
271 int StandardMunger::
272 compare_to_impl(const GeomMunger *other) const {
273  const StandardMunger *om = (const StandardMunger *)other;
274 
275  if (_munge_color != om->_munge_color) {
276  return (int)_munge_color - (int)om->_munge_color;
277  }
278  if (_munge_color_scale != om->_munge_color_scale) {
279  return (int)_munge_color_scale - (int)om->_munge_color_scale;
280  }
281  if (_munge_color) {
282  int compare = _color.compare_to(om->_color);
283  if (compare != 0) {
284  return compare;
285  }
286  }
287  if (_munge_color_scale) {
288  int compare = _color_scale.compare_to(om->_color_scale);
289  if (compare != 0) {
290  return compare;
291  }
292  }
293  if (_shader_skinning != om->_shader_skinning) {
294  return (int)_shader_skinning - (int)om->_shader_skinning;
295  }
296  if (_auto_shader != om->_auto_shader) {
297  return (int)_auto_shader - (int)om->_auto_shader;
298  }
299  if (_remove_material != om->_remove_material) {
300  return (int)_remove_material - (int)om->_remove_material;
301  }
302 
303  return StateMunger::compare_to_impl(other);
304 }
305 
306 /**
307  * Compares two GeomMungers, considering only whether they would produce a
308  * different answer to munge_format(), munge_data(), or munge_geom(). (They
309  * still might be different in other ways, but if they would produce the same
310  * answer, this function consider them to be the same.)
311  */
312 int StandardMunger::
313 geom_compare_to_impl(const GeomMunger *other) const {
314  const StandardMunger *om = (const StandardMunger *)other;
315 
316  if (_munge_color != om->_munge_color) {
317  return (int)_munge_color - (int)om->_munge_color;
318  }
319  if (_munge_color_scale != om->_munge_color_scale) {
320  return (int)_munge_color_scale - (int)om->_munge_color_scale;
321  }
322  if (_munge_color) {
323  int compare = _color.compare_to(om->_color);
324  if (compare != 0) {
325  return compare;
326  }
327  }
328  if (_munge_color_scale) {
329  int compare = _color_scale.compare_to(om->_color_scale);
330  if (compare != 0) {
331  return compare;
332  }
333  }
334  if (_shader_skinning != om->_shader_skinning) {
335  return (int)_shader_skinning - (int)om->_shader_skinning;
336  }
337 
338  return StateMunger::geom_compare_to_impl(other);
339 }
340 
341 /**
342  * Given an input state, returns the munged state.
343  */
344 CPT(RenderState) StandardMunger::
345 munge_state_impl(const RenderState *state) {
346  CPT(RenderState) munged_state = state;
347 
348  if (_munge_color) {
349  munged_state = munged_state->remove_attrib(ColorAttrib::get_class_slot());
350  munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
351  } else if (_munge_color_scale) {
352  munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
353  }
354 
355  if (_remove_material) {
356  munged_state = munged_state->remove_attrib(MaterialAttrib::get_class_slot());
357  }
358 
359  return munged_state;
360 }
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:27
get_color_type
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.h:46
Applies a scale to colors in the scene graph and on vertices.
bool has_alpha_scale() const
Returns true if the ColorScaleAttrib has a non-identity scale in the alpha component (ignoring RGB),...
has_scale
Returns true if the ColorScaleAttrib has a non-identity scale, false otherwise (in which case it migh...
bool has_rgb_scale() const
Returns true if the ColorScaleAttrib has a non-identity scale in the RGB components (ignoring alpha),...
get_scale
Returns the scale to be applied to colors.
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:50
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded.
get_animation_type
Returns the type of animation represented by this spec.
void set_hardware(int num_transforms, bool indexed_transforms)
Specifies that vertex animation is to be performed by the graphics hardware (or at least by the graph...
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This class defines the physical layout of the vertex data stored within a Geom.
A container for geometry primitives.
Definition: geom.h:54
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:100
void set_vertex_data(const GeomVertexData *data)
Replaces the Geom's underlying vertex data table with a completely new table.
Definition: geom.cxx:171
get_geom_rendering
Returns the set of GeomRendering bits that represent the rendering properties required to properly re...
Definition: geom.h:76
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
bool get_alpha_scale_via_texture() const
Returns true if this particular GSG can implement (or would prefer to implement) an alpha scale via a...
bool get_color_scale_via_lighting() const
Returns true if this particular GSG can implement (or would prefer to implement) set color and/or col...
virtual int get_supported_geom_rendering() const
Returns the union of Geom::GeomRendering values that this particular GSG can support directly.
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:30
bool has_any_on_light() const
Returns true if any light is turned on by the attrib, false otherwise.
Definition: lightAttrib.I:63
Indicates which, if any, material should be applied to geometry.
get_material
If the MaterialAttrib is not an 'off' MaterialAttrib, returns the material that is associated.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
Definition: shaderAttrib.I:71
Performs some generic munging that is appropriate for all GSG types; for instance,...
StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state, int num_components, NumericType numeric_type, Contents contents)
The StandardMunger constructor accepts additional parameters that specify the GSG's preferred color f...
GraphicsStateGuardian * get_gsg() const
Returns a pointer to the GSG that created this munger.
This is just a simple derivative of GeomMunger that adds the ability to munge states.
Definition: stateMunger.h:26
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:31
A thread; that is, a lightweight process.
Definition: thread.h:46
This structure collects together the different combinations of transforms and blend amounts used by a...
get_max_simultaneous_transforms
Returns the maximum number of unique VertexTransform objects that are applied to any one vertex simul...
get_num_transforms
Returns the number of unique VertexTransform objects represented in the table.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(GeomVertexData) StandardMunger
Given a source GeomVertexData, converts it as necessary for rendering.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.