1
0
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:
XProger 2016-11-01 04:13:01 +03:00
parent bb9b3963d2
commit ea0e1c87a1
9 changed files with 223 additions and 77 deletions

Binary file not shown.

View File

@ -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)

View File

@ -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() {

View File

@ -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);
}

View File

@ -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,

View File

@ -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 : {

View File

@ -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 :

View File

@ -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);

View File

@ -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