+ Vec3 newpos;
+ newpos.x = cam_pos.x + cos(theta) * dir.x - sin(theta) * dir.z;
+ newpos.y = cam_pos.y;
+ newpos.z = cam_pos.z + sin(theta) * dir.x + cos(theta) * dir.z;
+
+ if(noclip) {
+ cam_pos = newpos;
+ } else {
+ if(!constrain_walk_mesh(newpos, &cam_pos)) {
+ float dtheta = M_PI / 32.0;
+ float theta = dtheta;
+ Vec2 dir2d = newpos.xz() - cam_pos.xz();
+
+ for(int i=0; i<16; i++) {
+ Vec2 dvec = rotate(dir2d, theta);
+ Vec3 pos = cam_pos + Vec3(dvec.x, 0, dvec.y);
+ if(constrain_walk_mesh(pos, &cam_pos)) {
+ break;
+ }
+ dvec = rotate(dir2d, -theta);
+ pos = cam_pos + Vec3(dvec.x, 0, dvec.y);
+ if(constrain_walk_mesh(pos, &cam_pos)) {
+ break;
+ }
+ theta += dtheta;
+ }
+ }
+ floor_y = cam_pos.y - user_eye_height;
+ }
+
+ // calculate mouselook view matrix
+ mouse_view_matrix = Mat4::identity;
+ mouse_view_matrix.pre_translate(0, 0, -cam_dist);
+ if(!have_headtracking) {
+ mouse_view_matrix.pre_rotate_x(deg_to_rad(cam_phi));
+ }
+ mouse_view_matrix.pre_rotate_y(deg_to_rad(cam_theta));
+ mouse_view_matrix.pre_translate(-cam_pos.x, -cam_pos.y, -cam_pos.z);