nuclear@28: #include nuclear@28: #include nuclear@28: #include nuclear@28: #include "mingl.h" nuclear@28: #include "mglimpl.h" nuclear@28: nuclear@28: static struct state *st; nuclear@28: nuclear@28: static float distance_signed(vec3_t p, const struct plane *plane); nuclear@28: static int intersect(const ray3_t *ray, const struct plane *plane, float *t); nuclear@28: static int clip_polygon(struct vertex *vout, int *voutnum, const struct vertex *vin, int vnum, nuclear@28: const struct plane *plane); nuclear@28: nuclear@28: #define ZNEAR MAX_CLIP_PLANES nuclear@28: nuclear@28: int mgl_clip_init(struct state *state) nuclear@28: { nuclear@28: st = state; nuclear@28: nuclear@28: memset(st->clip_planes, 0, sizeof st->clip_planes); nuclear@28: nuclear@28: /* always setup a near clipping plane */ nuclear@28: st->clip_planes[ZNEAR].normal.x = st->clip_planes[ZNEAR].normal.y = 0; nuclear@28: st->clip_planes[ZNEAR].normal.z = -1; nuclear@28: st->clip_planes[ZNEAR].pt.x = st->clip_planes[ZNEAR].pt.y = 0; nuclear@28: st->clip_planes[ZNEAR].pt.z = -0.5; nuclear@28: nuclear@28: return 0; nuclear@28: } nuclear@28: nuclear@28: int mgl_clip_poly(struct vertex *v, int vnum) nuclear@28: { nuclear@28: int i, res, clipped_vnum; nuclear@28: struct vertex tmp[6]; nuclear@28: nuclear@28: for(i=0; iclip_planes + i); nuclear@28: if(res == -1) { nuclear@28: /* the polygon was completely outside */ nuclear@28: return 0; nuclear@28: } nuclear@28: if(res == 0) { nuclear@28: /* the polygon was clipped, update v and vnum */ nuclear@28: vnum = clipped_vnum; nuclear@28: memcpy(v, tmp, clipped_vnum * sizeof *v); nuclear@28: } nuclear@28: /* otherwise the polygon was completely inside, nothing to do... */ nuclear@28: } nuclear@28: nuclear@28: return vnum; nuclear@28: } nuclear@28: nuclear@28: static float distance_signed(vec3_t p, const struct plane *plane) nuclear@28: { nuclear@28: vec3_t ptdir; nuclear@28: ptdir.x = p.x - plane->pt.x; nuclear@28: ptdir.y = p.y - plane->pt.y; nuclear@28: ptdir.z = p.z - plane->pt.z; nuclear@28: nuclear@28: return vec3_dot(ptdir, plane->normal); nuclear@28: } nuclear@28: nuclear@28: static int intersect(const ray3_t *ray, const struct plane *plane, float *t) nuclear@28: { nuclear@28: vec3_t orig_pt_dir; nuclear@28: nuclear@28: float ndotdir = vec3_dot(plane->normal, ray->dir); nuclear@28: if(fabs(ndotdir) < 1e-4) { nuclear@28: *t = 0.0f; nuclear@28: return 0; nuclear@28: } nuclear@28: nuclear@28: orig_pt_dir.x = plane->pt.x - ray->origin.x; nuclear@28: orig_pt_dir.y = plane->pt.y - ray->origin.y; nuclear@28: orig_pt_dir.z = plane->pt.z - ray->origin.z; nuclear@28: nuclear@28: *t = vec3_dot(plane->normal, orig_pt_dir) / ndotdir; nuclear@28: return 1; nuclear@28: } nuclear@28: nuclear@28: static int clip_edge(struct vertex *poly, int *vnum, const struct vertex *v0, nuclear@28: const struct vertex *v1, const struct plane *plane); nuclear@28: nuclear@28: /* returns: nuclear@28: * 1 -> both inside nuclear@28: * 0 -> straddling and clipped nuclear@28: * -1 -> both outside nuclear@28: * nuclear@28: * the size of the vout polygon is returned throug voutnum nuclear@28: */ nuclear@28: static int clip_polygon(struct vertex *vout, int *voutnum, const struct vertex *vin, int vnum, nuclear@28: const struct plane *plane) nuclear@28: { nuclear@28: int i; nuclear@28: int edges_clipped = 0; nuclear@28: int out_vnum = 0; nuclear@28: nuclear@28: for(i=0; i 0 ? 0 : 1; nuclear@28: } nuclear@28: nuclear@28: /* returns: nuclear@28: * 1 -> both inside nuclear@28: * 0 -> straddling and clipped nuclear@28: * -1 -> both outside nuclear@28: * nuclear@28: * also returns the size of the polygon through vnumptr nuclear@28: */ nuclear@28: static int clip_edge(struct vertex *poly, int *vnumptr, const struct vertex *v0, nuclear@28: const struct vertex *v1, const struct plane *plane) nuclear@28: { nuclear@28: vec3_t pos0, pos1; nuclear@28: float d0, d1, t; nuclear@28: ray3_t ray; nuclear@28: int vnum = *vnumptr; nuclear@28: nuclear@28: pos0.x = v0->pos.x; pos0.y = v0->pos.y; pos0.z = v0->pos.z; nuclear@28: pos1.x = v1->pos.x; pos1.y = v1->pos.y; pos1.z = v1->pos.z; nuclear@28: nuclear@28: d0 = distance_signed(pos0, plane); nuclear@28: d1 = distance_signed(pos1, plane); nuclear@28: nuclear@28: ray.origin = pos0; nuclear@28: ray.dir.x = pos1.x - pos0.x; nuclear@28: ray.dir.y = pos1.y - pos0.y; nuclear@28: ray.dir.z = pos1.z - pos0.z; nuclear@28: nuclear@28: if(d0 >= 0.0) { nuclear@28: /* start inside */ nuclear@28: if(d1 >= 0.0) { nuclear@28: /* all inside */ nuclear@28: poly[vnum++] = *v1; /* append v1 */ nuclear@28: *vnumptr = vnum; nuclear@28: return 1; nuclear@28: } else { nuclear@28: /* going out */ nuclear@28: intersect(&ray, plane, &t); nuclear@28: nuclear@28: ray3_point(poly[vnum].pos, ray, t); nuclear@28: poly[vnum].pos.w = 1.0; nuclear@28: nuclear@28: vec3_lerp(poly[vnum].norm, v0->norm, v1->norm, t); nuclear@28: vec2_lerp(poly[vnum].tc, v0->tc, v1->tc, t); nuclear@28: poly[vnum].energy = v0->energy + (v1->energy - v0->energy) * t; nuclear@28: poly[vnum].cidx = v0->cidx; nuclear@28: vnum++; /* append new vertex on the intersection point */ nuclear@28: } nuclear@28: } else { nuclear@28: /* start outside */ nuclear@28: if(d1 >= 0) { nuclear@28: /* going in */ nuclear@28: intersect(&ray, plane, &t); nuclear@28: nuclear@28: ray3_point(poly[vnum].pos, ray, t); nuclear@28: poly[vnum].pos.w = 1.0; nuclear@28: nuclear@28: vec3_lerp(poly[vnum].norm, v0->norm, v1->norm, t); nuclear@28: vec2_lerp(poly[vnum].tc, v0->tc, v1->tc, t); nuclear@28: poly[vnum].energy = v0->energy + (v1->energy - v0->energy) * t; nuclear@28: poly[vnum].cidx = v0->cidx; nuclear@28: vnum++; /* append new vertex on the intersection point */ nuclear@28: nuclear@28: /* then append v1 ... */ nuclear@28: poly[vnum++] = *v1; nuclear@28: } else { nuclear@28: /* all outside */ nuclear@28: return -1; nuclear@28: } nuclear@28: } nuclear@28: nuclear@28: *vnumptr = vnum; nuclear@28: return 0; nuclear@28: }