Skip to content

Commit d5d2ed4

Browse files
authored
Vanilla-like camera (#894)
#866 Handles in-game camera; dialog camera is "look-a-like" and requires further investigation.
1 parent 2a7b9e7 commit d5d2ed4

15 files changed

Lines changed: 531 additions & 406 deletions

game/camera.cpp

Lines changed: 391 additions & 296 deletions
Large diffs are not rendered by default.

game/camera.h

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Camera final {
3030
Dive,
3131
Fall,
3232
Cutscene,
33+
FirstPerson,
3334
};
3435

3536
enum MarvinMode {
@@ -49,7 +50,7 @@ class Camera final {
4950
void reset(const Npc* pl);
5051

5152
void save(Serialize &s);
52-
void load(Serialize &s,Npc* pl);
53+
void load(Serialize &s, Npc* pl);
5354

5455
void changeZoom(int delta);
5556
void setViewport(uint32_t w, uint32_t h);
@@ -62,7 +63,7 @@ class Camera final {
6263
void moveLeft(uint64_t dt);
6364
void moveRight(uint64_t dt);
6465

65-
void setMode(Mode m);
66+
void setMode(const Mode m);
6667
void setMarvinMode(MarvinMode m);
6768
bool isMarvin() const;
6869
bool isFree() const;
@@ -85,17 +86,15 @@ class Camera final {
8586
void tick(uint64_t dt);
8687
void debugDraw(DbgPainter& p);
8788

88-
Tempest::PointF spin() const;
89-
Tempest::PointF destSpin() const;
90-
91-
Tempest::Vec3 destPosition() const;
89+
Tempest::PointF spin() const;
90+
Tempest::Vec3 destTarget() const;
91+
float azimuth() const;
9292

9393
void setSpin(const Tempest::PointF& p);
94-
void setDestSpin(const Tempest::PointF& p);
94+
void setTarget(const Tempest::Vec3& pos);
9595

96+
void setAngles(const Tempest::PointF& pos);
9697
void setPosition(const Tempest::Vec3& pos);
97-
void setDestPosition(const Tempest::Vec3& pos);
98-
9998
void setDialogDistance(float d);
10099

101100
void onRotateMouse(const Tempest::PointF& dpos);
@@ -119,29 +118,34 @@ class Camera final {
119118
float zFar() const;
120119

121120
private:
121+
struct Pin {
122+
Tempest::Vec3 origin = {};
123+
Tempest::Vec3 spin = {};
124+
};
125+
122126
struct State {
123127
float range = 3.f;
124128
Tempest::Vec3 spin = {};
125129
Tempest::Vec3 target = {};
126130
};
127131

128-
struct Pin {
129-
Tempest::Vec3 origin = {};
130-
Tempest::Vec3 spin = {};
132+
struct Interpolated {
133+
Tempest::Vec3 target = {};
134+
Tempest::Vec3 rotOffset = {};
131135
};
132136

133-
Tempest::Vec3 cameraPos = {};
134-
Tempest::Vec3 origin = {};
135-
Tempest::Vec3 rotOffset = {};
136-
Tempest::Vec3 offsetAng = {};
137-
State src, dst;
138-
137+
State state;
138+
Interpolated inter;
139139
Pin pin;
140140

141-
float dlgDist = 0;
142-
float userRange = 0.13f;
141+
Tempest::Vec3 origin = {};
142+
Tempest::Vec3 angles = {};
143+
Tempest::Vec3 veloTrans = {};
144+
float userRange = 0;
145+
143146
float targetVelo = 0;
144-
float veloTrans = 0;
147+
148+
float dlgRange = 0;
145149

146150
Tempest::Matrix4x4 proj;
147151
uint32_t vpWidth=0;
@@ -159,29 +163,30 @@ class Camera final {
159163

160164
mutable int raysCasted = 0;
161165

162-
static float maxDist;
163-
static float baseSpeeed;
164-
static float offsetAngleMul;
165166
static const float minLength;
166167

167-
void calcControlPoints(float dtF);
168+
void tickFirstPerson(float dtF);
169+
void tickThirdPerson(float dtF);
168170

169-
Tempest::Vec3 calcOffsetAngles(const Tempest::Vec3& srcOrigin, const Tempest::Vec3& target) const;
170-
Tempest::Vec3 calcOffsetAngles(Tempest::Vec3 srcOrigin, Tempest::Vec3 dstOrigin, Tempest::Vec3 target) const;
171-
Tempest::Vec3 calcCameraColision(const Tempest::Vec3& target, const Tempest::Vec3& origin, const Tempest::Vec3& rotSpin, float dist) const;
171+
Tempest::Vec3 clampRotation(Tempest::Vec3 spin);
172+
float calcCameraColision(const Tempest::Vec3& target, const Tempest::Vec3& dir, const Tempest::Vec3& rotSpin, float dist) const;
173+
Tempest::Vec3 calcCameraColision(const Tempest::Vec3& from, const Tempest::Vec3& dir) const;
174+
175+
Tempest::Vec3 calcLookAtAngles(const Tempest::Vec3& origin, const Tempest::Vec3& target,
176+
const Tempest::Vec3& rotOffset, const Tempest::Vec3& defSpin) const;
172177

173178
void implMove(Tempest::KeyEvent::KeyType t, uint64_t dt);
179+
174180
Tempest::Matrix4x4 mkView (const Tempest::Vec3& pos, const Tempest::Vec3& spin) const;
175181
Tempest::Matrix4x4 mkRotation(const Tempest::Vec3& spin) const;
176182
Tempest::Matrix4x4 mkViewShadow(const Tempest::Vec3& cameraPos, float rotation,
177183
const Tempest::Matrix4x4& viewProj, const Tempest::Vec3& lightDir, size_t layer) const;
178184
Tempest::Matrix4x4 mkViewShadowVsm(const Tempest::Vec3& cameraPos, const Tempest::Vec3& ldir) const;
179-
void resetDst();
180185

181-
void clampRotation(Tempest::Vec3& spin);
186+
Tempest::Vec3 followTarget(Tempest::Vec3 pos, Tempest::Vec3 dest, float dtF);
187+
Tempest::Vec3 followTrans (Tempest::Vec3 pos, Tempest::Vec3 dest, float dtF, float velo);
188+
Tempest::Vec3 followRot (Tempest::Vec3 spin, Tempest::Vec3 dest, float dtF, float velo);
182189

183-
void followCamera(Tempest::Vec3& pos, Tempest::Vec3 dest, float dtF);
184-
void followPos (Tempest::Vec3& pos, Tempest::Vec3 dest, float dtF);
185190
void followAng (Tempest::Vec3& spin, Tempest::Vec3 dest, float dtF);
186191
static void followAng (float& ang, float dest, float speed, float dtF);
187192

game/game/definitions/cameradefinitions.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
#include "cameradefinitions.h"
22

3+
#include <Tempest/Log>
4+
#include <zenkit/vobs/Camera.hh>
5+
36
#include "gothic.h"
47
#include "utils/string_frm.h"
58

9+
using namespace Tempest;
10+
611
CameraDefinitions::CameraDefinitions() {
712
auto vm = Gothic::inst().createPhoenixVm("Camera.dat");
813

@@ -28,6 +33,28 @@ CameraDefinitions::CameraDefinitions() {
2833
camModSwim = getCam("CAMMODSWIM");
2934
camModDive = getCam("CAMMODDIVE");
3035
camModFall = getCam("CAMMODFALL");
36+
37+
// dialog presets: unused yet
38+
std::vector<zenkit::VCutsceneCamera> cameras;
39+
try {
40+
std::unique_ptr<zenkit::Read> read;
41+
auto zen = Resources::openReader("DialogCams.ZEN", read);
42+
43+
while(!read->eof()) {
44+
zenkit::ArchiveObject obj {};
45+
zenkit::VCutsceneCamera preset {};
46+
zen->read_object_begin(obj);
47+
preset.load(*zen, Gothic::inst().version().game == 1 ? zenkit::GameVersion::GOTHIC_1
48+
: zenkit::GameVersion::GOTHIC_2);
49+
cameras.emplace_back(std::move(preset));
50+
if(!zen->read_object_end()) {
51+
zen->skip_object(true);
52+
}
53+
}
54+
}
55+
catch(...) {
56+
Log::e("unable to load Zen-file: \"DialogCams.ZEN\"");
57+
}
3158
}
3259

3360
const zenkit::ICamera& CameraDefinitions::mobsiCam(std::string_view tag, std::string_view pos) const {

game/game/playercontrol.cpp

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,9 @@ bool PlayerControl::isPressed(KeyCodec::Action a) const {
247247
return ctrl[a];
248248
}
249249

250-
void PlayerControl::onRotateMouse(float dAngle) {
251-
dAngle = std::max(-40.f,std::min(dAngle,40.f));
252-
rotMouse += dAngle*0.3f;
253-
}
254-
255-
void PlayerControl::onRotateMouseDy(float dAngle) {
256-
dAngle = std::max(-100.f,std::min(dAngle,100.f));
257-
rotMouseY += dAngle*0.2f;
250+
void PlayerControl::onRotateMouse(float dAngleX, float dAngleY) {
251+
rotMouse += dAngleX;
252+
rotMouseY += dAngleY;
258253
}
259254

260255
void PlayerControl::tickFocus() {
@@ -563,8 +558,6 @@ bool PlayerControl::tickMove(uint64_t dt) {
563558
if(pl==nullptr)
564559
return true;
565560

566-
static const float speedRotX = 750.f;
567-
rotMouse = std::min(std::abs(rotMouse), speedRotX*dtF) * (rotMouse>=0 ? 1 : -1);
568561
implMove(dt);
569562

570563
float runAngle = pl->runAngle();
@@ -664,7 +657,7 @@ void PlayerControl::implMove(uint64_t dt) {
664657
return;
665658
}
666659

667-
int rotation=0;
660+
int rotation = 0;
668661
if(allowRot) {
669662
if(this->wantsToTurnLeft()) {
670663
rot += rspeed;
@@ -680,7 +673,7 @@ void PlayerControl::implMove(uint64_t dt) {
680673
if(rotMouse>0)
681674
rotation = -1; else
682675
rotation = 1;
683-
rot +=rotMouse;
676+
rot += rotMouse;
684677
rotMouse = 0;
685678
}
686679
rotY+=rotMouseY;
@@ -1034,29 +1027,17 @@ void PlayerControl::quitPicklock(Npc& pl) {
10341027

10351028
void PlayerControl::assignRunAngle(Npc& pl, float rotation, uint64_t dt) {
10361029
float dtF = (float(dt)/1000.f);
1037-
float angle = pl.rotation();
1038-
float dangle = (rotation-angle)/dtF;
1039-
float sgn = (dangle>0 ? 1 : -1);
1040-
auto& wrld = pl.world();
1030+
auto camera = Gothic::inst().camera();
10411031

1042-
if(std::fabs(dangle)<0.1f || pl.walkMode()!=WalkBit::WM_Run) {
1043-
if(runAngleSmooth<wrld.tickCount())
1044-
runAngleDest = 0;
1045-
return;
1032+
float dest = 0;
1033+
if(camera!=nullptr && pl.walkMode()==WalkBit::WM_Run && pl.bodyState()==BS_RUN) {
1034+
const float az = camera->azimuth();
1035+
const float maxV = 14.5f;
1036+
dest = std::min(std::abs(az), maxV)*(az>=0 ? 1 : -1);
10461037
}
10471038

1048-
const float maxV = 15.0f;
1049-
dangle = std::pow(std::abs(dangle)/maxV,2.f)*maxV*sgn;
1050-
1051-
float dest = 0;
1052-
if(angle<rotation)
1053-
dest = std::min( dangle,maxV);
1054-
if(angle>rotation)
1055-
dest = -std::min(-dangle,maxV);
1056-
1057-
float a = std::clamp(dtF*2.5f, 0.f, 1.f);
1058-
runAngleDest = runAngleDest*(1.f-a)+dest*a;
1059-
runAngleSmooth = wrld.tickCount() + 200;
1039+
float a = std::min(dtF*5.f, 1.f);
1040+
runAngleDest = runAngleDest*(1.f-a)+dest*a;
10601041
}
10611042

10621043
void PlayerControl::setAnimRotate(Npc& pl, float rotation, int anim, bool force, uint64_t dt) {
@@ -1065,15 +1046,15 @@ void PlayerControl::setAnimRotate(Npc& pl, float rotation, int anim, bool force,
10651046
float dangle = (rotation-angle)/dtF;
10661047
auto& wrld = pl.world();
10671048

1068-
if(std::fabs(dangle)<100.f && !force) // 100 deg per second threshold
1049+
if(std::fabs(dangle)<30.f && !force) // 30 deg per second threshold
10691050
anim = 0;
10701051
if(anim!=0 && pl.isAttackAnim())
10711052
anim = 0;
10721053
if(rotationAni==anim && anim!=0)
10731054
force = true;
10741055
if(!force && wrld.tickCount()<turnAniSmooth)
10751056
return;
1076-
turnAniSmooth = wrld.tickCount() + 150;
1057+
turnAniSmooth = wrld.tickCount() + 100;
10771058
rotationAni = anim;
10781059
pl.setAnimRotate(anim);
10791060
}

game/game/playercontrol.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ class PlayerControl final {
2323
void onKeyPressed (KeyCodec::Action a, Tempest::Event::KeyType key, KeyCodec::Mapping mapping = KeyCodec::Mapping::Primary);
2424
void onKeyReleased(KeyCodec::Action a, KeyCodec::Mapping mapping = KeyCodec::Mapping::Primary);
2525
bool isPressed(KeyCodec::Action a) const;
26-
void onRotateMouse(float dAngle);
27-
void onRotateMouseDy(float dAngle);
26+
void onRotateMouse(float dAngleX, float dAngleY);
2827

2928
void changeZoom(int delta);
3029
void tickFocus();
@@ -147,7 +146,6 @@ class PlayerControl final {
147146
size_t pickLockProgress = 0;
148147

149148
float runAngleDest = 0.f;
150-
uint64_t runAngleSmooth = 0;
151149
uint64_t turnAniSmooth = 0;
152150
int rotationAni = 0;
153151
bool g2Ctrl = false;

game/game/serialize.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class SaveGameHeader;
3333
class Serialize {
3434
public:
3535
enum Version : uint16_t {
36-
Current = 53,
36+
Current = 54,
3737
MinVersion = 36,
3838

3939
Last_2025 = 53,

game/graphics/worldview.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ bool WorldView::isInPfxRange(const Vec3& pos) const {
3737

3838
void WorldView::tick(uint64_t /*dt*/) {
3939
auto& cam = owner.gameSession().camera();
40-
pfxGroup.setViewerPos(cam.destPosition());
40+
pfxGroup.setViewerPos(cam.originLwc());
4141
}
4242

4343
void WorldView::resetRendering() {

0 commit comments

Comments
 (0)