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 || (_auto_shader && hardware_animated_vertices &&
127  !basic_shaders_only && animation.get_animation_type() == AT_panda)) {
128  animation.set_hardware(4, true);
129 
130  } else if (hardware_animated_vertices &&
131  animation.get_animation_type() == AT_panda &&
132  new_data->get_slider_table() == nullptr) {
133  // Maybe we can animate the vertices with hardware.
134  const TransformBlendTable *table = new_data->get_transform_blend_table();
135  if (table != nullptr &&
136  table->get_num_transforms() != 0 &&
139  if (matrix_palette &&
141 
142  if (table->get_num_transforms() == table->get_max_simultaneous_transforms()) {
143  // We can support an indexed palette, but since that won't save us
144  // any per-vertex blends, go ahead and do a plain old nonindexed
145  // table instead.
146  animation.set_hardware(table->get_num_transforms(), false);
147 
148  } else {
149  // We can support an indexed palette, and that means we can reduce
150  // the number of blends we have to specify for each vertex.
151  animation.set_hardware(table->get_max_simultaneous_transforms(), true);
152  }
153 
154  } else if (table->get_num_transforms() <=
156  // We can't support an indexed palette, but we have few enough
157  // transforms that we can do a nonindexed table.
158  animation.set_hardware(table->get_num_transforms(), false);
159  }
160  }
161  }
162 
163  CPT(GeomVertexFormat) orig_format = new_data->get_format();
164  CPT(GeomVertexFormat) new_format = munge_format(orig_format, animation);
165 
166  if (new_format == orig_format) {
167  // Trivial case.
168  return new_data;
169  }
170 
171  return new_data->convert_to(new_format);
172 }
173 
174 /**
175  * Converts a Geom and/or its data as necessary.
176  */
177 void StandardMunger::
178 munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data,
179  Thread *) {
180  int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
181 
182  int unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
183  if (unsupported_bits != 0) {
184  // Even beyond munging the vertex format, we have to convert the Geom
185  // itself into a new primitive type the GSG can render directly. If we
186  // don't support a strip cut index, it might be faster to just decompose
187  // it rather than draw them one by one.
188  if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
189  (unsupported_bits & Geom::GR_strip_cut_index) != 0) {
190 
191  // This decomposes everything in the primitive, so that if (for
192  // instance) the primitive contained both strips and fans, but the GSG
193  // didn't support fans, it would decompose the strips too. To handle
194  // this correctly, we'd need a separate decompose_fans() and
195  // decompose_strips() call; but for now, we'll just say it's good
196  // enough. In practice, we don't have any GSG's that can support strips
197  // without also supporting fans.
198  geom = geom->decompose();
199 
200  // Decomposing might produce an indexed Geom, so re-check the
201  // unsupported bits.
202  unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
203  }
204  if ((unsupported_bits & Geom::GR_shade_model_bits) != 0) {
205  // Rotate the vertices to account for different shade-model expectations
206  // (e.g. SM_flat_last_vertex to SM_flat_first_vertex)
207  geom = geom->rotate();
208  }
209  if ((unsupported_bits & Geom::GR_indexed_bits) != 0) {
210  // Convert indexed geometry to nonindexed geometry.
211  PT(Geom) new_geom = geom->make_copy();
212  new_geom->set_vertex_data(vertex_data);
213  new_geom->make_nonindexed(false);
214  geom = new_geom;
215  vertex_data = new_geom->get_vertex_data();
216  }
217  }
218 }
219 
220 /**
221  * Converts a Geom and/or its data as necessary.
222  */
223 void StandardMunger::
224 premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
225  int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
226 
227  int unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
228  if (unsupported_bits != 0) {
229  // Even beyond munging the vertex format, we have to convert the Geom
230  // itself into a new primitive type the GSG can render directly. If we
231  // don't support a strip cut index, it might be faster to just decompose
232  // it rather than draw them one by one.
233  if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
234  (unsupported_bits & Geom::GR_strip_cut_index) != 0) {
235 
236  // This decomposes everything in the primitive, so that if (for
237  // instance) the primitive contained both strips and fans, but the GSG
238  // didn't support fans, it would decompose the strips too. To handle
239  // this correctly, we'd need a separate decompose_fans() and
240  // decompose_strips() call; but for now, we'll just say it's good
241  // enough. In practice, we don't have any GSG's that can support strips
242  // without also supporting fans.
243  geom = geom->decompose();
244 
245  // Decomposing might produce an indexed Geom, so re-check the
246  // unsupported bits.
247  unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
248  }
249  if ((unsupported_bits & Geom::GR_shade_model_bits) != 0) {
250  // Rotate the vertices to account for different shade-model expectations
251  // (e.g. SM_flat_last_vertex to SM_flat_first_vertex)
252  geom = geom->rotate();
253  }
254  if ((unsupported_bits & Geom::GR_indexed_bits) != 0) {
255  // Convert indexed geometry to nonindexed geometry.
256  PT(Geom) new_geom = geom->make_copy();
257  new_geom->set_vertex_data(vertex_data);
258  new_geom->make_nonindexed(false);
259  geom = new_geom;
260  vertex_data = new_geom->get_vertex_data();
261  }
262  }
263 }
264 
265 /**
266  * Called to compare two GeomMungers who are known to be of the same type, for
267  * an apples-to-apples comparison. This will never be called on two pointers
268  * of a different type.
269  */
270 int StandardMunger::
271 compare_to_impl(const GeomMunger *other) const {
272  const StandardMunger *om = (const StandardMunger *)other;
273 
274  if (_munge_color != om->_munge_color) {
275  return (int)_munge_color - (int)om->_munge_color;
276  }
277  if (_munge_color_scale != om->_munge_color_scale) {
278  return (int)_munge_color_scale - (int)om->_munge_color_scale;
279  }
280  if (_munge_color) {
281  int compare = _color.compare_to(om->_color);
282  if (compare != 0) {
283  return compare;
284  }
285  }
286  if (_munge_color_scale) {
287  int compare = _color_scale.compare_to(om->_color_scale);
288  if (compare != 0) {
289  return compare;
290  }
291  }
292  if (_shader_skinning != om->_shader_skinning) {
293  return (int)_shader_skinning - (int)om->_shader_skinning;
294  }
295  if (_auto_shader != om->_auto_shader) {
296  return (int)_auto_shader - (int)om->_auto_shader;
297  }
298  if (_remove_material != om->_remove_material) {
299  return (int)_remove_material - (int)om->_remove_material;
300  }
301 
302  return StateMunger::compare_to_impl(other);
303 }
304 
305 /**
306  * Compares two GeomMungers, considering only whether they would produce a
307  * different answer to munge_format(), munge_data(), or munge_geom(). (They
308  * still might be different in other ways, but if they would produce the same
309  * answer, this function consider them to be the same.)
310  */
311 int StandardMunger::
312 geom_compare_to_impl(const GeomMunger *other) const {
313  const StandardMunger *om = (const StandardMunger *)other;
314 
315  if (_munge_color != om->_munge_color) {
316  return (int)_munge_color - (int)om->_munge_color;
317  }
318  if (_munge_color_scale != om->_munge_color_scale) {
319  return (int)_munge_color_scale - (int)om->_munge_color_scale;
320  }
321  if (_munge_color) {
322  int compare = _color.compare_to(om->_color);
323  if (compare != 0) {
324  return compare;
325  }
326  }
327  if (_munge_color_scale) {
328  int compare = _color_scale.compare_to(om->_color_scale);
329  if (compare != 0) {
330  return compare;
331  }
332  }
333  if (_shader_skinning != om->_shader_skinning) {
334  return (int)_shader_skinning - (int)om->_shader_skinning;
335  }
336 
337  return StateMunger::geom_compare_to_impl(other);
338 }
339 
340 /**
341  * Given an input state, returns the munged state.
342  */
343 CPT(RenderState) StandardMunger::
344 munge_state_impl(const RenderState *state) {
345  CPT(RenderState) munged_state = state;
346 
347  if (_munge_color) {
348  munged_state = munged_state->remove_attrib(ColorAttrib::get_class_slot());
349  munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
350  } else if (_munge_color_scale) {
351  munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
352  }
353 
354  if (_remove_material) {
355  munged_state = munged_state->remove_attrib(MaterialAttrib::get_class_slot());
356  }
357 
358  return munged_state;
359 }
get_animation_type
Returns the type of animation represented by this spec.
This is just a simple derivative of GeomMunger that adds the ability to munge states.
Definition: stateMunger.h:26
bool get_runtime_color_scale() const
Returns true if this particular GSG can implement (or would prefer to implement) set color and/or col...
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
Definition: shaderAttrib.I:71
has_scale
Returns true if the ColorScaleAttrib has a non-identity scale, false otherwise (in which case it migh...
bool has_alpha_scale() const
Returns true if the ColorScaleAttrib has a non-identity scale in the alpha component (ignoring RGB),...
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Indicates which, if any, material should be applied to geometry.
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded.
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...
get_num_transforms
Returns the number of unique VertexTransform objects represented in the table.
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:50
GraphicsStateGuardian * get_gsg() const
Returns a pointer to the GSG that created this munger.
Performs some generic munging that is appropriate for all GSG types; for instance,...
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...
CPT(GeomVertexData) StandardMunger
Given a source GeomVertexData, converts it as necessary for rendering.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:31
get_max_vertex_transform_indices
Returns the maximum number of transforms there may be in a single TransformTable for this graphics ha...
get_scale
Returns the scale to be applied to colors.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:100
get_max_vertex_transforms
Returns the maximum number of transform matrices that may be simultaneously used to transform any one...
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:54
bool has_rgb_scale() const
Returns true if the ColorScaleAttrib has a non-identity scale in the RGB components (ignoring alpha),...
Applies a scale to colors in the scene graph and on vertices.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class defines the physical layout of the vertex data stored within a Geom.
get_max_simultaneous_transforms
Returns the maximum number of unique VertexTransform objects that are applied to any one vertex simul...
get_material
If the MaterialAttrib is not an 'off' MaterialAttrib, returns the material that is associated.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
void set_vertex_data(const GeomVertexData *data)
Replaces the Geom's underlying vertex data table with a completely new table.
Definition: geom.cxx:171
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...
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:27
get_geom_rendering
Returns the set of GeomRendering bits that represent the rendering properties required to properly re...
Definition: geom.h:76
virtual int get_supported_geom_rendering() const
Returns the union of Geom::GeomRendering values that this particular GSG can support directly.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_color_type
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.h:46
bool has_any_on_light() const
Returns true if any light is turned on by the attrib, false otherwise.
Definition: lightAttrib.I:62
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:30