+/*
+ * 3) [fov,nearz,farz] -> projection matrix
+ */
+static void camera_update_projection( camera *cam )
+{
+ m4x4_copy( cam->mtx.p, cam->mtx_prev.p );
+ m4x4_projection( cam->mtx.p, cam->fov,
+ (float)vg.window_x / (float)vg.window_y,
+ cam->nearz, cam->farz );
+}
+
+/*
+ * 4) [projection matrix, view matrix] -> previous pv, new pv
+ */
+static void camera_finalize( camera *cam )
+{
+ m4x4_copy( cam->mtx.pv, cam->mtx_prev.pv );
+ m4x4_mul( cam->mtx.p, cam->mtx.v, cam->mtx.pv );
+}
+
+/*
+ * http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
+ */
+static void m4x4_clip_projection( m4x4f mat, v4f plane )
+{
+ v4f c =
+ {
+ (vg_signf(plane[0]) + mat[2][0]) / mat[0][0],
+ (vg_signf(plane[1]) + mat[2][1]) / mat[1][1],
+ -1.0f,
+ (1.0f + mat[2][2]) / mat[3][2]
+ };
+
+ v4_muls( plane, 2.0f / v4_dot(plane,c), c );
+
+ mat[0][2] = c[0];
+ mat[1][2] = c[1];
+ mat[2][2] = c[2] + 1.0f;
+ mat[3][2] = c[3];
+}
+
+/*
+ * Undoes the above operation
+ */
+static void m4x4_reset_clipping( m4x4f mat, float ffar, float fnear )
+{
+ mat[0][2] = 0.0f;
+ mat[1][2] = 0.0f;
+ mat[2][2] = -(ffar + fnear) / (ffar - fnear);
+ mat[3][2] = -2.0f * ffar * fnear / (ffar - fnear);