Panda3D
Loading...
Searching...
No Matches
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
34CullableObject::FormatMap CullableObject::_format_map;
35LightMutex CullableObject::_format_lock;
36
37PStatCollector CullableObject::_munge_pcollector("*:Munge");
38PStatCollector CullableObject::_munge_geom_pcollector("*:Munge:Geom");
39PStatCollector CullableObject::_munge_sprites_pcollector("*:Munge:Sprites");
40PStatCollector CullableObject::_munge_sprites_verts_pcollector("*:Munge:Sprites:Verts");
41PStatCollector CullableObject::_munge_sprites_prims_pcollector("*:Munge:Sprites:Prims");
42PStatCollector CullableObject::_sw_sprites_pcollector("SW Sprites");
43
44TypeHandle 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 */
198void CullableObject::
199output(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 */
213bool CullableObject::
214munge_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 */
654CPT(RenderState) CullableObject::
655get_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 */
675CPT(RenderState) CullableObject::
676get_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 */
695CullableObject::SourceFormat::
696SourceFormat(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.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Thread * get_current_thread() const
Returns the currently-executing thread object, as passed to the CullTraverser constructor.
SceneSetup * get_scene() const
Returns the SceneSetup object.
GraphicsStateGuardianBase * get_gsg() const
Returns the GraphicsStateGuardian in effect.
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...
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...
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.
int get_first_vertex() const
Returns the first vertex number referenced by the primitive.
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.
Defines a series of disconnected triangles.
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.
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...
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.
get_default
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
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.
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.