/******************************************************************************\ Computes tile vectors for the parameter array. \******************************************************************************/ static void compute_tile_vectors(int i) { c_vec3_t ab, ac; /* Set tile normal vector */ ab = C_vec3_sub(r_globe_verts[3 * i].v.co, r_globe_verts[3 * i + 1].v.co); ac = C_vec3_sub(r_globe_verts[3 * i].v.co, r_globe_verts[3 * i + 2].v.co); r_tiles[i].normal = C_vec3_norm(C_vec3_cross(ab, ac)); r_globe_verts[3 * i].v.no = r_tiles[i].normal; r_globe_verts[3 * i + 1].v.no = r_tiles[i].normal; r_globe_verts[3 * i + 2].v.no = r_tiles[i].normal; /* Centroid */ r_tiles[i].origin = C_vec3_add(r_globe_verts[3 * i].v.co, r_globe_verts[3 * i + 1].v.co); r_tiles[i].origin = C_vec3_add(r_tiles[i].origin, r_globe_verts[3 * i + 2].v.co); r_tiles[i].origin = C_vec3_divf(r_tiles[i].origin, 3.f); /* Forward vector */ r_tiles[i].forward = C_vec3_sub(r_globe_verts[3 * i].v.co, r_tiles[i].origin); r_tiles[i].forward = C_vec3_norm(r_tiles[i].forward); }
/******************************************************************************\ 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; } } }
/******************************************************************************\ Render normals. Must be called within 3D mode. \******************************************************************************/ void R_render_normals(int count, c_vec3_t *co, c_vec3_t *no, int stride) { c_vec3_t co2; int i; if (!r_test_normals.value.n) return; R_gl_disable(GL_FOG); R_gl_disable(GL_LIGHTING); R_texture_select(NULL); glEnableClientState(GL_VERTEX_ARRAY); for (i = 0; i < count; i++) { co2 = C_vec3_add(*co, *no); glBegin(GL_LINE_STRIP); glColor4f(1.f, 1.f, 0.f, 1.f); glVertex3f(co->x, co->y, co->z); glColor4f(1.f, 0.f, 0.f, 1.f); glVertex3f(co2.x, co2.y, co2.z); glEnd(); co = (c_vec3_t *)((char *)co + stride); no = (c_vec3_t *)((char *)no + stride); } glColor4f(1.f, 1.f, 1.f, 1.f); glDisableClientState(GL_VERTEX_ARRAY); R_gl_restore(); R_check_errors(); }
/******************************************************************************\ Rotate the camera incrementally relative to the current orientation. Angles represent rotation around their axes (i.e. [x] value around the x-axis). \******************************************************************************/ void R_rotate_cam_by(c_vec3_t angle) { if (!angle.x && !angle.y && !angle.z) return; last_cam_move = c_frame; cam_gradual = FALSE; cam_rot_diff = C_vec3_add(cam_rot_diff, angle); }
/******************************************************************************\ Subdivide each globe tile into four tiles. Partioned tile vertices are numbered in the following manner: 3 / \ 4---5 6 2---1 9 / \ \ / / \ 7---8 0 10-11 A vertex's neighbor is the vertex of the tile that shares the next counter- clockwise edge of the tile from that vertex. \******************************************************************************/ static void subdivide4(void) { c_vec3_t mid_0_1, mid_0_2, mid_1_2; r_globe_vertex_t *verts; int i, i_flip, j, n[3], n_flip[3]; for (i = r_tiles_max - 1; i >= 0; i--) { verts = r_globe_verts + 12 * i; /* Determine which faces are flipped (over 0 vertex) */ i_flip = i < flip_limit; for (j = 0; j < 3; j++) { n[j] = r_globe_verts[3 * i + j].next / 3; n_flip[j] = (n[j] < flip_limit) != i_flip; } /* Compute mid-point coordinates */ mid_0_1 = C_vec3_add(r_globe_verts[3 * i].v.co, r_globe_verts[3 * i + 1].v.co); mid_0_1 = C_vec3_divf(mid_0_1, 2.f); mid_0_2 = C_vec3_add(r_globe_verts[3 * i].v.co, r_globe_verts[3 * i + 2].v.co); mid_0_2 = C_vec3_divf(mid_0_2, 2.f); mid_1_2 = C_vec3_add(r_globe_verts[3 * i + 1].v.co, r_globe_verts[3 * i + 2].v.co); mid_1_2 = C_vec3_divf(mid_1_2, 2.f); /* Bottom-right triangle */ verts[9].v.co = mid_0_2; verts[9].next = 12 * i + 1; verts[10].v.co = mid_1_2; verts[10].next = 12 * n[1] + 8; verts[11].v.co = r_globe_verts[3 * i + 2].v.co; verts[11].next = 12 * n[2] + (n_flip[2] ? 7 : 3); /* Bottom-left triangle */ verts[6].v.co = mid_0_1; verts[6].next = 12 * n[0] + (n_flip[0] ? 9 : 4); verts[7].v.co = r_globe_verts[3 * i + 1].v.co; verts[7].next = 12 * n[1] + 11; verts[8].v.co = mid_1_2; verts[8].next = 12 * i; /* Top triangle */ verts[3].v.co = r_globe_verts[3 * i].v.co; verts[3].next = 12 * n[0] + (n_flip[0] ? 3 : 7); verts[4].v.co = mid_0_1; verts[4].next = 12 * i + 2; verts[5].v.co = mid_0_2; verts[5].next = 12 * n[2] + (n_flip[2] ? 4 : 9); /* Center triangle */ verts[0].v.co = mid_1_2; verts[0].next = 12 * i + 10; verts[1].v.co = mid_0_2; verts[1].next = 12 * i + 5; verts[2].v.co = mid_0_1; verts[2].next = 12 * i + 6; } flip_limit *= 4; r_tiles_max *= 4; r_globe_radius *= 2; sphericize(); }