Panda3D
|
00001 // Filename: cullableObject.cxx 00002 // Created by: drose (04Mar02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "cullableObject.h" 00016 #include "lightAttrib.h" 00017 #include "nodePath.h" 00018 #include "texGenAttrib.h" 00019 #include "renderState.h" 00020 #include "clockObject.h" 00021 #include "cullTraverser.h" 00022 #include "sceneSetup.h" 00023 #include "lens.h" 00024 #include "stateMunger.h" 00025 #include "pStatTimer.h" 00026 #include "geomVertexWriter.h" 00027 #include "geomVertexReader.h" 00028 #include "geomTriangles.h" 00029 #include "light.h" 00030 #include "lightMutexHolder.h" 00031 #include "geomDrawCallbackData.h" 00032 00033 CullableObject::FormatMap CullableObject::_format_map; 00034 LightMutex CullableObject::_format_lock; 00035 00036 PStatCollector CullableObject::_munge_geom_pcollector("*:Munge:Geom"); 00037 PStatCollector CullableObject::_munge_sprites_pcollector("*:Munge:Sprites"); 00038 PStatCollector CullableObject::_munge_sprites_verts_pcollector("*:Munge:Sprites:Verts"); 00039 PStatCollector CullableObject::_munge_sprites_prims_pcollector("*:Munge:Sprites:Prims"); 00040 PStatCollector CullableObject::_munge_light_vector_pcollector("*:Munge:Light Vector"); 00041 PStatCollector CullableObject::_sw_sprites_pcollector("SW Sprites"); 00042 00043 TypeHandle CullableObject::_type_handle; 00044 00045 //////////////////////////////////////////////////////////////////// 00046 // Function: CullableObject::munge_geom 00047 // Access: Public 00048 // Description: Uses the indicated GeomMunger to transform the geom 00049 // and/or its vertices. 00050 // 00051 // If force is false, this may do nothing and return 00052 // false if the vertex data is nonresident. If force is 00053 // true, this will always return true, but it may have 00054 // to block while the vertex data is paged in. 00055 //////////////////////////////////////////////////////////////////// 00056 bool CullableObject:: 00057 munge_geom(GraphicsStateGuardianBase *gsg, 00058 GeomMunger *munger, const CullTraverser *traverser, 00059 bool force) { 00060 nassertr(munger != (GeomMunger *)NULL, false); 00061 Thread *current_thread = traverser->get_current_thread(); 00062 PStatTimer timer(_munge_geom_pcollector, current_thread); 00063 if (_geom != (Geom *)NULL) { 00064 _munger = munger; 00065 00066 int geom_rendering; 00067 00068 { 00069 GeomPipelineReader geom_reader(_geom, current_thread); 00070 _munged_data = geom_reader.get_vertex_data(); 00071 00072 #ifdef _DEBUG 00073 { 00074 GeomVertexDataPipelineReader data_reader(_munged_data, current_thread); 00075 data_reader.check_array_readers(); 00076 nassertr(geom_reader.check_valid(&data_reader), false); 00077 } 00078 #endif // _DEBUG 00079 00080 geom_rendering = geom_reader.get_geom_rendering(); 00081 geom_rendering = _state->get_geom_rendering(geom_rendering); 00082 geom_rendering = _modelview_transform->get_geom_rendering(geom_rendering); 00083 00084 if (geom_rendering & Geom::GR_point_bits) { 00085 if (geom_reader.get_primitive_type() != Geom::PT_points) { 00086 if (singular_points) { 00087 // Isolate the points so there's no unneeded overlap. 00088 _geom = _geom->make_points(); 00089 } 00090 } 00091 } 00092 } 00093 00094 GraphicsStateGuardianBase *gsg = traverser->get_gsg(); 00095 int gsg_bits = gsg->get_supported_geom_rendering(); 00096 if (!hardware_point_sprites) { 00097 // If support for hardware point sprites or perspective-scaled 00098 // points is disabled, we don't allow the GSG to tell us it 00099 // supports them. 00100 gsg_bits &= ~(Geom::GR_point_perspective | Geom::GR_point_sprite); 00101 } 00102 if (!hardware_points) { 00103 // If hardware-points is off, we don't allow any kind of point 00104 // rendering, except plain old one-pixel points; 00105 gsg_bits &= ~(Geom::GR_point_bits & ~Geom::GR_point); 00106 } 00107 int unsupported_bits = geom_rendering & ~gsg_bits; 00108 00109 if ((unsupported_bits & Geom::GR_point_bits) != 0) { 00110 // The GSG doesn't support rendering these fancy points 00111 // directly; we have to render them in software instead. 00112 // Munge them into quads. This will replace the _geom and 00113 // _munged_data, and might also replace _state. 00114 if (pgraph_cat.is_spam()) { 00115 pgraph_cat.spam() 00116 << "munge_points_to_quads() for geometry with bits: " 00117 << hex << geom_rendering << ", unsupported: " 00118 << (unsupported_bits & Geom::GR_point_bits) << dec << "\n"; 00119 } 00120 if (!munge_points_to_quads(traverser, force)) { 00121 return false; 00122 } 00123 } 00124 00125 bool cpu_animated = false; 00126 00127 if (unsupported_bits & Geom::GR_texcoord_light_vector) { 00128 // If we have to compute the light vector, we have to animate 00129 // the vertices in the CPU--and we have to do it before we call 00130 // munge_geom(), which might lose the tangent and binormal. 00131 CPT(GeomVertexData) animated_vertices = 00132 _munged_data->animate_vertices(force, current_thread); 00133 if (animated_vertices != _munged_data) { 00134 cpu_animated = true; 00135 _munged_data = animated_vertices; 00136 } 00137 if (!munge_texcoord_light_vector(traverser, force)) { 00138 return false; 00139 } 00140 } 00141 00142 // Now invoke the munger to ensure the resulting geometry is in 00143 // a GSG-friendly form. 00144 if (!munger->munge_geom(_geom, _munged_data, force, current_thread)) { 00145 return false; 00146 } 00147 00148 StateMunger *state_munger; 00149 DCAST_INTO_R(state_munger, munger, false); 00150 _state = state_munger->munge_state(_state); 00151 00152 if (!cpu_animated) { 00153 // If there is any animation left in the vertex data after it 00154 // has been munged--that is, we couldn't arrange to handle the 00155 // animation in hardware--then we have to calculate that 00156 // animation now. 00157 CPT(GeomVertexData) animated_vertices = 00158 _munged_data->animate_vertices(force, current_thread); 00159 if (animated_vertices != _munged_data) { 00160 cpu_animated = true; 00161 _munged_data = animated_vertices; 00162 } 00163 } 00164 00165 #ifndef NDEBUG 00166 if (show_vertex_animation) { 00167 GeomVertexDataPipelineReader data_reader(_munged_data, current_thread); 00168 bool hardware_animated = (data_reader.get_format()->get_animation().get_animation_type() == Geom::AT_hardware); 00169 if (cpu_animated || hardware_animated) { 00170 // These vertices were animated, so flash them red or blue. 00171 static const double flash_rate = 1.0; // 1 state change per second 00172 int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * flash_rate); 00173 if ((cycle & 1) == 0) { 00174 _state = cpu_animated ? get_flash_cpu_state() : get_flash_hardware_state(); 00175 } 00176 } 00177 } 00178 #endif 00179 } 00180 00181 if (_fancy) { 00182 // Only check the _next pointer if the _fancy flag is set. 00183 if (_next != (CullableObject *)NULL) { 00184 if (_next->_state != (RenderState *)NULL) { 00185 _next->munge_geom(gsg, gsg->get_geom_munger(_next->_state, current_thread), 00186 traverser, force); 00187 } else { 00188 _next->munge_geom(gsg, munger, traverser, force); 00189 } 00190 } 00191 } 00192 00193 return true; 00194 } 00195 00196 //////////////////////////////////////////////////////////////////// 00197 // Function: CullableObject::Destructor 00198 // Access: Public 00199 // Description: Automatically deletes the whole chain of these things. 00200 //////////////////////////////////////////////////////////////////// 00201 CullableObject:: 00202 ~CullableObject() { 00203 if (_fancy) { 00204 // Only check the _next pointer if the _fancy flag is set. 00205 if (_next != (CullableObject *)NULL) { 00206 delete _next; 00207 } 00208 set_draw_callback(NULL); 00209 } 00210 } 00211 00212 //////////////////////////////////////////////////////////////////// 00213 // Function: CullableObject::output 00214 // Access: Public 00215 // Description: 00216 //////////////////////////////////////////////////////////////////// 00217 void CullableObject:: 00218 output(ostream &out) const { 00219 if (_geom != (Geom *)NULL) { 00220 out << *_geom; 00221 } else { 00222 out << "(null)"; 00223 } 00224 } 00225 00226 00227 //////////////////////////////////////////////////////////////////// 00228 // Function: CullableObject::munge_points_to_quads 00229 // Access: Private 00230 // Description: Converts a table of points to quads for rendering on 00231 // systems that don't support fancy points. 00232 // 00233 // This may replace _geom, _munged_data, and _state. 00234 //////////////////////////////////////////////////////////////////// 00235 bool CullableObject:: 00236 munge_points_to_quads(const CullTraverser *traverser, bool force) { 00237 Thread *current_thread = traverser->get_current_thread(); 00238 00239 // Better get the animated vertices, in case we're showing sprites 00240 // on an animated model for some reason. 00241 CPT(GeomVertexData) source_data = 00242 _munged_data->animate_vertices(force, current_thread); 00243 00244 if (!force && !source_data->request_resident()) { 00245 return false; 00246 } 00247 00248 PStatTimer timer(_munge_sprites_pcollector, current_thread); 00249 _sw_sprites_pcollector.add_level(source_data->get_num_rows()); 00250 00251 GraphicsStateGuardianBase *gsg = traverser->get_gsg(); 00252 00253 GeomVertexReader vertex(source_data, InternalName::get_vertex(), 00254 current_thread); 00255 GeomVertexReader normal(source_data, InternalName::get_normal(), 00256 current_thread); 00257 GeomVertexReader color(source_data, InternalName::get_color(), 00258 current_thread); 00259 GeomVertexReader texcoord(source_data, InternalName::get_texcoord(), 00260 current_thread); 00261 GeomVertexReader rotate(source_data, InternalName::get_rotate(), 00262 current_thread); 00263 GeomVertexReader size(source_data, InternalName::get_size(), 00264 current_thread); 00265 GeomVertexReader aspect_ratio(source_data, InternalName::get_aspect_ratio(), 00266 current_thread); 00267 00268 bool has_normal = (normal.has_column()); 00269 bool has_color = (color.has_column()); 00270 bool has_texcoord = (texcoord.has_column()); 00271 bool has_rotate = (rotate.has_column()); 00272 bool has_size = (size.has_column()); 00273 bool has_aspect_ratio = (aspect_ratio.has_column()); 00274 00275 bool sprite_texcoord = false; 00276 const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, _state->get_attrib(TexGenAttrib::get_class_slot())); 00277 if (tex_gen != (TexGenAttrib *)NULL) { 00278 if (tex_gen->get_mode(TextureStage::get_default()) == TexGenAttrib::M_point_sprite) { 00279 sprite_texcoord = true; 00280 00281 // Turn off the TexGenAttrib, since we don't want it now. 00282 _state = _state->set_attrib(tex_gen->remove_stage(TextureStage::get_default())); 00283 } 00284 } 00285 00286 PN_stdfloat point_size = 1.0f; 00287 bool perspective = false; 00288 const RenderModeAttrib *render_mode = DCAST(RenderModeAttrib, _state->get_attrib(RenderModeAttrib::get_class_slot())); 00289 if (render_mode != (RenderModeAttrib *)NULL) { 00290 point_size = render_mode->get_thickness(); 00291 perspective = render_mode->get_perspective(); 00292 00293 if (render_mode->get_mode() != RenderModeAttrib::M_filled_flat) { 00294 // Render the new polygons with M_filled_flat, for a slight 00295 // performance advantage when software rendering. 00296 _state = _state->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled_flat)); 00297 } 00298 } 00299 00300 // Get the vertex format of the newly created geometry. 00301 CPT(GeomVertexFormat) new_format; 00302 00303 { 00304 LightMutexHolder holder(_format_lock); 00305 SourceFormat sformat(source_data->get_format(), sprite_texcoord); 00306 FormatMap::iterator fmi = _format_map.find(sformat); 00307 if (fmi != _format_map.end()) { 00308 new_format = (*fmi).second; 00309 00310 } else { 00311 // We have to construct the format now. 00312 PT(GeomVertexArrayFormat) new_array_format; 00313 if (sformat._retransform_sprites) { 00314 // With retransform_sprites in effect, we will be sending ordinary 00315 // 3-D points to the graphics API. 00316 new_array_format = 00317 new GeomVertexArrayFormat(InternalName::get_vertex(), 3, 00318 Geom::NT_stdfloat, 00319 Geom::C_point); 00320 } else { 00321 // Without retransform_sprites, we will be sending 4-component 00322 // clip-space points. 00323 new_array_format = 00324 new GeomVertexArrayFormat(InternalName::get_vertex(), 4, 00325 Geom::NT_stdfloat, 00326 Geom::C_clip_point); 00327 } 00328 if (has_normal) { 00329 const GeomVertexColumn *c = normal.get_column(); 00330 new_array_format->add_column 00331 (InternalName::get_normal(), c->get_num_components(), 00332 c->get_numeric_type(), c->get_contents()); 00333 } 00334 if (has_color) { 00335 const GeomVertexColumn *c = color.get_column(); 00336 new_array_format->add_column 00337 (InternalName::get_color(), c->get_num_components(), 00338 c->get_numeric_type(), c->get_contents()); 00339 } 00340 if (sprite_texcoord) { 00341 new_array_format->add_column 00342 (InternalName::get_texcoord(), 2, 00343 Geom::NT_stdfloat, 00344 Geom::C_texcoord); 00345 00346 } else if (has_texcoord) { 00347 const GeomVertexColumn *c = texcoord.get_column(); 00348 new_array_format->add_column 00349 (InternalName::get_texcoord(), c->get_num_components(), 00350 c->get_numeric_type(), c->get_contents()); 00351 } 00352 00353 new_format = GeomVertexFormat::register_format(new_array_format); 00354 _format_map[sformat] = new_format; 00355 } 00356 } 00357 00358 const LMatrix4 &modelview = _modelview_transform->get_mat(); 00359 00360 SceneSetup *scene = traverser->get_scene(); 00361 const Lens *lens = scene->get_lens(); 00362 const LMatrix4 &projection = lens->get_projection_mat(); 00363 00364 int viewport_width = scene->get_viewport_width(); 00365 int viewport_height = scene->get_viewport_height(); 00366 00367 // We need a standard projection matrix, in a known coordinate 00368 // system, to compute the perspective height. 00369 LMatrix4 height_projection; 00370 if (perspective) { 00371 height_projection = 00372 LMatrix4::convert_mat(CS_yup_right, lens->get_coordinate_system()) * 00373 projection; 00374 } 00375 00376 LMatrix4 render_transform = modelview * projection; 00377 LMatrix4 inv_render_transform; 00378 inv_render_transform.invert_from(render_transform); 00379 00380 // Now convert all of the vertices in the GeomVertexData to quads. 00381 // We always convert all the vertices, assuming all the vertices are 00382 // referenced by GeomPrimitives, because we want to optimize for the 00383 // most common case. 00384 int orig_verts = source_data->get_num_rows(); 00385 int new_verts = 4 * orig_verts; // each vertex becomes four. 00386 00387 PT(GeomVertexData) new_data = new GeomVertexData 00388 (source_data->get_name(), new_format, Geom::UH_stream); 00389 new_data->unclean_set_num_rows(new_verts); 00390 00391 GeomVertexWriter new_vertex(new_data, InternalName::get_vertex()); 00392 GeomVertexWriter new_normal(new_data, InternalName::get_normal()); 00393 GeomVertexWriter new_color(new_data, InternalName::get_color()); 00394 GeomVertexWriter new_texcoord(new_data, InternalName::get_texcoord()); 00395 00396 // We'll keep an array of all of the points' eye-space coordinates, 00397 // and their distance from the camera, so we can sort the points for 00398 // each primitive, below. 00399 PointData *points; 00400 { 00401 PStatTimer t2(_munge_sprites_verts_pcollector, current_thread); 00402 points = (PointData *)alloca(orig_verts * sizeof(PointData)); 00403 int vi = 0; 00404 while (!vertex.is_at_end()) { 00405 // Get the point in eye-space coordinates. 00406 LPoint3 eye = modelview.xform_point(vertex.get_data3()); 00407 points[vi]._eye = eye; 00408 points[vi]._dist = gsg->compute_distance_to(points[vi]._eye); 00409 00410 // The point in clip coordinates. 00411 LPoint4 p4 = LPoint4(eye[0], eye[1], eye[2], 1.0f) * projection; 00412 00413 if (has_size) { 00414 point_size = size.get_data1f(); 00415 } 00416 00417 PN_stdfloat scale_y = point_size; 00418 if (perspective) { 00419 // Perspective-sized points. Here point_size is the point's 00420 // height in 3-d units. To arrange that, we need to figure out 00421 // the appropriate scaling factor based on the current viewport 00422 // and projection matrix. 00423 PN_stdfloat scale = _modelview_transform->get_scale()[1]; 00424 LVector3 height(0.0f, point_size * scale, scale); 00425 height = height * height_projection; 00426 scale_y = height[1] * viewport_height; 00427 00428 // We should then divide the radius by the distance from the 00429 // camera plane, to emulate the glPointParameters() behavior. 00430 if (!lens->is_orthographic()) { 00431 scale_y /= gsg->compute_distance_to(eye); 00432 } 00433 } 00434 00435 // Also factor in the homogeneous scale for being in clip 00436 // coordinates still. 00437 scale_y *= p4[3]; 00438 00439 PN_stdfloat scale_x = scale_y; 00440 if (has_aspect_ratio) { 00441 scale_x *= aspect_ratio.get_data1f(); 00442 } 00443 00444 // Define the first two corners based on the scales in X and Y. 00445 LPoint2 c0(scale_x, scale_y); 00446 LPoint2 c1(-scale_x, scale_y); 00447 00448 if (has_rotate) { 00449 // If we have a rotate factor, apply it to those two corners. 00450 PN_stdfloat r = rotate.get_data1f(); 00451 LMatrix3 mat = LMatrix3::rotate_mat(r); 00452 c0 = c0 * mat; 00453 c1 = c1 * mat; 00454 } 00455 00456 // Finally, scale the corners in their newly-rotated position, 00457 // to compensate for the aspect ratio of the viewport. 00458 PN_stdfloat rx = 1.0f / viewport_width; 00459 PN_stdfloat ry = 1.0f / viewport_height; 00460 c0.set(c0[0] * rx, c0[1] * ry); 00461 c1.set(c1[0] * rx, c1[1] * ry); 00462 00463 if (retransform_sprites) { 00464 // With retransform_sprites in effect, we must reconvert the 00465 // resulting quad back into the original 3-D space. 00466 new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] + c0[0], p4[1] + c0[1], p4[2], p4[3]))); 00467 new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3]))); 00468 new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3]))); 00469 new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]))); 00470 00471 if (has_normal) { 00472 const LNormal &c = normal.get_data3(); 00473 new_normal.set_data3(c); 00474 new_normal.set_data3(c); 00475 new_normal.set_data3(c); 00476 new_normal.set_data3(c); 00477 } 00478 00479 } else { 00480 // Without retransform_sprites, we can simply load the 00481 // clip-space coordinates. 00482 new_vertex.set_data4(p4[0] + c0[0], p4[1] + c0[1], p4[2], p4[3]); 00483 new_vertex.set_data4(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3]); 00484 new_vertex.set_data4(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3]); 00485 new_vertex.set_data4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]); 00486 00487 if (has_normal) { 00488 LNormal c = render_transform.xform_vec(normal.get_data3()); 00489 new_normal.set_data3(c); 00490 new_normal.set_data3(c); 00491 new_normal.set_data3(c); 00492 new_normal.set_data3(c); 00493 } 00494 } 00495 if (has_color) { 00496 const LColor &c = color.get_data4(); 00497 new_color.set_data4(c); 00498 new_color.set_data4(c); 00499 new_color.set_data4(c); 00500 new_color.set_data4(c); 00501 } 00502 if (sprite_texcoord) { 00503 new_texcoord.set_data2(1.0f, 0.0f); 00504 new_texcoord.set_data2(0.0f, 0.0f); 00505 new_texcoord.set_data2(1.0f, 1.0f); 00506 new_texcoord.set_data2(0.0f, 1.0f); 00507 } else if (has_texcoord) { 00508 const LVecBase4 &c = texcoord.get_data4(); 00509 new_texcoord.set_data4(c); 00510 new_texcoord.set_data4(c); 00511 new_texcoord.set_data4(c); 00512 new_texcoord.set_data4(c); 00513 } 00514 00515 ++vi; 00516 } 00517 00518 nassertr(vi == orig_verts, false); 00519 nassertr(new_data->get_num_rows() == new_verts, false); 00520 } 00521 00522 PT(Geom) new_geom = new Geom(new_data); 00523 00524 // Create an appropriate GeomVertexArrayFormat for the primitive 00525 // index. 00526 static CPT(GeomVertexArrayFormat) new_prim_format; 00527 if (new_prim_format == (GeomVertexArrayFormat *)NULL) { 00528 new_prim_format = 00529 GeomVertexArrayFormat::register_format 00530 (new GeomVertexArrayFormat(InternalName::get_index(), 1, 00531 GeomEnums::NT_uint16, GeomEnums::C_index)); 00532 } 00533 00534 // Replace each primitive in the Geom (it's presumably a GeomPoints 00535 // primitive, although it might be some other kind of primitive if 00536 // we got here because RenderModeAttrib::M_point is enabled) with a 00537 // new primitive that replaces each vertex with a quad of the 00538 // appropriate scale and orientation. 00539 00540 // BUG: if we're rendering polygons in M_point mode with a 00541 // CullFaceAttrib in effect, we won't actually apply the 00542 // CullFaceAttrib but will always render all of the vertices of the 00543 // polygons. This is certainly a bug, but a very minor one; and in 00544 // order to fix it we'd have to do the face culling ourselves--not 00545 // sure if it's worth it. 00546 00547 { 00548 PStatTimer t3(_munge_sprites_prims_pcollector, current_thread); 00549 GeomPipelineReader geom_reader(_geom, current_thread); 00550 int num_primitives = geom_reader.get_num_primitives(); 00551 for (int pi = 0; pi < num_primitives; ++pi) { 00552 const GeomPrimitive *primitive = geom_reader.get_primitive(pi); 00553 if (primitive->get_num_vertices() != 0) { 00554 // Extract out the list of vertices referenced by the primitive. 00555 int num_vertices = primitive->get_num_vertices(); 00556 unsigned int *vertices = (unsigned int *)alloca(num_vertices * sizeof(unsigned int)); 00557 unsigned int *vertices_end = vertices + num_vertices; 00558 00559 if (primitive->is_indexed()) { 00560 // Indexed case. 00561 GeomVertexReader index(primitive->get_vertices(), 0, current_thread); 00562 for (unsigned int *vi = vertices; vi != vertices_end; ++vi) { 00563 unsigned int v = index.get_data1i(); 00564 nassertr(v < (unsigned int)orig_verts, false); 00565 (*vi) = v; 00566 } 00567 } else { 00568 // Nonindexed case. 00569 unsigned int first_vertex = primitive->get_first_vertex(); 00570 for (int i = 0; i < num_vertices; ++i) { 00571 unsigned int v = i + first_vertex; 00572 nassertr(v < (unsigned int)orig_verts, false); 00573 vertices[i] = v; 00574 } 00575 } 00576 00577 // Now sort the points in order from back-to-front so they will 00578 // render properly with transparency, at least with each other. 00579 sort(vertices, vertices_end, SortPoints(points)); 00580 00581 // Go through the points, now in sorted order, and generate a pair 00582 // of triangles for each one. We generate indexed triangles 00583 // instead of two-triangle strips, since this seems to be 00584 // generally faster on PC hardware (otherwise, we'd have to nearly 00585 // double the vertices to stitch all the little triangle strips 00586 // together). 00587 PT(GeomPrimitive) new_primitive = new GeomTriangles(Geom::UH_stream); 00588 int new_prim_verts = 6 * num_vertices; // two triangles per point. 00589 00590 PT(GeomVertexArrayData) new_index 00591 = new GeomVertexArrayData(new_prim_format, GeomEnums::UH_stream); 00592 new_index->unclean_set_num_rows(new_prim_verts); 00593 00594 GeomVertexWriter index(new_index, 0); 00595 nassertr(index.has_column(), false); 00596 for (unsigned int *vi = vertices; vi != vertices_end; ++vi) { 00597 int new_vi = (*vi) * 4; 00598 nassertr(index.get_write_row() + 6 <= new_prim_verts, false); 00599 index.set_data1i(new_vi); 00600 index.set_data1i(new_vi + 1); 00601 index.set_data1i(new_vi + 2); 00602 index.set_data1i(new_vi + 2); 00603 index.set_data1i(new_vi + 1); 00604 index.set_data1i(new_vi + 3); 00605 } 00606 new_primitive->set_vertices(new_index, new_prim_verts); 00607 00608 int min_vi = primitive->get_min_vertex(); 00609 int max_vi = primitive->get_max_vertex(); 00610 new_primitive->set_minmax(min_vi * 4, max_vi * 4 + 3, NULL, NULL); 00611 00612 new_geom->add_primitive(new_primitive); 00613 } 00614 } 00615 } 00616 00617 _geom = new_geom.p(); 00618 _munged_data = new_data; 00619 00620 return true; 00621 } 00622 00623 //////////////////////////////////////////////////////////////////// 00624 // Function: CullableObject::munge_texcoord_light_vector 00625 // Access: Private 00626 // Description: Generates the vector from each vertex to the 00627 // indicated light as a 3-d texture coordinate. 00628 // 00629 // This may replace _geom, _munged_data, and _state. 00630 //////////////////////////////////////////////////////////////////// 00631 bool CullableObject:: 00632 munge_texcoord_light_vector(const CullTraverser *traverser, bool force) { 00633 Thread *current_thread = traverser->get_current_thread(); 00634 PStatTimer timer(_munge_light_vector_pcollector, current_thread); 00635 00636 if (_net_transform->is_singular()) { 00637 // If we're under a singular transform, never mind. 00638 return true; 00639 } 00640 00641 if (!_munged_data->has_column(InternalName::get_vertex()) || 00642 !_munged_data->has_column(InternalName::get_normal())) { 00643 // No vertex or normal; can't compute light vector. 00644 return true; 00645 } 00646 00647 CPT(TexGenAttrib) tex_gen = DCAST(TexGenAttrib, _state->get_attrib(TexGenAttrib::get_class_slot())); 00648 nassertr(tex_gen != (TexGenAttrib *)NULL, false); 00649 00650 const TexGenAttrib::LightVectors &light_vectors = tex_gen->get_light_vectors(); 00651 TexGenAttrib::LightVectors::const_iterator lvi; 00652 for (lvi = light_vectors.begin(); 00653 lvi != light_vectors.end(); 00654 ++lvi) { 00655 TextureStage *stage = (*lvi); 00656 NodePath light = tex_gen->get_light(stage); 00657 if (light.is_empty()) { 00658 // If a particular light isn't specified in the TexGenAttrib, 00659 // use the most important light in the current state. 00660 CPT(RenderAttrib) attrib = _state->get_attrib(LightAttrib::get_class_slot()); 00661 if (attrib != (RenderAttrib *)NULL) { 00662 CPT(LightAttrib) la = DCAST(LightAttrib, attrib); 00663 light = la->get_most_important_light(); 00664 } 00665 } 00666 if (!light.is_empty()) { 00667 string source_name = tex_gen->get_source_name(stage); 00668 Light *light_obj = light.node()->as_light(); 00669 nassertr(light_obj != (Light *)NULL, false); 00670 00671 // Determine the names of the tangent and binormal columns 00672 // associated with the stage's texcoord name. 00673 PT(InternalName) tangent_name = InternalName::get_tangent_name(source_name); 00674 PT(InternalName) binormal_name = InternalName::get_binormal_name(source_name); 00675 00676 PT(InternalName) texcoord_name = stage->get_texcoord_name(); 00677 00678 if (_munged_data->has_column(tangent_name) && 00679 _munged_data->has_column(binormal_name)) { 00680 00681 if (!force && !_munged_data->request_resident()) { 00682 // The data isn't resident; give up. 00683 return false; 00684 } 00685 00686 // Create a new column for the new texcoords. 00687 PT(GeomVertexData) new_data = _munged_data->replace_column 00688 (texcoord_name, 3, Geom::NT_stdfloat, Geom::C_texcoord); 00689 _munged_data = new_data; 00690 00691 // Remove this TexGen stage from the state, since we're handling 00692 // it now. 00693 _state = _state->add_attrib(tex_gen->remove_stage(stage)); 00694 00695 // Get the transform from the light to the object. 00696 CPT(TransformState) light_transform = 00697 _net_transform->invert_compose(light.get_net_transform()); 00698 const LMatrix4 &light_mat = light_transform->get_mat(); 00699 00700 GeomVertexWriter texcoord(new_data, texcoord_name, current_thread); 00701 GeomVertexReader vertex(new_data, InternalName::get_vertex(), 00702 current_thread); 00703 GeomVertexReader tangent(new_data, tangent_name, current_thread); 00704 GeomVertexReader binormal(new_data, binormal_name, current_thread); 00705 GeomVertexReader normal(new_data, InternalName::get_normal(), 00706 current_thread); 00707 00708 while (!vertex.is_at_end()) { 00709 LPoint3 p = vertex.get_data3(); 00710 LVector3 t = tangent.get_data3(); 00711 LVector3 b = binormal.get_data3(); 00712 LVector3 n = normal.get_data3(); 00713 00714 LVector3 lv; 00715 if (light_obj->get_vector_to_light(lv, p, light_mat)) { 00716 texcoord.add_data3(lv.dot(t), lv.dot(b), lv.dot(n)); 00717 } 00718 } 00719 } 00720 } 00721 } 00722 00723 return true; 00724 } 00725 00726 //////////////////////////////////////////////////////////////////// 00727 // Function: CullableObject::get_flash_cpu_state 00728 // Access: Private, Static 00729 // Description: Returns a RenderState for flashing the object red, to 00730 // show it is animated by the CPU when 00731 // show-vertex-animation is on. 00732 //////////////////////////////////////////////////////////////////// 00733 CPT(RenderState) CullableObject:: 00734 get_flash_cpu_state() { 00735 static const LColor flash_cpu_color(0.8f, 0.2, 0.2, 1.0f); 00736 00737 // Once someone asks for this pointer, we hold its reference count 00738 // and never free it. 00739 static CPT(RenderState) flash_cpu_state = (const RenderState *)NULL; 00740 if (flash_cpu_state == (const RenderState *)NULL) { 00741 flash_cpu_state = RenderState::make 00742 (LightAttrib::make_all_off(), 00743 TextureAttrib::make_off(), 00744 ColorAttrib::make_flat(flash_cpu_color)); 00745 } 00746 00747 return flash_cpu_state; 00748 } 00749 00750 //////////////////////////////////////////////////////////////////// 00751 // Function: CullableObject::get_flash_hardware_state 00752 // Access: Private, Static 00753 // Description: Returns a RenderState for flashing the object blue, 00754 // to show it is animated by the hardware when 00755 // show-vertex-animation is on. 00756 //////////////////////////////////////////////////////////////////// 00757 CPT(RenderState) CullableObject:: 00758 get_flash_hardware_state() { 00759 static const LColor flash_hardware_color(0.2, 0.2, 0.8, 1.0); 00760 00761 // Once someone asks for this pointer, we hold its reference count 00762 // and never free it. 00763 static CPT(RenderState) flash_hardware_state = (const RenderState *)NULL; 00764 if (flash_hardware_state == (const RenderState *)NULL) { 00765 flash_hardware_state = RenderState::make 00766 (LightAttrib::make_all_off(), 00767 TextureAttrib::make_off(), 00768 ColorAttrib::make_flat(flash_hardware_color)); 00769 } 00770 00771 return flash_hardware_state; 00772 } 00773 00774 //////////////////////////////////////////////////////////////////// 00775 // Function: CullableObject::draw_fancy 00776 // Access: Private 00777 // Description: Something fancy about this object. Draw it properly. 00778 //////////////////////////////////////////////////////////////////// 00779 void CullableObject:: 00780 draw_fancy(GraphicsStateGuardianBase *gsg, bool force, 00781 Thread *current_thread) { 00782 nassertv(_fancy); 00783 if (_draw_callback != (CallbackObject *)NULL) { 00784 // It has a callback associated. 00785 gsg->clear_before_callback(); 00786 gsg->set_state_and_transform(_state, _internal_transform); 00787 GeomDrawCallbackData cbdata(this, gsg, force); 00788 _draw_callback->do_callback(&cbdata); 00789 if (cbdata.get_lost_state()) { 00790 // Tell the GSG to forget its state. 00791 gsg->clear_state_and_transform(); 00792 } 00793 // Now the callback has taken care of drawing. 00794 00795 } else if (_next != (CullableObject *)NULL) { 00796 // It has decals. 00797 draw_with_decals(gsg, force, current_thread); 00798 00799 } else { 00800 // Huh, nothing fancy after all. Somehow the _fancy flag got set 00801 // incorrectly; that's a bug. 00802 gsg->set_state_and_transform(_state, _internal_transform); 00803 draw_inline(gsg, force, current_thread); 00804 nassertv(false); 00805 } 00806 } 00807 00808 //////////////////////////////////////////////////////////////////// 00809 // Function: CullableObject::draw_with_decals 00810 // Access: Private 00811 // Description: Draws the current CullableObject, assuming it has 00812 // attached decals. 00813 //////////////////////////////////////////////////////////////////// 00814 void CullableObject:: 00815 draw_with_decals(GraphicsStateGuardianBase *gsg, bool force, 00816 Thread *current_thread) { 00817 nassertv(_fancy && _next != (CullableObject *)NULL); 00818 // We draw with a three-step process. 00819 00820 // First, render all of the base geometry for the first pass. 00821 CPT(RenderState) state = gsg->begin_decal_base_first(); 00822 00823 CullableObject *base = this; 00824 while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) { 00825 gsg->set_state_and_transform(base->_state->compose(state), base->_internal_transform); 00826 base->draw_inline(gsg, force, current_thread); 00827 00828 base = base->_next; 00829 } 00830 00831 if (base != (CullableObject *)NULL) { 00832 // Now, draw all the decals. 00833 state = gsg->begin_decal_nested(); 00834 00835 CullableObject *decal = base->_next; 00836 while (decal != (CullableObject *)NULL) { 00837 gsg->set_state_and_transform(decal->_state->compose(state), decal->_internal_transform); 00838 decal->draw_inline(gsg, force, current_thread); 00839 decal = decal->_next; 00840 } 00841 } 00842 00843 // And now, re-draw the base geometry, if required. 00844 state = gsg->begin_decal_base_second(); 00845 if (state != (const RenderState *)NULL) { 00846 base = this; 00847 while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) { 00848 gsg->set_state_and_transform(base->_state->compose(state), base->_internal_transform); 00849 base->draw_inline(gsg, force, current_thread); 00850 00851 base = base->_next; 00852 } 00853 } 00854 } 00855 00856 //////////////////////////////////////////////////////////////////// 00857 // Function: CullableObject::SourceFormat::Constructor 00858 // Access: Public 00859 // Description: 00860 //////////////////////////////////////////////////////////////////// 00861 CullableObject::SourceFormat:: 00862 SourceFormat(const GeomVertexFormat *format, bool sprite_texcoord) : 00863 _format(format), 00864 _sprite_texcoord(sprite_texcoord) 00865 { 00866 _retransform_sprites = retransform_sprites; 00867 }