Panda3D
 All Classes Functions Variables Enumerations
cullableObject.cxx
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 }
 All Classes Functions Variables Enumerations