Entropie git · main
Entropie festival game; first steps
C 88.5% Markdown 9.1% GLSL 2.3%git clone https://git.christianimmanuel.de/games/Entropie.gitwget https://git.christianimmanuel.de/games/Entropie/archive/Entropie.tar.gzentropie/src/people/body_internal.h raw
#ifndef PEOPLE_BODY_INTERNAL_H
#define PEOPLE_BODY_INTERNAL_H
/*
* Inside the body (body.c, body_pose.c): proportions, timings and the
* little helpers both halves share. Not for use outside the body.
*/
#include "people/body.h"
#include "render/shapes.h"
/* Proportions of a 1.75 m figure (scaled to the actual height). */
#define REF_HEIGHT 1.75f
#define PELVIS_Y 0.97f
#define HIP_X 0.075f
#define HIP_DROP 0.05f
#define THIGH 0.44f
#define SHIN 0.42f
#define ANKLE_Y BODY_ANKLE_Y
#define FOOT_LENGTH 0.15f
#define FOOT_X 0.085f
#define SPINE 0.36f
#define NECK 0.17f
#define HEAD_UP 0.12f
#define SHOULDER_X 0.19f
#define SHOULDER_UP 0.07f
#define UPPER_ARM 0.29f
#define FOREARM 0.26f
#define HAND 0.08f
/* Stepping */
#define STEP_UP 0.6f /* how high a foot may step up (scaled) */
#define MAX_DROP 0.45f /* ... and down */
#define STEP_THRESHOLD 0.09f /* drift that triggers a step while moving */
#define IDLE_THRESHOLD 0.14f /* ... while standing (avoids fidgeting) */
#define OVER_CLEAR 0.07f /* a foot clears what it steps over by this much (scaled) */
#define OVER_RISE 4.0f /* m/s the lift for it may grow mid-step (scaled) */
#define OVER_STRIDE 0.95f /* a step over something lands at most this far from the other foot (scaled) */
#define OVER_LEAP 1.3f /* running: up to this many step lengths */
#define OVER_LEFT 0.2f /* the aim ran this far past a step waiting in front of something: go past it */
#define OVER_LEAP_LATE 0.6f /* ... while the foot is no further into its step than this */
#define LEAP_SPEED 2.5f /* m/s: from here on ... */
#define LEAP_BEHIND 0.8f /* ... a foot this far behind leaves before the other one is over (both in the air) */
#define LATE_QUICK 3.0f /* running: a step held back this much quicker per meter it lands behind the hips */
#define LIMB_R 0.05f /* a shin's half thickness (kept clear of things) */
#define LEG_NEAR 1.3f /* only a foot this near the body minds its leg (scaled) */
#define LEG_AHEAD 0.25f /* s: a standing leg is checked where the body will be this soon */
#define LEG_FORGET 0.5f /* m/s: ... it lets go of that slowly */
#define LIFT_DROP 3.0f /* m/s a lifted foot comes down at most */
#define LEG_MOVING 0.3f /* m/s: slower, a swinging foot doesn't lift its leg over things */
#define LEG_RISE 4.0f /* m/s a foot lifts when its leg would go into something */
#define LEG_HOLD 0.85f /* until this far into a step, a foot waits for its leg to clear */
#define LEG_TOUCH 0.015f /* (let off) */
#define LIFT_MOST 0.62f /* a foot lifts at most this high over what it passes */
#define STEP_ON_SMALL 0.12f /* things this low (scaled) a careless foot just steps on */
#define OVER_SWING_OUT 0.12f /* a foot stepping over something swings out this far to the side (scaled) ... */
#define OVER_SWING_FULL 0.35f /* ... over things this high (less over lower ones) */
#define PLAN_FIT 0.3f /* sportier than this, steps are fitted to what's coming (fully from +0.4) ... */
#define PLAN_AHEAD 3.0f /* ... looking this far ahead (scaled) ... */
#define PLAN_TAKE_OFF 0.25f /* ... for a take-off this far before it (+ a bit per m/s) */
#define OVER_SLOW 1.0f /* a step over something takes this much longer per meter of its height */
#define LIFT_RISE 2.5f /* m/s a foot is lifted at most to keep clear of something (scaled) */
#define STAND_ON_MOST 0.42f /* a foot comes down on top of something at most this high (scaled) */
#define AIM_GLIDE 0.6f /* m/s a stepping foot's aim may shift on its own (not carried by the body) */
#define TURN_THRESHOLD 0.82f /* cos of how far the body may turn before a foot follows */
#define FOOT_GAP 0.12f /* feet never come closer sideways than this */
#define HEEL_LIFT 0.09f /* rear foot rolls onto its toes (unscaled) */
#define STEP_LIFT 0.10f
#define MIN_STEP_TIME 0.16f
#define MAX_STEP_TIME 0.42f
#define RUN_SPEED 3.5f /* from here on both feet may be in the air */
#define MAX_LEAD 0.48f /* how far ahead of the hips a foot lands */
#define TELEPORT_SPEED 40.0f /* faster than this: replant the feet */
#define AIR_GRACE 0.15f /* brief bumps off the ground don't count as flying */
#define LANDING_STEP_TIME 0.12f
#define STUMBLE_TIME 0.8f
#define CATCH_STEP_TIME 0.16f /* quick step to catch yourself */
#define TOE_OUT 0.12f /* radians feet point outwards */
/* Falling down and getting up (seconds) */
#define FALL_TIME 0.6f
#define LIE_DOWN_TIME 2.0f
#define GET_UP_TIME 1.7f
#define LIE_HEIGHT 0.12f /* torso middle above the ground while lying */
#define FALL_REACH 0.95f /* hips land this far from the feet after a fall */
/* Expression */
#define BURP_TIME 0.9f
#define VOMIT_TIME 2.6f
#define VOMIT_SPLASH 1.1f /* seconds into it */
#define LIE_SAMPLES 9
#define LIE_STEP 0.3f /* meters between ground samples under a lying body */
#define BLINK_TIME 0.13f
/* Ways to fall */
enum { FALL_PLANK, FALL_CRUMPLE, FALL_TWIST, FALL_DIVE };
/* Drop and roll */
#define DIVE_TIME 0.38f /* down to the ground, quick */
#define ROLL_REACH (1.6f * PI_F) /* radians at the furthest */
#define ROLL_PACE 2.2f /* radians per second of the to and fro */
#define ROLL_TIME (2.0f * PI_F / ROLL_PACE) /* one way, back, the other way and back */
#define ROLL_REST 0.4f /* lying a moment after rolling */
#define ROLL_RADIUS 0.14f /* the body rolls sideways like a log this thick */
#define ROLL_OVER_TIME 1.1f /* s rolling over once (the roll way up) */
/* Jumping */
#define TAKE_OFF_SPEED 1.0f /* rising this fast off the ground is a jump */
#define PUSH_OFF_TIME 0.08f /* the push-off foot leaves the ground this much later */
#define TRAIL_LAND_DELAY 0.09f /* running jump: the trailing foot comes down after the leading one */
/* Idle gestures with one hand */
enum { GESTURE_NONE, GESTURE_HIP, GESTURE_HEAD, GESTURE_CHIN, GESTURE_POCKET,
GESTURE_NECK, /* rubbing the back of the neck (tired, shy) */
GESTURE_NOSE, /* rubbing the nose (nervous) */
GESTURE_EAR, /* at the earlobe (nervous, shy) */
GESTURE_HAIR, /* a hand back through the hair (proud, lively) */
GESTURE_THUMB, /* thumb hooked in the belt (proud, at ease) */
GESTURE_CHEST, /* hand on the chest (shy) */
GESTURE_SHADE, /* shading the eyes, looking out (lively) */
GESTURE_WAVE, /* talking: waving hello or goodbye (Body_talkGesture) */
GESTURE_SHRUG, /* ... a palm up and out: "no idea", "never mind" */
GESTURE_POINT, /* ... pointing ahead: "over there" */
GESTURE_COUNT };
#define GESTURE_FADE 0.4f
/* Standing about, the whole body: nobody stands quite still for long */
enum {
FIDGET_NONE,
FIDGET_SHAKE_LEG, /* weight on one leg, the other foot up and shaken loose */
FIDGET_ROCK, /* up on the toes and back down, twice */
FIDGET_STRETCH, /* arms up over the head, chest out */
FIDGET_SHOULDERS, /* rolling the shoulders */
FIDGET_NECK, /* head over to one side, then the other */
FIDGET_CROSS_ARMS, /* arms folded for a while */
FIDGET_TAP_FOOT, /* the toes of one foot tapping */
FIDGET_RUB_HANDS, /* rubbing the hands together (nervous) */
FIDGET_HEAD_BEHIND, /* hands clasped behind the head, elbows out (at ease, proud) */
FIDGET_AKIMBO, /* both hands on the hips (proud) */
FIDGET_KNEES, /* out of breath: bent over, hands on the knees (the unfit) */
FIDGET_ON_HEAD, /* out of breath: hands on top of the head, chest open (the sporty) */
FIDGET_COUNT
};
#define FIDGET_FADE 0.35f
#define STANCE_STEP 0.17f /* a new stance is at least a step away (see IDLE_THRESHOLD) */
/* Body volume that arms keep out of (unscaled; see figure.frag) */
#define TORSO_HALF_WIDTH 0.145f
#define TORSO_HALF_DEPTH 0.10f
#define PELVIS_RADIUS 0.10f
#define THIGH_RADIUS 0.08f
#define HEAD_RADIUS 0.11f
#define ELBOW_RADIUS 0.05f
#define WRIST_RADIUS 0.04f
#define PALM_RADIUS 0.035f
#define LEG_RADIUS 0.05f /* thigh and shin, kept clear of things */
#define KNEE_FOLLOWS_FOOT 0.45f /* the knee points this much the way the foot does, the rest straight ahead ... */
#define KNEE_OUT -0.12f /* ... and this much out (+) or in (a little in: no bow legs) */
#define KNEE_OUT_MOST 1.4f /* radians a knee may swing out round the leg ... */
#define KNEE_OUT_STEPS 7
#define KNEE_IN_MOST 0.5f /* ... or in (radians) */
#define KNEE_IN_STEPS 2
#define KNEE_OFF_SPEED 1.6f /* ... the knee moving there at most this fast (m/s) */
#define LEG_LET_OFF 0.01f /* (a leg this little into something is let be) */
#define LEG_RAISE_BELOW_HIP 0.35f /* a raised foot stays at least this far below the hip */
#define LEG_RAISE_SPEED 2.5f /* m/s a foot comes up off the ground when its leg must */
#define OVER_LEAN 0.22f /* radians the body leans forward stepping over something high */
#define BOB_OMEGA 28.0f /* the running wave follows the strides this quickly */
#define RUN_TUCK_BACK -0.30f /* running, the swing foot's curve: pulled up behind the seat ... */
#define RUN_TUCK_UP 0.85f
#define RUN_DRIVE_AHEAD 0.45f /* ... then through in front, the knee up */
#define RUN_DRIVE_UP 0.55f
#define ARM_SWING 1.25f /* rad the arms swing per m the opposite foot is ahead (walking; running more) */
#define SWING_RUN_EASE 2.5f /* per s a running swing turns into a walking one, slowing down */
#define STANCE_RUN 0.11f /* s a foot stays down at a full run (bending, then pushing off) */
#define BOB_RUN 0.8f /* running: the wave this much deeper (down on the bent leg, up in the flight) */
#define BOB_FLIGHT 1.6f /* ... in the flight the body goes up past standing height (the wave's top) */
#define SWING_CHEST 0.8f /* a two-handed swing off to one side: the shoulders turn this much with it ... */
#define SWING_HIPS 0.3f /* ... the hips ... */
#define SWING_HEAD 0.3f /* ... the head ... */
#define SWING_ARCH 0.15f /* ... and the back arches winding up, bends into the hit (rad) */
#define WALK_BOB 0.022f /* m walking: up mid-step, down as a foot lands (either way) */
#define BOB_FROM 1.8f /* m/s: from a brisk walk on ... */
#define BOB_FULL 3.6f /* ... to a run: the body rises and falls with each stride */
#define BOB_FIT 0.035f /* m down onto each step, sporty ... */
#define BOB_UNFIT 0.04f /* ... and this much more for the unsporty */
#define BOB_NOD 0.12f /* radians the unsporty nod forward with it */
#define JOINT_TOP_HAND 14.0f /* m/s (scaled, relative to the body) a hand can move at most (a throw) ... */
#define JOINT_TOP_FOOT 12.0f /* ... a foot (sprinting) ... */
#define JOINT_TOP_MIDDLE 9.0f /* ... a knee ... */
#define JOINT_TOP_ELBOW 5.5f /* ... an elbow (it swings round the arm, never flips over) ... */
#define JOINT_TOP_TRUNK 5.0f /* ... hips, chest, head, shoulders */
#define KNEE_GAP 0.13f /* knees never come closer than this */
/* Easing rates (per second) */
#define EASE_VELOCITY 10.0f
#define EASE_POSE 6.0f
#define EASE_PELVIS 10.0f
#define EASE_MOOD 1.5f
#define PELVIS_SPEED 1.2f /* max vertical hip speed (m/s, unscaled) */
#define PELVIS_OMEGA 14.0f /* springs (rad/s): how quickly the hips follow up and down ... */
#define SWAY_OMEGA 13.0f /* ... and from foot to foot */
#define HAND_OMEGA 26.0f /* ... and the hands to what they reach for */
#define HAND_WEIGHT_OMEGA 11.0f /* ... and a hand taking up (or giving up) what it does */
#define SWAY_MOST 0.045f /* m the hips go over the standing foot at most (scaled out: unscaled body) */
#define ROOT_OMEGA 12.0f /* the hips follow the character's position on a spring ... */
#define ROOT_LAG 0.08f /* ... never further behind than this (meters) */
#define HAND_FOLLOW 4.0f /* a hand goal moving faster than this (m/s) jumped: the hand eases there */
#define POSE_OMEGA 9.0f /* ... and bending down, leaning in */
#define POLE_TURN 9.0f /* radians a second a knee or elbow may turn round its limb */
/* Arm swing springs: a little lag and overshoot gives the follow-through */
#define ARM_STIFFNESS 80.0f
#define ARM_DAMPING 11.0f
#define FORE_STIFFNESS 50.0f
#define FORE_DAMPING 8.0f
#define UP vec3(0.0f, 1.0f, 0.0f)
static inline float ease(float value, float goal, float rate, float dt) {
return value + (goal - value) * fminf(1.0f, rate * dt);
}
static inline Vec3 flat(Vec3 v) { return vec3(v.x, 0.0f, v.z); }
static inline float shyness(const Body *b) { return fmaxf(-b->shown.pride, 0.0f); }
static inline float proudness(const Body *b) { return fmaxf(b->shown.pride, 0.0f); }
/* 0 = walking .. 1 = running (longer swings with both feet in the air) */
static inline float runAmount(float speed) {
return clampf((speed - RUN_SPEED) / 2.5f, 0.0f, 1.0f);
}
/* Smoking (body.c) */
#define ROLL_CIG_TIME 7.0f /* rolling one */
#define LIGHT_TIME 1.8f /* the flame to it, the first drag */
#define DRAG_TIME 1.4f
/* Peeing: 0..1, hands at the belt, head down a little. */
static inline float peeing(const Body *b) {
if (b->pee <= 0.0f) return 0.0f;
float p = 1.0f - b->pee / fmaxf(b->pee_total, 1.0f);
return smoothstepf(0.0f, 0.12f, p) * (1.0f - smoothstepf(0.9f, 1.0f, p));
}
/* Ground under a lying body at a distance along fall_dir from the hips (meters). */
static inline float lyingGround(const Body *b, float along) {
float t = clampf((along + LIE_STEP * 4.0f) / LIE_STEP, 0.0f, (float)(LIE_SAMPLES - 1));
int i = (int)t;
if (i >= LIE_SAMPLES - 1) return b->lie_ground[LIE_SAMPLES - 1];
float f = t - (float)i;
return b->lie_ground[i] * (1.0f - f) + b->lie_ground[i + 1] * f;
}
/* Being sick: 0..1 into it; bent over (0..1); heaving with the mouth open (0..1). */
static inline float vomitPhase(const Body *b) { return b->vomit > 0.0f ? 1.0f - b->vomit / VOMIT_TIME : 0.0f; }
static inline float bentOver(const Body *b) {
float p = vomitPhase(b);
return b->vomit > 0.0f ? smoothstepf(0.0f, 0.3f, p) * (1.0f - smoothstepf(0.8f, 1.0f, p)) : 0.0f;
}
static inline float heaving(const Body *b) {
float p = vomitPhase(b);
return b->vomit > 0.0f ? smoothstepf(0.33f, 0.4f, p) * (1.0f - smoothstepf(0.6f, 0.75f, p)) : 0.0f;
}
/* How far into its gesture a hand is (0..1). */
static inline float gestureWeight(const Body *b, int side) {
if (b->gesture_time <= 0.0f || b->gesture_side != side) return 0.0f;
return smoothstepf(0.0f, GESTURE_FADE, b->gesture_time) *
smoothstepf(0.0f, GESTURE_FADE, b->gesture_len - b->gesture_time) * smoothstepf(0.0f, 1.0f, b->gesture_fade);
}
/* How far into this fidget the body is (0..1), and where in it (0..1). */
static inline float fidgetWeight(const Body *b, int kind) {
if (b->fidget != kind || b->fidget_time <= 0.0f) return 0.0f;
return smoothstepf(0.0f, FIDGET_FADE, b->fidget_time) * smoothstepf(0.0f, FIDGET_FADE, b->fidget_len - b->fidget_time)
* smoothstepf(0.0f, 1.0f, b->fidget_fade);
}
/* Out of breath, bent over with the hands on the knees (eased in and out slower than a fidget). */
static inline float catchingBreath(const Body *b) {
if (b->fidget != FIDGET_KNEES || b->fidget_time <= 0.0f) return 0.0f;
return smoothstepf(0.0f, 0.9f, b->fidget_time) * smoothstepf(0.0f, 0.9f, b->fidget_len - b->fidget_time) * smoothstepf(0.0f, 1.0f, b->fidget_fade);
}
/* Bent over: being sick, or catching breath. */
static inline float bentDown(const Body *b) { return fmaxf(bentOver(b), 0.85f * catchingBreath(b)); }
static inline float fidgetPhase(const Body *b) {
return b->fidget_len > 0.0f ? 1.0f - b->fidget_time / b->fidget_len : 0.0f;
}
/* Forward kinematics for a hanging, swinging limb (angle in the y/z plane). */
static inline Vec3 swing(Vec3 from, float length, float angle, float out) {
return vec3_add(from, vec3_scale(vec3_normalize(vec3(out, -cosf(angle), sinf(angle))), length));
}
/* Critically damped spring (no overshoot): follows the target, smooth in speed too. */
/* A critically damped spring towards goal (moving along at goal_v), solved
exactly: the same smooth motion at any frame rate, never overshooting or
flickering however long a frame takes. */
static inline void springStep(float *value, float *velocity, float goal, float goal_v, float omega, float dt) {
if (dt <= 0.0f) return;
float d = *value - goal, w = *velocity - goal_v;
float e = expf(-omega * dt), t = (w + omega * d) * dt;
*value = goal + goal_v * dt + (d + t) * e; /* (the goal moves on meanwhile: no lag behind a steady goal) */
*velocity = goal_v + (w - omega * t) * e;
}
static inline void springStep3(Vec3 *value, Vec3 *velocity, Vec3 goal, Vec3 goal_v, float omega, float dt) {
springStep(&value->x, &velocity->x, goal.x, goal_v.x, omega, dt);
springStep(&value->y, &velocity->y, goal.y, goal_v.y, omega, dt);
springStep(&value->z, &velocity->z, goal.z, goal_v.z, omega, dt);
}
static inline void springCritical(float *value, float *velocity, float target, float omega, float dt) {
springStep(value, velocity, target, 0.0f, omega, dt);
}
#endif /* PEOPLE_BODY_INTERNAL_H */