|
@@ -1,24 +1,31 @@
|
|
|
#include "client/rendering/Engine.h"
|
|
|
#include "client/Game.h"
|
|
|
-#include "client/rendering/Framebuffers.h"
|
|
|
#include "client/rendering/Mesh.h"
|
|
|
-#include "client/rendering/NoiseTexture.h"
|
|
|
-#include "client/rendering/Shaders.h"
|
|
|
#include "math/Frustum.h"
|
|
|
+#include "rendering/Framebuffer.h"
|
|
|
#include "rendering/Window.h"
|
|
|
#include "utils/Logger.h"
|
|
|
+#include "utils/Random.h"
|
|
|
#include "wrapper/GL.h"
|
|
|
|
|
|
static Window window;
|
|
|
-static Shaders shaders;
|
|
|
-static Framebuffers framebuffers;
|
|
|
+static Shader worldShader;
|
|
|
+static Shader ssaoShader;
|
|
|
+static Shader ssaoBlurShader;
|
|
|
+static Shader shadowShader;
|
|
|
+static Shader postWorldShader;
|
|
|
+static Shader overlayShader;
|
|
|
+static Framebuffer<5> worldBuffer;
|
|
|
+static Framebuffer<1> ssaoBuffer;
|
|
|
+static Framebuffer<1> ssaoBlurBuffer;
|
|
|
+static Framebuffer<1> shadowBuffer;
|
|
|
static Size lastSize{0, 0};
|
|
|
static Frustum frustum{60.0f, 0.1f, 1000.0f, window.getSize()};
|
|
|
static MatrixStack<16> model;
|
|
|
Renderer Engine::renderer;
|
|
|
ShaderMatrix Engine::matrix{nullptr, model, nullptr};
|
|
|
float Engine::lag = 0.0f;
|
|
|
-static NoiseTexture ssaoNoise;
|
|
|
+static Texture ssaoNoise;
|
|
|
static Mesh rectangle;
|
|
|
static Matrix worldProj;
|
|
|
static Matrix worldView;
|
|
@@ -31,23 +38,86 @@ static float shadowRadius = 0.01f;
|
|
|
static float shadowBias = 0.0002f;
|
|
|
static bool running = true;
|
|
|
|
|
|
+static Error compileShader(Shader& s, const char* name) {
|
|
|
+ constexpr const char* prefix = "resources/shader/";
|
|
|
+ return s.compile(StringBuffer<50>(prefix).append(name).append(".vs"),
|
|
|
+ StringBuffer<50>(prefix).append(name).append(".fs"));
|
|
|
+}
|
|
|
+
|
|
|
+static Error initShaders() {
|
|
|
+ Error error = compileShader(worldShader, "world");
|
|
|
+ if(error.has()) {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ error = compileShader(ssaoShader, "ssao");
|
|
|
+ if(error.has()) {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ error = compileShader(ssaoBlurShader, "ssaoBlur");
|
|
|
+ if(error.has()) {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ error = compileShader(shadowShader, "worldShadow");
|
|
|
+ if(error.has()) {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ error = compileShader(postWorldShader, "worldPost");
|
|
|
+ if(error.has()) {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ return compileShader(overlayShader, "overlay");
|
|
|
+}
|
|
|
+
|
|
|
+static void resizeFramebuffers(const Size& size) {
|
|
|
+ worldBuffer.resize(size);
|
|
|
+ ssaoBuffer.resize(size);
|
|
|
+ ssaoBlurBuffer.resize(size);
|
|
|
+ shadowBuffer.resize(size);
|
|
|
+}
|
|
|
+
|
|
|
+static Error initFramebuffers(const Size& size) {
|
|
|
+ Error error = worldBuffer.init(
|
|
|
+ size, TextureFormat::float32(3), TextureFormat::float32(3),
|
|
|
+ TextureFormat::color8(4), TextureFormat::float32(1),
|
|
|
+ TextureFormat::depth32(true));
|
|
|
+ if(error.has()) {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ error = ssaoBuffer.init(size, TextureFormat::float32(1));
|
|
|
+ if(error.has()) {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ error = ssaoBlurBuffer.init(size, TextureFormat::float32(1));
|
|
|
+ if(error.has()) {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ return shadowBuffer.init(size, TextureFormat::depth32());
|
|
|
+}
|
|
|
+
|
|
|
static bool initRectangle() {
|
|
|
if(rectangle.init()) {
|
|
|
return true;
|
|
|
}
|
|
|
- TypedBuffer<Triangle> buffer(2);
|
|
|
- buffer.add(
|
|
|
- Triangle(Vertex(Vector3(-1.0f, -1.0f, 0.0f), Vector2(0, 0.0f)),
|
|
|
- Vertex(Vector3(1.0f, 1.0f, 0.0f), Vector2(1.0f, 1.0f)),
|
|
|
- Vertex(Vector3(-1.0f, 1.0f, 0.0f), Vector2(0.0f, 1.0f))));
|
|
|
- buffer.add(
|
|
|
- Triangle(Vertex(Vector3(-1.0f, -1.0f, 0.0f), Vector2(0, 0.0f)),
|
|
|
- Vertex(Vector3(1.0f, -1.0f, 0.0f), Vector2(1.0f, 0.0f)),
|
|
|
- Vertex(Vector3(1.0f, 1.0f, 0.0f), Vector2(1.0f, 1.0f))));
|
|
|
- rectangle.build(buffer);
|
|
|
+ rectangle.build(TypedBuffer<Mesh::Triangle>(2)
|
|
|
+ .add({{{-1.0f, -1.0f, +0.0f}, {0.0f, 0.0f}},
|
|
|
+ {{+1.0f, +1.0f, +0.0f}, {1.0f, 1.0f}},
|
|
|
+ {{-1.0f, +1.0f, +0.0f}, {0.0f, 1.0f}}})
|
|
|
+ .add({{{-1.0f, -1.0f, +0.0f}, {0.0f, 0.0f}},
|
|
|
+ {{+1.0f, -1.0f, +0.0f}, {1.0f, 0.0f}},
|
|
|
+ {{+1.0f, +1.0f, +0.0f}, {1.0f, 1.0f}}}));
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+static void initNoise() {
|
|
|
+ ssaoNoise.init(TextureFormat::float32(3), 0);
|
|
|
+ Random r(1);
|
|
|
+ Array<float, 48> data;
|
|
|
+ for(int i = 0; i < 48; i++) {
|
|
|
+ data[i] = r.nextFloat() * 2.0f - 1.0f;
|
|
|
+ }
|
|
|
+ ssaoNoise.setData(4, 4, data.begin());
|
|
|
+}
|
|
|
+
|
|
|
bool Engine::init() {
|
|
|
WindowOptions options(4, 0, {1024, 620}, false, "test");
|
|
|
Error error = window.open(options);
|
|
@@ -56,108 +126,109 @@ bool Engine::init() {
|
|
|
return true;
|
|
|
}
|
|
|
lastSize = window.getSize();
|
|
|
- error = shaders.init();
|
|
|
+ error = initShaders();
|
|
|
if(error.has()) {
|
|
|
LOG_ERROR(error.message);
|
|
|
return true;
|
|
|
}
|
|
|
- error = framebuffers.init(window.getSize());
|
|
|
+ error = initFramebuffers(window.getSize());
|
|
|
if(error.has()) {
|
|
|
LOG_ERROR(error.message);
|
|
|
return true;
|
|
|
}
|
|
|
- if(renderer.init() || ssaoNoise.init() || initRectangle()) {
|
|
|
+ initNoise();
|
|
|
+ if(renderer.init() || initRectangle()) {
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
static void renderShadow() {
|
|
|
- framebuffers.shadow.bindAndClear();
|
|
|
+ shadowBuffer.bindAndClear();
|
|
|
GL::enableDepthTesting();
|
|
|
- shaders.shadow.use();
|
|
|
+ shadowShader.use();
|
|
|
worldShadowProjView = worldShadowProj;
|
|
|
worldShadowProjView *= worldShadowView;
|
|
|
- shaders.shadow.setMatrix("projView", worldShadowProjView.getValues());
|
|
|
+ shadowShader.setMatrix("projView", worldShadowProjView.getValues());
|
|
|
model.clear();
|
|
|
- shaders.shadow.setMatrix("model", model.peek().getValues());
|
|
|
- Engine::matrix = {&shaders.shadow, model, &worldView};
|
|
|
+ shadowShader.setMatrix("model", model.peek().getValues());
|
|
|
+ Engine::matrix = {&shadowShader, model, &worldView};
|
|
|
Game::renderWorld();
|
|
|
}
|
|
|
|
|
|
static void renderWorld() {
|
|
|
- framebuffers.world.bindAndClear();
|
|
|
+ worldBuffer.bindAndClear();
|
|
|
GL::enableDepthTesting();
|
|
|
- shaders.world.use();
|
|
|
+ worldShader.use();
|
|
|
|
|
|
Matrix rWorldShadowProjView;
|
|
|
rWorldShadowProjView.scale(0.5f).translate(Vector3(0.5f, 0.5f, 0.5f));
|
|
|
rWorldShadowProjView *= worldShadowProjView;
|
|
|
|
|
|
- shaders.world.setMatrix("projViewShadow", rWorldShadowProjView.getValues());
|
|
|
- shaders.world.setMatrix("proj", worldProj.getValues());
|
|
|
+ worldShader.setMatrix("projViewShadow", rWorldShadowProjView.getValues());
|
|
|
+ worldShader.setMatrix("proj", worldProj.getValues());
|
|
|
worldView = Matrix();
|
|
|
- shaders.world.setMatrix("view", worldView.getValues());
|
|
|
+ worldShader.setMatrix("view", worldView.getValues());
|
|
|
model.clear();
|
|
|
- shaders.world.setMatrix("model", model.peek().getValues());
|
|
|
- framebuffers.shadow.bindTextureTo(0, 1);
|
|
|
- shaders.world.setInt("shadows", useShadows);
|
|
|
- shaders.world.setFloat("radius", shadowRadius);
|
|
|
- shaders.world.setFloat("zbias", shadowBias);
|
|
|
- Engine::matrix = {&shaders.world, model, &worldView};
|
|
|
+ worldShader.setMatrix("model", model.peek().getValues());
|
|
|
+ shadowBuffer.bindTextureTo(0, 1);
|
|
|
+ worldShader.setInt("shadows", useShadows);
|
|
|
+ worldShader.setFloat("radius", shadowRadius);
|
|
|
+ worldShader.setFloat("zbias", shadowBias);
|
|
|
+ Engine::matrix = {&worldShader, model, &worldView};
|
|
|
Game::renderWorld();
|
|
|
}
|
|
|
|
|
|
static void renderSSAO() {
|
|
|
- shaders.ssao.use();
|
|
|
+ ssaoShader.use();
|
|
|
|
|
|
Matrix rProj;
|
|
|
rProj.scale(0.5f).translate(Vector3(0.5f, 0.5f, 0.5f));
|
|
|
rProj *= worldProj;
|
|
|
|
|
|
- shaders.ssao.setMatrix("proj", rProj.getValues());
|
|
|
+ ssaoShader.setMatrix("proj", rProj.getValues());
|
|
|
const Size& size = window.getSize();
|
|
|
- shaders.ssao.setInt("width", size.width);
|
|
|
- shaders.ssao.setInt("height", size.height);
|
|
|
- framebuffers.world.bindTextureTo(0, 0);
|
|
|
- framebuffers.world.bindTextureTo(4, 1);
|
|
|
+ ssaoShader.setInt("width", size.width);
|
|
|
+ ssaoShader.setInt("height", size.height);
|
|
|
+ worldBuffer.bindTextureTo(0, 0);
|
|
|
+ worldBuffer.bindTextureTo(4, 1);
|
|
|
ssaoNoise.bindTo(2);
|
|
|
- framebuffers.ssao.bindAndClear();
|
|
|
+ ssaoBuffer.bindAndClear();
|
|
|
rectangle.draw();
|
|
|
|
|
|
- shaders.ssaoBlur.use();
|
|
|
- framebuffers.ssao.bindTextureTo(0, 0);
|
|
|
- framebuffers.ssaoBlur.bindAndClear();
|
|
|
+ ssaoBlurShader.use();
|
|
|
+ ssaoBuffer.bindTextureTo(0, 0);
|
|
|
+ ssaoBlurBuffer.bindAndClear();
|
|
|
rectangle.draw();
|
|
|
}
|
|
|
|
|
|
static void renderPostWorld() {
|
|
|
GL::bindMainFramebuffer();
|
|
|
GL::clear();
|
|
|
- shaders.postWorld.use();
|
|
|
- framebuffers.world.bindTextureTo(2, 0);
|
|
|
- framebuffers.ssaoBlur.bindTextureTo(0, 1);
|
|
|
- framebuffers.world.bindTextureTo(3, 2);
|
|
|
- framebuffers.world.bindTextureTo(1, 3);
|
|
|
- shaders.postWorld.setInt("ssao", useSsao);
|
|
|
- shaders.postWorld.setInt("shadows", useShadows);
|
|
|
+ postWorldShader.use();
|
|
|
+ worldBuffer.bindTextureTo(2, 0);
|
|
|
+ ssaoBlurBuffer.bindTextureTo(0, 1);
|
|
|
+ worldBuffer.bindTextureTo(3, 2);
|
|
|
+ worldBuffer.bindTextureTo(1, 3);
|
|
|
+ postWorldShader.setInt("ssao", useSsao);
|
|
|
+ postWorldShader.setInt("shadows", useShadows);
|
|
|
rectangle.draw();
|
|
|
}
|
|
|
|
|
|
static void renderOverlay() {
|
|
|
GL::disableDepthTesting();
|
|
|
- shaders.overlay.use();
|
|
|
+ overlayShader.use();
|
|
|
|
|
|
const Size& size = window.getSize();
|
|
|
Matrix m;
|
|
|
m.scale(Vector3(2.0f / size.width, -2.0f / size.height, 1.0f))
|
|
|
.translate(Vector3(-1.0f, 1.0f, 0.0f));
|
|
|
- shaders.overlay.setMatrix("view", m.getValues());
|
|
|
+ overlayShader.setMatrix("view", m.getValues());
|
|
|
model.clear();
|
|
|
- shaders.overlay.setMatrix("model", model.peek().getValues());
|
|
|
+ overlayShader.setMatrix("model", model.peek().getValues());
|
|
|
|
|
|
GL::enableBlending();
|
|
|
- Engine::matrix = {&shaders.overlay, model, &m};
|
|
|
+ Engine::matrix = {&overlayShader, model, &m};
|
|
|
Game::renderOverlay();
|
|
|
GL::disableBlending();
|
|
|
}
|
|
@@ -197,7 +268,7 @@ static void startRender() {
|
|
|
const Size& size = window.getSize();
|
|
|
if(size.width != lastSize.width || size.height != lastSize.height) {
|
|
|
GL::setViewport(size.width, size.height);
|
|
|
- framebuffers.resize(size);
|
|
|
+ resizeFramebuffers(size);
|
|
|
lastSize = size;
|
|
|
}
|
|
|
GL::printError("loop error");
|