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 }
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
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
Thread * get_current_thread() const
Returns the currently-executing thread object, as passed to the CullTraverser constructor.
Definition: cullTraverser.I:27
SceneSetup * get_scene() const
Returns the SceneSetup object.
Definition: cullTraverser.I:35
GraphicsStateGuardianBase * get_gsg() const
Returns the GraphicsStateGuardian in effect.
Definition: cullTraverser.I:18
bool munge_geom(GraphicsStateGuardianBase *gsg, GeomMunger *munger, const CullTraverser *traverser, bool force)
Uses the indicated GeomMunger to transform the geom and/or its vertices.
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:50
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
Encapsulates the data from a Geom, pre-fetched for one stage of the pipeline.
Definition: geom.h:405
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
int get_max_vertex() const
Returns the maximum vertex index number used by all the primitives in this object.
get_num_vertices
Returns the number of indices used by all the primitives in this object.
Definition: geomPrimitive.h:99
int get_first_vertex() const
Returns the first vertex number referenced by the primitive.
Definition: geomPrimitive.I:98
const GeomVertexArrayFormat * get_index_format() const
Returns a registered format appropriate for using to store the index table.
int get_min_vertex() const
Returns the minimum vertex index number used by all the primitives in this object.
bool is_indexed() const
Returns true if the primitive is indexed, false otherwise.
Definition: geomPrimitive.I:86
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
This is the data for one array of a GeomVertexData structure.
This describes the structure of a single array within a Geom data.
get_column
Returns the specification with the indicated name, or NULL if the name is not used.
get_num_columns
Returns the number of different columns in the array.
get_stride
Returns the total number of bytes reserved in the array for each vertex.
This defines how a single column is interleaved within a vertex array stored within a Geom.
int get_start() const
Returns the byte within the array record at which this column starts.
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_total_bytes() const
Returns the number of bytes used by each element of the column: component_bytes * 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...
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This class defines the physical layout of the vertex data stored within a Geom.
get_animation
Returns the GeomVertexAnimationSpec that indicates how this format's vertices are set up for animatio...
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
A container for geometry primitives.
Definition: geom.h:54
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
virtual bool is_orthographic() const
Returns true if the lens represents a orthographic projection (i.e.
Definition: lens.cxx:558
get_coordinate_system
Returns the coordinate system that all 3-d computations are performed within for this Lens.
Definition: lens.h:74
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
Similar to MutexHolder, but for a light mutex.
This is a standard, non-reentrant mutex, similar to the Mutex class.
Definition: lightMutex.h:41
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
Specifies how polygons are to be drawn.
get_perspective
Returns the perspective flag.
get_thickness
Returns the line width or point thickness.
get_mode
Returns the render mode.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
This object holds the camera position, etc., and other general setup information for rendering a part...
Definition: sceneSetup.h:32
const Lens * get_lens() const
Returns the particular Lens used for rendering.
Definition: sceneSetup.I:131
int get_viewport_width() const
Returns the width of the viewport (display region) in pixels.
Definition: sceneSetup.I:59
int get_viewport_height() const
Returns the height of the viewport (display region) in pixels.
Definition: sceneSetup.I:67
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
Definition: shaderAttrib.I:71
This is just a simple derivative of GeomMunger that adds the ability to munge states.
Definition: stateMunger.h:26
bool should_munge_state() const
Returns true if this munger has something interesting to do to the state.
Definition: stateMunger.I:28
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Definition: texGenAttrib.h:32
get_default
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
Definition: textureStage.h:207
A thread; that is, a lightweight process.
Definition: thread.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(RenderState) CullableObject
Returns a RenderState for flashing the object red, to show it is animated by the CPU when show-vertex...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.