diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 597a015ad8..ee5966f20e 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -895,11 +895,12 @@ finish_decal() { // are ok, false to abort this group of primitives. //////////////////////////////////////////////////////////////////// bool GraphicsStateGuardian:: -begin_draw_primitives(const Geom *, const GeomMunger *munger, +begin_draw_primitives(const Geom *geom, const GeomMunger *munger, const GeomVertexData *data) { _munger = munger; _vertex_data = data; + nassertr(geom->check_valid(data), false); return _vertex_data->has_vertex(); } diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 9338d1c17a..ca7b4691e7 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -593,7 +593,7 @@ get_num_bytes() const { //////////////////////////////////////////////////////////////////// // Function: Geom::transform_vertices -// Access: Published, Virtual +// Access: Published // Description: Applies the indicated transform to all of the // vertices in the Geom. If the Geom happens to share a // vertex table with another Geom, this operation will @@ -652,6 +652,30 @@ check_valid() const { return true; } +//////////////////////////////////////////////////////////////////// +// Function: Geom::check_valid +// Access: Published +// Description: Verifies that the all of the primitives within the +// geom reference vertices that actually exist within +// the indicated GeomVertexData. Returns true if the +// geom appears to be valid, false otherwise. +//////////////////////////////////////////////////////////////////// +bool Geom:: +check_valid(const GeomVertexData *vertex_data) const { + CDReader cdata(_cycler); + + Primitives::const_iterator pi; + for (pi = cdata->_primitives.begin(); + pi != cdata->_primitives.end(); + ++pi) { + if (!(*pi)->check_valid(vertex_data)) { + return false; + } + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: Geom::output // Access: Published, Virtual diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index cef8bf8afe..3476798fab 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -96,11 +96,9 @@ PUBLISHED: int get_num_bytes() const; INLINE UpdateSeq get_modified() const; - // Temporarily virtual. virtual void transform_vertices(const LMatrix4f &mat); - - // Temporarily virtual. virtual bool check_valid() const; + bool check_valid(const GeomVertexData *vertex_data) const; virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level = 0) const; diff --git a/panda/src/particlesystem/spriteParticleRenderer.cxx b/panda/src/particlesystem/spriteParticleRenderer.cxx index b17d7a6e76..d8177f88c9 100644 --- a/panda/src/particlesystem/spriteParticleRenderer.cxx +++ b/panda/src/particlesystem/spriteParticleRenderer.cxx @@ -530,6 +530,8 @@ init_geoms() { } } } + + nassertv(render_node->check_valid()); } //////////////////////////////////////////////////////////////////// @@ -726,9 +728,21 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) { } } + int n = 0; + GeomNode *render_node = get_render_node(); + for (i = 0; i < anim_count; ++i) { for (j = 0; j < _anim_size[i]; ++j) { _sprites[i][j]->clear_vertices(); + + // We have to reassign the GeomVertexData and GeomPrimitive to + // the Geom, and the Geom to the GeomNode, in case it got + // flattened away. + _sprite_primitive[i][j]->set_primitive(0, _sprites[i][j]); + _sprite_primitive[i][j]->set_vertex_data(_vdata[i][j]); + + render_node->set_geom(n, _sprite_primitive[i][j]); + ++n; } } @@ -750,11 +764,13 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) { for (i = 0; i < anim_count; ++i) { for (j = 0; j < _anim_size[i]; ++j) { + nassertv(_sprite_primitive[i][j]->check_valid()); _sprite_primitive[i][j]->set_bound(BoundingSphere(aabb_center, radius)); } } get_render_node()->mark_bound_stale(); + nassertv(render_node->check_valid()); _animation_removed = false; } diff --git a/panda/src/pgraph/cullableObject.cxx b/panda/src/pgraph/cullableObject.cxx index 60065cd67f..af9c8552f2 100644 --- a/panda/src/pgraph/cullableObject.cxx +++ b/panda/src/pgraph/cullableObject.cxx @@ -54,6 +54,7 @@ munge_geom(GraphicsStateGuardianBase *gsg, if (_geom != (Geom *)NULL) { _munger = munger; _munged_data = _geom->get_vertex_data(); + nassertv(_geom->check_valid(_munged_data)); int geom_rendering = _geom->get_geom_rendering(); geom_rendering = _state->get_geom_rendering(geom_rendering); @@ -305,159 +306,161 @@ munge_points_to_quads(const CullTraverser *traverser) { int num_primitives = _geom->get_num_primitives(); for (int pi = 0; pi < num_primitives; ++pi) { const GeomPrimitive *primitive = _geom->get_primitive(pi); + if (primitive->get_num_vertices() != 0) { + // We must first convert all of the points to eye space. + int num_points = primitive->get_max_vertex() + 1; - // We must first convert all of the points to eye space. - int num_points = primitive->get_max_vertex() + 1; - int num_vertices = primitive->get_num_vertices(); - PointData *points = (PointData *)alloca(num_points * sizeof(PointData)); - unsigned int *vertices = (unsigned int *)alloca(num_vertices * sizeof(unsigned int)); - unsigned int *vertices_end = vertices + num_vertices; + int num_vertices = primitive->get_num_vertices(); + PointData *points = (PointData *)alloca(num_points * sizeof(PointData)); + unsigned int *vertices = (unsigned int *)alloca(num_vertices * sizeof(unsigned int)); + unsigned int *vertices_end = vertices + num_vertices; + + if (primitive->is_indexed()) { + GeomVertexReader index(primitive->get_vertices(), 0); + for (unsigned int *vi = vertices; vi != vertices_end; ++vi) { + // Get the point in eye-space coordinates. + unsigned int v = index.get_data1i(); + nassertv(v < (unsigned int)num_points); + (*vi) = v; + vertex.set_row(v); + points[v]._eye = modelview.xform_point(vertex.get_data3f()); + points[v]._dist = gsg->compute_distance_to(points[v]._eye); + } + } else { + // Nonindexed case. + unsigned int first_vertex = primitive->get_first_vertex(); + for (int i = 0; i < num_vertices; ++i) { + unsigned int v = i + first_vertex; + nassertv(v < (unsigned int)num_points); + vertices[i] = v; + vertex.set_row(v); + points[v]._eye = modelview.xform_point(vertex.get_data3f()); + points[v]._dist = gsg->compute_distance_to(points[v]._eye); + } + } + + // Now sort the points in order from back-to-front so they will + // render properly with transparency, at least with each other. + sort(vertices, vertices_end, SortPoints(points)); + + // Go through the points, now in sorted order, and generate a pair + // of triangles for each one. We generate indexed triangles + // instead of two-triangle strips, since this seems to be + // generally faster on PC hardware (otherwise, we'd have to nearly + // double the vertices to stitch all the little triangle strips + // together). + PT(GeomPrimitive) new_primitive = new GeomTriangles(Geom::UH_client); - if (primitive->is_indexed()) { - GeomVertexReader index(primitive->get_vertices(), 0); for (unsigned int *vi = vertices; vi != vertices_end; ++vi) { - // Get the point in eye-space coordinates. - unsigned int v = index.get_data1i(); - nassertv(v < (unsigned int)num_points); - (*vi) = v; - vertex.set_row(v); - points[v]._eye = modelview.xform_point(vertex.get_data3f()); - points[v]._dist = gsg->compute_distance_to(points[v]._eye); - } - } else { - // Nonindexed case. - unsigned int first_vertex = primitive->get_first_vertex(); - for (int i = 0; i < num_vertices; ++i) { - unsigned int v = i + first_vertex; - nassertv(v < (unsigned int)num_points); - vertices[i] = v; - vertex.set_row(i + first_vertex); - points[v]._eye = modelview.xform_point(vertex.get_data3f()); - points[v]._dist = gsg->compute_distance_to(points[v]._eye); - } - } - - // Now sort the points in order from back-to-front so they will - // render properly with transparency, at least with each other. - sort(vertices, vertices_end, SortPoints(points)); - - // Go through the points, now in sorted order, and generate a pair - // of triangles for each one. We generate indexed triangles - // instead of two-triangle strips, since this seems to be - // generally faster on PC hardware (otherwise, we'd have to nearly - // double the vertices to stitch all the little triangle strips - // together). - PT(GeomPrimitive) new_primitive = new GeomTriangles(Geom::UH_client); - - for (unsigned int *vi = vertices; vi != vertices_end; ++vi) { - // The point in eye coordinates. - const LPoint3f &eye = points[*vi]._eye; + // The point in eye coordinates. + const LPoint3f &eye = points[*vi]._eye; - // The point in clip coordinates. - LPoint4f p4 = LPoint4f(eye[0], eye[1], eye[2], 1.0f) * projection; + // The point in clip coordinates. + LPoint4f p4 = LPoint4f(eye[0], eye[1], eye[2], 1.0f) * projection; - if (has_size) { - size.set_row(*vi); - point_size = size.get_data1f(); - } + if (has_size) { + size.set_row(*vi); + point_size = size.get_data1f(); + } - float scale_y = point_size; - if (perspective) { - // Perspective-sized points. Here point_size is the point's - // height in 3-d units. To arrange that, we need to figure - // out the appropriate scaling factor based on the current - // viewport and projection matrix. - float scale = _modelview_transform->get_scale()[1]; - LVector3f height(0.0f, point_size * scale, scale); - height = height * height_projection; - scale_y = height[1] * viewport_height; + float scale_y = point_size; + if (perspective) { + // Perspective-sized points. Here point_size is the point's + // height in 3-d units. To arrange that, we need to figure + // out the appropriate scaling factor based on the current + // viewport and projection matrix. + float scale = _modelview_transform->get_scale()[1]; + LVector3f height(0.0f, point_size * scale, scale); + height = height * height_projection; + scale_y = height[1] * viewport_height; - // We should then divide the radius by the distance from the - // camera plane, to emulate the glPointParameters() behavior. - if (!lens->is_orthographic()) { - scale_y /= gsg->compute_distance_to(eye); - } - } + // We should then divide the radius by the distance from the + // camera plane, to emulate the glPointParameters() behavior. + if (!lens->is_orthographic()) { + scale_y /= gsg->compute_distance_to(eye); + } + } - // Also factor in the homogeneous scale for being in clip - // coordinates still. - scale_y *= p4[3]; + // Also factor in the homogeneous scale for being in clip + // coordinates still. + scale_y *= p4[3]; - float scale_x = scale_y; - if (has_aspect_ratio) { - aspect_ratio.set_row(*vi); - scale_x *= aspect_ratio.get_data1f(); + float scale_x = scale_y; + if (has_aspect_ratio) { + aspect_ratio.set_row(*vi); + scale_x *= aspect_ratio.get_data1f(); + } + + // Define the first two corners based on the scales in X and Y. + LPoint2f c0(scale_x, scale_y); + LPoint2f c1(-scale_x, scale_y); + + if (has_rotate) { + // If we have a rotate factor, apply it to those two corners. + rotate.set_row(*vi); + float r = rotate.get_data1f(); + LMatrix3f mat = LMatrix3f::rotate_mat(r); + c0 = c0 * mat; + c1 = c1 * mat; + } + + // Finally, scale the corners in their newly-rotated position, + // to compensate for the aspect ratio of the viewport. + float rx = 1.0f / viewport_width; + float ry = 1.0f / viewport_height; + c0.set(c0[0] * rx, c0[1] * ry); + c1.set(c1[0] * rx, c1[1] * ry); + + new_vertex.add_data4f(p4[0] + c0[0], p4[1] + c0[1], p4[2], p4[3]); + new_vertex.add_data4f(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3]); + new_vertex.add_data4f(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3]); + new_vertex.add_data4f(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]); + + if (has_normal) { + normal.set_row(*vi); + Normalf c = render_transform.xform_vec(normal.get_data3f()); + new_normal.add_data3f(c); + new_normal.add_data3f(c); + new_normal.add_data3f(c); + new_normal.add_data3f(c); + } + if (has_color) { + color.set_row(*vi); + const Colorf &c = color.get_data4f(); + new_color.add_data4f(c); + new_color.add_data4f(c); + new_color.add_data4f(c); + new_color.add_data4f(c); + } + if (sprite_texcoord) { + new_texcoord.add_data2f(1.0f, 0.0f); + new_texcoord.add_data2f(0.0f, 0.0f); + new_texcoord.add_data2f(1.0f, 1.0f); + new_texcoord.add_data2f(0.0f, 1.0f); + } else if (has_texcoord) { + texcoord.set_row(*vi); + const LVecBase4f &c = texcoord.get_data4f(); + new_texcoord.add_data4f(c); + new_texcoord.add_data4f(c); + new_texcoord.add_data4f(c); + new_texcoord.add_data4f(c); + } + + new_primitive->add_vertex(new_vi); + new_primitive->add_vertex(new_vi + 1); + new_primitive->add_vertex(new_vi + 2); + new_primitive->close_primitive(); + + new_primitive->add_vertex(new_vi + 2); + new_primitive->add_vertex(new_vi + 1); + new_primitive->add_vertex(new_vi + 3); + new_primitive->close_primitive(); + + new_vi += 4; } - // Define the first two corners based on the scales in X and Y. - LPoint2f c0(scale_x, scale_y); - LPoint2f c1(-scale_x, scale_y); - - if (has_rotate) { - // If we have a rotate factor, apply it to those two corners. - rotate.set_row(*vi); - float r = rotate.get_data1f(); - LMatrix3f mat = LMatrix3f::rotate_mat(r); - c0 = c0 * mat; - c1 = c1 * mat; - } - - // Finally, scale the corners in their newly-rotated position, - // to compensate for the aspect ratio of the viewport. - float rx = 1.0f / viewport_width; - float ry = 1.0f / viewport_height; - c0.set(c0[0] * rx, c0[1] * ry); - c1.set(c1[0] * rx, c1[1] * ry); - - new_vertex.add_data4f(p4[0] + c0[0], p4[1] + c0[1], p4[2], p4[3]); - new_vertex.add_data4f(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3]); - new_vertex.add_data4f(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3]); - new_vertex.add_data4f(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]); - - if (has_normal) { - normal.set_row(*vi); - Normalf c = render_transform.xform_vec(normal.get_data3f()); - new_normal.add_data3f(c); - new_normal.add_data3f(c); - new_normal.add_data3f(c); - new_normal.add_data3f(c); - } - if (has_color) { - color.set_row(*vi); - const Colorf &c = color.get_data4f(); - new_color.add_data4f(c); - new_color.add_data4f(c); - new_color.add_data4f(c); - new_color.add_data4f(c); - } - if (sprite_texcoord) { - new_texcoord.add_data2f(1.0f, 0.0f); - new_texcoord.add_data2f(0.0f, 0.0f); - new_texcoord.add_data2f(1.0f, 1.0f); - new_texcoord.add_data2f(0.0f, 1.0f); - } else if (has_texcoord) { - texcoord.set_row(*vi); - const LVecBase4f &c = texcoord.get_data4f(); - new_texcoord.add_data4f(c); - new_texcoord.add_data4f(c); - new_texcoord.add_data4f(c); - new_texcoord.add_data4f(c); - } - - new_primitive->add_vertex(new_vi); - new_primitive->add_vertex(new_vi + 1); - new_primitive->add_vertex(new_vi + 2); - new_primitive->close_primitive(); - - new_primitive->add_vertex(new_vi + 2); - new_primitive->add_vertex(new_vi + 1); - new_primitive->add_vertex(new_vi + 3); - new_primitive->close_primitive(); - - new_vi += 4; + new_geom->add_primitive(new_primitive); } - - new_geom->add_primitive(new_primitive); } _geom = new_geom.p(); diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index af3b352227..3917b92395 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -420,6 +420,45 @@ add_geoms_from(const GeomNode *other) { } } +//////////////////////////////////////////////////////////////////// +// Function: GeomNode::set_geom +// Access: Public +// Description: Replaces the nth Geom of the node with a new pointer. +// There must already be a Geom in this slot. +//////////////////////////////////////////////////////////////////// +void GeomNode:: +set_geom(int n, Geom *geom) { + nassertv(geom != (Geom *)NULL); + nassertv(geom->check_valid()); + + CDWriter cdata(_cycler); + nassertv(n >= 0 && n < (int)cdata->_geoms.size()); + cdata->_geoms[n]._geom = geom; + + mark_bound_stale(); +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomNode::check_valid +// Access: Published +// Description: Verifies that the each Geom within the GeomNode +// reference vertices that actually exist within its +// GeomVertexData. Returns true if the GeomNode appears +// to be valid, false otherwise. +//////////////////////////////////////////////////////////////////// +bool GeomNode:: +check_valid() const { + int num_geoms = get_num_geoms(); + for (int i = 0; i < num_geoms; i++) { + const Geom *geom = get_geom(i); + if (!geom->check_valid()) { + return false; + } + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: GeomNode::unify // Access: Published diff --git a/panda/src/pgraph/geomNode.h b/panda/src/pgraph/geomNode.h index 490bd214e7..843618560d 100644 --- a/panda/src/pgraph/geomNode.h +++ b/panda/src/pgraph/geomNode.h @@ -65,8 +65,10 @@ PUBLISHED: int add_geom(Geom *geom, const RenderState *state = RenderState::make_empty()); void add_geoms_from(const GeomNode *other); + void set_geom(int n, Geom *geom); INLINE void remove_geom(int n); INLINE void remove_all_geoms(); + bool check_valid() const; void unify();