+
+
+/* returns:
+ * 1 -> both inside
+ * 0 -> straddling and clipped
+ * -1 -> both outside
+ */
+static int clip_edge(struct poly *pout, const struct vertex *v0, const struct vertex *v1,
+ const struct plane *plane)
+{
+ float d0, d1, t;
+ cgm_ray ray;
+ int i, vnum = dynarr_size(pout->verts);
+ struct vertex vnew;
+
+ d0 = plane_sdist(plane, &v0->pos);
+ d1 = plane_sdist(plane, &v1->pos);
+
+ ray.orig = v0->pos;
+ ray.dir = v1->pos;
+ cgm_vsub(&ray.dir, &v0->pos);
+
+ for(i=0; i<3; i++) {
+ ray.origin[i] = pos0[i];
+ ray.dir[i] = pos1[i] - pos0[i];
+ }
+
+ if(d0 >= 0.0) {
+ /* start inside */
+ if(d1 >= 0.0) {
+ /* all inside */
+ DYNARR_PUSH(pout->verts, v1); /* append v1 */
+ return 1;
+ } else {
+ /* going out */
+ t = ray_plane(&ray, plane);
+ cgm_raypos(&vnew->pos, &ray, t);
+
+ cgm_vlerp(&vnew->norm, &v0->norm, &v1->norm, t);
+ vnew->uv.x = cgm_lerp(v0->uv.x, v1->uv.x, t);
+ vnew->uv.y = cgm_lerp(v0->uv.y, v1->uv.y, t);
+ /* append new vertex on the intersection point */
+ DYNARR_PUSH(pout->verts, &vnew);
+ }
+ } else {
+ /* start outside */
+ if(d1 >= 0) {
+ /* going in */
+ t = ray_plane(&ray, plane);
+ cgm_raypos(&vnew->pos, &ray, t);
+
+ cgm_vlerp(&vnew->norm, &v0->norm, &v1->norm, t);
+ vnew->uv.x = cgm_lerp(v0->uv.x, v1->uv.x, t);
+ vnew->uv.y = cgm_lerp(v0->uv.y, v1->uv.y, t);
+ /* append new vertex on the intersection point */
+ DYNARR_PUSH(pout->verts, &vnew);
+ /* then append v1 ... */
+ DYNARR_PUSH(pout->verts, v1);
+ } else {
+ /* all outside */
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int clip_poly(struct poly *pout, const struct poly *pin, const struct plane *plane)
+{
+ int i, nextidx, res = 0, vnum;
+ int edges_clipped = 0;
+
+ dynarr_clear(pout->verts);
+
+ vnum = dynarr_size(pin->verts);
+ for(i=0; i<vnum; i++) {
+ nextidx = i + 1;
+ if(nextidx >= vnum) nextidx = 0;
+ res = clip_edge(pout, pin->verts + i, pin->verts + nextidx, plane);
+ if(res == 0) {
+ ++edges_clipped;
+ }
+ }
+
+ return edges_clipped > 0 ? 0 : 1;
+
+}