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  */
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 }
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:27
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
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.
has_scale
Returns true if the ColorScaleAttrib has a non-identity scale, false otherwise (in which case it migh...
get_scale
Returns the scale to be applied to colors.
This specialization on GeomMunger finesses vertices for DirectX rendering.
Definition: dxGeomMunger9.h:29
virtual void wp_callback(void *)
This callback is set to be made whenever the associated _texture or _tex_gen attributes are destructe...
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.
get_indexed_transforms
This is only meaningful for animation_type AT_hardware.
get_num_transforms
This is only meaningful for animation_type AT_hardware.
This describes the structure of a single array within a Geom data.
This defines how a single column is interleaved within a vertex array stored within a Geom.
int get_num_values() const
Returns the number of numeric values of the column: the number of distinct numeric values that go int...
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
const InternalName * get_name() const
Returns the name of this particular data field, e.g.
Contents get_contents() const
Returns the token representing the semantic meaning of the stored value.
int get_num_components() const
Returns the number of components of the column: the number of instances of the NumericType in each el...
This class defines the physical layout of the vertex data stored within a Geom.
const GeomVertexColumn * get_normal_column() const
Returns the column definition of the "normal" column, or NULL if there is no such column.
const GeomVertexColumn * get_vertex_column() const
Returns the column definition of the "vertex" column, or NULL if there is no such column.
const GeomVertexColumn * get_color_column() const
Returns the column definition of the "color" column, or NULL if there is no such column.
get_column
Returns the ith column of the specification, across all arrays.
void remove_column(const InternalName *name, bool keep_empty_array=false)
Removes the named column from the format, from whichever array it exists in.
Encapsulates all the communication with a particular instance of a given rendering backend.
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...
get_max_texture_stages
Returns the maximum number of simultaneous textures that may be applied to geometry with multitexturi...
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.
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,...
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Definition: texGenAttrib.h:32
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:31
get_num_on_ff_stages
Returns the number of on-stages that are relevant to the classic fixed function pipeline.
Definition: textureAttrib.h:58
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
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...
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
get_texcoord_name
See set_texcoord_name.
Definition: textureStage.h:194
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(GeomVertexFormat) DXGeomMunger9
Given a source GeomVertexFormat, converts it if necessary to the appropriate format for rendering.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...