Browse Source

auto camera mode along points

Kajetan Johannes Hammerle 2 years ago
parent
commit
b3813676f1

+ 140 - 58
client/Game.cpp

@@ -1,71 +1,116 @@
+#include <cmath>
+
 #include "client/Game.h"
 #include "client/utils/Utils.h"
 #include "rendering/Renderer.h"
 #include "common/utils/String.h"
+#include "common/utils/Random.h"
 
 Game::Game(const Control& control, const Camera& camera, Ray& ray, const Clock& fps, const Clock& tps,
         RenderSettings& renderSettings) :
-control(control), camera(camera), ray(ray), fps(fps), tps(tps), renderSettings(renderSettings), lengthAngle(20.0f),
-widthAngle(35.0f), world(blockRegistry), worldRenderer(world) {
-    pos.set(0, 10, 0);
-}
+control(control), camera(camera), ray(ray), fps(fps), tps(tps), renderSettings(renderSettings), lengthAngle(240.0f),
+widthAngle(20.0f), world(blockRegistry), worldRenderer(world), pointIndex(0), moveSpeed(0.25f), movedLength(0.0f),
+mode(Mode::AUTO) {
+    Random r(0);
+    float h = World::WORLD_SIZE * 0.75f;
+    float mid = World::WORLD_SIZE * 0.5f;
+    float randLength = World::WORLD_SIZE * 0.125f;
+    pos.set(0, h, 0);
 
-void Game::tick() {
-    const float speed = 0.25f;
-    if(control.keys.down.isDown()) {
-        pos.addMul(camera.getFlatBack(), speed);
-    }
-    if(control.keys.up.isDown()) {
-        pos.addMul(camera.getFlatBack(), -speed);
-    }
-    if(control.keys.left.isDown()) {
-        pos.addMul(camera.getFlatRight(), -speed);
+    for(uint i = 0; i < cameraPoints.getCapacity(); i++) {
+        Vector offset(mid, h, mid);
+        offset.add(Vector(r.nextFloat(randLength), r.nextFloat(randLength), r.nextFloat(randLength)));
+        Vector v;
+        v.setAngles(i * 360.0f / cameraPoints.getCapacity(), 0.0f).mul(mid * 0.5f).add(offset);
+        cameraPoints.add( {v, 0.0f});
     }
-    if(control.keys.right.isDown()) {
-        pos.addMul(camera.getFlatRight(), speed);
-    }
-    if(control.keys.jump.isDown()) {
-        pos.addMul(camera.getFlatUp(), speed);
-    }
-    if(control.keys.sneak.isDown()) {
-        pos.addMul(camera.getFlatUp(), -speed);
+    for(uint i = 0; i < cameraPoints.getLength(); i++) {
+        cameraPoints[i].distance = distance(i, 20);
     }
+}
 
-    const float rotation = 5.0f;
-    if(control.keys.camLeft.isDown()) {
-        lengthAngle += rotation;
-    }
-    if(control.keys.camRight.isDown()) {
-        lengthAngle -= rotation;
-    }
-    if(control.keys.camUp.isDown() && widthAngle - rotation > -90.0f) {
-        widthAngle -= rotation;
-    }
-    if(control.keys.camDown.isDown() && widthAngle + rotation < 90.0f) {
-        widthAngle += rotation;
-    }
+void Game::tick() {
+    if(mode == Mode::PLAYER) {
+        const float speed = 0.25f;
+        if(control.keys.down.isDown()) {
+            pos.addMul(camera.getFlatBack(), speed);
+        }
+        if(control.keys.up.isDown()) {
+            pos.addMul(camera.getFlatBack(), -speed);
+        }
+        if(control.keys.left.isDown()) {
+            pos.addMul(camera.getFlatRight(), -speed);
+        }
+        if(control.keys.right.isDown()) {
+            pos.addMul(camera.getFlatRight(), speed);
+        }
+        if(control.keys.jump.isDown()) {
+            pos.addMul(camera.getFlatUp(), speed);
+        }
+        if(control.keys.sneak.isDown()) {
+            pos.addMul(camera.getFlatUp(), -speed);
+        }
 
-    ray.store();
-    ray.set(pos, lengthAngle, widthAngle);
+        const float rotation = 5.0f;
+        if(control.keys.camLeft.isDown()) {
+            lengthAngle += rotation;
+        }
+        if(control.keys.camRight.isDown()) {
+            lengthAngle -= rotation;
+        }
+        if(control.keys.camUp.isDown() && widthAngle - rotation > -90.0f) {
+            widthAngle -= rotation;
+        }
+        if(control.keys.camDown.isDown() && widthAngle + rotation < 90.0f) {
+            widthAngle += rotation;
+        }
 
-    if(control.keys.test5.getDownTime() == 1) {
-        renderSettings.ssao = !renderSettings.ssao;
+        ray.store();
+        ray.set(pos, lengthAngle, widthAngle);
+    } else if(mode == Mode::AUTO) {
+        movedLength += moveSpeed;
     }
-    /*if(control.keys.test.isDown()) {
-        renderSettings.testRadius /= 0.95f;
+
+    if(control.keys.test.getDownTime() == 1) {
+        mode = Mode::PLAYER;
     }
-    if(control.keys.test2.isDown()) {
-        renderSettings.testRadius *= 0.95f;
+    if(control.keys.test2.getDownTime() == 1) {
+        mode = Mode::AUTO;
     }
-    if(control.keys.test3.isDown()) {
-        renderSettings.testBias /= 0.95f;
+    if(control.keys.test5.getDownTime() == 1) {
+        renderSettings.ssao = !renderSettings.ssao;
     }
-    if(control.keys.test4.isDown()) {
-        renderSettings.testBias *= 0.95f;
-    }*/
 }
 
 void Game::renderWorld(float lag, Renderer& renderer) const {
+    if(mode == Mode::AUTO) {
+        float leftLength = (movedLength - moveSpeed) + moveSpeed * lag;
+        uint index = 0;
+        while(leftLength >= cameraPoints[index].distance) {
+            leftLength -= cameraPoints[index].distance;
+            index = (index + 1) % cameraPoints.getLength();
+        }
+
+        uint prev = index;
+        float t = leftLength / cameraPoints[index].distance;
+        if(prev == 0) {
+            prev = cameraPoints.getLength() - 1;
+        } else {
+            prev = (prev - 1) % cameraPoints.getLength();
+        }
+        uint currentA = (prev + 1) % cameraPoints.getLength();
+        uint currentB = (prev + 2) % cameraPoints.getLength();
+        uint next = (prev + 3) % cameraPoints.getLength();
+
+        Vector tangentA = splineTangent(cameraPoints[prev].pos, cameraPoints[currentA].pos, cameraPoints[currentB].pos);
+        Vector tangentB = splineTangent(cameraPoints[currentA].pos, cameraPoints[currentB].pos, cameraPoints[next].pos);
+
+        Vector interpolatedPos = interpolate(cameraPoints[currentA].pos, cameraPoints[currentB].pos, tangentA, tangentB, t);
+
+        pos.set(interpolatedPos);
+        ray.set(interpolatedPos, lengthAngle, widthAngle);
+        ray.store();
+    }
     worldRenderer.render(lag, renderer);
 }
 
@@ -74,18 +119,55 @@ void Game::renderTextOverlay(float lag, Renderer& renderer, FontRenderer& fr) co
     renderer.scale(1.0f).update();
 
     String s;
-    s.append("FPS: ").append(fps.getUpdatesPerSecond());
-    fr.drawString(10, 10, s);
-    s.clear().append("TPS: ").append(tps.getUpdatesPerSecond());
-    fr.drawString(10, 20, s);
-    s.clear().append("Bias: ").append("%.6f", renderSettings.testBias);
-    fr.drawString(10, 30, s);
-    s.clear().append("Radius: ").append("%.6f", renderSettings.testRadius);
-    fr.drawString(10, 40, s);
-    s.clear().append("Shadows: ").append(renderSettings.shadows);
-    fr.drawString(10, 50, s);
+    fr.drawString(10, 10, s.append("FPS: ").append(fps.getUpdatesPerSecond()));
+    fr.drawString(10, 19, s.clear().append("TPS: ").append(tps.getUpdatesPerSecond()));
+    s.clear();
+    pos.toString(s);
+    fr.drawString(10, 28, s);
+    for(uint i = 0; i < cameraPoints.getLength(); i++) {
+        s.clear().append(i + 1).append(": ");
+        cameraPoints[i].pos.toString(s);
+        fr.drawString(10, i * 9 + 37, s);
+    }
 }
 
 bool Game::isRunning() const {
     return true;
 }
+
+Vector Game::splineTangent(const Vector& prev, const Vector& current, const Vector& next) const {
+    Vector v(current);
+    v.sub(prev).mul(0.5f).addMul(next, 0.5f).addMul(current, -0.5f);
+    return v;
+}
+
+Vector Game::interpolate(const Vector& a, const Vector& b, const Vector& tanA, const Vector& tanB, float t) const {
+    float t2 = t * t;
+    float t3 = t2 * t;
+    Vector v;
+    v.addMul(a, 2.0f * t3 - 3.0f * t2 + 1.0f).addMul(b, -2.0f * t3 + 3.0f * t2)
+            .addMul(tanA, t3 - 2.0f * t2 + t).addMul(tanB, t3 - t2);
+    return v;
+}
+
+float Game::distance(uint index, uint splits) const {
+    uint prev = index == 0 ? cameraPoints.getLength() - 1 : index - 1;
+    uint currentA = (prev + 1) % cameraPoints.getLength();
+    uint currentB = (prev + 2) % cameraPoints.getLength();
+    uint next = (prev + 3) % cameraPoints.getLength();
+
+    Vector tangentA = splineTangent(cameraPoints[prev].pos, cameraPoints[currentA].pos, cameraPoints[currentB].pos);
+    Vector tangentB = splineTangent(cameraPoints[currentA].pos, cameraPoints[currentB].pos, cameraPoints[next].pos);
+
+    Vector currentPos;
+    Vector currentNext = interpolate(cameraPoints[currentA].pos, cameraPoints[currentB].pos, tangentA, tangentB, 0.0f);
+
+    float sum = 0.0f;
+    for(uint i = 0; i <= splits; i++) {
+        currentPos = currentNext;
+        float t = (i + 1.0f) / (splits + 1.0f);
+        currentNext = interpolate(cameraPoints[currentA].pos, cameraPoints[currentB].pos, tangentA, tangentB, t);
+        sum += currentPos.sub(currentNext).length();
+    }
+    return sum;
+}

+ 25 - 5
client/Game.h

@@ -15,15 +15,19 @@
 
 class Game final {
 public:
-    Game(const Control& control, const Camera& camera, Ray& ray, const Clock& fps, const Clock& tps, 
+    Game(const Control& control, const Camera& camera, Ray& ray, const Clock& fps, const Clock& tps,
             RenderSettings& renderSettings);
 
     void tick();
     void renderWorld(float lag, Renderer& renderer) const;
     void renderTextOverlay(float lag, Renderer& renderer, FontRenderer& fr) const;
-    
+
     bool isRunning() const;
 
+    Vector splineTangent(const Vector& prev, const Vector& current, const Vector& next) const;
+    Vector interpolate(const Vector& a, const Vector& b, const Vector& tanA, const Vector& tanB, float t) const;
+    float distance(uint index, uint splits) const;
+
 private:
     const Control& control;
     const Camera& camera;
@@ -34,12 +38,28 @@ private:
 
     float lengthAngle;
     float widthAngle;
-    Vector pos;
-    
+    mutable Vector pos;
+
     BlockRegistry blockRegistry;
     World world;
-    
+
     WorldRenderer worldRenderer;
+
+    struct Point {
+        Vector pos;
+        float distance;
+    };
+
+    List<Point, 25> cameraPoints;
+    uint pointIndex;
+    float moveSpeed;
+    float movedLength;
+
+    enum Mode {
+        AUTO, PLAYER
+    };
+    
+    Mode mode;
 };
 
 #endif

+ 1 - 1
client/input/Keys.cpp

@@ -13,7 +13,7 @@ bool Keys::Key::isReleased() const {
     return shouldRelease;
 }
 
-u32 Keys::Key::getDownTime() const {
+uint Keys::Key::getDownTime() const {
     return downTime;
 }
 

+ 2 - 2
client/input/Keys.h

@@ -15,7 +15,7 @@ public:
 
         bool isDown() const;
         bool isReleased() const;
-        u32 getDownTime() const;
+        uint getDownTime() const;
 
     private:
         Key();
@@ -27,7 +27,7 @@ public:
         int glfwKey;
         bool down;
         bool shouldRelease;
-        u32 downTime;
+        uint downTime;
     };
 
 private:

+ 6 - 2
client/math/Vector.cpp

@@ -128,6 +128,10 @@ float Vector::squareLength() const {
     return x * x + y * y + z * z;
 }
 
+float Vector::length() const {
+    return sqrt(squareLength());
+}
+
 float Vector::dot(const Vector& v) const {
     return x * v.x + y * v.y + z * v.z;
 }
@@ -136,6 +140,6 @@ float Vector::dotInverse(const Vector& v) const {
     return x * (-v.x) + y * (-v.y) + z * (-v.z);
 }
 
-std::ostream& operator<<(std::ostream& os, const Vector& v) {
-    return os << "Vector(x = " << v.getX() << ", y = " << v.getY() << ", z = " << v.getZ() << ")";
+void Vector::toString(String& s) const {
+    s.append("(x = ").append(x).append(", y = ").append(y).append(", z = ").append(z).append(")");
 }

+ 4 - 4
client/math/Vector.h

@@ -1,8 +1,7 @@
 #ifndef VECTOR_H
 #define VECTOR_H
 
-#include <iostream>
-
+#include "common/utils/String.h"
 #include "client/math/Matrix.h"
 
 class Vector final {
@@ -35,9 +34,12 @@ public:
 
     Vector& normalize();
     float squareLength() const;
+    float length() const;
 
     float dot(const Vector& v) const;
     float dotInverse(const Vector& v) const;
+    
+    void toString(String& s) const;
 
 private:
     float x;
@@ -45,6 +47,4 @@ private:
     float z;
 };
 
-std::ostream& operator<<(std::ostream& os, const Vector& v);
-
 #endif

+ 4 - 0
common/utils/Random.cpp

@@ -20,6 +20,10 @@ float Random::nextFloat() {
     return next() * (1.0f / (0xFFFFFF + 1.0f));
 }
 
+float Random::nextFloat(float scale) {
+    return (nextFloat() - 0.5f) * 2.0f * scale;
+}
+
 u64 Random::nextSeed() {
     seed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFF;
     return seed;

+ 1 - 0
common/utils/Random.h

@@ -11,6 +11,7 @@ public:
     u32 next();
     u32 next(uint bound);
     float nextFloat();
+    float nextFloat(float scale);
 
 private:
     u64 nextSeed();

+ 1 - 1
common/world/World.h

@@ -9,7 +9,7 @@ public:
     void setBlock(uint x, uint y, uint z, const Block& block);
     const Block& getBlock(uint x, uint y, uint z) const;
     
-    static constexpr uint WORLD_SIZE = 64;
+    static constexpr uint WORLD_SIZE = 32;
 
 private:
     static constexpr uint BITMASK = WORLD_SIZE - 1;