mirror of
https://github.com/XProger/OpenLara.git
synced 2025-01-17 21:09:00 +01:00
#23 ponytail
This commit is contained in:
parent
86cf3f8db9
commit
ce83f7a333
@ -461,15 +461,15 @@ namespace Debug {
|
||||
|
||||
int offset = level.meshOffsets[m.mStart + k];
|
||||
TR::Mesh *mesh = (TR::Mesh*)&level.meshes[offset];
|
||||
if (!mesh->flags) continue;
|
||||
//if (!mesh->flags) continue;
|
||||
Debug::Draw::sphere(matrix * joint * mesh->center, mesh->radius, vec4(0, 1, 1, 0.5f));
|
||||
|
||||
/*
|
||||
{ //if (e.id != 0) {
|
||||
char buf[255];
|
||||
sprintf(buf, "(%d) radius %d flags %d", (int)e.type, (int)mesh->radius, (int)mesh->flags);
|
||||
Debug::Draw::text(matrix * joint * mesh->center, vec4(0.5, 1, 0.5, 1), buf);
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
Debug::Draw::box(matrix, frame->box.min(), frame->box.max(), vec4(1.0));
|
||||
|
||||
|
@ -477,6 +477,7 @@ namespace TR {
|
||||
VIEW_TARGET = 169, // invisible
|
||||
WATERFALL = 170, // invisible (water splash generator)
|
||||
|
||||
BRAID = 189, // Lara's ponytail
|
||||
GLYPH = 190, // sprite
|
||||
|
||||
} type;
|
||||
@ -837,6 +838,7 @@ namespace TR {
|
||||
int16 muzzleFlash;
|
||||
int16 puzzleSet;
|
||||
int16 weapons[4];
|
||||
int16 braid;
|
||||
} extra;
|
||||
|
||||
Level(Stream &stream, bool demo) {
|
||||
@ -1039,6 +1041,7 @@ namespace TR {
|
||||
memset(&extra, 0, sizeof(extra));
|
||||
for (int i = 0; i < 4; i++)
|
||||
extra.weapons[i] = -1;
|
||||
extra.braid = -1;
|
||||
|
||||
for (int i = 0; i < modelsCount; i++)
|
||||
switch (models[i].type) {
|
||||
@ -1048,6 +1051,7 @@ namespace TR {
|
||||
case Entity::LARA_SHOTGUN : extra.weapons[1] = i; break;
|
||||
case Entity::LARA_MAGNUMS : extra.weapons[2] = i; break;
|
||||
case Entity::LARA_UZIS : extra.weapons[3] = i; break;
|
||||
case Entity::BRAID : extra.braid = i; break;
|
||||
default : ;
|
||||
}
|
||||
// init cutscene transform
|
||||
|
181
src/lara.h
181
src/lara.h
@ -171,6 +171,7 @@ struct Lara : Character {
|
||||
BODY_LEG_R = BODY_LEG_R1 | BODY_LEG_R2 | BODY_LEG_R3,
|
||||
BODY_UPPER = BODY_CHEST | BODY_ARM_L | BODY_ARM_R, // without head
|
||||
BODY_LOWER = BODY_HIP | BODY_LEG_L | BODY_LEG_R,
|
||||
BODY_BRAID_MASK = BODY_HEAD | BODY_CHEST | BODY_ARM_L1 | BODY_ARM_L2 | BODY_ARM_R1 | BODY_ARM_R2,
|
||||
};
|
||||
|
||||
bool home;
|
||||
@ -202,7 +203,168 @@ struct Lara : Character {
|
||||
int lastPickUp;
|
||||
int viewTarget;
|
||||
|
||||
Lara(IGame *game, int entity, bool home) : Character(game, entity, 1000), home(home), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), viewTarget(-1) {
|
||||
struct Braid {
|
||||
Lara *lara;
|
||||
vec3 offset;
|
||||
|
||||
Basis *basis;
|
||||
struct Joint {
|
||||
vec3 posPrev, pos;
|
||||
float length;
|
||||
} *joints;
|
||||
int jointsCount;
|
||||
float time;
|
||||
|
||||
Braid(Lara *lara, const vec3 &offset) : lara(lara), offset(offset), time(0.0f) {
|
||||
TR::Level *level = lara->level;
|
||||
TR::Model *model = getModel();
|
||||
jointsCount = model->mCount + 1;
|
||||
joints = new Joint[jointsCount];
|
||||
basis = new Basis[jointsCount - 1];
|
||||
|
||||
Basis basis = getBasis();
|
||||
basis.translate(offset);
|
||||
|
||||
TR::Node *node = (int)model->node < level->nodesDataSize ? (TR::Node*)&level->nodesData[model->node] : NULL;
|
||||
for (int i = 0; i < jointsCount - 1; i++) {
|
||||
TR::Node &t = node[min(i, model->mCount - 2)];
|
||||
joints[i].posPrev = joints[i].pos = basis.pos;
|
||||
joints[i].length = t.z;
|
||||
basis.translate(vec3(0.0f, 0.0f, -t.z));
|
||||
}
|
||||
joints[jointsCount - 1].posPrev = joints[jointsCount - 1].pos = basis.pos;
|
||||
joints[jointsCount - 1].length = 1.0f;
|
||||
}
|
||||
|
||||
~Braid() {
|
||||
delete[] joints;
|
||||
delete[] basis;
|
||||
}
|
||||
|
||||
TR::Model* getModel() const {
|
||||
return &lara->level->models[lara->level->extra.braid];
|
||||
}
|
||||
|
||||
Basis getBasis() {
|
||||
return lara->animation.getJoints(lara->getMatrix(), 14, true);
|
||||
}
|
||||
|
||||
vec3 getPos() {
|
||||
return getBasis() * offset;
|
||||
}
|
||||
|
||||
void integrate() {
|
||||
float TIMESTEP = Core::deltaTime;
|
||||
float ACCEL = 6.0f * GRAVITY * TIMESTEP * TIMESTEP;
|
||||
float DAMPING = 1.5f;
|
||||
|
||||
if (lara->getRoom().flags.water) {
|
||||
ACCEL *= -1.0f;
|
||||
DAMPING = 4.0f;
|
||||
}
|
||||
|
||||
DAMPING = 1.0f / (1.0f + DAMPING * TIMESTEP); // Pade approximation
|
||||
|
||||
for (int i = 1; i < jointsCount; i++) {
|
||||
Joint &j = joints[i];
|
||||
vec3 delta = j.pos - j.posPrev;
|
||||
delta = delta.normal() * (min(delta.length(), 2048.0f * Core::deltaTime) * DAMPING); // speed limit
|
||||
j.posPrev = j.pos;
|
||||
j.pos += delta;
|
||||
if (lara->stand == STAND_ONWATER) {
|
||||
if (j.pos.y > lara->pos.y)
|
||||
j.pos.y += ACCEL;
|
||||
else
|
||||
j.pos.y -= ACCEL;
|
||||
} else
|
||||
j.pos.y += ACCEL;
|
||||
}
|
||||
}
|
||||
|
||||
void collide() {
|
||||
TR::Level *level = lara->level;
|
||||
TR::Model *model = lara->getModel();
|
||||
|
||||
#define BRAID_RADIUS 16.0f
|
||||
|
||||
for (int i = 0; i < model->mCount; i++) {
|
||||
if (!(BODY_BRAID_MASK & (1 << i))) continue;
|
||||
|
||||
int offset = level->meshOffsets[model->mStart + i];
|
||||
TR::Mesh *mesh = (TR::Mesh*)&level->meshes[offset];
|
||||
|
||||
vec3 center = lara->animation.getJoints(lara->getMatrix(), i, true) * mesh->center;
|
||||
float radiusSq = mesh->radius + BRAID_RADIUS;
|
||||
radiusSq *= radiusSq;
|
||||
|
||||
for (int j = 1; j < jointsCount; j++) {
|
||||
vec3 dir = joints[j].pos - center;
|
||||
float len = dir.length2() + EPS;
|
||||
if (len < radiusSq) {
|
||||
len = sqrtf(len);
|
||||
dir *= (mesh->radius + BRAID_RADIUS- len) / len;
|
||||
joints[j].pos += dir * 0.9f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef BRAID_RADIUS
|
||||
}
|
||||
|
||||
void solve() {
|
||||
for (int i = 0; i < jointsCount - 1; i++) {
|
||||
Joint &a = joints[i];
|
||||
Joint &b = joints[i + 1];
|
||||
|
||||
vec3 dir = b.pos - a.pos;
|
||||
float len = dir.length() + EPS;
|
||||
dir *= 1.0f / len;
|
||||
|
||||
float d = a.length - len;
|
||||
|
||||
if (i > 0) {
|
||||
dir *= d * (0.5f * 1.0f);
|
||||
a.pos -= dir;
|
||||
b.pos += dir;
|
||||
} else
|
||||
b.pos += dir * (d * 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void update() {
|
||||
joints[0].pos = getPos();
|
||||
integrate(); // Verlet integration step
|
||||
collide(); // check collision with Lara's mesh
|
||||
for (int i = 0; i < jointsCount; i++) // solve connections (springs)
|
||||
solve();
|
||||
|
||||
vec3 headDir = getBasis().rot * vec3(0.0f, 0.0f, -1.0f);
|
||||
|
||||
for (int i = 0; i < jointsCount - 1; i++) {
|
||||
vec3 d = (joints[i + 1].pos - joints[i].pos).normal();
|
||||
vec3 r = d.cross(headDir).normal();
|
||||
vec3 u = d.cross(r).normal();
|
||||
|
||||
mat4 m;
|
||||
m.up = vec4(u, 0.0f);
|
||||
m.dir = vec4(d, 0.0f);
|
||||
m.right = vec4(r, 0.0f);
|
||||
m.offset = vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
basis[i].identity();
|
||||
basis[i].translate(joints[i].pos);
|
||||
basis[i].rotate(m.getRot());
|
||||
}
|
||||
}
|
||||
|
||||
void render(MeshBuilder *mesh) {
|
||||
Core::active.shader->setParam(uBasis, basis[0], jointsCount);
|
||||
mesh->renderModel(lara->level->extra.braid);
|
||||
}
|
||||
|
||||
} *braid;
|
||||
|
||||
Lara(IGame *game, int entity, bool home) : Character(game, entity, 1000), home(home), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), viewTarget(-1), braid(NULL) {
|
||||
|
||||
if (getEntity().type == TR::Entity::LARA) {
|
||||
if (getRoom().flags.water)
|
||||
@ -229,6 +391,9 @@ struct Lara : Character {
|
||||
arms[i].rot = quat(0, 0, 0, 1);
|
||||
arms[i].rotAbs = quat(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
if (level->extra.braid > -1)
|
||||
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
|
||||
/*
|
||||
pos = vec3(40448, 3584, 60928);
|
||||
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||
@ -236,7 +401,7 @@ struct Lara : Character {
|
||||
stand = STAND_ONWATER;
|
||||
animation.setAnim(ANIM_TO_ONWATER);
|
||||
updateEntity();
|
||||
*/
|
||||
*/
|
||||
#ifdef _DEBUG
|
||||
/*
|
||||
// gym
|
||||
@ -330,6 +495,10 @@ struct Lara : Character {
|
||||
#endif
|
||||
chestOffset = animation.getJoints(getMatrix(), 7).pos;
|
||||
}
|
||||
|
||||
virtual ~Lara() {
|
||||
delete braid;
|
||||
}
|
||||
|
||||
void wpnSet(Weapon::Type wType) {
|
||||
wpnCurrent = wType;
|
||||
@ -1663,6 +1832,8 @@ struct Lara : Character {
|
||||
updateEntity();
|
||||
}
|
||||
|
||||
if (braid)
|
||||
braid->update();
|
||||
}
|
||||
|
||||
virtual vec3& getPos() {
|
||||
@ -1866,16 +2037,20 @@ struct Lara : Character {
|
||||
Basis b(basis);
|
||||
b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f));
|
||||
b.translate(offset);
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
|
||||
Core::active.shader->setParam(uBasis, b);
|
||||
mesh->renderModel(level->extra.muzzleFlash);
|
||||
Core::setBlending(bmNone);
|
||||
}
|
||||
|
||||
virtual void render(Frustum *frustum, MeshBuilder *mesh) {
|
||||
Controller::render(frustum, mesh);
|
||||
chestOffset = animation.getJoints(getMatrix(), 7).pos; // TODO: move to update func
|
||||
|
||||
if (braid)
|
||||
braid->render(mesh);
|
||||
|
||||
if (wpnCurrent != Weapon::SHOTGUN && Core::pass != Core::passShadow && (arms[0].shotTimer < MUZZLE_FLASH_TIME || arms[1].shotTimer < MUZZLE_FLASH_TIME)) {
|
||||
mat4 matrix = getMatrix();
|
||||
Core::active.shader->setParam(uType, Shader::FLASH);
|
||||
|
@ -123,8 +123,8 @@ struct Level : IGame {
|
||||
level->renderEnvironment(room, pos, textures, 4);
|
||||
|
||||
// second pass - downsample it
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
// glDisable(GL_CULL_FACE);
|
||||
Core::setDepthTest(false);
|
||||
|
||||
level->setPassShader(Core::passFilter);
|
||||
Core::active.shader->setParam(uType, Shader::FILTER_DOWNSAMPLE);
|
||||
|
||||
@ -152,8 +152,7 @@ struct Level : IGame {
|
||||
}
|
||||
Core::setTarget(NULL);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
// glEnable(GL_CULL_FACE);
|
||||
Core::setDepthTest(true);
|
||||
}
|
||||
|
||||
void precessQueue() {
|
||||
@ -745,7 +744,7 @@ struct Level : IGame {
|
||||
initReflections();
|
||||
for (int i = 0; i < level.soundSourcesCount; i++) {
|
||||
TR::SoundSource &src = level.soundSources[i];
|
||||
lara->playSound(src.id, vec3(src.x, src.y, src.z), Sound::PAN | Sound::LOOP);
|
||||
lara->playSound(src.id, vec3(float(src.x), float(src.y), float(src.z)), Sound::PAN | Sound::LOOP);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,7 +350,7 @@ struct Bubble : Sprite {
|
||||
float speed;
|
||||
|
||||
Bubble(IGame *game, int entity) : Sprite(game, entity, true, Sprite::FRAME_RANDOM) {
|
||||
speed = (10.0f + randf() * 6.0) * 30.0f;
|
||||
speed = (10.0f + randf() * 6.0f) * 30.0f;
|
||||
// get water height => bubble life time
|
||||
TR::Entity &e = getEntity();
|
||||
int dx, dz;
|
||||
|
Loading…
x
Reference in New Issue
Block a user