ref: 5fcf2feec81e753d0188bb10da9db0a5ee061957
dir: /src/wipeout/camera.c/
#include "../mem.h" #include "../utils.h" #include "../types.h" #include "../render.h" #include "../system.h" #include "object.h" #include "track.h" #include "ship.h" #include "weapon.h" #include "droid.h" #include "camera.h" void camera_init(camera_t *camera, section_t *section) { camera->section = section; for (int i = 0; i < 10; i++) { camera->section = camera->section->next; } camera->position = camera->section->center; camera->velocity = vec3(0, 0, 0); camera->angle = vec3(0, 0, 0); camera->angular_velocity = vec3(0, 0, 0); camera->mat = mat4_identity(); camera->has_initial_section = false; } void camera_update(camera_t *camera, ship_t *ship, droid_t *droid) { camera->last_position = camera->position; (camera->update_func)(camera, ship, droid); camera->real_velocity = vec3_mulf(vec3_sub(camera->position, camera->last_position), 1.0/system_tick()); } void camera_update_race_external(camera_t *camera, ship_t *ship, droid_t *droid) { vec3_t pos = vec3_sub(ship->position, vec3_mulf(ship->dir_forward, 1024)); pos.y -= 200; camera->section = track_nearest_section(pos, camera->section, NULL); section_t *next = camera->section->next; vec3_t target = vec3_project_to_ray(pos, next->center, camera->section->center); vec3_t diff_from_center = vec3_sub(pos, target); vec3_t acc = diff_from_center; acc.y += vec3_len(diff_from_center) * 0.5; camera->velocity = vec3_sub(camera->velocity, vec3_mulf(acc, 0.015625 * 30 * system_tick())); camera->velocity = vec3_sub(camera->velocity, vec3_mulf(camera->velocity, 0.125 * 30 * system_tick())); pos = vec3_add(pos, camera->velocity); camera->position = pos; camera->angle = vec3(ship->angle.x, ship->angle.y, 0); } void camera_update_race_internal(camera_t *camera, ship_t *ship, droid_t *droid) { camera->section = ship->section; camera->position = ship_cockpit(ship); camera->angle = vec3(ship->angle.x, ship->angle.y, ship->angle.z); } void camera_update_race_intro(camera_t *camera, ship_t *ship, droid_t *droid) { // Set to final position vec3_t pos = vec3_sub(ship->position, vec3_mulf(ship->dir_forward, 0.25 * 4096)); pos.x += sin(( (ship->update_timer - UPDATE_TIME_RACE_VIEW) * 30 * 3.0 * M_PI * 2) / 4096.0) * 4096; pos.y -= (2 * (ship->update_timer - UPDATE_TIME_RACE_VIEW) * 30) + 200; pos.z += sin(( (ship->update_timer - UPDATE_TIME_RACE_VIEW) * 30 * 3.0 * M_PI * 2) / 4096.0) * 4096; if (!camera->has_initial_section) { camera->section = ship->section; camera->has_initial_section = true; } else { camera->section = track_nearest_section(pos, camera->section, NULL); } camera->position = pos; camera->angle.z = 0; camera->angle.x = ship->angle.x * 0.5; vec3_t target = vec3_sub(ship->position, pos); camera->angle.y = -atan2(target.x, target.z); if (ship->update_timer <= UPDATE_TIME_RACE_VIEW) { flags_add(ship->flags, SHIP_VIEW_INTERNAL); camera->update_func = camera_update_race_internal; } } void camera_update_attract_circle(camera_t *camera, ship_t *ship, droid_t *droid) { camera->update_timer -= system_tick(); if (camera->update_timer <= 0) { camera->update_func = camera_update_attract_random; } // FIXME: not exactly sure what I'm doing here. The PSX version behaves // differently. camera->section = ship->section; camera->position.x = ship->position.x + sin(ship->angle.y) * 512; camera->position.y = ship->position.y + ((ship->angle.x * 512 / (M_PI * 2)) - 200); camera->position.z = ship->position.z - cos(ship->angle.y) * 512; camera->position.x += sin(camera->update_timer * 0.25) * 512; camera->position.y -= 400; camera->position.z += cos(camera->update_timer * 0.25) * 512; camera->position = vec3_sub(camera->position, vec3_mulf(ship->dir_up, 256)); vec3_t target = vec3_sub(ship->position, camera->position); float height = sqrt(target.x * target.x + target.z * target.z); camera->angle.x = -atan2(target.y, height); camera->angle.y = -atan2(target.x, target.z); } void camera_update_rescue(camera_t *camera, ship_t *ship, droid_t *droid) { camera->position = vec3_add(camera->section->center, vec3(300, -1500, 300)); vec3_t target = vec3_sub(droid->position, camera->position); float height = sqrt(target.x * target.x + target.z * target.z); camera->angle.x = -atan2(target.y, height); camera->angle.y = -atan2(target.x, target.z); } void camera_update_attract_internal(camera_t *camera, ship_t *ship, droid_t *droid) { camera->update_timer -= system_tick(); if (camera->update_timer <= 0) { camera->update_func = camera_update_attract_random; } camera->section = ship->section; camera->position = ship_cockpit(ship); camera->angle = vec3(ship->angle.x, ship->angle.y, 0); // No roll } void camera_update_static_follow(camera_t *camera, ship_t *ship, droid_t *droid) { camera->update_timer -= system_tick(); if (camera->update_timer <= 0) { camera->update_func = camera_update_attract_random; } vec3_t target = vec3_sub(ship->position, camera->position); float height = sqrt(target.x * target.x + target.z * target.z); camera->angle.x = -atan2(target.y, height); camera->angle.y = -atan2(target.x, target.z); } void camera_update_attract_random(camera_t *camera, ship_t *ship, droid_t *droid) { flags_rm(ship->flags, SHIP_VIEW_INTERNAL); if (rand() % 2) { camera->update_func = camera_update_attract_circle; camera->update_timer = 5; } else { camera->update_func = camera_update_static_follow; camera->update_timer = 5; section_t *section = ship->section->next; for (int i = 0; i < 10; i++) { section = section->next; } camera->section = section; camera->position = section->center; camera->position.y -= 500; } (camera->update_func)(camera, ship, droid); }