mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-11 15:45:05 +02:00
free camera mode (hold R and L stick)
This commit is contained in:
96
src/camera.h
96
src/camera.h
@@ -31,6 +31,10 @@
|
||||
#define CAM_LOOK_ANGLE_XMIN (-75.0f * DEG2RAD)
|
||||
#define CAM_LOOK_ANGLE_Y ( 80.0f * DEG2RAD)
|
||||
|
||||
#define SPECTATOR_TIMER 1.0f
|
||||
#define SPECTATOR_POS_SPEED 4096.0f
|
||||
#define SPECTATOR_ROT_SPEED PIH
|
||||
#define SPECTATOR_SMOOTH 4.0f
|
||||
|
||||
struct Camera : ICamera {
|
||||
IGame *game;
|
||||
@@ -52,9 +56,18 @@ struct Camera : ICamera {
|
||||
int speed;
|
||||
bool smooth;
|
||||
|
||||
bool spectator;
|
||||
vec3 specPos, specPosSmooth;
|
||||
vec3 specRot, specRotSmooth;
|
||||
float specTimer;
|
||||
int16 specRoom;
|
||||
|
||||
Camera(IGame *game, Character *owner) : ICamera(), game(game), level(game->getLevel()), frustum(new Frustum()), timer(-1.0f), viewIndex(-1), viewIndexLast(-1), viewTarget(NULL) {
|
||||
this->owner = owner;
|
||||
reset();
|
||||
|
||||
spectator = false;
|
||||
specTimer = 0.0f;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
@@ -92,7 +105,7 @@ struct Camera : ICamera {
|
||||
}
|
||||
|
||||
virtual int getRoomIndex() const {
|
||||
return eye.room;
|
||||
return spectator ? specRoom : eye.room;
|
||||
}
|
||||
|
||||
void updateListener(const mat4 &matrix) {
|
||||
@@ -404,8 +417,11 @@ struct Camera : ICamera {
|
||||
if (mode == MODE_LOOK) {
|
||||
float d = 3.0f * Core::deltaTime;
|
||||
|
||||
lookAngle.x += Input::joy[cameraIndex].L.y * d;
|
||||
lookAngle.y += Input::joy[cameraIndex].L.x * d;
|
||||
vec2 L = Input::joy[cameraIndex].L;
|
||||
if (L.length() < JOY_DEAD_ZONE) L = vec2(0.0f);
|
||||
|
||||
lookAngle.x += L.y * d;
|
||||
lookAngle.y += L.x * d;
|
||||
|
||||
if (Input::state[cameraIndex][cUp]) lookAngle.x -= d;
|
||||
if (Input::state[cameraIndex][cDown]) lookAngle.x += d;
|
||||
@@ -504,11 +520,6 @@ struct Camera : ICamera {
|
||||
|
||||
level->getSector(eye.room, eye.pos);
|
||||
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
|
||||
updateListener(mViewInv * Input::hmd.head);
|
||||
else
|
||||
updateListener(mViewInv);
|
||||
|
||||
smooth = true;
|
||||
|
||||
viewIndexLast = viewIndex;
|
||||
@@ -527,6 +538,75 @@ struct Camera : ICamera {
|
||||
viewTargetLast = viewTarget;
|
||||
viewTarget = NULL;
|
||||
}
|
||||
|
||||
Input::Joystick &specJoy = Input::joy[cameraIndex];
|
||||
|
||||
if (specJoy.down[jkL] && specJoy.down[jkR]) {
|
||||
specTimer += Core::deltaTime;
|
||||
if (specTimer > SPECTATOR_TIMER) {
|
||||
spectator = !spectator;
|
||||
specTimer = 0.0f;
|
||||
specPos = eye.pos;
|
||||
specRot = targetAngle;
|
||||
specRot.z = PI;
|
||||
specRot.y += PI;
|
||||
specPosSmooth = specPos;
|
||||
specRotSmooth = specRot;
|
||||
specRoom = eye.room;
|
||||
}
|
||||
} else {
|
||||
specTimer = 0.0f;
|
||||
}
|
||||
|
||||
if (spectator) {
|
||||
vec2 L = specJoy.L;
|
||||
vec2 R = specJoy.R;
|
||||
float U = specJoy.RT;
|
||||
float D = specJoy.LT;
|
||||
|
||||
// apply dead zone
|
||||
if (L.length() < 0.05f) L = vec2(0.0f);
|
||||
if (R.length() < 0.05f) R = vec2(0.0f);
|
||||
if (U < 0.05) U = 0.0f;
|
||||
if (D < 0.05) D = 0.0f;
|
||||
|
||||
vec3 dir = vec3(L.x, D - U, L.y) * (SPECTATOR_POS_SPEED * Core::deltaTime);
|
||||
vec2 rot = R * (SPECTATOR_ROT_SPEED * Core::deltaTime);
|
||||
|
||||
vec3 d = vec3(specRot.x, specRot.y);
|
||||
vec3 r = d.cross(vec3(0.0f, 1.0f, 0.0f)).normal();
|
||||
|
||||
specPos += r * dir.x + vec3(0.0f, dir.y, 0.0f) + d * dir.z;
|
||||
|
||||
specRot.x += rot.y;
|
||||
specRot.y += rot.x;
|
||||
specRot.x = clamp(specRot.x, -PIH, +PIH);
|
||||
|
||||
specPosSmooth = specPosSmooth.lerp(specPos, SPECTATOR_SMOOTH * Core::deltaTime);
|
||||
specRotSmooth = specRotSmooth.lerp(specRot, SPECTATOR_SMOOTH * Core::deltaTime);
|
||||
|
||||
mViewInv.identity();
|
||||
mViewInv.translate(specPosSmooth);
|
||||
mViewInv.rotateY(specRotSmooth.y);
|
||||
mViewInv.rotateX(specRotSmooth.x);
|
||||
mViewInv.rotateZ(specRotSmooth.z);
|
||||
|
||||
level->getSector(specRoom, specPos);
|
||||
/*
|
||||
for (int i = 0; i < level->roomsCount; i++) {
|
||||
TR::Room &room = level->rooms[i];
|
||||
if (room.contains(specPos)) {
|
||||
eye.room = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
|
||||
updateListener(mViewInv * Input::hmd.head);
|
||||
else
|
||||
updateListener(mViewInv);
|
||||
}
|
||||
|
||||
virtual void setup(bool calcMatrices) {
|
||||
|
@@ -1893,6 +1893,10 @@ namespace TR {
|
||||
uint32 meshIndex; // index into static meshes array
|
||||
} *meshes;
|
||||
|
||||
bool contains(const vec3 &p) const {
|
||||
return p.x >= info.x && p.x <= info.x + xSectors * 1024 && p.z >= info.z && p.z <= info.z + zSectors * 1024 && p.y >= info.yTop && p.y <= info.yBottom;
|
||||
}
|
||||
|
||||
vec3 getOffset() const {
|
||||
return vec3(float(info.x), 0.0f, float(info.z));
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@
|
||||
|
||||
#define INPUT_JOY_COUNT 4
|
||||
#define MAX_PLAYERS COUNT(Core::settings.controls)
|
||||
#define JOY_DEAD_ZONE 0.3f
|
||||
|
||||
namespace Input {
|
||||
InputKey lastKey;
|
||||
|
@@ -296,7 +296,8 @@ const char *helpText =
|
||||
"Swan dive - Up & Walk & Jump@"
|
||||
"First Person View - Look & Action@"
|
||||
"DOZY on - Look & Duck & Action & Jump@"
|
||||
"DOZY off - Walk";
|
||||
"DOZY off - Walk@"
|
||||
"Free Camera - hold L & R stick";
|
||||
|
||||
#include "lang/en.h"
|
||||
#include "lang/fr.h"
|
||||
|
27
src/lara.h
27
src/lara.h
@@ -3102,28 +3102,35 @@ struct Lara : Character {
|
||||
if (input & LOOK)
|
||||
return input;
|
||||
|
||||
if (camera->spectator)
|
||||
return input;
|
||||
|
||||
Input::Joystick &joy = Input::joy[Core::settings.controls[pid].joyIndex];
|
||||
|
||||
if (!((state == STATE_STOP || state == STATE_SURF_TREAD || state == STATE_HANG) && fabsf(joy.L.x) < 0.5f && fabsf(joy.L.y) < 0.5f)) {
|
||||
vec2 L = joy.L;
|
||||
|
||||
if (L.length() < JOY_DEAD_ZONE) L = vec2(0.0f); // dead zone
|
||||
|
||||
if (!((state == STATE_STOP || state == STATE_SURF_TREAD || state == STATE_HANG) && fabsf(L.x) < 0.5f && fabsf(L.y) < 0.5f)) {
|
||||
bool moving = state == STATE_RUN || state == STATE_WALK || state == STATE_BACK || state == STATE_FAST_BACK || state == STATE_SURF_SWIM || state == STATE_SURF_BACK || state == STATE_FORWARD_JUMP;
|
||||
|
||||
if (!moving) {
|
||||
if (fabsf(joy.L.x) < fabsf(joy.L.y))
|
||||
joy.L.x = 0.0f;
|
||||
if (fabsf(L.x) < fabsf(L.y))
|
||||
L.x = 0.0f;
|
||||
else
|
||||
joy.L.y = 0.0f;
|
||||
L.y = 0.0f;
|
||||
}
|
||||
|
||||
if (joy.L.x != 0.0f) {
|
||||
input |= (joy.L.x < 0.0f) ? LEFT : RIGHT;
|
||||
if (L.x != 0.0f) {
|
||||
input |= (L.x < 0.0f) ? LEFT : RIGHT;
|
||||
if (moving || stand == STAND_UNDERWATER || stand == STAND_ONWATER)
|
||||
rotFactor.y = min(fabsf(joy.L.x) / 0.9f, 1.0f);
|
||||
rotFactor.y = min(fabsf(L.x) / 0.9f, 1.0f);
|
||||
}
|
||||
|
||||
if (joy.L.y != 0.0f) {
|
||||
input |= (joy.L.y < 0.0f) ? FORTH : BACK;
|
||||
if (L.y != 0.0f) {
|
||||
input |= (L.y < 0.0f) ? FORTH : BACK;
|
||||
if (stand == STAND_UNDERWATER)
|
||||
rotFactor.x = min(fabsf(joy.L.y) / 0.9f, 1.0f);
|
||||
rotFactor.x = min(fabsf(L.y) / 0.9f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -103,15 +103,8 @@ JoyKey joyToInputKey(int code) {
|
||||
return jkNone;
|
||||
}
|
||||
|
||||
#define JOY_DEAD_ZONE_STICK 0.3f
|
||||
#define JOY_DEAD_ZONE_TRIGGER 0.01f
|
||||
|
||||
vec2 joyAxis(float x, float y) {
|
||||
if (fabsf(x) > JOY_DEAD_ZONE_STICK || fabsf(y) > JOY_DEAD_ZONE_STICK)
|
||||
return vec2(x, y);
|
||||
return vec2(0.0f);
|
||||
}
|
||||
|
||||
vec2 joyTrigger(float x) {
|
||||
return vec2(x > JOY_DEAD_ZONE_TRIGGER ? x : 0.0f, 0.0f);
|
||||
}
|
||||
@@ -146,8 +139,8 @@ void joyUpdate() {
|
||||
Input::setJoyPos(j, key, joyTrigger(state.analogButton[i]));
|
||||
}
|
||||
|
||||
Input::setJoyPos(j, jkL, joyAxis(state.axis[0], state.axis[1]));
|
||||
Input::setJoyPos(j, jkR, joyAxis(state.axis[2], state.axis[3]));
|
||||
Input::setJoyPos(j, jkL, vec2(state.axis[0], state.axis[1]));
|
||||
Input::setJoyPos(j, jkR, vec2(state.axis[2], state.axis[3]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -115,7 +115,6 @@ DWORD (WINAPI *XInputSetState) (DWORD dwUserIndex, XINPUT_VIBRATION* pVibration)
|
||||
void (WINAPI *XInputEnable) (BOOL enable) = NULL;
|
||||
#define XInputGetProc(x) (x = (decltype(x))GetProcAddress(h, #x))
|
||||
|
||||
#define JOY_DEAD_ZONE_STICK 0.3f
|
||||
#define JOY_DEAD_ZONE_TRIGGER 0.01f
|
||||
#define JOY_MIN_UPDATE_FX_TIME 50
|
||||
|
||||
@@ -188,15 +187,10 @@ float joyAxis(int x, int xMin, int xMax) {
|
||||
vec2 joyDir(float ax, float ay) {
|
||||
vec2 dir = vec2(ax, ay);
|
||||
float dist = min(1.0f, dir.length());
|
||||
if (dist < JOY_DEAD_ZONE_STICK) dist = 0.0f;
|
||||
|
||||
return dir.normal() * dist;
|
||||
}
|
||||
|
||||
int joyDeadZone(int value, int zone) {
|
||||
return (value < -zone || value > zone) ? value : 0;
|
||||
}
|
||||
|
||||
void joyUpdate() {
|
||||
for (int j = 0; j < INPUT_JOY_COUNT; j++) {
|
||||
if (!joyDevice[j].ready) continue;
|
||||
@@ -208,12 +202,12 @@ void joyUpdate() {
|
||||
if (XInputGetState(j, &state) == ERROR_SUCCESS) {
|
||||
//osJoyVibrate(j, state.Gamepad.bLeftTrigger / 255.0f, state.Gamepad.bRightTrigger / 255.0f); // vibration test
|
||||
|
||||
Input::setJoyPos(j, jkL, joyDir(joyAxis(joyDeadZone( state.Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE), -32768, 32767),
|
||||
joyAxis(joyDeadZone(-state.Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE), -32768, 32767)));
|
||||
Input::setJoyPos(j, jkR, joyDir(joyAxis(joyDeadZone( state.Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE), -32768, 32767),
|
||||
joyAxis(joyDeadZone(-state.Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE), -32768, 32767)));
|
||||
Input::setJoyPos(j, jkLT, vec2(joyDeadZone(state.Gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / 255.0f, 0.0f));
|
||||
Input::setJoyPos(j, jkRT, vec2(joyDeadZone(state.Gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / 255.0f, 0.0f));
|
||||
Input::setJoyPos(j, jkL, joyDir(joyAxis( state.Gamepad.sThumbLX, -32768, 32767),
|
||||
joyAxis(-state.Gamepad.sThumbLY, -32768, 32767)));
|
||||
Input::setJoyPos(j, jkR, joyDir(joyAxis( state.Gamepad.sThumbRX, -32768, 32767),
|
||||
joyAxis(-state.Gamepad.sThumbRY, -32768, 32767)));
|
||||
Input::setJoyPos(j, jkLT, vec2(state.Gamepad.bLeftTrigger / 255.0f, 0.0f));
|
||||
Input::setJoyPos(j, jkRT, vec2(state.Gamepad.bRightTrigger/ 255.0f, 0.0f));
|
||||
|
||||
static const JoyKey keys[] = { jkUp, jkDown, jkLeft, jkRight, jkStart, jkSelect, jkL, jkR, jkLB, jkRB, jkNone, jkNone, jkA, jkB, jkX, jkY };
|
||||
for (int i = 0; i < 16; i++)
|
||||
|
Reference in New Issue
Block a user