|
@@ -3,6 +3,7 @@
|
|
|
#include "Texture3D.h"
|
|
|
#include "math/Frustum.h"
|
|
|
#include "rendering/FileTexture.h"
|
|
|
+#include "rendering/Framebuffer.h"
|
|
|
#include "rendering/Shader.h"
|
|
|
#include "rendering/VertexBuffer.h"
|
|
|
#include "rendering/Window.h"
|
|
@@ -12,11 +13,16 @@
|
|
|
#include "utils/Utils.h"
|
|
|
#include "wrapper/GL.h"
|
|
|
|
|
|
+static constexpr float STEP = 1.0f / 31.5f;
|
|
|
+
|
|
|
static Window window;
|
|
|
|
|
|
-static Shader shader;
|
|
|
-static Shader noiceShader;
|
|
|
+static Shader cubeShader;
|
|
|
+static Shader noiseShader;
|
|
|
static Shader particleShader;
|
|
|
+static Shader backgroundShader;
|
|
|
+static Shader postShader;
|
|
|
+static Framebuffer<1> shadowBuffer;
|
|
|
static LayeredFramebuffer noiceBuffer;
|
|
|
static FileTexture bricks;
|
|
|
static FileTexture bricksBump;
|
|
@@ -25,6 +31,12 @@ static VertexBuffer rectangleBuffer;
|
|
|
static VertexBuffer emptyBuffer;
|
|
|
static Frustum frustum{60.0f, 0.1f, 1000.0f, window.getSize()};
|
|
|
|
|
|
+static Matrix projection;
|
|
|
+static Matrix view;
|
|
|
+static Matrix shadowView;
|
|
|
+static Matrix shadowProjectionView;
|
|
|
+static Matrix model;
|
|
|
+
|
|
|
static Button up{GLFW_KEY_SPACE, "Up"};
|
|
|
static Button down{GLFW_KEY_LEFT_SHIFT, "Down"};
|
|
|
static Button left{GLFW_KEY_A, "left"};
|
|
@@ -57,17 +69,17 @@ static Vector3 emitterPos;
|
|
|
static float emitterAge = 999999.0f;
|
|
|
static float timeFactor = 1.0f;
|
|
|
|
|
|
-static void tickGame() {
|
|
|
+static void tickTimeFactors() {
|
|
|
if(timeUp.isDown()) {
|
|
|
timeFactor *= 1.05f;
|
|
|
- std::cout << timeFactor << "\n";
|
|
|
}
|
|
|
if(timeDown.isDown()) {
|
|
|
timeFactor /= 1.05f;
|
|
|
- std::cout << timeFactor << "\n";
|
|
|
}
|
|
|
-
|
|
|
timeTicks++;
|
|
|
+}
|
|
|
+
|
|
|
+static void tickMovement() {
|
|
|
oldHeight = height;
|
|
|
oldPosition = position;
|
|
|
if(up.isDown()) {
|
|
@@ -76,7 +88,7 @@ static void tickGame() {
|
|
|
if(down.isDown()) {
|
|
|
height -= 1.0f;
|
|
|
}
|
|
|
- const float speed = 1.15f;
|
|
|
+ constexpr float speed = 5.5f;
|
|
|
if(left.isDown()) {
|
|
|
position += Vector3(speed, 0.0f, 0.0f);
|
|
|
}
|
|
@@ -89,7 +101,9 @@ static void tickGame() {
|
|
|
if(back.isDown()) {
|
|
|
position -= Vector3(0.0f, 0.0f, speed);
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
+static void tickParallaxSettings() {
|
|
|
if(scaleUp.isDown()) {
|
|
|
heightScale += 0.005f;
|
|
|
}
|
|
@@ -117,38 +131,53 @@ static void tickGame() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void renderGame(float lag) {
|
|
|
- GL::enableDepthTesting();
|
|
|
+static void tickGame() {
|
|
|
+ tickTimeFactors();
|
|
|
+ tickMovement();
|
|
|
+ tickParallaxSettings();
|
|
|
+}
|
|
|
+
|
|
|
+static void prepareMatrices(float lag) {
|
|
|
+ projection = frustum.updateProjection();
|
|
|
+
|
|
|
+ view.translateTo(Vector3(0.0f, 0.0f, 0.0f));
|
|
|
+ view.translate(Utils::interpolate(oldPosition, position, lag));
|
|
|
+ float h = -32.0f + (oldHeight - height) * lag;
|
|
|
+ view.translateY(h);
|
|
|
+ shadowView.translateTo(Vector3(-32.0f - 180.0f, h, -340.0f));
|
|
|
+
|
|
|
+ shadowProjectionView.translateTo(Vector3(0.0f, 0.0f, 0.0f));
|
|
|
+ shadowProjectionView.scale(0.5f);
|
|
|
+ shadowProjectionView.translate(Vector3(0.5f, 0.5f, 0.5f));
|
|
|
+ shadowProjectionView *= projection;
|
|
|
+ shadowProjectionView *= shadowView;
|
|
|
+}
|
|
|
+
|
|
|
+static void renderNoise() {
|
|
|
GL::setViewport(64, 64);
|
|
|
- noiceShader.use();
|
|
|
+ noiseShader.use();
|
|
|
noiceBuffer.bindAndClear();
|
|
|
- float step = 1.0f / 31.5f;
|
|
|
- noiceShader.setFloat("height", oldHeight * step);
|
|
|
+ noiseShader.setFloat("height", oldHeight * STEP);
|
|
|
for(int i = 0; i < 64; i++) {
|
|
|
- noiceShader.setFloat("layer", i * step - 1.0f);
|
|
|
+ noiseShader.setFloat("layer", i * STEP - 1.0f);
|
|
|
noiceBuffer.bindLayer(i);
|
|
|
rectangleBuffer.draw(6);
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
+static void renderCubes(Matrix& view) {
|
|
|
GL::setViewport(window.getSize().width, window.getSize().height);
|
|
|
- shader.use();
|
|
|
- GL::bindMainFramebuffer();
|
|
|
- GL::clear();
|
|
|
- Matrix& proj = frustum.updateProjection();
|
|
|
- shader.setMatrix("proj", proj.getValues());
|
|
|
-
|
|
|
- Matrix m;
|
|
|
- m.translate(Utils::interpolate(oldPosition, position, lag));
|
|
|
- m.translateY(-32.0f + (oldHeight - height) * lag);
|
|
|
- shader.setMatrix("view", m.getValues());
|
|
|
- shader.setFloat("height", oldHeight * step * 0.5f);
|
|
|
-
|
|
|
- shader.setVector("viewPos", -position + Vector3(0.0f, 32.0f, 0.0f));
|
|
|
- shader.setVector("lightPos", Vector3());
|
|
|
- shader.setFloat("heightScale", heightScale);
|
|
|
- shader.setInt("steps", steps);
|
|
|
- shader.setInt("fineSteps", fineSteps);
|
|
|
- shader.setInt("kajetan", mode);
|
|
|
+ cubeShader.use();
|
|
|
+ cubeShader.setMatrix("proj", projection.getValues());
|
|
|
+ cubeShader.setMatrix("view", view.getValues());
|
|
|
+ cubeShader.setMatrix("shadow", shadowProjectionView.getValues());
|
|
|
+ cubeShader.setFloat("height", oldHeight * STEP * 0.5f);
|
|
|
+ cubeShader.setVector("viewPos", -position + Vector3(0.0f, 32.0f, 0.0f));
|
|
|
+ cubeShader.setVector("lightPos", Vector3());
|
|
|
+ cubeShader.setFloat("heightScale", heightScale);
|
|
|
+ cubeShader.setInt("steps", steps);
|
|
|
+ cubeShader.setInt("fineSteps", fineSteps);
|
|
|
+ cubeShader.setInt("kajetan", mode);
|
|
|
|
|
|
if(toggle.isDown()) {
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
@@ -157,12 +186,60 @@ static void renderGame(float lag) {
|
|
|
bricks.bindTo(1);
|
|
|
bricksBump.bindTo(2);
|
|
|
bricksNormal.bindTo(3);
|
|
|
- emptyBuffer.drawPoints(64 * 64 * 64);
|
|
|
+ shadowBuffer.bindTextureTo(0, 4);
|
|
|
+
|
|
|
+ for(int i = 0; i < 3; i++) {
|
|
|
+ model.translateTo(Vector3(80.0f * i, 0.0f, 0.0f));
|
|
|
+ cubeShader.setMatrix("model", model.getValues());
|
|
|
+ emptyBuffer.drawPoints(64 * 64 * 64);
|
|
|
+ }
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
|
+}
|
|
|
|
|
|
+static void pickParticleCenter() {
|
|
|
+ if(!primaryMouse.wasReleased()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ noiceBuffer.bindTextureTo(0);
|
|
|
+ static float buffer[64][64][64];
|
|
|
+ glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, buffer);
|
|
|
+
|
|
|
+ float hWidth = window.getSize().width * 0.5f;
|
|
|
+ float hHeight = window.getSize().height * 0.5f;
|
|
|
+
|
|
|
+ float x = (window.buttons.getMouseX() - hWidth) / hWidth;
|
|
|
+ float y = -(window.buttons.getMouseY() - hHeight) / hHeight;
|
|
|
+
|
|
|
+ float aspect = hWidth / hHeight;
|
|
|
+ float tan = tanf((0.5f * frustum.fieldOfView) * M_PI / 180.0f);
|
|
|
+ float q = 1.0f / tan;
|
|
|
+
|
|
|
+ Vector3 direction(x / (q / aspect), y / q, 1.0f);
|
|
|
+ direction[2] = -direction[2];
|
|
|
+ direction.normalize();
|
|
|
+
|
|
|
+ Vector3 pos = -position;
|
|
|
+ pos[1] = 32.0f;
|
|
|
+ pos[1] = 32.0f;
|
|
|
+ for(int i = 0; i < 150; i++) {
|
|
|
+ int x = pos[0] + 0.5f;
|
|
|
+ int y = pos[1] + 0.5f;
|
|
|
+ int z = pos[2] + 0.5f;
|
|
|
+ if(x >= 0 && x < 64 && y >= 0 && y < 64 && z >= 0 && z < 64 &&
|
|
|
+ buffer[x][y][z] > 0.5f) {
|
|
|
+ emitterPos = pos + Vector3(0.0f, height, 0.0f);
|
|
|
+ emitterAge = timeTicks;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ pos += direction;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void renderParticles(float lag) {
|
|
|
glPointSize(5.0f);
|
|
|
particleShader.use();
|
|
|
- particleShader.setMatrix("proj", proj.getValues());
|
|
|
+ particleShader.setMatrix("proj", projection.getValues());
|
|
|
+ Matrix m;
|
|
|
m.translateTo(Utils::interpolate(oldPosition, position, lag));
|
|
|
m.translateY(-32.0f - (oldHeight + (height - oldHeight) * lag));
|
|
|
particleShader.setMatrix("view", m.getValues());
|
|
@@ -171,41 +248,7 @@ static void renderGame(float lag) {
|
|
|
GL::enableBlending();
|
|
|
glDepthMask(false);
|
|
|
|
|
|
- if(primaryMouse.wasReleased()) {
|
|
|
- noiceBuffer.bindTextureTo(0);
|
|
|
- static float buffer[64][64][64];
|
|
|
- glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, buffer);
|
|
|
-
|
|
|
- float hWidth = window.getSize().width * 0.5f;
|
|
|
- float hHeight = window.getSize().height * 0.5f;
|
|
|
-
|
|
|
- float x = (window.buttons.getMouseX() - hWidth) / hWidth;
|
|
|
- float y = -(window.buttons.getMouseY() - hHeight) / hHeight;
|
|
|
-
|
|
|
- float aspect = hWidth / hHeight;
|
|
|
- float tan = tanf((0.5f * frustum.fieldOfView) * M_PI / 180.0f);
|
|
|
- float q = 1.0f / tan;
|
|
|
-
|
|
|
- Vector3 direction(x / (q / aspect), y / q, 1.0f);
|
|
|
- direction[2] = -direction[2];
|
|
|
- direction.normalize();
|
|
|
-
|
|
|
- Vector3 pos = -position;
|
|
|
- pos[1] = 32.0f;
|
|
|
- pos[1] = 32.0f;
|
|
|
- for(int i = 0; i < 150; i++) {
|
|
|
- int x = pos[0] + 0.5f;
|
|
|
- int y = pos[1] + 0.5f;
|
|
|
- int z = pos[2] + 0.5f;
|
|
|
- if(x >= 0 && x < 64 && y >= 0 && y < 64 && z >= 0 && z < 64 &&
|
|
|
- buffer[x][y][z] > 0.5f) {
|
|
|
- emitterPos = pos + Vector3(0.0f, height, 0.0f);
|
|
|
- emitterAge = timeTicks;
|
|
|
- break;
|
|
|
- }
|
|
|
- pos += direction;
|
|
|
- }
|
|
|
- }
|
|
|
+ pickParticleCenter();
|
|
|
particleShader.setFloat("timeFactor", timeFactor);
|
|
|
|
|
|
particleShader.setVector("position", emitterPos);
|
|
@@ -236,6 +279,40 @@ static void renderGame(float lag) {
|
|
|
GL::disableBlending();
|
|
|
}
|
|
|
|
|
|
+static void renderBackground(Matrix& view) {
|
|
|
+ backgroundShader.use();
|
|
|
+ shadowBuffer.bindTextureTo(0, 0);
|
|
|
+ backgroundShader.setMatrix("proj", frustum.updateProjection().getValues());
|
|
|
+ backgroundShader.setMatrix("view", view.getValues());
|
|
|
+ model.translateTo(Vector3(0.0f, 0.0f, 0.0f));
|
|
|
+ model.scale(Vector3(260.0f, 120.0f, 1.0f));
|
|
|
+ model.translate(Vector3(0.0f, 20.0f, -200.0f));
|
|
|
+ backgroundShader.setMatrix("model", model.getValues());
|
|
|
+ backgroundShader.setMatrix("shadow", shadowProjectionView.getValues());
|
|
|
+ rectangleBuffer.draw(6);
|
|
|
+}
|
|
|
+
|
|
|
+static void renderGame(float lag) {
|
|
|
+ GL::enableDepthTesting();
|
|
|
+ prepareMatrices(lag);
|
|
|
+ renderNoise();
|
|
|
+
|
|
|
+ shadowBuffer.bindAndClear();
|
|
|
+ renderCubes(shadowView);
|
|
|
+ renderBackground(shadowView);
|
|
|
+
|
|
|
+ GL::bindMainFramebuffer();
|
|
|
+ GL::clear();
|
|
|
+
|
|
|
+ renderCubes(view);
|
|
|
+ renderBackground(view);
|
|
|
+ renderParticles(lag);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
void Game::init() {
|
|
|
WindowOptions options(4, 0, {1024, 620}, false, "test");
|
|
|
Error error = window.open(options);
|
|
@@ -243,14 +320,14 @@ void Game::init() {
|
|
|
error.message.printLine();
|
|
|
return;
|
|
|
}
|
|
|
- error = shader.compile("resources/vertex.vs", "resources/geometry.gs",
|
|
|
- "resources/fragment.fs");
|
|
|
+ error = cubeShader.compile("resources/cubes.vs", "resources/cubes.gs",
|
|
|
+ "resources/cubes.fs");
|
|
|
if(error.has()) {
|
|
|
error.message.printLine();
|
|
|
return;
|
|
|
}
|
|
|
- error = noiceShader.compile("resources/noiceVertex.vs", nullptr,
|
|
|
- "resources/noiceFragment.fs");
|
|
|
+ error = noiseShader.compile("resources/noise.vs", nullptr,
|
|
|
+ "resources/noise.fs");
|
|
|
if(error.has()) {
|
|
|
error.message.printLine();
|
|
|
return;
|
|
@@ -262,6 +339,23 @@ void Game::init() {
|
|
|
error.message.printLine();
|
|
|
return;
|
|
|
}
|
|
|
+ error = backgroundShader.compile("resources/background.vs", nullptr,
|
|
|
+ "resources/background.fs");
|
|
|
+ if(error.has()) {
|
|
|
+ error.message.printLine();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ error =
|
|
|
+ postShader.compile("resources/post.vs", nullptr, "resources/post.fs");
|
|
|
+ if(error.has()) {
|
|
|
+ error.message.printLine();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ error = shadowBuffer.init(window.getSize(), TextureFormat::depth32());
|
|
|
+ if(error.has()) {
|
|
|
+ error.message.printLine();
|
|
|
+ return;
|
|
|
+ }
|
|
|
error = bricks.load("resources/bricks.png", 0);
|
|
|
if(error.has()) {
|
|
|
error.message.printLine();
|
|
@@ -277,7 +371,6 @@ void Game::init() {
|
|
|
error.message.printLine();
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
noiceBuffer.init(64, 64, 64);
|
|
|
window.buttons.add(up);
|
|
|
window.buttons.add(down);
|