Panda3D
standardMunger.cxx
1 // Filename: standardMunger.cxx
2 // Created by: drose (21Mar05)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "standardMunger.h"
16 #include "renderState.h"
17 #include "graphicsStateGuardian.h"
18 #include "dcast.h"
19 #include "config_gobj.h"
20 #include "displayRegion.h"
21 
22 TypeHandle StandardMunger::_type_handle;
23 
24 ////////////////////////////////////////////////////////////////////
25 // Function: StandardMunger::Constructor
26 // Access: Public
27 // Description: The StandardMunger constructor accepts additional
28 // parameters that specify the GSG's preferred color
29 // format (since we might be munging the color anyway,
30 // we might as well convert it as we munge).
31 ////////////////////////////////////////////////////////////////////
34  int num_components,
35  StandardMunger::NumericType numeric_type,
36  StandardMunger::Contents contents) :
37  StateMunger(gsg),
38  _num_components(num_components),
39  _numeric_type(numeric_type),
40  _contents(contents),
41  _munge_color(false),
42  _munge_color_scale(false),
43  _auto_shader(false)
44 {
45  _render_mode = DCAST(RenderModeAttrib, state->get_attrib(RenderModeAttrib::get_class_slot()));
46 
47  if (!get_gsg()->get_runtime_color_scale()) {
48  // We might need to munge the colors.
49  const ColorAttrib *color_attrib = (const ColorAttrib *)
50  state->get_attrib(ColorAttrib::get_class_slot());
51  const ColorScaleAttrib *color_scale_attrib = (const ColorScaleAttrib *)
52  state->get_attrib(ColorScaleAttrib::get_class_slot());
53 
54  if (color_attrib != (ColorAttrib *)NULL &&
55  color_attrib->get_color_type() == ColorAttrib::T_flat) {
56 
58  // We only need to munge the color directly if the GSG says it
59  // can't cheat the color via lighting (presumably, in this case,
60  // by applying a material).
61  _color = color_attrib->get_color();
62  if (color_scale_attrib != (ColorScaleAttrib *)NULL &&
63  color_scale_attrib->has_scale()) {
64  const LVecBase4 &cs = color_scale_attrib->get_scale();
65  _color.set(_color[0] * cs[0],
66  _color[1] * cs[1],
67  _color[2] * cs[2],
68  _color[3] * cs[3]);
69  }
70  _munge_color = true;
71  }
72 
73  } else if (color_scale_attrib != (ColorScaleAttrib *)NULL &&
74  color_scale_attrib->has_scale()) {
75  _color_scale = color_scale_attrib->get_scale();
76 
77  const TextureAttrib *tex_attrib = (const TextureAttrib *)
78  state->get_attrib(TextureAttrib::get_class_slot());
79 
80  // If the GSG says it can't cheat this RGB or alpha scale, we have
81  // to apply the color scale directly.
82  if ((color_scale_attrib->has_rgb_scale() && !get_gsg()->get_color_scale_via_lighting()) ||
83  (color_scale_attrib->has_alpha_scale() && !get_gsg()->get_alpha_scale_via_texture(tex_attrib))) {
84  _munge_color_scale = true;
85  }
86 
87  // Known bug: if there is a material on an object that would
88  // obscure the effect of color_scale, we scale the lighting
89  // anyway, thus applying the effect even if it should be obscured.
90  // It doesn't seem worth the effort to detect this contrived
91  // situation and handle it correctly.
92  }
93  }
94 
95  const ShaderAttrib *shader_attrib = (const ShaderAttrib *)
96  state->get_attrib_def(ShaderAttrib::get_class_slot());
97  if (shader_attrib->auto_shader()) {
98  _auto_shader = true;
99  }
100  if (shader_attrib->get_flag(ShaderAttrib::F_hardware_skinning)) {
101  // Hijack this field, such as not to break ABI compatibility.
102  // This hack is not present in 1.10.
103  _num_components |= 0x10000;
104  }
105 }
106 
107 ////////////////////////////////////////////////////////////////////
108 // Function: StandardMunger::Destructor
109 // Access: Public, Virtual
110 // Description:
111 ////////////////////////////////////////////////////////////////////
112 StandardMunger::
113 ~StandardMunger() {
114 }
115 
116 ////////////////////////////////////////////////////////////////////
117 // Function: StandardMunger::munge_data_impl
118 // Access: Protected, Virtual
119 // Description: Given a source GeomVertexData, converts it as
120 // necessary for rendering.
121 ////////////////////////////////////////////////////////////////////
122 CPT(GeomVertexData) StandardMunger::
123 munge_data_impl(const GeomVertexData *data) {
124  CPT(GeomVertexData) new_data = data;
125 
126  if (_munge_color) {
127  new_data = new_data->set_color(_color, _num_components & 0xffff,
128  _numeric_type, _contents);
129  } else if (_munge_color_scale) {
130  new_data = new_data->scale_color(_color_scale, _num_components & 0xffff,
131  _numeric_type, _contents);
132  }
133 
134  GeomVertexAnimationSpec animation = new_data->get_format()->get_animation();
135  if (_num_components & 0x10000) {
136  animation.set_hardware(4, true);
137 
138  } else if (hardware_animated_vertices &&
139  animation.get_animation_type() == AT_panda &&
140  new_data->get_slider_table() == (SliderTable *)NULL) {
141  // Maybe we can animate the vertices with hardware.
142  const TransformBlendTable *table = new_data->get_transform_blend_table();
143  if (table != (TransformBlendTable *)NULL &&
144  table->get_num_transforms() != 0 &&
147  if (matrix_palette &&
149 
150  if (table->get_num_transforms() == table->get_max_simultaneous_transforms()) {
151  // We can support an indexed palette, but since that won't
152  // save us any per-vertex blends, go ahead and do a plain
153  // old nonindexed table instead.
154  animation.set_hardware(table->get_num_transforms(), false);
155 
156  } else {
157  // We can support an indexed palette, and that means we can
158  // reduce the number of blends we have to specify for each
159  // vertex.
160  animation.set_hardware(table->get_max_simultaneous_transforms(), true);
161  }
162 
163  } else if (table->get_num_transforms() <=
165  // We can't support an indexed palette, but we have few enough
166  // transforms that we can do a nonindexed table.
167  animation.set_hardware(table->get_num_transforms(), false);
168  }
169  }
170  }
171 
172  CPT(GeomVertexFormat) orig_format = new_data->get_format();
173  CPT(GeomVertexFormat) new_format = munge_format(orig_format, animation);
174 
175  if (new_format == orig_format) {
176  // Trivial case.
177  return new_data;
178  }
179 
180  return new_data->convert_to(new_format);
181 }
182 
183 ////////////////////////////////////////////////////////////////////
184 // Function: StandardMunger::munge_geom_impl
185 // Access: Protected, Virtual
186 // Description: Converts a Geom and/or its data as necessary.
187 ////////////////////////////////////////////////////////////////////
188 void StandardMunger::
189 munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data,
190  Thread *) {
191  int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
192 
193  int unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
194  if (unsupported_bits != 0) {
195  // Even beyond munging the vertex format, we have to convert the
196  // Geom itself into a new primitive type the GSG can render
197  // directly.
198  // If we don't support a strip cut index, it might be faster to
199  // just decompose it rather than draw them one by one.
200  if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
201  (unsupported_bits & Geom::GR_strip_cut_index) != 0) {
202  // This decomposes everything in the primitive, so that if (for
203  // instance) the primitive contained both strips and fans, but
204  // the GSG didn't support fans, it would decompose the strips
205  // too. To handle this correctly, we'd need a separate
206  // decompose_fans() and decompose_strips() call; but for now,
207  // we'll just say it's good enough. In practice, we don't have
208  // any GSG's that can support strips without also supporting
209  // fans.
210  geom = geom->decompose();
211 
212  // Decomposing might produce an indexed Geom, so re-check the
213  // unsupported bits.
214  unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
215  }
216  if ((unsupported_bits & Geom::GR_shade_model_bits) != 0) {
217  // Rotate the vertices to account for different shade-model
218  // expectations (e.g. SM_flat_last_vertex to
219  // SM_flat_first_vertex)
220  geom = geom->rotate();
221  }
222  if ((unsupported_bits & Geom::GR_indexed_bits) != 0) {
223  // Convert indexed geometry to nonindexed geometry.
224  PT(Geom) new_geom = geom->make_copy();
225  new_geom->set_vertex_data(vertex_data);
226  new_geom->make_nonindexed(false);
227  geom = new_geom;
228  vertex_data = new_geom->get_vertex_data();
229  }
230  }
231 }
232 
233 ////////////////////////////////////////////////////////////////////
234 // Function: StandardMunger::premunge_geom_impl
235 // Access: Protected, Virtual
236 // Description: Converts a Geom and/or its data as necessary.
237 ////////////////////////////////////////////////////////////////////
238 void StandardMunger::
239 premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
240  int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
241 
242  int unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
243  if (unsupported_bits != 0) {
244  // Even beyond munging the vertex format, we have to convert the
245  // Geom itself into a new primitive type the GSG can render
246  // directly.
247  // If we don't support a strip cut index, it might be faster to
248  // just decompose it rather than draw them one by one.
249  if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
250  (unsupported_bits & Geom::GR_strip_cut_index) != 0) {
251  // This decomposes everything in the primitive, so that if (for
252  // instance) the primitive contained both strips and fans, but
253  // the GSG didn't support fans, it would decompose the strips
254  // too. To handle this correctly, we'd need a separate
255  // decompose_fans() and decompose_strips() call; but for now,
256  // we'll just say it's good enough. In practice, we don't have
257  // any GSG's that can support strips without also supporting
258  // fans.
259  geom = geom->decompose();
260 
261  // Decomposing might produce an indexed Geom, so re-check the
262  // unsupported bits.
263  unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
264  }
265  if ((unsupported_bits & Geom::GR_shade_model_bits) != 0) {
266  // Rotate the vertices to account for different shade-model
267  // expectations (e.g. SM_flat_last_vertex to
268  // SM_flat_first_vertex)
269  geom = geom->rotate();
270  }
271  if ((unsupported_bits & Geom::GR_indexed_bits) != 0) {
272  // Convert indexed geometry to nonindexed geometry.
273  PT(Geom) new_geom = geom->make_copy();
274  new_geom->set_vertex_data(vertex_data);
275  new_geom->make_nonindexed(false);
276  geom = new_geom;
277  vertex_data = new_geom->get_vertex_data();
278  }
279  }
280 }
281 
282 ////////////////////////////////////////////////////////////////////
283 // Function: StandardMunger::compare_to_impl
284 // Access: Protected, Virtual
285 // Description: Called to compare two GeomMungers who are known to be
286 // of the same type, for an apples-to-apples comparison.
287 // This will never be called on two pointers of a
288 // different type.
289 ////////////////////////////////////////////////////////////////////
290 int StandardMunger::
291 compare_to_impl(const GeomMunger *other) const {
292  const StandardMunger *om = DCAST(StandardMunger, other);
293 
294  if (_render_mode != om->_render_mode) {
295  return _render_mode < om->_render_mode ? -1 : 1;
296  }
297 
298  if (_munge_color != om->_munge_color) {
299  return (int)_munge_color - (int)om->_munge_color;
300  }
301  if (_munge_color_scale != om->_munge_color_scale) {
302  return (int)_munge_color_scale - (int)om->_munge_color_scale;
303  }
304  if (_munge_color) {
305  int compare = _color.compare_to(om->_color);
306  if (compare != 0) {
307  return compare;
308  }
309  }
310  if (_munge_color_scale) {
311  int compare = _color_scale.compare_to(om->_color_scale);
312  if (compare != 0) {
313  return compare;
314  }
315  }
316  bool shader_skinning = ((_num_components & 0x10000) != 0);
317  bool om_shader_skinning = ((om->_num_components & 0x10000) != 0);
318  if (shader_skinning != om_shader_skinning) {
319  return (int)shader_skinning - (int)om_shader_skinning;
320  }
321  if (_auto_shader != om->_auto_shader) {
322  return (int)_auto_shader - (int)om->_auto_shader;
323  }
324 
325  return StateMunger::compare_to_impl(other);
326 }
327 
328 ////////////////////////////////////////////////////////////////////
329 // Function: StandardMunger::geom_compare_to_impl
330 // Access: Protected, Virtual
331 // Description: Compares two GeomMungers, considering only whether
332 // they would produce a different answer to
333 // munge_format(), munge_data(), or munge_geom(). (They
334 // still might be different in other ways, but if they
335 // would produce the same answer, this function consider
336 // them to be the same.)
337 ////////////////////////////////////////////////////////////////////
338 int StandardMunger::
339 geom_compare_to_impl(const GeomMunger *other) const {
340  const StandardMunger *om = DCAST(StandardMunger, other);
341  if (_munge_color != om->_munge_color) {
342  return (int)_munge_color - (int)om->_munge_color;
343  }
344  if (_munge_color_scale != om->_munge_color_scale) {
345  return (int)_munge_color_scale - (int)om->_munge_color_scale;
346  }
347  if (_munge_color) {
348  int compare = _color.compare_to(om->_color);
349  if (compare != 0) {
350  return compare;
351  }
352  }
353  if (_munge_color_scale) {
354  int compare = _color_scale.compare_to(om->_color_scale);
355  if (compare != 0) {
356  return compare;
357  }
358  }
359  bool shader_skinning = ((_num_components & 0x10000) != 0);
360  bool om_shader_skinning = ((om->_num_components & 0x10000) != 0);
361  if (shader_skinning != om_shader_skinning) {
362  return (int)shader_skinning - (int)om_shader_skinning;
363  }
364 
365  return StateMunger::geom_compare_to_impl(other);
366 }
367 
368 ////////////////////////////////////////////////////////////////////
369 // Function: StandardMunger::munge_state_impl
370 // Access: Protectes, Virtual
371 // Description: Given an input state, returns the munged state.
372 ////////////////////////////////////////////////////////////////////
373 CPT(RenderState) StandardMunger::
374 munge_state_impl(const RenderState *state) {
375  CPT(RenderState) munged_state = state;
376 
377  if (_munge_color) {
378  munged_state = munged_state->remove_attrib(ColorAttrib::get_class_slot());
379  munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
380  } else if (_munge_color_scale) {
381  munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
382  }
383 
384  if (_auto_shader) {
385  CPT(RenderState) shader_state = munged_state->get_auto_shader_state();
386  ShaderGenerator *shader_generator = get_gsg()->get_shader_generator();
387  if (shader_generator == NULL) {
388  pgraph_cat.error()
389  << "auto_shader enabled, but GSG has no shader generator assigned!\n";
390  return munged_state;
391  }
392  if (shader_state->_generated_shader == NULL) {
393  // Cache the generated ShaderAttrib on the shader state.
394  shader_state->_generated_shader = shader_generator->synthesize_shader(shader_state);
395  }
396  munged_state = munged_state->set_attrib(shader_state->_generated_shader);
397  }
398 
399  return munged_state;
400 }
This is just a simple derivative of GeomMunger that adds the ability to munge states.
Definition: stateMunger.h:30
bool has_scale() const
Returns true if the ColorScaleAttrib has a non-identity scale, false otherwise (in which case it migh...
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:81
bool has_alpha_scale() const
Returns true if the ColorScaleAttrib has a non-identity scale in the alpha component (ignoring RGB)...
const LColor & get_color() const
If the type is T_flat or T_off, this returns the color that will be applied to geometry.
Definition: colorAttrib.I:58
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...
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded...
const LVecBase4 & get_scale() const
Returns the scale to be applied to colors.
StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state, int num_components, NumericType numeric_type, Contents contents)
The StandardMunger constructor accepts additional parameters that specify the GSG&#39;s preferred color f...
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:57
GraphicsStateGuardian * get_gsg() const
Returns a pointer to the GSG that created this munger.
ShaderGenerator * get_shader_generator() const
Returns the ShaderGenerator object that will be used by this GSG to generate shaders when necessary...
Performs some generic munging that is appropriate for all GSG types; for instance, applies ColorAttrib and ColorScaleAttrib to the vertices, and checks for hardware-accelerated animation capabilities.
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...
Type get_color_type() const
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.I:46
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:34
int get_max_vertex_transforms() const
Returns the maximum number of transform matrices that may be simultaneously used to transform any one...
Stores the total set of VertexSliders that the vertices in a particular GeomVertexData object might d...
Definition: sliderTable.h:42
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:118
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
int compare_to(const LVecBase4f &other) const
This flavor of compare_to uses a default threshold value based on the numeric type.
Definition: lvecBase4.h:988
The ShaderGenerator is a device that effectively replaces the classic fixed function pipeline with a ...
A container for geometry primitives.
Definition: geom.h:58
bool has_rgb_scale() const
Returns true if the ColorScaleAttrib has a non-identity scale in the RGB components (ignoring alpha)...
int get_geom_rendering() const
Returns the set of GeomRendering bits that represent the rendering properties required to properly re...
Definition: geom.I:54
AnimationType get_animation_type() const
Returns the type of animation represented by this spec.
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:53
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
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&#39;s underlying vertex data table with a completely new table.
Definition: geom.cxx:183
A thread; that is, a lightweight process.
Definition: thread.h:51
int get_num_transforms() const
Returns the number of unique VertexTransform objects represented in the table.
Specifies how polygons are to be drawn.
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:30
virtual int get_supported_geom_rendering() const
Returns the union of Geom::GeomRendering values that this particular GSG can support directly...
int get_max_vertex_transform_indices() const
Returns the maximum number of transforms there may be in a single TransformTable for this graphics ha...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
int get_max_simultaneous_transforms() const
Returns the maximum number of unique VertexTransform objects that are applied to any one vertex simul...