Panda3D
cullableObject.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 cullableObject.cxx
10  * @author drose
11  * @date 2002-03-04
12  */
13 
14 #include "cullableObject.h"
15 #include "lightAttrib.h"
16 #include "nodePath.h"
17 #include "colorAttrib.h"
18 #include "texGenAttrib.h"
19 #include "textureAttrib.h"
20 #include "shaderAttrib.h"
21 #include "renderState.h"
22 #include "clockObject.h"
23 #include "cullTraverser.h"
24 #include "sceneSetup.h"
25 #include "lens.h"
26 #include "stateMunger.h"
27 #include "pStatTimer.h"
28 #include "geomVertexWriter.h"
29 #include "geomVertexReader.h"
30 #include "geomTriangles.h"
31 #include "light.h"
32 #include "lightMutexHolder.h"
33 
34 CullableObject::FormatMap CullableObject::_format_map;
35 LightMutex CullableObject::_format_lock;
36 
37 PStatCollector CullableObject::_munge_pcollector("*:Munge");
38 PStatCollector CullableObject::_munge_geom_pcollector("*:Munge:Geom");
39 PStatCollector CullableObject::_munge_sprites_pcollector("*:Munge:Sprites");
40 PStatCollector CullableObject::_munge_sprites_verts_pcollector("*:Munge:Sprites:Verts");
41 PStatCollector CullableObject::_munge_sprites_prims_pcollector("*:Munge:Sprites:Prims");
42 PStatCollector CullableObject::_sw_sprites_pcollector("SW Sprites");
43 
44 TypeHandle CullableObject::_type_handle;
45 
46 /**
47  * Uses the indicated GeomMunger to transform the geom and/or its vertices.
48  *
49  * If force is false, this may do nothing and return false if the vertex data
50  * is nonresident. If force is true, this will always return true, but it may
51  * have to block while the vertex data is paged in.
52  */
55  const CullTraverser *traverser, bool force) {
56  nassertr(munger != nullptr, false);
57 
58  Thread *current_thread = traverser->get_current_thread();
59  PStatTimer timer(_munge_pcollector, current_thread);
60  if (_geom != nullptr) {
61  GraphicsStateGuardianBase *gsg = traverser->get_gsg();
62  int gsg_bits = gsg->get_supported_geom_rendering();
63  if (!hardware_point_sprites) {
64  // If support for hardware point sprites or perspective-scaled points is
65  // disabled, we don't allow the GSG to tell us it supports them.
66  gsg_bits &= ~(Geom::GR_point_perspective | Geom::GR_point_sprite);
67  }
68  if (!hardware_points) {
69  // If hardware-points is off, we don't allow any kind of point
70  // rendering, except plain old one-pixel points;
71  gsg_bits &= ~(Geom::GR_point_bits & ~Geom::GR_point);
72  }
73  int geom_rendering;
74  int unsupported_bits;
75 
76  {
77  GeomPipelineReader geom_reader(_geom, current_thread);
78  _munged_data = geom_reader.get_vertex_data();
79 
80 #ifdef _DEBUG
81  {
82  GeomVertexDataPipelineReader data_reader(_munged_data, current_thread);
83  data_reader.check_array_readers();
84  nassertr(geom_reader.check_valid(&data_reader), false);
85  }
86 #endif // _DEBUG
87 
88  geom_rendering = geom_reader.get_geom_rendering();
89  geom_rendering = _state->get_geom_rendering(geom_rendering);
90  geom_rendering = _internal_transform->get_geom_rendering(geom_rendering);
91  unsupported_bits = geom_rendering & ~gsg_bits;
92 
93  if (unsupported_bits & Geom::GR_per_point_size) {
94  // If we have a shader that processes the point size, we can assume it
95  // does the right thing.
96  const ShaderAttrib *sattr;
97  if (_state->get_attrib(sattr) && sattr->get_flag(ShaderAttrib::F_shader_point_size)) {
98  unsupported_bits &= ~Geom::GR_per_point_size;
99  }
100  }
101 
102  if (geom_rendering & Geom::GR_point_bits) {
103  if (geom_reader.get_primitive_type() != Geom::PT_points) {
104  if (singular_points ||
105  (unsupported_bits & Geom::GR_render_mode_point) != 0) {
106  // Isolate the points so there's no unneeded overlap.
107  _geom = _geom->make_points();
108  }
109  }
110  }
111  if (unsupported_bits & Geom::GR_render_mode_wireframe) {
112  if (geom_reader.get_primitive_type() != Geom::PT_lines) {
113  _geom = _geom->make_lines();
114  }
115  }
116  }
117 
118  if ((unsupported_bits & Geom::GR_point_bits) != 0) {
119  // The GSG doesn't support rendering these fancy points directly; we
120  // have to render them in software instead. Munge them into quads.
121  // This will replace the _geom and _munged_data, and might also replace
122  // _state.
123  if (pgraph_cat.is_spam()) {
124  pgraph_cat.spam()
125  << "munge_points_to_quads() for geometry with bits: "
126  << std::hex << geom_rendering << ", unsupported: "
127  << (unsupported_bits & Geom::GR_point_bits) << std::dec << "\n";
128  }
129  if (!munge_points_to_quads(traverser, force)) {
130  return false;
131  }
132  }
133 
134  // Now invoke the munger to ensure the resulting geometry is in a GSG-
135  // friendly form.
136  {
137  PStatTimer timer(_munge_geom_pcollector, current_thread);
138  if (!munger->munge_geom(_geom, _munged_data, force, current_thread)) {
139  return false;
140  }
141  }
142 
143  // If we have prepared it for skinning via the shader generator, mark a
144  // flag on the state so that the shader generator will do this. We should
145  // probably find a cleaner way to do this.
146  const ShaderAttrib *sattr;
147  if (_state->get_attrib(sattr) && sattr->auto_shader()) {
148  GeomVertexDataPipelineReader data_reader(_munged_data, current_thread);
149  if (data_reader.get_format()->get_animation().get_animation_type() == Geom::AT_hardware) {
150  static CPT(RenderState) state = RenderState::make(
151  DCAST(ShaderAttrib, ShaderAttrib::make())->set_flag(ShaderAttrib::F_hardware_skinning, true));
152  _state = _state->compose(state);
153  }
154 
155  gsg->ensure_generated_shader(_state);
156  } else {
157  // We may need to munge the state for the fixed-function pipeline.
158  StateMunger *state_munger = (StateMunger *)munger;
159  if (state_munger->should_munge_state()) {
160  _state = state_munger->munge_state(_state);
161  }
162  }
163 
164  // If there is any animation left in the vertex data after it has been
165  // munged--that is, we couldn't arrange to handle the animation in
166  // hardware--then we have to calculate that animation now.
167  bool cpu_animated = false;
168 
169  CPT(GeomVertexData) animated_vertices =
170  _munged_data->animate_vertices(force, current_thread);
171  if (animated_vertices != _munged_data) {
172  cpu_animated = true;
173  std::swap(_munged_data, animated_vertices);
174  }
175 
176 #ifndef NDEBUG
177  if (show_vertex_animation) {
178  GeomVertexDataPipelineReader data_reader(_munged_data, current_thread);
179  bool hardware_animated = (data_reader.get_format()->get_animation().get_animation_type() == Geom::AT_hardware);
180  if (cpu_animated || hardware_animated) {
181  // These vertices were animated, so flash them red or blue.
182  static const double flash_rate = 1.0; // 1 state change per second
183  int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * flash_rate);
184  if ((cycle & 1) == 0) {
185  _state = cpu_animated ? get_flash_cpu_state() : get_flash_hardware_state();
186  }
187  }
188  }
189 #endif
190  }
191 
192  return true;
193 }
194 
195 /**
196  *
197  */
198 void CullableObject::
199 output(std::ostream &out) const {
200  if (_geom != nullptr) {
201  out << *_geom;
202  } else {
203  out << "(null)";
204  }
205 }
206 
207 /**
208  * Converts a table of points to quads for rendering on systems that don't
209  * support fancy points.
210  *
211  * This may replace _geom, _munged_data, and _state.
212  */
213 bool CullableObject::
214 munge_points_to_quads(const CullTraverser *traverser, bool force) {
215  Thread *current_thread = traverser->get_current_thread();
216 
217  // Better get the animated vertices, in case we're showing sprites on an
218  // animated model for some reason.
219  CPT(GeomVertexData) source_data =
220  _munged_data->animate_vertices(force, current_thread);
221 
222  if (!force && !source_data->request_resident()) {
223  return false;
224  }
225 
226  GeomVertexDataPipelineReader reader(source_data, current_thread);
227  reader.check_array_readers();
228 
229  PStatTimer timer(_munge_sprites_pcollector, current_thread);
230  _sw_sprites_pcollector.add_level(reader.get_num_rows());
231 
232  GraphicsStateGuardianBase *gsg = traverser->get_gsg();
233 
234  GeomVertexReader vertex(&reader, InternalName::get_vertex());
235  GeomVertexReader normal(&reader, InternalName::get_normal());
236  GeomVertexReader rotate(&reader, InternalName::get_rotate());
237  GeomVertexReader size(&reader, InternalName::get_size());
238  GeomVertexReader aspect_ratio(&reader, InternalName::get_aspect_ratio());
239 
240  bool has_normal = (normal.has_column());
241  bool has_color = (reader.has_column(InternalName::get_color()));
242  bool has_texcoord = (reader.has_column(InternalName::get_texcoord()));
243  bool has_rotate = (rotate.has_column());
244  bool has_size = (size.has_column());
245  bool has_aspect_ratio = (aspect_ratio.has_column());
246 
247  bool sprite_texcoord = false;
248  const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, _state->get_attrib(TexGenAttrib::get_class_slot()));
249  if (tex_gen != nullptr) {
250  if (tex_gen->get_mode(TextureStage::get_default()) == TexGenAttrib::M_point_sprite) {
251  sprite_texcoord = true;
252 
253  // Turn off the TexGenAttrib, since we don't want it now.
254  _state = _state->set_attrib(tex_gen->remove_stage(TextureStage::get_default()));
255  }
256  }
257 
258  PN_stdfloat point_size = 1;
259  bool perspective = false;
260  const RenderModeAttrib *render_mode = DCAST(RenderModeAttrib, _state->get_attrib(RenderModeAttrib::get_class_slot()));
261  if (render_mode != nullptr) {
262  point_size = render_mode->get_thickness();
263  perspective = render_mode->get_perspective();
264 
265  if (render_mode->get_mode() != RenderModeAttrib::M_filled_flat) {
266  // Render the new polygons with M_filled_flat, for a slight performance
267  // advantage when software rendering.
268  _state = _state->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled_flat));
269  }
270  }
271 
272  // Get the vertex format of the newly created geometry.
273  CPT(GeomVertexFormat) new_format;
274 
275  {
276  LightMutexHolder holder(_format_lock);
277  SourceFormat sformat(reader.get_format(), sprite_texcoord);
278  FormatMap::iterator fmi = _format_map.find(sformat);
279  if (fmi != _format_map.end()) {
280  new_format = (*fmi).second;
281 
282  } else {
283  // We have to construct the format now.
284  PT(GeomVertexArrayFormat) new_array_format;
285  if (sformat._retransform_sprites) {
286  // With retransform_sprites in effect, we will be sending ordinary 3-D
287  // points to the graphics API.
288  new_array_format =
289  new GeomVertexArrayFormat(InternalName::get_vertex(), 3,
290  Geom::NT_stdfloat,
291  Geom::C_point);
292  } else {
293  // Without retransform_sprites, we will be sending 4-component clip-
294  // space points.
295  new_array_format =
296  new GeomVertexArrayFormat(InternalName::get_vertex(), 4,
297  Geom::NT_stdfloat,
298  Geom::C_clip_point);
299  }
300  if (has_normal) {
301  const GeomVertexColumn *c = reader.get_format()->get_normal_column();
302  new_array_format->add_column
303  (InternalName::get_normal(), c->get_num_components(),
304  c->get_numeric_type(), c->get_contents());
305  }
306  if (has_color) {
307  const GeomVertexColumn *c = reader.get_format()->get_color_column();
308  new_array_format->add_column
309  (InternalName::get_color(), c->get_num_components(),
310  c->get_numeric_type(), c->get_contents());
311  }
312  if (sprite_texcoord) {
313  new_array_format->add_column
314  (InternalName::get_texcoord(), 2,
315  Geom::NT_stdfloat,
316  Geom::C_texcoord);
317 
318  } else if (has_texcoord) {
319  const GeomVertexColumn *c = reader.get_format()->get_column(InternalName::get_texcoord());
320  new_array_format->add_column
321  (InternalName::get_texcoord(), c->get_num_components(),
322  c->get_numeric_type(), c->get_contents());
323  }
324 
325  // Go through the other columns and copy them from the original.
326  for (size_t ai = 0; ai < sformat._format->get_num_arrays(); ++ai) {
327  const GeomVertexArrayFormat *aformat = sformat._format->get_array(ai);
328 
329  for (size_t ci = 0; ci < aformat->get_num_columns(); ++ci) {
330  const GeomVertexColumn *column = aformat->get_column(ci);
331  const InternalName *name = column->get_name();
332  if (name != InternalName::get_vertex() &&
333  name != InternalName::get_normal() &&
334  name != InternalName::get_color() &&
335  name != InternalName::get_texcoord() &&
336  name != InternalName::get_rotate() &&
337  name != InternalName::get_size() &&
338  name != InternalName::get_aspect_ratio()) {
339 
340  new_array_format->add_column(name,
341  column->get_num_components(), column->get_numeric_type(),
342  column->get_contents());
343  }
344  }
345  }
346 
347  new_format = GeomVertexFormat::register_format(new_array_format);
348  _format_map[sformat] = new_format;
349  }
350  }
351 
352  CoordinateSystem internal_cs = gsg->get_internal_coordinate_system();
353  LMatrix4 internal = _internal_transform->get_mat();
354  PN_stdfloat scale = _internal_transform->get_scale()[1];
355 
356  SceneSetup *scene = traverser->get_scene();
357  const Lens *lens = scene->get_lens();
358  LMatrix4 projection =
359  LMatrix4::convert_mat(internal_cs, lens->get_coordinate_system()) *
360  lens->get_projection_mat();
361 
362  int viewport_width = scene->get_viewport_width();
363  int viewport_height = scene->get_viewport_height();
364 
365  // We need a standard projection matrix, in a known coordinate system, to
366  // compute the perspective height.
367  LMatrix4 height_projection;
368  if (perspective) {
369  height_projection =
370  LMatrix4::convert_mat(CS_yup_right, lens->get_coordinate_system()) *
371  lens->get_projection_mat();
372  }
373 
374  LMatrix4 render_transform = internal * projection;
375  LMatrix4 inv_render_transform;
376  inv_render_transform.invert_from(render_transform);
377 
378  // Now convert all of the vertices in the GeomVertexData to quads. We
379  // always convert all the vertices, assuming all the vertices are referenced
380  // by GeomPrimitives, because we want to optimize for the most common case.
381  int orig_verts = reader.get_num_rows();
382  int new_verts = 4 * orig_verts; // each vertex becomes four.
383 
384  PT(GeomVertexData) new_data = new GeomVertexData
385  (source_data->get_name(), new_format, Geom::UH_stream);
386  new_data->unclean_set_num_rows(new_verts);
387 
388  GeomVertexWriter new_vertex(new_data, InternalName::get_vertex());
389  GeomVertexWriter new_normal(new_data, InternalName::get_normal());
390  GeomVertexWriter new_texcoord(new_data, InternalName::get_texcoord());
391 
392  nassertr(new_vertex.has_column(), false);
393  unsigned char *write_ptr = new_vertex.get_array_handle()->get_write_pointer();
394 
395  // Collect all other columns that we just need to copy the data of.
396  struct CopyOp {
397  unsigned char *_to_pointer;
398  const unsigned char *_from_pointer;
399  size_t _num_bytes;
400  size_t _from_stride;
401  };
402  pvector<CopyOp> copies;
403 
404  const GeomVertexArrayFormat *aformat = new_format->get_array(0);
405  for (size_t ci = 0; ci < aformat->get_num_columns(); ++ci) {
406  const GeomVertexColumn *column = aformat->get_column(ci);
407  const InternalName *name = column->get_name();
408  if (name != InternalName::get_vertex() &&
409  (retransform_sprites || name != InternalName::get_normal()) &&
410  (!sprite_texcoord || name != InternalName::get_texcoord())) {
411 
412  int source_array;
413  const GeomVertexColumn *source_column;
414  if (reader.get_format()->get_array_info(name, source_array, source_column)) {
415  CopyOp copy;
416  copy._to_pointer = write_ptr + (size_t)column->get_start();
417  copy._from_pointer = reader.get_array_reader(source_array)->get_read_pointer(true) + (size_t)source_column->get_start();
418  copy._num_bytes = (size_t)column->get_total_bytes();
419  copy._from_stride = reader.get_format()->get_array(source_array)->get_stride();
420 
421  if (!copies.empty() &&
422  (copy._to_pointer == copies.back()._to_pointer + copies.back()._num_bytes) &&
423  (copy._from_pointer == copies.back()._from_pointer + copies.back()._num_bytes)) {
424  // Merge with previous.
425  copies.back()._num_bytes += copy._num_bytes;
426  } else {
427  copies.push_back(copy);
428  }
429  }
430  }
431  }
432  size_t to_stride = aformat->get_stride();
433 
434  // We'll keep an array of all of the points' eye-space coordinates, and
435  // their distance from the camera, so we can sort the points for each
436  // primitive, below.
437  PointData *points;
438  {
439  PStatTimer t2(_munge_sprites_verts_pcollector, current_thread);
440  points = (PointData *)alloca(orig_verts * sizeof(PointData));
441  int vi = 0;
442  while (!vertex.is_at_end()) {
443  // Get the point in eye-space coordinates.
444  LPoint3 eye = internal.xform_point(vertex.get_data3());
445  PN_stdfloat dist = gsg->compute_distance_to(eye);
446  points[vi]._dist = dist;
447 
448  // The point in clip coordinates.
449  LPoint4 p4 = LPoint4(eye[0], eye[1], eye[2], 1.0f) * projection;
450 
451  if (has_size) {
452  point_size = size.get_data1();
453  }
454 
455  PN_stdfloat scale_y = point_size;
456  if (perspective) {
457  // Perspective-sized points. Here point_size is the point's height in
458  // 3-d units. To arrange that, we need to figure out the appropriate
459  // scaling factor based on the current viewport and projection matrix.
460  LVector3 height(0.0f, point_size * scale, scale);
461  height = height * height_projection;
462  scale_y = height[1] * viewport_height;
463 
464  // We should then divide the radius by the distance from the camera
465  // plane, to emulate the glPointParameters() behavior.
466  if (!lens->is_orthographic()) {
467  scale_y /= dist;
468  }
469  }
470 
471  // Also factor in the homogeneous scale for being in clip coordinates
472  // still.
473  scale_y *= p4[3];
474 
475  PN_stdfloat scale_x = scale_y;
476  if (has_aspect_ratio) {
477  scale_x *= aspect_ratio.get_data1();
478  }
479 
480  // Define the first two corners based on the scales in X and Y.
481  LPoint2 c0(scale_x, scale_y);
482  LPoint2 c1(-scale_x, scale_y);
483 
484  if (has_rotate) {
485  // If we have a rotate factor, apply it to those two corners.
486  PN_stdfloat r = rotate.get_data1();
487  LMatrix3 mat = LMatrix3::rotate_mat(r);
488  c0 = c0 * mat;
489  c1 = c1 * mat;
490  }
491 
492  // Finally, scale the corners in their newly-rotated position, to
493  // compensate for the aspect ratio of the viewport.
494  PN_stdfloat rx = 1.0f / viewport_width;
495  PN_stdfloat ry = 1.0f / viewport_height;
496  c0.set(c0[0] * rx, c0[1] * ry);
497  c1.set(c1[0] * rx, c1[1] * ry);
498 
499  if (retransform_sprites) {
500  // With retransform_sprites in effect, we must reconvert the resulting
501  // quad back into the original 3-D space.
502  new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] + c0[0], p4[1] + c0[1], p4[2], p4[3])));
503  new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3])));
504  new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3])));
505  new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3])));
506 
507  } else {
508  // Without retransform_sprites, we can simply load the clip-space
509  // coordinates.
510  new_vertex.set_data4(p4[0] + c0[0], p4[1] + c0[1], p4[2], p4[3]);
511  new_vertex.set_data4(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3]);
512  new_vertex.set_data4(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3]);
513  new_vertex.set_data4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]);
514 
515  if (has_normal) {
516  // We need to transform the normals to clip-space too, then.
517  LNormal c = render_transform.xform_vec(normal.get_data3());
518  new_normal.set_data3(c);
519  new_normal.set_data3(c);
520  new_normal.set_data3(c);
521  new_normal.set_data3(c);
522  }
523  }
524  if (sprite_texcoord) {
525  new_texcoord.set_data2(1.0f, 0.0f);
526  new_texcoord.set_data2(0.0f, 0.0f);
527  new_texcoord.set_data2(1.0f, 1.0f);
528  new_texcoord.set_data2(0.0f, 1.0f);
529  }
530 
531  // Other columns are simply duplicated for each vertex.
532  for (CopyOp &copy : copies) {
533  memcpy(copy._to_pointer, copy._from_pointer, copy._num_bytes);
534  copy._to_pointer += to_stride;
535  memcpy(copy._to_pointer, copy._from_pointer, copy._num_bytes);
536  copy._to_pointer += to_stride;
537  memcpy(copy._to_pointer, copy._from_pointer, copy._num_bytes);
538  copy._to_pointer += to_stride;
539  memcpy(copy._to_pointer, copy._from_pointer, copy._num_bytes);
540  copy._to_pointer += to_stride;
541  copy._from_pointer += copy._from_stride;
542  }
543 
544  ++vi;
545  }
546 
547  nassertr(vi == orig_verts, false);
548  nassertr(new_data->get_num_rows() == new_verts, false);
549  }
550 
551  // Determine the format we should use to store the indices. Don't choose
552  // NT_uint8, as Direct3D 9 doesn't support it.
553  const GeomVertexArrayFormat *new_prim_format = nullptr;
554  if (new_verts < 0xffff) {
555  new_prim_format = GeomPrimitive::get_index_format(GeomEnums::NT_uint16);
556 
557  } else {
558  new_prim_format = GeomPrimitive::get_index_format(GeomEnums::NT_uint32);
559  }
560 
561  PT(Geom) new_geom = new Geom(new_data);
562 
563  // Replace each primitive in the Geom (it's presumably a GeomPoints
564  // primitive, although it might be some other kind of primitive if we got
565  // here because RenderModeAttrib::M_point is enabled) with a new primitive
566  // that replaces each vertex with a quad of the appropriate scale and
567  // orientation.
568 
569  // BUG: if we're rendering polygons in M_point mode with a CullFaceAttrib in
570  // effect, we won't actually apply the CullFaceAttrib but will always render
571  // all of the vertices of the polygons. This is certainly a bug, but a very
572  // minor one; and in order to fix it we'd have to do the face culling
573  // ourselves--not sure if it's worth it.
574 
575  {
576  PStatTimer t3(_munge_sprites_prims_pcollector, current_thread);
577  GeomPipelineReader geom_reader(_geom, current_thread);
578  int num_primitives = geom_reader.get_num_primitives();
579  for (int pi = 0; pi < num_primitives; ++pi) {
580  const GeomPrimitive *primitive = geom_reader.get_primitive(pi);
581  if (primitive->get_num_vertices() != 0) {
582  // Extract out the list of vertices referenced by the primitive.
583  int num_vertices = primitive->get_num_vertices();
584  unsigned int *vertices = (unsigned int *)alloca(num_vertices * sizeof(unsigned int));
585  unsigned int *vertices_end = vertices + num_vertices;
586 
587  if (primitive->is_indexed()) {
588  // Indexed case.
589  GeomVertexReader index(primitive->get_vertices(), 0, current_thread);
590  for (unsigned int *vi = vertices; vi != vertices_end; ++vi) {
591  unsigned int v = index.get_data1i();
592  nassertr(v < (unsigned int)orig_verts, false);
593  (*vi) = v;
594  }
595  } else {
596  // Nonindexed case.
597  unsigned int first_vertex = primitive->get_first_vertex();
598  for (int i = 0; i < num_vertices; ++i) {
599  unsigned int v = i + first_vertex;
600  nassertr(v < (unsigned int)orig_verts, false);
601  vertices[i] = v;
602  }
603  }
604 
605  // Now sort the points in order from back-to-front so they will render
606  // properly with transparency, at least with each other.
607  std::sort(vertices, vertices_end, SortPoints(points));
608 
609  // Go through the points, now in sorted order, and generate a pair of
610  // triangles for each one. We generate indexed triangles instead of
611  // two-triangle strips, since this seems to be generally faster on PC
612  // hardware (otherwise, we'd have to nearly double the vertices to
613  // stitch all the little triangle strips together).
614  PT(GeomPrimitive) new_primitive = new GeomTriangles(Geom::UH_stream);
615  int new_prim_verts = 6 * num_vertices; // two triangles per point.
616 
617  PT(GeomVertexArrayData) new_index
618  = new GeomVertexArrayData(new_prim_format, GeomEnums::UH_stream);
619  new_index->unclean_set_num_rows(new_prim_verts);
620 
621  GeomVertexWriter index(new_index, 0);
622  nassertr(index.has_column(), false);
623  for (unsigned int *vi = vertices; vi != vertices_end; ++vi) {
624  int new_vi = (*vi) * 4;
625  nassertr(index.get_write_row() + 6 <= new_prim_verts, false);
626  index.set_data1i(new_vi);
627  index.set_data1i(new_vi + 1);
628  index.set_data1i(new_vi + 2);
629  index.set_data1i(new_vi + 2);
630  index.set_data1i(new_vi + 1);
631  index.set_data1i(new_vi + 3);
632  }
633  new_primitive->set_vertices(new_index, new_prim_verts);
634 
635  int min_vi = primitive->get_min_vertex();
636  int max_vi = primitive->get_max_vertex();
637  new_primitive->set_minmax(min_vi * 4, max_vi * 4 + 3, nullptr, nullptr);
638 
639  new_geom->add_primitive(new_primitive);
640  }
641  }
642  }
643 
644  _geom = new_geom.p();
645  _munged_data = std::move(new_data);
646 
647  return true;
648 }
649 
650 /**
651  * Returns a RenderState for flashing the object red, to show it is animated
652  * by the CPU when show-vertex-animation is on.
653  */
654 CPT(RenderState) CullableObject::
655 get_flash_cpu_state() {
656  static const LColor flash_cpu_color(0.8f, 0.2, 0.2, 1.0f);
657 
658  // Once someone asks for this pointer, we hold its reference count and never
659  // free it.
660  static CPT(RenderState) flash_cpu_state = nullptr;
661  if (flash_cpu_state == nullptr) {
662  flash_cpu_state = RenderState::make
663  (LightAttrib::make_all_off(),
664  TextureAttrib::make_off(),
665  ColorAttrib::make_flat(flash_cpu_color));
666  }
667 
668  return flash_cpu_state;
669 }
670 
671 /**
672  * Returns a RenderState for flashing the object blue, to show it is animated
673  * by the hardware when show-vertex-animation is on.
674  */
675 CPT(RenderState) CullableObject::
676 get_flash_hardware_state() {
677  static const LColor flash_hardware_color(0.2, 0.2, 0.8, 1.0);
678 
679  // Once someone asks for this pointer, we hold its reference count and never
680  // free it.
681  static CPT(RenderState) flash_hardware_state = nullptr;
682  if (flash_hardware_state == nullptr) {
683  flash_hardware_state = RenderState::make
684  (LightAttrib::make_all_off(),
685  TextureAttrib::make_off(),
686  ColorAttrib::make_flat(flash_hardware_color));
687  }
688 
689  return flash_hardware_state;
690 }
691 
692 /**
693  *
694  */
695 CullableObject::SourceFormat::
696 SourceFormat(const GeomVertexFormat *format, bool sprite_texcoord) :
697  _format(format),
698  _sprite_texcoord(sprite_texcoord)
699 {
700  _retransform_sprites = retransform_sprites;
701 }
Geom
A container for geometry primitives.
Definition: geom.h:54
RenderModeAttrib::get_mode
get_mode
Returns the render mode.
Definition: renderModeAttrib.h:69
SceneSetup::get_viewport_height
int get_viewport_height() const
Returns the height of the viewport (display region) in pixels.
Definition: sceneSetup.I:67
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
GeomVertexColumn::get_start
int get_start() const
Returns the byte within the array record at which this column starts.
Definition: geomVertexColumn.I:133
nodePath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayData
This is the data for one array of a GeomVertexData structure.
Definition: geomVertexArrayData.h:58
GeomPrimitive::get_first_vertex
int get_first_vertex() const
Returns the first vertex number referenced by the primitive.
Definition: geomPrimitive.I:98
cullTraverser.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
RenderModeAttrib::get_thickness
get_thickness
Returns the line width or point thickness.
Definition: renderModeAttrib.h:70
geomVertexWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Lens::get_projection_mat
const LMatrix4 & get_projection_mat(StereoChannel channel=SC_mono) const
Returns the complete transformation matrix from a 3-d point in space to a point on the film,...
Definition: lens.I:563
stateMunger.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
GeomVertexData
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
Definition: geomVertexData.h:68
GeomVertexArrayFormat::get_column
get_column
Returns the specification with the indicated name, or NULL if the name is not used.
Definition: geomVertexArrayFormat.h:106
geomVertexReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pmap
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
cullableObject.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayFormat::get_num_columns
get_num_columns
Returns the number of different columns in the array.
Definition: geomVertexArrayFormat.h:106
ShaderAttrib::auto_shader
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
Definition: shaderAttrib.I:71
CullTraverser::get_scene
SceneSetup * get_scene() const
Returns the SceneSetup object.
Definition: cullTraverser.I:35
clockObject.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ClockObject::get_global_clock
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
colorAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexWriter
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
Definition: geomVertexWriter.h:55
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
ShaderAttrib
Definition: shaderAttrib.h:39
InternalName
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
GeomVertexReader
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
Definition: geomVertexReader.h:47
GeomMunger::munge_geom
bool munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data, bool force, Thread *current_thread)
Applies the indicated munger to the geom and its data, and returns a (possibly different) geom and da...
Definition: geomMunger.cxx:95
CPT
CPT(RenderState) CullableObject
Returns a RenderState for flashing the object red, to show it is animated by the CPU when show-vertex...
Definition: cullableObject.cxx:654
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
LightMutex
This is a standard, non-reentrant mutex, similar to the Mutex class.
Definition: lightMutex.h:41
Lens::get_coordinate_system
get_coordinate_system
Returns the coordinate system that all 3-d computations are performed within for this Lens.
Definition: lens.h:74
PStatTimer
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
GeomPrimitive::get_index_format
const GeomVertexArrayFormat * get_index_format() const
Returns a registered format appropriate for using to store the index table.
Definition: geomPrimitive.I:389
renderState.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
SceneSetup
This object holds the camera position, etc., and other general setup information for rendering a part...
Definition: sceneSetup.h:32
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
light.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexFormat::get_animation
get_animation
Returns the GeomVertexAnimationSpec that indicates how this format's vertices are set up for animatio...
Definition: geomVertexFormat.h:72
texGenAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPipelineReader
Encapsulates the data from a Geom, pre-fetched for one stage of the pipeline.
Definition: geom.h:405
GeomPrimitive::get_num_vertices
get_num_vertices
Returns the number of indices used by all the primitives in this object.
Definition: geomPrimitive.h:99
lightMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CullTraverser::get_current_thread
Thread * get_current_thread() const
Returns the currently-executing thread object, as passed to the CullTraverser constructor.
Definition: cullTraverser.I:27
sceneSetup.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::get_min_vertex
int get_min_vertex() const
Returns the minimum vertex index number used by all the primitives in this object.
Definition: geomPrimitive.I:181
PStatCollector
A lightweight class that represents a single element that may be timed and/or counted via stats.
Definition: pStatCollector.h:43
RenderModeAttrib
Specifies how polygons are to be drawn.
Definition: renderModeAttrib.h:27
shaderAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexColumn::get_name
const InternalName * get_name() const
Returns the name of this particular data field, e.g.
Definition: geomVertexColumn.I:77
geomTriangles.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Lens
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
GeomVertexColumn::get_total_bytes
int get_total_bytes() const
Returns the number of bytes used by each element of the column: component_bytes * num_components.
Definition: geomVertexColumn.I:171
GeomPrimitive::get_max_vertex
int get_max_vertex() const
Returns the maximum vertex index number used by all the primitives in this object.
Definition: geomPrimitive.I:192
GeomVertexColumn::get_numeric_type
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
Definition: geomVertexColumn.I:116
GeomVertexColumn::get_contents
Contents get_contents() const
Returns the token representing the semantic meaning of the stored value.
Definition: geomVertexColumn.I:124
GeomVertexFormat
This class defines the physical layout of the vertex data stored within a Geom.
Definition: geomVertexFormat.h:55
CullableObject::munge_geom
bool munge_geom(GraphicsStateGuardianBase *gsg, GeomMunger *munger, const CullTraverser *traverser, bool force)
Uses the indicated GeomMunger to transform the geom and/or its vertices.
Definition: cullableObject.cxx:54
GeomTriangles
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
StateMunger
This is just a simple derivative of GeomMunger that adds the ability to munge states.
Definition: stateMunger.h:26
textureAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ClockObject::get_frame_time
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.h:91
GeomVertexColumn::get_num_components
int get_num_components() const
Returns the number of components of the column: the number of instances of the NumericType in each el...
Definition: geomVertexColumn.I:87
Lens::is_orthographic
virtual bool is_orthographic() const
Returns true if the lens represents a orthographic projection (i.e.
Definition: lens.cxx:558
TexGenAttrib
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Definition: texGenAttrib.h:32
GraphicsStateGuardianBase
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Definition: graphicsStateGuardianBase.h:110
GeomVertexColumn
This defines how a single column is interleaved within a vertex array stored within a Geom.
Definition: geomVertexColumn.h:37
GeomVertexArrayFormat::get_stride
get_stride
Returns the total number of bytes reserved in the array for each vertex.
Definition: geomVertexArrayFormat.h:82
CullTraverser::get_gsg
GraphicsStateGuardianBase * get_gsg() const
Returns the GraphicsStateGuardian in effect.
Definition: cullTraverser.I:18
TextureStage::get_default
get_default
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
Definition: textureStage.h:205
lightAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::is_indexed
bool is_indexed() const
Returns true if the primitive is indexed, false otherwise.
Definition: geomPrimitive.I:86
StateMunger::should_munge_state
bool should_munge_state() const
Returns true if this munger has something interesting to do to the state.
Definition: stateMunger.I:28
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
SceneSetup::get_lens
const Lens * get_lens() const
Returns the particular Lens used for rendering.
Definition: sceneSetup.I:131
SceneSetup::get_viewport_width
int get_viewport_width() const
Returns the width of the viewport (display region) in pixels.
Definition: sceneSetup.I:59
RenderModeAttrib::get_perspective
get_perspective
Returns the perspective flag.
Definition: renderModeAttrib.h:71
GeomVertexArrayFormat
This describes the structure of a single array within a Geom data.
Definition: geomVertexArrayFormat.h:47
GeomPrimitive
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
GeomVertexDataPipelineReader
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
Definition: geomVertexData.h:442
lens.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomMunger
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:50