/******************************************************************************\ Smooth globe vertex normals. \******************************************************************************/ static void smooth_normals(void) { c_vec3_t vert_no, normal; int i, j, len; C_var_unlatch(&r_globe_smooth); if (r_globe_smooth.value.f <= 0.f) return; if (r_globe_smooth.value.f > 1.f) r_globe_smooth.value.f = 1.f; for (i = 0; i < r_tiles_max * 3; i++) { /* Compute the average normal for this point */ normal = C_vec3(0.f, 0.f, 0.f); len = 0; j = r_globe_verts[i].next; while (j != i) { normal = C_vec3_add(normal, r_globe_verts[j].v.no); j = r_globe_verts[j].next; len++; } normal = C_vec3_scalef(normal, r_globe_smooth.value.f / len); /* Set the normal for all vertices in the ring */ j = r_globe_verts[i].next; while (j != i) { vert_no = C_vec3_scalef(r_tiles[j / 3].normal, 1.f - r_globe_smooth.value.f); vert_no = C_vec3_add(vert_no, normal); r_globe_verts[j].v.no = vert_no; j = r_globe_verts[j].next; } } }
/******************************************************************************\ Space out the vertices at even distance from the sphere. \******************************************************************************/ static void sphericize(void) { c_vec3_t origin, co; float scale; int i; origin = C_vec3(0.f, 0.f, 0.f); for (i = 0; i < r_tiles_max * 3; i++) { co = r_globe_verts[i].v.co; scale = r_globe_radius / C_vec3_len(co); r_globe_verts[i].v.co = C_vec3_scalef(co, scale); } }
/******************************************************************************\ Begin a gradual rotation to the target normal. \******************************************************************************/ void R_rotate_cam_to(c_vec3_t pos) { c_vec3_t norm_origin; if (!pos.x && !pos.y && !pos.z) return; norm_origin = C_vec3_norm(r_cam_origin); pos = C_vec3_norm(pos); gradual_axis = C_vec3_norm(C_vec3_cross(pos, norm_origin)); gradual_angle = acosf(C_vec3_dot(pos, norm_origin)); if (gradual_angle < 0.f) { gradual_angle = -gradual_angle; gradual_axis = C_vec3_scalef(gradual_axis, -1.f); } R_grab_cam(); cam_gradual = TRUE; }
/******************************************************************************\ Sets the height of one tile. \******************************************************************************/ static void set_tile_height(int tile, float height) { c_vec3_t co; float dist; int i, j, verts[6], verts_len; for (i = 0; i < 3; i++) { verts_len = vertex_indices(3 * tile + i, verts); height = height / verts_len; for (j = 0; j < verts_len; j++) { co = r_globe_verts[verts[j]].v.co; dist = C_vec3_len(co); co = C_vec3_scalef(co, (dist + height) / dist); r_globe_verts[verts[j]].v.co = co; } } }
/******************************************************************************\ Calculates a new camera rotation matrix and reloads the modelview matrix. \******************************************************************************/ void R_update_camera(void) { c_vec3_t x_axis, y_axis, z_axis, diff; R_push_mode(R_MODE_3D); glMatrixMode(GL_MODELVIEW); /* Update zoom */ r_cam_zoom += cam_zoom_diff; if (r_cam_zoom > r_zoom_max) r_cam_zoom = r_zoom_max; if (r_cam_zoom < R_ZOOM_MIN) r_cam_zoom = R_ZOOM_MIN; cam_zoom_diff = 0.f; /* Momentum mode changes the meaning of the camera difference vector to velocity rather than change-per-frame */ diff = cam_rot_diff; if (cam_momentum) { float prop; diff = C_vec3_scalef(diff, c_frame_sec); prop = 1.f - c_frame_sec * CAM_FRICTION; if (prop <= 0.f) { cam_rot_diff = C_vec3(0.f, 0.f, 0.f); cam_momentum = FALSE; } else { cam_rot_diff = C_vec3_scalef(cam_rot_diff, prop); if (C_vec3_len(cam_rot_diff) < STOP_MARGIN) { cam_rot_diff = C_vec3(0.f, 0.f, 0.f); cam_momentum = FALSE; } } } else cam_rot_diff = C_vec3(0.f, 0.f, 0.f); /* Apply the rotation differences from last frame to the rotation matrix to get view-oriented scrolling */ glLoadMatrixf(cam_rotation); x_axis = C_vec3(cam_rotation[0], cam_rotation[4], cam_rotation[8]); y_axis = C_vec3(cam_rotation[1], cam_rotation[5], cam_rotation[9]); z_axis = C_vec3(cam_rotation[2], cam_rotation[6], cam_rotation[10]); glRotatef(C_rad_to_deg(diff.x), x_axis.x, x_axis.y, x_axis.z); glRotatef(C_rad_to_deg(diff.y), y_axis.x, y_axis.y, y_axis.z); glRotatef(C_rad_to_deg(diff.z), z_axis.x, z_axis.y, z_axis.z); /* If we are in gradual rotation mode, update it */ if (cam_gradual) { float angle; angle = gradual_angle * GRADUAL_RATE * c_frame_sec; if (angle > gradual_angle) angle = gradual_angle; glRotatef(C_rad_to_deg(angle), gradual_axis.x, gradual_axis.y, gradual_axis.z); gradual_angle -= angle; if (gradual_angle < STOP_MARGIN) cam_gradual = FALSE; } /* Recreate the full camera matrix with the new rotation */ glGetFloatv(GL_MODELVIEW_MATRIX, cam_rotation); check_rotation(); glLoadIdentity(); glTranslatef(0, 0, -r_globe_radius - r_cam_zoom); glMultMatrixf(cam_rotation); glGetFloatv(GL_MODELVIEW_MATRIX, r_cam_matrix); /* Extract the camera location from the matrix for use by other parts of the program. We cannot replace these new vectors with the axes above because they are changed by the rotations. */ r_cam_forward = C_vec3(-cam_rotation[2], -cam_rotation[6], -cam_rotation[10]); r_cam_normal = C_vec3(cam_rotation[1], cam_rotation[5], cam_rotation[9]); r_cam_origin = C_vec3_scalef(r_cam_forward, -r_globe_radius - r_cam_zoom); R_pop_mode(); }