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