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