This repository has been archived on 2022-05-21. You can view files and clone it, but cannot push or open issues or pull requests.
LEFTONE/core/loplayer/camera.c

274 lines
7.3 KiB
C
Raw Normal View History

#include "./camera.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include "util/math/algorithm.h"
#include "util/math/matrix.h"
#include "util/math/vector.h"
#include "util/mpkutil/get.h"
#include "util/mpkutil/pack.h"
#include "core/locommon/easing.h"
#include "core/locommon/position.h"
#include "core/locommon/ticker.h"
#include "./entity.h"
#include "./event.h"
#include "./status.h"
#define LOPLAYER_CAMERA_STATE_EACH_(PROC) do { \
PROC(DEFAULT, default); \
PROC(COMBAT, combat); \
PROC(DEAD, dead); \
PROC(MENU, menu); \
} while (0)
static void loplayer_camera_bind_position_in_area_(
const loplayer_camera_t* camera,
locommon_position_t* pos,
const locommon_position_t* areapos,
const vec2_t* areasize) {
assert(camera != NULL);
assert(locommon_position_valid(pos));
assert(locommon_position_valid(areapos));
assert(vec2_valid(areasize));
vec2_t szoffset = camera->display_chunksz;
vec2_diveq(&szoffset, camera->scale);
vec2_t sz;
vec2_sub(&sz, areasize, &szoffset);
vec2_t v;
locommon_position_sub(&v, pos, areapos);
# define fix_coordinate_(axis) do { \
if (sz.axis > 0) { \
if (MATH_ABS(v.axis) > sz.axis) v.axis = MATH_SIGN(v.axis)*sz.axis; \
} else { \
v.axis = 0; \
} \
} while (0)
fix_coordinate_(x);
fix_coordinate_(y);
# undef fix_coordinate_
*pos = *areapos;
vec2_addeq(&pos->fract, &v);
locommon_position_reduce(pos);
}
const char* loplayer_camera_state_stringify(loplayer_camera_state_t state) {
# define each_(NAME, name) do { \
if (state == LOPLAYER_CAMERA_STATE_##NAME) return #name; \
} while (0)
LOPLAYER_CAMERA_STATE_EACH_(each_);
assert(false);
return NULL;
# undef each_
}
bool loplayer_camera_state_unstringify(
loplayer_camera_state_t* state, const char* str, size_t len) {
assert(state != NULL);
# define each_(NAME, name) do { \
if (strncmp(str, #name, len) == 0 && #name[len] == 0) { \
*state = LOPLAYER_CAMERA_STATE_##NAME; \
return true; \
} \
} while (0)
LOPLAYER_CAMERA_STATE_EACH_(each_);
return false;
# undef each_
}
void loplayer_camera_initialize(
loplayer_camera_t* camera,
loshader_set_t* shaders,
const locommon_ticker_t* ticker,
const loplayer_event_t* event,
const loplayer_status_t* status,
const loplayer_entity_t* entity,
const mat4_t* proj) {
assert(camera != NULL);
assert(shaders != NULL);
assert(ticker != NULL);
assert(event != NULL);
assert(status != NULL);
assert(entity != NULL);
assert(mat4_valid(proj));
mat4_t inv_proj;
mat4_inv(&inv_proj, proj);
static const vec4_t chunk = vec4(1, 1, 0, 0);
vec4_t chunksz;
mat4_mul_vec4(&chunksz, &inv_proj, &chunk);
*camera = (typeof(*camera)) {
.shaders = shaders,
.ticker = ticker,
.event = event,
.status = status,
.entity = entity,
.display_chunksz = chunksz.xy,
.matrix = mat4_scale(1, 1, 1),
.scale = 1.0f,
.cinesco = {
.color = vec4(0, 0, 0, 1),
},
.state = LOPLAYER_CAMERA_STATE_DEFAULT,
.brightness = 1,
};
}
void loplayer_camera_deinitialize(loplayer_camera_t* camera) {
assert(camera != NULL);
}
void loplayer_camera_update(loplayer_camera_t* camera) {
assert(camera != NULL);
const float d = camera->ticker->delta_f;
const loplayer_status_t* stat = camera->status;
locommon_position_t target = camera->entity->super.super.pos;
/* ---- movement ---- */
const loplayer_event_param_t* e = loplayer_event_get_param(camera->event);
if (e != NULL && e->area_size.x > 0 && e->area_size.y > 0) {
loplayer_camera_bind_position_in_area_(
camera, &target, &e->area_pos, &e->area_size);
}
vec2_t dist;
locommon_position_sub(&dist, &target, &camera->pos);
if (vec2_pow_length(&dist) > 2) camera->pos = target;
locommon_easing_smooth_position(&camera->pos, &target, d*10);
# define ease_float_(name, ed, speed) \
locommon_easing_smooth_float(&camera->name, ed, d*(speed))
/* ---- cinema scope ---- */
ease_float_(cinesco.size, !!(e != NULL && e->cinescope)*.3f, 2);
/* ---- damage effect ---- */
const bool damaged =
stat->last_damage_time > 0 &&
stat->last_damage_time+500 > camera->ticker->time;
ease_float_(pe.raster, !!damaged*.5f, damaged? 5: 3);
/* ---- amnesia effect ---- */
const uint64_t amnesia_st = stat->recipient.effects.amnesia.begin;
const uint64_t amnesia_dur = stat->recipient.effects.amnesia.duration;
ease_float_(
pe.amnesia_displacement,
!!(amnesia_st+amnesia_dur > camera->ticker->time), 5);
/* ---- dying effect ---- */
const float dying = stat->dying_effect;
camera->pixsort = dying < .1f? dying/.1f: powf(1-(dying-.1f), 1.5f);
if (camera->pixsort < 0) camera->pixsort = 0;
/* ---- switch by current state ---- */
switch (camera->state) {
case LOPLAYER_CAMERA_STATE_DEFAULT:
ease_float_(scale, 1.0f, 10);
ease_float_(pe.whole_blur, 0.0f, 1);
ease_float_(pe.radial_displacement, 0.0f, 5);
ease_float_(pe.radial_fade, 0.5f, 3);
break;
case LOPLAYER_CAMERA_STATE_COMBAT:
ease_float_(scale, 1.5f, 8);
ease_float_(pe.whole_blur, 0.0f, 1);
ease_float_(pe.radial_displacement, 0.6f, 3);
ease_float_(pe.radial_fade, 0.8f, 1);
break;
case LOPLAYER_CAMERA_STATE_DEAD:
ease_float_(scale, 2.0f, 1);
ease_float_(pe.whole_blur, 1.0f, 1);
ease_float_(pe.radial_displacement, 0.3f, .7f);
ease_float_(pe.radial_fade, 1.5f, .7f);
break;
case LOPLAYER_CAMERA_STATE_MENU:
ease_float_(scale, 1.0f, 10);
ease_float_(pe.whole_blur, 0.9f, 1);
ease_float_(pe.radial_displacement, 0.0f, 10);
ease_float_(pe.radial_fade, 0.6f, 1);
break;
}
# undef ease_float_
/* ---- fixed params ---- */
camera->pe.brightness = camera->brightness;
/* ---- matrix ---- */
camera->matrix = mat4_scale(camera->scale, camera->scale, 1);
}
void loplayer_camera_draw(const loplayer_camera_t* camera) {
assert(camera != NULL);
loshader_pixsort_drawer_set_intensity(
camera->shaders->drawer.pixsort, camera->pixsort);
loshader_posteffect_drawer_set_param(
camera->shaders->drawer.posteffect, &camera->pe);
loshader_cinescope_drawer_set_param(
camera->shaders->drawer.cinescope, &camera->cinesco);
}
void loplayer_camera_pack(
const loplayer_camera_t* camera, msgpack_packer* packer) {
assert(camera != NULL);
assert(packer != NULL);
msgpack_pack_map(packer, 2);
mpkutil_pack_str(packer, "state");
mpkutil_pack_str(packer, loplayer_camera_state_stringify(camera->state));
mpkutil_pack_str(packer, "pos");
locommon_position_pack(&camera->pos, packer);
}
bool loplayer_camera_unpack(
loplayer_camera_t* camera, const msgpack_object* obj) {
assert(camera != NULL);
if (obj == NULL) return false;
const msgpack_object_map* root = mpkutil_get_map(obj);
# define item_(v) mpkutil_get_map_item_by_str(root, v)
const char* v;
size_t len;
if (!mpkutil_get_str(item_("state"), &v, &len) ||
!loplayer_camera_state_unstringify(&camera->state, v, len)) {
return false;
}
if (!locommon_position_unpack(&camera->pos, item_("pos"))) {
return false;
}
# undef item_
return true;
}