Panda3D
dxGeomMunger9.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 dxGeomMunger9.cxx
10  * @author drose
11  * @date 2005-03-11
12  */
13 
14 #include "dxGeomMunger9.h"
15 #include "geomVertexReader.h"
16 #include "geomVertexWriter.h"
17 #include "config_dxgsg9.h"
18 
19 GeomMunger *DXGeomMunger9::_deleted_chain = nullptr;
20 TypeHandle DXGeomMunger9::_type_handle;
21 
22 /**
23  *
24  */
25 DXGeomMunger9::
26 DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state) :
27  StandardMunger(gsg, state, 1, NT_packed_dabc, C_color),
28  _texture(nullptr),
29  _tex_gen(nullptr)
30 {
31  const TextureAttrib *texture = nullptr;
32  const TexGenAttrib *tex_gen = nullptr;
33  state->get_attrib(texture);
34  state->get_attrib(tex_gen);
35  _texture = texture;
36  _tex_gen = tex_gen;
37 
38  if (!gsg->get_color_scale_via_lighting()) {
39  // We might need to munge the colors, if we are overriding the vertex
40  // colors and the GSG can't cheat the color via lighting.
41 
42  const ColorAttrib *color_attrib;
43  const ShaderAttrib *shader_attrib;
44  state->get_attrib_def(shader_attrib);
45 
46  if (!shader_attrib->auto_shader() &&
47  shader_attrib->get_shader() == nullptr &&
48  state->get_attrib(color_attrib) &&
49  color_attrib->get_color_type() != ColorAttrib::T_vertex) {
50 
51  if (color_attrib->get_color_type() == ColorAttrib::T_off) {
52  _color.set(1, 1, 1, 1);
53  } else {
54  _color = color_attrib->get_color();
55  }
56 
57  const ColorScaleAttrib *color_scale_attrib;
58  if (state->get_attrib(color_scale_attrib) &&
59  color_scale_attrib->has_scale()) {
60  _color.componentwise_mult(color_scale_attrib->get_scale());
61  }
62  _munge_color = true;
63  _should_munge_state = true;
64  }
65  }
66 
67  _filtered_texture = nullptr;
68  _reffed_filtered_texture = false;
69  if (texture != nullptr) {
70  _filtered_texture = texture->filter_to_max(gsg->get_max_texture_stages());
71  if (_filtered_texture != texture) {
72  _filtered_texture->ref();
73  _reffed_filtered_texture = true;
74  }
75  }
76  // Set a callback to unregister ourselves when either the Texture or the
77  // TexGen object gets deleted.
78  _texture.add_callback(this);
79  _tex_gen.add_callback(this);
80 }
81 
82 /**
83  *
84  */
85 DXGeomMunger9::
86 ~DXGeomMunger9() {
87  if (_reffed_filtered_texture) {
88  unref_delete(_filtered_texture);
89  _reffed_filtered_texture = false;
90  }
91 
92  _texture.remove_callback(this);
93  _tex_gen.remove_callback(this);
94 }
95 
96 /**
97  * This callback is set to be made whenever the associated _texture or
98  * _tex_gen attributes are destructed, in which case the GeomMunger is invalid
99  * and should no longer be used.
100  */
101 void DXGeomMunger9::
102 wp_callback(void *) {
103  unregister_myself();
104 
105  if (_reffed_filtered_texture) {
106  unref_delete(_filtered_texture);
107  _reffed_filtered_texture = false;
108  }
109 }
110 
111 /**
112  * Given a source GeomVertexFormat, converts it if necessary to the
113  * appropriate format for rendering.
114  */
115 CPT(GeomVertexFormat) DXGeomMunger9::
116 munge_format_impl(const GeomVertexFormat *orig,
117  const GeomVertexAnimationSpec &animation) {
118  if (dxgsg9_cat.is_debug()) {
119  if (animation.get_animation_type() != AT_none) {
120  dxgsg9_cat.debug()
121  << "preparing animation type " << animation << " for " << *orig
122  << "\n";
123  }
124  }
125  // We have to build a completely new format that includes only the
126  // appropriate components, in the appropriate order, in just one array.
127  PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig);
128  new_format->set_animation(animation);
129  PT(GeomVertexArrayFormat) new_array_format = new GeomVertexArrayFormat;
130 
131  const GeomVertexColumn *vertex_type = orig->get_vertex_column();
132  const GeomVertexColumn *normal_type = orig->get_normal_column();
133  const GeomVertexColumn *color_type = orig->get_color_column();
134 
135  if (vertex_type != nullptr) {
136  new_array_format->add_column
137  (InternalName::get_vertex(), 3, NT_float32,
138  vertex_type->get_contents());
139  new_format->remove_column(vertex_type->get_name());
140 
141  } else {
142  // If we don't have a vertex type, not much we can do.
143  return orig;
144  }
145 
146  if (animation.get_animation_type() == AT_hardware &&
147  animation.get_num_transforms() > 0) {
148  if (animation.get_num_transforms() > 1) {
149  // If we want hardware animation, we need to reserve space for the blend
150  // weights.
151  new_array_format->add_column
152  (InternalName::get_transform_weight(), animation.get_num_transforms() - 1,
153  NT_float32, C_other);
154  }
155 
156  if (animation.get_indexed_transforms()) {
157  // Also, if we'll be indexing into the transform table, reserve space
158  // for the index.
159  new_array_format->add_column
160  (InternalName::get_transform_index(), 1,
161  NT_packed_dcba, C_index);
162  }
163 
164  // Make sure the old weights and indices are removed, just in case.
165  new_format->remove_column(InternalName::get_transform_weight());
166  new_format->remove_column(InternalName::get_transform_index());
167 
168  // And we don't need the transform_blend table any more.
169  new_format->remove_column(InternalName::get_transform_blend());
170  }
171 
172  if (normal_type != nullptr) {
173  new_array_format->add_column
174  (InternalName::get_normal(), 3, NT_float32, C_normal);
175  new_format->remove_column(normal_type->get_name());
176  }
177 
178  if (color_type != nullptr) {
179  new_array_format->add_column
180  (InternalName::get_color(), 1, NT_packed_dabc, C_color);
181  new_format->remove_column(color_type->get_name());
182  }
183 
184  // To support multitexture, we will need to add all of the relevant texcoord
185  // types, and in the order specified by the TextureAttrib.
186 
187  // Now set up each of the active texture coordinate stages--or at least
188  // those for which we're not generating texture coordinates automatically.
189 
190  if (_filtered_texture != nullptr) {
191  int num_stages = _filtered_texture->get_num_on_ff_stages();
192  vector_int ff_tc_index(num_stages, 0);
193 
194  // Be sure we add the texture coordinates in the right order, as specified
195  // by the attrib. To ensure this, we first walk through the stages of the
196  // attrib and get the index numbers in the appropriate order.
197  int si, tc_index;
198  int max_tc_index = -1;
199  for (si = 0; si < num_stages; ++si) {
200  int tc_index = _filtered_texture->get_ff_tc_index(si);
201  nassertr(tc_index < num_stages, orig);
202  ff_tc_index[tc_index] = si;
203  max_tc_index = std::max(tc_index, max_tc_index);
204  }
205 
206  // Now walk through the texture coordinates in the order they will appear
207  // on the final geometry. For each one, get the texture coordinate name
208  // from the associated stage.
209  for (tc_index = 0; tc_index <= max_tc_index; ++tc_index) {
210  si = ff_tc_index[tc_index];
211  TextureStage *stage = _filtered_texture->get_on_ff_stage(si);
212  InternalName *name = stage->get_texcoord_name();
213 
214  const GeomVertexColumn *texcoord_type = orig->get_column(name);
215 
216  if (texcoord_type != nullptr) {
217  new_array_format->add_column
218  (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
219  } else {
220  // We have to add something as a placeholder, even if the texture
221  // coordinates aren't defined.
222  new_array_format->add_column(name, 2, NT_float32, C_texcoord);
223  }
224  new_format->remove_column(name);
225  }
226  }
227 
228  // Now go through the remaining arrays and make sure they are tightly
229  // packed. If not, repack them.
230  for (size_t i = 0; i < new_format->get_num_arrays(); ++i) {
231  CPT(GeomVertexArrayFormat) orig_a = new_format->get_array(i);
232  if (orig_a->count_unused_space() != 0) {
234  for (int j = 0; j < orig_a->get_num_columns(); ++j) {
235  const GeomVertexColumn *column = orig_a->get_column(j);
236  new_a->add_column(column->get_name(), column->get_num_components(),
237  column->get_numeric_type(), column->get_contents());
238  }
239  new_format->set_array(i, new_a);
240  }
241  }
242 
243  // Make sure the FVF-style array we just built up is first in the list.
244  new_format->insert_array(0, new_array_format);
245 
246  return GeomVertexFormat::register_format(new_format);
247 }
248 
249 /**
250  * Given a source GeomVertexFormat, converts it if necessary to the
251  * appropriate format for rendering.
252  */
253 CPT(GeomVertexFormat) DXGeomMunger9::
254 premunge_format_impl(const GeomVertexFormat *orig) {
255  // We have to build a completely new format that includes only the
256  // appropriate components, in the appropriate order, in just one array.
257  PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig);
258  PT(GeomVertexArrayFormat) new_array_format = new GeomVertexArrayFormat;
259 
260  const GeomVertexColumn *vertex_type = orig->get_vertex_column();
261  const GeomVertexColumn *normal_type = orig->get_normal_column();
262  const GeomVertexColumn *color_type = orig->get_color_column();
263 
264  if (vertex_type != nullptr) {
265  new_array_format->add_column
266  (InternalName::get_vertex(), 3, NT_float32,
267  vertex_type->get_contents());
268  new_format->remove_column(vertex_type->get_name());
269 
270  } else {
271  // If we don't have a vertex type, not much we can do.
272  return orig;
273  }
274 
275  if (normal_type != nullptr) {
276  new_array_format->add_column
277  (InternalName::get_normal(), 3, NT_float32, C_normal);
278  new_format->remove_column(normal_type->get_name());
279  }
280 
281  if (color_type != nullptr) {
282  new_array_format->add_column
283  (InternalName::get_color(), 1, NT_packed_dabc, C_color);
284  new_format->remove_column(color_type->get_name());
285  }
286 
287  // To support multitexture, we will need to add all of the relevant texcoord
288  // types, and in the order specified by the TextureAttrib.
289 
290  // Now set up each of the active texture coordinate stages--or at least
291  // those for which we're not generating texture coordinates automatically.
292 
293  if (_filtered_texture != nullptr) {
294  int num_stages = _filtered_texture->get_num_on_ff_stages();
295  vector_int ff_tc_index(num_stages, 0);
296 
297  // Be sure we add the texture coordinates in the right order, as specified
298  // by the attrib. To ensure this, we first walk through the stages of the
299  // attrib and get the index numbers in the appropriate order.
300  int si, tc_index;
301  int max_tc_index = -1;
302  for (si = 0; si < num_stages; ++si) {
303  int tc_index = _filtered_texture->get_ff_tc_index(si);
304  nassertr(tc_index < num_stages, orig);
305  ff_tc_index[tc_index] = si;
306  max_tc_index = std::max(tc_index, max_tc_index);
307  }
308 
309  // Now walk through the texture coordinates in the order they will appear
310  // on the final geometry. For each one, get the texture coordinate name
311  // from the associated stage.
312  for (tc_index = 0; tc_index <= max_tc_index; ++tc_index) {
313  si = ff_tc_index[tc_index];
314  TextureStage *stage = _filtered_texture->get_on_ff_stage(si);
315  InternalName *name = stage->get_texcoord_name();
316 
317  const GeomVertexColumn *texcoord_type = orig->get_column(name);
318 
319  if (texcoord_type != nullptr) {
320  new_array_format->add_column
321  (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
322  } else {
323  // We have to add something as a placeholder, even if the texture
324  // coordinates aren't defined.
325  new_array_format->add_column(name, 2, NT_float32, C_texcoord);
326  }
327  new_format->remove_column(name);
328  }
329  }
330 
331  // Now go through the remaining arrays and make sure they are tightly
332  // packed. If not, repack them.
333  for (size_t i = 0; i < new_format->get_num_arrays(); ++i) {
334  CPT(GeomVertexArrayFormat) orig_a = new_format->get_array(i);
335  if (orig_a->count_unused_space() != 0) {
337  for (int j = 0; j < orig_a->get_num_columns(); ++j) {
338  const GeomVertexColumn *column = orig_a->get_column(j);
339  new_a->add_column(column->get_name(), column->get_num_components(),
340  column->get_numeric_type(), column->get_contents());
341  }
342  new_format->set_array(i, new_a);
343  }
344  }
345 
346  // Make sure the FVF-style array we just built up is first in the list.
347  new_format->insert_array(0, new_array_format);
348 
349  return GeomVertexFormat::register_format(new_format);
350 }
351 
352 /**
353  * Called to compare two GeomMungers who are known to be of the same type, for
354  * an apples-to-apples comparison. This will never be called on two pointers
355  * of a different type.
356  */
357 int DXGeomMunger9::
358 compare_to_impl(const GeomMunger *other) const {
359  const DXGeomMunger9 *om = DCAST(DXGeomMunger9, other);
360  if (_filtered_texture != om->_filtered_texture) {
361  return _filtered_texture < om->_filtered_texture ? -1 : 1;
362  }
363  if (_tex_gen.owner_before(om->_tex_gen)) {
364  return -1;
365  }
366  if (om->_tex_gen.owner_before(_tex_gen)) {
367  return 1;
368  }
369 
370  return StandardMunger::compare_to_impl(other);
371 }
372 
373 /**
374  * Called to compare two GeomMungers who are known to be of the same type, for
375  * an apples-to-apples comparison. This will never be called on two pointers
376  * of a different type.
377  */
378 int DXGeomMunger9::
379 geom_compare_to_impl(const GeomMunger *other) const {
380  // Unlike GLGeomMunger, we do consider _filtered_texture and _tex_gen
381  // important for this purpose, since they control the number and order of
382  // texture coordinates we might put into the FVF.
383  const DXGeomMunger9 *om = DCAST(DXGeomMunger9, other);
384  if (_filtered_texture != om->_filtered_texture) {
385  return _filtered_texture < om->_filtered_texture ? -1 : 1;
386  }
387  if (_tex_gen.owner_before(om->_tex_gen)) {
388  return -1;
389  }
390  if (om->_tex_gen.owner_before(_tex_gen)) {
391  return 1;
392  }
393 
394  return StandardMunger::geom_compare_to_impl(other);
395 }
get_animation_type
Returns the type of animation represented by this spec.
const GeomVertexColumn * get_color_column() const
Returns the column definition of the "color" column, or NULL if there is no such column.
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...
Contents get_contents() const
Returns the token representing the semantic meaning of the stored value.
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 void wp_callback(void *)
This callback is set to be made whenever the associated _texture or _tex_gen attributes are destructe...
int get_ff_tc_index(int n) const
For each TextureStage listed in get_on_ff_stage(), this returns a unique index number for the texture...
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded.
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:50
get_color
If the type is T_flat or T_off, this returns the color that will be applied to geometry.
Definition: colorAttrib.h:47
Performs some generic munging that is appropriate for all GSG types; for instance,...
get_max_texture_stages
Returns the maximum number of simultaneous textures that may be applied to geometry with multitexturi...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This defines how a single column is interleaved within a vertex array stored within a Geom.
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:31
get_scale
Returns the scale to be applied to colors.
const GeomVertexColumn * get_normal_column() const
Returns the column definition of the "normal" column, or NULL if there is no such column.
CPT(GeomVertexFormat) DXGeomMunger9
Given a source GeomVertexFormat, converts it if necessary to the appropriate format for rendering.
void remove_column(const InternalName *name, bool keep_empty_array=false)
Removes the named column from the format, from whichever array it exists in.
get_num_transforms
This is only meaningful for animation_type AT_hardware.
const GeomVertexColumn * get_vertex_column() const
Returns the column definition of the "vertex" column, or NULL if there is no such column.
get_column
Returns the ith column of the specification, across all arrays.
int get_num_values() const
Returns the number of numeric values of the column: the number of distinct numeric values that go int...
This specialization on GeomMunger finesses vertices for DirectX rendering.
Definition: dxGeomMunger9.h:29
get_indexed_transforms
This is only meaningful for animation_type AT_hardware.
get_on_ff_stage
Returns the nth stage turned on by the attribute, sorted in render order, including only those releva...
Definition: textureAttrib.h:58
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
void ref() const
Explicitly increments the reference count.
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
This class defines the physical layout of the vertex data stored within a Geom.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Encapsulates all the communication with a particular instance of a given rendering backend.
This describes the structure of a single array within a Geom data.
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:27
const InternalName * get_name() const
Returns the name of this particular data field, e.g.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_on_ff_stages
Returns the number of on-stages that are relevant to the classic fixed function pipeline.
Definition: textureAttrib.h:58
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
int get_num_components() const
Returns the number of components of the column: the number of instances of the NumericType in each el...
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Definition: texGenAttrib.h:32
get_color_type
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.h:46
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
get_texcoord_name
See set_texcoord_name.
Definition: textureStage.h:192