mirror of
https://github.com/XProger/OpenLara.git
synced 2025-04-21 19:41:53 +02:00
fix normals, #3 movable blocks
This commit is contained in:
parent
bb9b3963d2
commit
ea0e1c87a1
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
@ -5,7 +5,7 @@
|
||||
#include "controller.h"
|
||||
#include "lara.h"
|
||||
|
||||
#define MAX_CLIP_PLANES 10
|
||||
#define MAX_CLIP_PLANES 16
|
||||
|
||||
#define CAMERA_OFFSET (1024.0f + 256.0f)
|
||||
|
||||
|
@ -107,6 +107,27 @@ struct Controller {
|
||||
return state = anim.state;
|
||||
}
|
||||
|
||||
bool canSetState(int state) {
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
|
||||
if (state == anim->state)
|
||||
return true;
|
||||
|
||||
int fIndex = int(animTime * 30.0f);
|
||||
|
||||
for (int i = 0; i < anim->scCount; i++) {
|
||||
TR::AnimState &s = level->states[anim->scOffset + i];
|
||||
if (s.state == state)
|
||||
for (int j = 0; j < s.rangesCount; j++) {
|
||||
TR::AnimRange &range = level->ranges[s.rangesOffset + j];
|
||||
if (anim->frameStart + fIndex >= range.low && anim->frameStart + fIndex <= range.high)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool setState(int state) {
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
|
||||
@ -183,19 +204,28 @@ struct Controller {
|
||||
return vec3(angle.x, angle.y);
|
||||
}
|
||||
|
||||
void turnToWall() {
|
||||
void alignToWall(float offset = 0.0f) {
|
||||
float fx = pos.x / 1024.0f;
|
||||
float fz = pos.z / 1024.0f;
|
||||
fx -= (int)fx;
|
||||
fz -= (int)fz;
|
||||
|
||||
float k;
|
||||
int k;
|
||||
if (fx > 1.0f - fz)
|
||||
k = fx < fz ? 0 : 1;
|
||||
else
|
||||
k = fx < fz ? 3 : 2;
|
||||
|
||||
angle.y = k * PI * 0.5f; // clamp angle to n*PI/2
|
||||
|
||||
if (offset != 0.0f) {
|
||||
vec3 dir = getDir() * (512.0f - offset);
|
||||
if (k % 2)
|
||||
pos.x = int(pos.x / 1024.0f) * 1024.0f + 512.0f + dir.x;
|
||||
else
|
||||
pos.z = int(pos.z / 1024.0f) * 1024.0f + 512.0f + dir.z;
|
||||
}
|
||||
updateEntity();
|
||||
}
|
||||
|
||||
virtual Box getBoundingBox() {
|
||||
|
@ -313,14 +313,14 @@ namespace Debug {
|
||||
|
||||
bool current = (int)p.x == x && (int)p.z == z;
|
||||
debugFloor(level, roomIndex, room.info.x + x * 1024, room.info.z + z * 1024);
|
||||
|
||||
/*
|
||||
if (current && s.boxIndex != 0xFFFF && level.boxes[s.boxIndex].overlap != 0xFFFF) {
|
||||
glColor4f(0.0f, 1.0f, 0.0f, 0.25f);
|
||||
debugBox(level.boxes[s.boxIndex]);
|
||||
glColor4f(1.0f, 1.0f, 0.0f, 0.25f);
|
||||
debugOverlaps(level, s.boxIndex);
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
@ -314,6 +314,9 @@ namespace TR {
|
||||
TRAP_DART = 39,
|
||||
TRAP_DARTGUN = 40,
|
||||
|
||||
BLOCK_1 = 48,
|
||||
BLOCK_2 = 49,
|
||||
|
||||
SWITCH = 55,
|
||||
SWITCH_WATER = 56,
|
||||
DOOR_1 = 57,
|
||||
|
154
src/lara.h
154
src/lara.h
@ -1,7 +1,10 @@
|
||||
#ifndef H_LARA
|
||||
#define H_LARA
|
||||
|
||||
/*****************************************/
|
||||
/* Desine sperare qui hic intras */
|
||||
/*****************************************/
|
||||
#include "controller.h"
|
||||
#include "trigger.h"
|
||||
|
||||
#define FAST_TURN_TIME 1.0f
|
||||
|
||||
@ -138,54 +141,52 @@ struct Lara : Controller {
|
||||
|
||||
Lara(TR::Level *level, int entity) : Controller(level, entity) {
|
||||
#ifdef _DEBUG
|
||||
/*
|
||||
/*
|
||||
// gym
|
||||
pos = vec3(43182, 2473, 51556);
|
||||
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||
getEntity().room = 12;
|
||||
*/
|
||||
/*
|
||||
|
||||
// level 2 (pool)
|
||||
pos = vec3(70067, -256, 29104);
|
||||
angle = vec3(0.0f, -0.68f, 0.0f);
|
||||
getEntity().room = 15;
|
||||
*/
|
||||
|
||||
// level 2 (blade)
|
||||
pos = vec3(27221, -1024, 29205);
|
||||
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||
getEntity().room = 61;
|
||||
|
||||
/*
|
||||
|
||||
// level 2 (wolf)
|
||||
pos = vec3(75671, -1024, 22862);
|
||||
angle = vec3(0.0f, -PI * 0.25f, 0.0f);
|
||||
getEntity().room = 13;
|
||||
*/
|
||||
|
||||
/*
|
||||
// level 2 (room 1)
|
||||
pos = vec3(31400, -2560, 25200);
|
||||
angle = vec3(0.0f, PI, 0.0f);
|
||||
getEntity().room = 43;
|
||||
|
||||
|
||||
// level 2 (medikit)
|
||||
pos = vec3(30800, -7936, 22131);
|
||||
angle = vec3(0.0f, 0.0f, 0.0f);
|
||||
getEntity().room = 58;
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
||||
// level 2 (block)
|
||||
pos = vec3(60843, 1024, 30557);
|
||||
angle = vec3(0.0f, PI, 0.0f);
|
||||
getEntity().room = 19;
|
||||
/*
|
||||
// level 3a
|
||||
pos = vec3(41015, 3584, 34494);
|
||||
angle = vec3(0.0f, -PI, 0.0f);
|
||||
getEntity().room = 51;
|
||||
*/
|
||||
/*
|
||||
|
||||
// level 1
|
||||
pos = vec3(20215, 6656, 52942);
|
||||
angle = vec3(0.0f, PI, 0.0f);
|
||||
getEntity().room = 14;
|
||||
*/
|
||||
*/
|
||||
updateEntity();
|
||||
#endif
|
||||
}
|
||||
@ -207,7 +208,7 @@ struct Lara : Controller {
|
||||
}
|
||||
outState = state;
|
||||
|
||||
turnToWall();
|
||||
alignToWall();
|
||||
dst.y -= pos.y - infoDst.floor;
|
||||
pos = dst; // set new position
|
||||
|
||||
@ -267,6 +268,10 @@ struct Lara : Controller {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkAngle(TR::angle rotation) {
|
||||
return fabsf(shortAngle(rotation, getEntity().rotation)) < PI * 0.25f;
|
||||
}
|
||||
|
||||
void doTrigger() {
|
||||
if (actionCommand) return;
|
||||
|
||||
@ -290,14 +295,14 @@ struct Lara : Controller {
|
||||
actionState = (isActive && stand == STAND_GROUND) ? STATE_SWITCH_UP : STATE_SWITCH_DOWN;
|
||||
if ((mask & ACTION) == 0 || state == actionState)
|
||||
return;
|
||||
if (fabsf(shortAngle(level->entities[info.trigCmd[0].args].rotation, e.rotation)) > PI * 0.25f) // TODO clamp angles
|
||||
if (!checkAngle(level->entities[info.trigCmd[0].args].rotation))
|
||||
return;
|
||||
break;
|
||||
case TR::Level::Trigger::KEY :
|
||||
actionState = STATE_USE_KEY;
|
||||
if (isActive || (mask & ACTION) == 0 || state == actionState) // TODO: STATE_USE_PUZZLE
|
||||
return;
|
||||
if (fabsf(shortAngle(level->entities[info.trigCmd[0].args].rotation, e.rotation)) > PI * 0.25f) // TODO clamp angles
|
||||
if (!checkAngle(level->entities[info.trigCmd[0].args].rotation))
|
||||
return;
|
||||
break;
|
||||
case TR::Level::Trigger::PICKUP :
|
||||
@ -479,7 +484,7 @@ struct Lara : Controller {
|
||||
} while (info.ceiling > p.y - LARA_HANG_OFFSET && info.roomAbove != 0xFF);
|
||||
|
||||
if (abs(int(info.floor - (p.y - LARA_HANG_OFFSET))) < 16) {
|
||||
turnToWall();
|
||||
alignToWall();
|
||||
pos = pos - getDir() * 96.0f; // TODO: collision wall offset
|
||||
pos.y = info.floor + LARA_HANG_OFFSET;
|
||||
updateEntity();
|
||||
@ -502,12 +507,65 @@ struct Lara : Controller {
|
||||
return state;
|
||||
}
|
||||
|
||||
float distTo(const TR::Entity &e) {
|
||||
return (pos - vec3(e.x, e.y, e.z)).length();
|
||||
}
|
||||
|
||||
Block* getBlock() {
|
||||
int x = getEntity().x;
|
||||
int y = getEntity().y;
|
||||
int z = getEntity().z;
|
||||
|
||||
for (int i = 0; i < level->entitiesCount; i++) {
|
||||
TR::Entity &e = level->entities[i];
|
||||
if ((e.type == TR::Entity::BLOCK_1 || e.type == TR::Entity::BLOCK_2) && e.y == y) {
|
||||
int dx = abs(e.x - x);
|
||||
int dz = abs(e.z - z);
|
||||
if ((dx <= (512 + 128) && dz <= (512 - 128)) ||
|
||||
(dx <= (512 - 128) && dz <= (512 + 128))) {
|
||||
|
||||
alignToWall();
|
||||
|
||||
Block *block = (Block*)e.controller;
|
||||
block->angle.y = angle.y;
|
||||
block->updateEntity();
|
||||
return block;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual int getStateGround() {
|
||||
angle.x = 0.0f;
|
||||
|
||||
if (mask == ACTION && doPickUp())
|
||||
if ((mask & ACTION) && doPickUp())
|
||||
return STATE_PICK_UP;
|
||||
|
||||
if ( (mask & (FORTH | ACTION)) == (FORTH | ACTION) && (animIndex == ANIM_STAND || animIndex == ANIM_STAND_NORMAL) ) {
|
||||
vec3 p = pos + getDir() * 64.0f;
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.z, info, true);
|
||||
int h = (int)pos.y - info.floor;
|
||||
|
||||
int aIndex = animIndex;
|
||||
if (info.floor == info.ceiling || h < 256 + 128) {
|
||||
; // do nothing
|
||||
} else if (h <= 2 * 256 + 128) {
|
||||
aIndex = ANIM_CLIMB_2;
|
||||
pos.y = info.floor + 512;
|
||||
} else if (h <= 3 * 256 + 128) {
|
||||
aIndex = ANIM_CLIMB_3;
|
||||
pos.y = info.floor + 768;
|
||||
} else if (h <= 7 * 256 + 128)
|
||||
aIndex = ANIM_CLIMB_JUMP;
|
||||
|
||||
if (aIndex != animIndex) {
|
||||
alignToWall();
|
||||
return setAnimation(aIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// hit test
|
||||
if (animIndex != ANIM_HIT_FRONT)
|
||||
@ -554,29 +612,18 @@ struct Lara : Controller {
|
||||
return STATE_STOP;
|
||||
}
|
||||
|
||||
if ( (mask & (FORTH | ACTION)) == (FORTH | ACTION) && (animIndex == ANIM_STAND || animIndex == ANIM_STAND_NORMAL) ) {
|
||||
vec3 p = pos + getDir() * 64.0f;
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.z, info, true);
|
||||
int h = (int)pos.y - info.floor;
|
||||
|
||||
int aIndex = animIndex;
|
||||
if (h < 256 + 128) {
|
||||
; // do nothing
|
||||
} else if (h <= 2 * 256 + 128) {
|
||||
aIndex = ANIM_CLIMB_2;
|
||||
pos.y = info.floor + 512;
|
||||
} else if (h <= 3 * 256 + 128) {
|
||||
aIndex = ANIM_CLIMB_3;
|
||||
pos.y = info.floor + 768;
|
||||
} else if (h <= 7 * 256 + 128)
|
||||
aIndex = ANIM_CLIMB_JUMP;
|
||||
|
||||
if (aIndex != animIndex) {
|
||||
turnToWall();
|
||||
updateEntity();
|
||||
return setAnimation(aIndex);
|
||||
if (mask & ACTION) {
|
||||
if (state == STATE_PUSH_PULL_READY && (mask & (FORTH | BACK))) {
|
||||
int pushState = (mask & FORTH) ? STATE_PUSH_BLOCK : STATE_PULL_BLOCK;
|
||||
Block *block = getBlock();
|
||||
if (canSetState(pushState) && block->doMove(mask & FORTH)) {
|
||||
alignToWall(128.0f);
|
||||
return pushState;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == STATE_PUSH_PULL_READY || getBlock())
|
||||
return STATE_PUSH_PULL_READY;
|
||||
}
|
||||
|
||||
// only dpad buttons pressed
|
||||
@ -629,10 +676,8 @@ struct Lara : Controller {
|
||||
TR::Level::FloorInfo info;
|
||||
vec3 p = pos + getDir() * 128.0f;
|
||||
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.z, info, true);
|
||||
if (info.floor - info.ceiling >= 768) {
|
||||
LOG("%d %d %d\n", info.floor, info.ceiling, info.floor - info.ceiling);
|
||||
return (mask & WALK) ? STATE_HANDSTAND : STATE_HANG_UP;
|
||||
}
|
||||
if (info.floor - info.ceiling >= 768)
|
||||
return (mask & WALK) ? STATE_HANDSTAND : STATE_HANG_UP;
|
||||
}
|
||||
return STATE_HANG;
|
||||
}
|
||||
@ -983,9 +1028,18 @@ struct Lara : Controller {
|
||||
int fSize = sizeof(TR::AnimFrame) + getModel().mCount * sizeof(uint16) * 2;
|
||||
TR::AnimFrame *frame = (TR::AnimFrame*)&level->frameData[((anim->frameOffset + (int(animTime * 30.0f / anim->frameRate) * fSize)) >> 1)];
|
||||
|
||||
f = info.floor - (p.y + frame->box.maxY);
|
||||
c = (p.y + frame->box.minY) - info.ceiling;
|
||||
canPassGap = f >= -256 && c >= (state == STATE_UP_JUMP ? 0.0f : -256);
|
||||
f = info.floor - (pos.y + frame->box.maxY);
|
||||
c = (pos.y + frame->box.minY) - info.ceiling;
|
||||
canPassGap = f >= -256;
|
||||
if (canPassGap && c < 0) {
|
||||
if (c > -256) { // position correction for ceiling step (less than 256)
|
||||
pos.y -= c;
|
||||
if (velocity.y < 0.0f) {
|
||||
velocity.y = 0.0f;
|
||||
}
|
||||
} else
|
||||
canPassGap = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STAND_GROUND : {
|
||||
|
@ -94,6 +94,10 @@ struct Level {
|
||||
case TR::Entity::TRAP_DARTGUN :
|
||||
entity.controller = new Dartgun(&level, i);
|
||||
break;
|
||||
case TR::Entity::BLOCK_1 :
|
||||
case TR::Entity::BLOCK_2 :
|
||||
entity.controller = new Block(&level, i);
|
||||
break;
|
||||
case TR::Entity::SWITCH :
|
||||
case TR::Entity::SWITCH_WATER :
|
||||
case TR::Entity::HOLE_PUZZLE :
|
||||
|
51
src/mesh.h
51
src/mesh.h
@ -58,6 +58,19 @@ struct Mesh {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define CHECK_NORMAL(n) \
|
||||
if (!(n.x | n.y | n.z)) {\
|
||||
vec3 o(mVertices[f.vertices[0]]);\
|
||||
vec3 a = o - mVertices[f.vertices[1]];\
|
||||
vec3 b = o - mVertices[f.vertices[2]];\
|
||||
o = b.cross(a).normal() * 16300.0f;\
|
||||
n.x = (int)o.x;\
|
||||
n.y = (int)o.y;\
|
||||
n.z = (int)o.z;\
|
||||
}\
|
||||
|
||||
|
||||
struct MeshBuilder {
|
||||
// rooms
|
||||
struct RoomRange {
|
||||
@ -253,7 +266,7 @@ struct MeshBuilder {
|
||||
int16 *lights = NULL;
|
||||
int nCount = ptr->nCount;
|
||||
|
||||
if (ptr->nCount > 0) {
|
||||
if (nCount > 0) {
|
||||
normals = (TR::Vertex*)&ptr->normals;
|
||||
OFFSET(ptr->nCount * sizeof(TR::Vertex));
|
||||
} else {
|
||||
@ -262,6 +275,7 @@ struct MeshBuilder {
|
||||
}
|
||||
|
||||
int vStart = vCount;
|
||||
short4 pn = { 0 };
|
||||
// rectangles
|
||||
for (int j = 0; j < ptr->rCount; j++) {
|
||||
TR::Rectangle &f = ((TR::Rectangle*)&ptr->rectangles)[j];
|
||||
@ -270,19 +284,18 @@ struct MeshBuilder {
|
||||
addQuad(indices, iCount, vCount, vStart, vertices, &t);
|
||||
|
||||
for (int k = 0; k < 4; k++) {
|
||||
auto &v = mVertices[f.vertices[k]];
|
||||
uint16 idx = f.vertices[k];
|
||||
TR::Vertex &v = mVertices[idx];
|
||||
|
||||
vertices[vCount].coord = { v.x, v.y, v.z, 0 };
|
||||
vertices[vCount].coord = { v.x, v.y, v.z, 0 };
|
||||
|
||||
if (nCount > 0) {
|
||||
TR::Vertex &n = normals[f.vertices[k]];
|
||||
if (n.x | n.y | n.z)
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
else
|
||||
vertices[vCount].normal = vertices[vCount].coord;
|
||||
if (normals) {
|
||||
TR::Vertex &n = normals[idx];
|
||||
CHECK_NORMAL(n);
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
vertices[vCount].color = { 255, 255, 255, 255 };
|
||||
} else {
|
||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||
uint8 a = 255 - (lights[idx] >> 5);
|
||||
vertices[vCount].normal = { 0, 0, 0, 1 };
|
||||
vertices[vCount].color = { a, a, a, 255 };
|
||||
}
|
||||
@ -304,10 +317,8 @@ struct MeshBuilder {
|
||||
|
||||
if (nCount > 0) {
|
||||
TR::Vertex &n = normals[f.vertices[k]];
|
||||
if (n.x | n.y | n.z)
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
else
|
||||
vertices[vCount].normal = vertices[vCount].coord;
|
||||
CHECK_NORMAL(n);
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
vertices[vCount].color = { 255, 255, 255, 255 };
|
||||
} else {
|
||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||
@ -333,10 +344,8 @@ struct MeshBuilder {
|
||||
|
||||
if (nCount > 0) {
|
||||
TR::Vertex &n = normals[f.vertices[k]];
|
||||
if (n.x | n.y | n.z)
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
else
|
||||
vertices[vCount].normal = vertices[vCount].coord;
|
||||
CHECK_NORMAL(n);
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
vertices[vCount].color = { c.r, c.g, c.b, 255 };
|
||||
} else {
|
||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||
@ -362,10 +371,8 @@ struct MeshBuilder {
|
||||
|
||||
if (nCount > 0) {
|
||||
TR::Vertex &n = normals[f.vertices[k]];
|
||||
if (n.x | n.y | n.z)
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
else
|
||||
vertices[vCount].normal = vertices[vCount].coord;
|
||||
CHECK_NORMAL(n);
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
vertices[vCount].color = { c.r, c.g, c.b, 255 };
|
||||
} else {
|
||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||
|
@ -127,4 +127,52 @@ struct Boulder : Trigger {
|
||||
}
|
||||
};
|
||||
|
||||
// not a trigger
|
||||
struct Block : Controller {
|
||||
|
||||
enum {
|
||||
STATE_STAND = 1,
|
||||
STATE_PUSH,
|
||||
STATE_PULL,
|
||||
};
|
||||
|
||||
Block(TR::Level *level, int entity) : Controller(level, entity) {
|
||||
updateFloor(true);
|
||||
}
|
||||
|
||||
void updateFloor(bool rise) {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||
if (info.roomNext != 0xFF)
|
||||
e.room = info.roomNext;
|
||||
int dx, dz;
|
||||
TR::Room::Sector &s = level->getSector(e.room, e.x, e.z, dx, dz);
|
||||
s.floor += rise ? -4 : 4;
|
||||
}
|
||||
|
||||
bool doMove(bool push) {
|
||||
// check floor height of next floor
|
||||
vec3 dir = getDir() * (push ? 1024.0f : -2048.0f);
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x + (int)dir.x, e.z + (int)dir.z, info, true);
|
||||
if ((info.slantX | info.slantZ) || info.floor != e.y)
|
||||
return false;
|
||||
if (!setState(push ? STATE_PUSH : STATE_PULL))
|
||||
return false;
|
||||
updateFloor(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
if (state == STATE_STAND) return;
|
||||
updateAnimation(true);
|
||||
if (state == STATE_STAND) {
|
||||
updateEntity();
|
||||
updateFloor(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user