6 float plane_dist(const struct plane *p, const cgm_vec3 *pt)
8 return fabs(plane_sdist(p, pt));
11 float plane_sdist(const struct plane *p, const cgm_vec3 *pt)
15 return cgm_vdot(&v, &p->norm);
18 void midplane(struct plane *p, const cgm_vec3 *a, const cgm_vec3 *b)
21 cgm_vsub(&p->norm, a);
22 cgm_vnormalize(&p->norm);
23 p->pt.x = a->x + p->norm.x * 0.5f;
24 p->pt.y = a->y + p->norm.y * 0.5f;
25 p->pt.z = a->z + p->norm.z * 0.5f;
28 void poly_normal(const struct poly *poly, cgm_vec3 *n)
32 va = poly->verts[1].pos;
33 cgm_vsub(&va, &poly->verts[0].pos);
34 vb = poly->verts[2].pos;
35 cgm_vsub(&vb, &poly->verts[0].pos);
37 cgm_vcross(n, &va, &vb);
41 void poly_plane(const struct poly *poly, struct plane *plane)
43 plane->pt = poly->verts[0].pos;
44 poly_normal(poly, &plane->norm);
47 int plane_poly(const struct plane *plane, struct poly *poly, float size)
49 static const float corn[][2] = {{1,1}, {-1,1}, {-1,-1}, {1, -1}};
55 if(!(poly->verts = dynarr_alloc(4, sizeof *poly->verts))) {
56 fprintf(stderr, "plane_poly: failed to allocate polygon vertices\n");
60 cgm_vcons(&up, 0, 1, 0);
61 if(1.0f - fabs(cgm_vdot(&up, &plane->norm)) < 1e-2) {
62 cgm_vcons(&up, 0, 0, -1);
64 cgm_vcross(&right, &up, &plane->norm);
65 cgm_vnormalize(&right);
66 cgm_vcross(&up, &plane->norm, &right);
71 vptr->pos.x = plane->pt.x + (right.x * corn[i][0] + up.x * corn[i][1]) * size;
72 vptr->pos.y = plane->pt.y + (right.y * corn[i][0] + up.y * corn[i][1]) * size;
73 vptr->pos.z = plane->pt.z + (right.z * corn[i][0] + up.z * corn[i][1]) * size;
75 vptr->norm = plane->norm;
76 vptr->uv.x = vptr->uv.y = 0;
82 float ray_plane(const cgm_ray *ray, const struct plane *plane)
87 ndotdir = cgm_vdot(&plane->norm, &ray->dir);
88 if(fabs(ndotdir) < 1e-4) {
93 cgm_vsub(&pptdir, &ray->origin);
94 t = cgm_vdot(&plane->norm, &pptdir) / ndotdir;
101 float ray_poly(const cgm_ray *ray, const struct poly *poly)
105 cgm_vec3 hitp, vdir, edir, indir, vcross, incross;
108 poly_plane(poly, &plane);
109 if((t = ray_plane(ray, &plane)) < 0.0f) {
112 cgm_raypos(&hitp, ray, t);
114 /* see if the point is inside or outside the polygon */
115 nverts = dynarr_size(poly->verts);
116 for(i=0; i<nverts; i++) {
118 cgm_vsub(&hitp, &poly->verts[i].pos);
119 edir = poly->verts[(i + 1) & nverts].pos;
120 cgm_vsub(&edir, &poly->verts[i].pos);
121 indir = poly->verts[(i + 2) & nverts].pos;
122 cgm_vsub(&indir, &poly->verts[i].pos);
124 cgm_vcross(&vcross, &vdir, &edir);
125 cgm_vcross(&incross, &indir, &edir);
127 if(cgm_vdot(&vcross, &incross) < 0.0f) {
134 int init_poly(struct poly *p)
136 p->verts = dynarr_alloc(0, sizeof *p->verts);
138 return p->verts ? 0 : -1;
141 void destroy_poly(struct poly *p)
143 dynarr_free(p->verts);
148 * 0 -> straddling and clipped
151 static int clip_edge(struct poly *pout, const struct vertex *v0, const struct vertex *v1,
152 const struct plane *plane)
158 d0 = plane_sdist(plane, &v0->pos);
159 d1 = plane_sdist(plane, &v1->pos);
161 ray.origin = v0->pos;
163 cgm_vsub(&ray.dir, &v0->pos);
169 DYNARR_PUSH(pout->verts, v1); /* append v1 */
173 t = ray_plane(&ray, plane);
174 cgm_raypos(&vnew.pos, &ray, t);
176 cgm_vlerp(&vnew.norm, &v0->norm, &v1->norm, t);
177 vnew.uv.x = cgm_lerp(v0->uv.x, v1->uv.x, t);
178 vnew.uv.y = cgm_lerp(v0->uv.y, v1->uv.y, t);
179 /* append new vertex on the intersection point */
180 DYNARR_PUSH(pout->verts, &vnew);
186 t = ray_plane(&ray, plane);
187 cgm_raypos(&vnew.pos, &ray, t);
189 cgm_vlerp(&vnew.norm, &v0->norm, &v1->norm, t);
190 vnew.uv.x = cgm_lerp(v0->uv.x, v1->uv.x, t);
191 vnew.uv.y = cgm_lerp(v0->uv.y, v1->uv.y, t);
192 /* append new vertex on the intersection point */
193 DYNARR_PUSH(pout->verts, &vnew);
194 /* then append v1 ... */
195 DYNARR_PUSH(pout->verts, v1);
206 int clip_poly(struct poly *pout, const struct poly *pin, const struct plane *plane)
208 int i, nextidx, res = 0, vnum;
209 int edges_clipped = 0;
211 DYNARR_CLEAR(pout->verts);
213 vnum = dynarr_size(pin->verts);
214 for(i=0; i<vnum; i++) {
216 if(nextidx >= vnum) nextidx = 0;
217 res = clip_edge(pout, pin->verts + i, pin->verts + nextidx, plane);
223 return edges_clipped > 0 ? 0 : 1;