prevent crash when sprite particle renderer is flattened accidentally

This commit is contained in:
Jason Yeung 2005-10-25 00:01:49 +00:00
parent 3e66211e38
commit 168d499af6
7 changed files with 229 additions and 146 deletions

View File

@ -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();
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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();