|
@@ -21,20 +21,17 @@
|
|
|
#include "client/Game.h"
|
|
|
#include "rendering/NoiseTexture.h"
|
|
|
|
|
|
-struct InternGameClient
|
|
|
-{
|
|
|
- ~InternGameClient()
|
|
|
- {
|
|
|
- if(window != nullptr)
|
|
|
- {
|
|
|
+struct InternGameClient {
|
|
|
+
|
|
|
+ ~InternGameClient() {
|
|
|
+ if(window != nullptr) {
|
|
|
glfwDestroyWindow(window);
|
|
|
}
|
|
|
- if(glfwInitDone)
|
|
|
- {
|
|
|
+ if(glfwInitDone) {
|
|
|
glfwTerminate();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
bool glfwInitDone = false;
|
|
|
GLFWwindow* window = nullptr;
|
|
|
};
|
|
@@ -53,23 +50,22 @@ static Keys keys;
|
|
|
static MouseButtons mButtons;
|
|
|
static bool useSSAO = false;
|
|
|
|
|
|
-struct Shaders
|
|
|
-{
|
|
|
- Shaders() :
|
|
|
- world("resources/shader/worldVertex.vs", "resources/shader/worldFragment.fs"),
|
|
|
- ssao("resources/shader/ssaoVertex.vs", "resources/shader/ssaoFragment.fs"),
|
|
|
- ssaoBlur("resources/shader/ssaoBlurVertex.vs", "resources/shader/ssaoBlurFragment.fs"),
|
|
|
- shadow("resources/shader/worldShadowVertex.vs", "resources/shader/worldShadowFragment.fs"),
|
|
|
- postWorld("resources/shader/worldPostVertex.vs", "resources/shader/worldPostFragment.fs"),
|
|
|
- text("resources/shader/textVertex.vs", "resources/shader/textFragment.fs")
|
|
|
- {
|
|
|
+struct Shaders {
|
|
|
+
|
|
|
+ Shaders() :
|
|
|
+ world("resources/shader/worldVertex.vs", "resources/shader/worldFragment.fs"),
|
|
|
+ ssao("resources/shader/ssaoVertex.vs", "resources/shader/ssaoFragment.fs"),
|
|
|
+ ssaoBlur("resources/shader/ssaoBlurVertex.vs", "resources/shader/ssaoBlurFragment.fs"),
|
|
|
+ shadow("resources/shader/worldShadowVertex.vs", "resources/shader/worldShadowFragment.fs"),
|
|
|
+ postWorld("resources/shader/worldPostVertex.vs", "resources/shader/worldPostFragment.fs"),
|
|
|
+ text("resources/shader/textVertex.vs", "resources/shader/textFragment.fs") {
|
|
|
worldProj.set(11, -1.0f);
|
|
|
worldProj.set(15, 0.0f);
|
|
|
-
|
|
|
+
|
|
|
worldShadowProj.set(11, -1.0f);
|
|
|
worldShadowProj.set(15, 0.0f);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
Shader world;
|
|
|
Shader ssao;
|
|
|
Shader ssaoBlur;
|
|
@@ -77,33 +73,30 @@ struct Shaders
|
|
|
Shader postWorld;
|
|
|
Shader text;
|
|
|
bool once = true;
|
|
|
-
|
|
|
+
|
|
|
Matrix worldProj;
|
|
|
Matrix worldView;
|
|
|
-
|
|
|
+
|
|
|
Matrix worldShadowProj;
|
|
|
Matrix worldShadowView;
|
|
|
Matrix worldShadowProjView;
|
|
|
-
|
|
|
- bool isValid() const
|
|
|
- {
|
|
|
- return world.isValid() && ssao.isValid() && ssaoBlur.isValid() &&
|
|
|
+
|
|
|
+ bool isValid() const {
|
|
|
+ return world.isValid() && ssao.isValid() && ssaoBlur.isValid() &&
|
|
|
shadow.isValid() && postWorld.isValid() && text.isValid();
|
|
|
}
|
|
|
-
|
|
|
- void updateWorldProjection()
|
|
|
- {
|
|
|
+
|
|
|
+ void updateWorldProjection() {
|
|
|
float tan = tanf((0.5f * fovY) * M_PI / 180.0f);
|
|
|
float q = 1.0f / tan;
|
|
|
float aspect = (float) width / height;
|
|
|
-
|
|
|
+
|
|
|
worldProj.set(0, q / aspect);
|
|
|
worldProj.set(5, q);
|
|
|
- worldProj.set(10,(nearClip + farClip) / (nearClip - farClip));
|
|
|
+ worldProj.set(10, (nearClip + farClip) / (nearClip - farClip));
|
|
|
worldProj.set(14, (2.0f * nearClip * farClip) / (nearClip - farClip));
|
|
|
|
|
|
- if(once)
|
|
|
- {
|
|
|
+ if(once) {
|
|
|
worldShadowProj.setToIdentity();
|
|
|
worldShadowProj.set(0, 2.0f / (10.0f * aspect));
|
|
|
worldShadowProj.set(5, 2.0f / (10.0f));
|
|
@@ -111,14 +104,13 @@ struct Shaders
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- void updateWorldView(float lag, Camera& cam)
|
|
|
- {
|
|
|
+ void updateWorldView(float lag, Camera& cam) {
|
|
|
cam.update(lag);
|
|
|
Vector right = cam.getRight();
|
|
|
Vector up = cam.getUp();
|
|
|
Vector back = cam.getBack();
|
|
|
Vector pos = cam.getPosition();
|
|
|
-
|
|
|
+
|
|
|
worldView.set(0, right.getX());
|
|
|
worldView.set(1, up.getX());
|
|
|
worldView.set(2, back.getX());
|
|
@@ -131,15 +123,14 @@ struct Shaders
|
|
|
worldView.set(12, right.dotInverse(pos));
|
|
|
worldView.set(13, up.dotInverse(pos));
|
|
|
worldView.set(14, back.dotInverse(pos));
|
|
|
-
|
|
|
- if(once)
|
|
|
- {
|
|
|
+
|
|
|
+ if(once) {
|
|
|
|
|
|
right.set(0.939693f, 0.0f, -0.34202f);
|
|
|
back.set(0.280166f, 0.573576f, 0.769751f);
|
|
|
up.set(-0.196175f, 0.819152f, -0.538986f);
|
|
|
pos.set(0.0f, 2.5f, 0.0f);
|
|
|
-
|
|
|
+
|
|
|
once = false;
|
|
|
worldShadowView.set(0, right.getX());
|
|
|
worldShadowView.set(1, up.getX());
|
|
@@ -157,48 +148,44 @@ struct Shaders
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-struct Framebuffers
|
|
|
-{
|
|
|
- Framebuffers(u32 w, u32 h) :
|
|
|
- world(w, h, Framebuffer::POSITION | Framebuffer::NORMAL | Framebuffer::COLOR | Framebuffer::RED | Framebuffer::DEPTH24_STENCIL8, 0),
|
|
|
- ssao(w, h, Framebuffer::RED, 0),
|
|
|
- ssaoBlur(w, h, Framebuffer::RED, 0),
|
|
|
- shadow(w, h, Framebuffer::DEPTH24_STENCIL8, GL_LEQUAL)
|
|
|
- {
|
|
|
+struct Framebuffers {
|
|
|
+
|
|
|
+ Framebuffers(u32 w, u32 h) :
|
|
|
+ world(w, h, Framebuffer::POSITION | Framebuffer::NORMAL | Framebuffer::COLOR | Framebuffer::RED | Framebuffer::DEPTH24_STENCIL8, 0),
|
|
|
+ ssao(w, h, Framebuffer::RED, 0),
|
|
|
+ ssaoBlur(w, h, Framebuffer::RED, 0),
|
|
|
+ shadow(w, h, Framebuffer::DEPTH24_STENCIL8, GL_LEQUAL) {
|
|
|
}
|
|
|
-
|
|
|
- void resize(u32 w, u32 h) const
|
|
|
- {
|
|
|
+
|
|
|
+ void resize(u32 w, u32 h) const {
|
|
|
world.resize(w, h);
|
|
|
ssao.resize(w, h);
|
|
|
ssaoBlur.resize(w, h);
|
|
|
shadow.resize(w, h);
|
|
|
}
|
|
|
-
|
|
|
- bool isValid() const
|
|
|
- {
|
|
|
+
|
|
|
+ bool isValid() const {
|
|
|
return world.isValid() && ssao.isValid() && ssaoBlur.isValid();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
Framebuffer world;
|
|
|
Framebuffer ssao;
|
|
|
Framebuffer ssaoBlur;
|
|
|
Framebuffer shadow;
|
|
|
};
|
|
|
|
|
|
-struct InternGame
|
|
|
-{
|
|
|
- InternGame() : ssaoNoise(4, 4)
|
|
|
- {
|
|
|
- rectangle.add({-1, -1, 0, 0, 0, 0, 0, 0});
|
|
|
- rectangle.add({ 1, 1, 0, 1, 1, 0, 0, 0});
|
|
|
- rectangle.add({-1, 1, 0, 0, 1, 0, 0, 0});
|
|
|
- rectangle.add({-1, -1, 0, 0, 0, 0, 0, 0});
|
|
|
- rectangle.add({ 1, -1, 0, 1, 0, 0, 0, 0});
|
|
|
- rectangle.add({ 1, 1, 0, 1, 1, 0, 0, 0});
|
|
|
+struct InternGame {
|
|
|
+
|
|
|
+ InternGame() : ssaoNoise(4, 4) {
|
|
|
+ rectangle.add( {-1, -1, 0, 0, 0, 0, 0, 0});
|
|
|
+ rectangle.add( {1, 1, 0, 1, 1, 0, 0, 0});
|
|
|
+ rectangle.add( {-1, 1, 0, 0, 1, 0, 0, 0});
|
|
|
+ rectangle.add( {-1, -1, 0, 0, 0, 0, 0, 0});
|
|
|
+ rectangle.add( {1, -1, 0, 1, 0, 0, 0, 0});
|
|
|
+ rectangle.add( {1, 1, 0, 1, 1, 0, 0, 0});
|
|
|
rectangle.build();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
Game game;
|
|
|
Camera cam;
|
|
|
MatrixStack model;
|
|
@@ -207,16 +194,13 @@ struct InternGame
|
|
|
Mesh rectangle;
|
|
|
};
|
|
|
|
|
|
-static u64 getTimeNanos()
|
|
|
-{
|
|
|
+static u64 getTimeNanos() {
|
|
|
return glfwGetTimerValue() * timeFactor;
|
|
|
}
|
|
|
|
|
|
-static bool initGLFW()
|
|
|
-{
|
|
|
+static bool initGLFW() {
|
|
|
client.glfwInitDone = glfwInit();
|
|
|
- if(!client.glfwInitDone)
|
|
|
- {
|
|
|
+ if(!client.glfwInitDone) {
|
|
|
std::cout << "could not initialize GLFW\n";
|
|
|
return true;
|
|
|
}
|
|
@@ -224,22 +208,20 @@ static bool initGLFW()
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static bool initWindow(int w, int h, const char* windowName)
|
|
|
-{
|
|
|
+static bool initWindow(int w, int h, const char* windowName) {
|
|
|
width = w;
|
|
|
height = h;
|
|
|
-
|
|
|
+
|
|
|
glfwDefaultWindowHints();
|
|
|
glfwWindowHint(GLFW_VISIBLE, 0);
|
|
|
glfwWindowHint(GLFW_RESIZABLE, 1);
|
|
|
-
|
|
|
+
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
-
|
|
|
+
|
|
|
client.window = glfwCreateWindow(width, height, windowName, nullptr, nullptr);
|
|
|
- if(client.window == nullptr)
|
|
|
- {
|
|
|
+ if(client.window == nullptr) {
|
|
|
std::cout << "could not create window\n";
|
|
|
return true;
|
|
|
}
|
|
@@ -248,11 +230,9 @@ static bool initWindow(int w, int h, const char* windowName)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static bool initGLEW()
|
|
|
-{
|
|
|
+static bool initGLEW() {
|
|
|
GLenum err = glewInit();
|
|
|
- if(err != GLEW_OK)
|
|
|
- {
|
|
|
+ if(err != GLEW_OK) {
|
|
|
std::cout << "could not initialize GLEW: " << glewGetErrorString(err) << "\n";
|
|
|
return true;
|
|
|
}
|
|
@@ -260,40 +240,29 @@ static bool initGLEW()
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static void initCallbacks()
|
|
|
-{
|
|
|
+static void initCallbacks() {
|
|
|
|
|
|
- glfwSetKeyCallback(client.window, [](GLFWwindow*, int key, int, int action, int)
|
|
|
- {
|
|
|
- if(action == GLFW_PRESS)
|
|
|
- {
|
|
|
+ glfwSetKeyCallback(client.window, [](GLFWwindow*, int key, int, int action, int) {
|
|
|
+ if(action == GLFW_PRESS) {
|
|
|
keys.press(key);
|
|
|
- }
|
|
|
- else if(action == GLFW_RELEASE)
|
|
|
- {
|
|
|
+ } else if(action == GLFW_RELEASE) {
|
|
|
keys.release(key);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- glfwSetMouseButtonCallback(client.window, [](GLFWwindow*, int button, int action, int)
|
|
|
- {
|
|
|
- if(action == GLFW_PRESS)
|
|
|
- {
|
|
|
+ glfwSetMouseButtonCallback(client.window, [](GLFWwindow*, int button, int action, int) {
|
|
|
+ if(action == GLFW_PRESS) {
|
|
|
mButtons.press(button);
|
|
|
- }
|
|
|
- else if(action == GLFW_RELEASE)
|
|
|
- {
|
|
|
+ } else if(action == GLFW_RELEASE) {
|
|
|
mButtons.release(button);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- glfwSetCursorPosCallback(client.window, [](GLFWwindow*, double x, double y)
|
|
|
- {
|
|
|
+ glfwSetCursorPosCallback(client.window, [](GLFWwindow*, double x, double y) {
|
|
|
mButtons.move(x, y);
|
|
|
});
|
|
|
|
|
|
- glfwSetFramebufferSizeCallback(client.window, [](GLFWwindow*, int w, int h)
|
|
|
- {
|
|
|
+ glfwSetFramebufferSizeCallback(client.window, [](GLFWwindow*, int w, int h) {
|
|
|
glViewport(0, 0, w, h);
|
|
|
width = w;
|
|
|
height = h;
|
|
@@ -301,27 +270,24 @@ static void initCallbacks()
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-static void tick(InternGame& game)
|
|
|
-{
|
|
|
+static void tick(InternGame& game) {
|
|
|
keys.tick();
|
|
|
mButtons.tick();
|
|
|
game.game.tick(keys, mButtons, game.cam);
|
|
|
- if(keys.test.getDownTime() == 1)
|
|
|
- {
|
|
|
+ if(keys.test.getDownTime() == 1) {
|
|
|
useSSAO = !useSSAO;
|
|
|
}
|
|
|
mButtons.postTick();
|
|
|
}
|
|
|
|
|
|
-static void renderShadow(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb)
|
|
|
-{
|
|
|
+static void renderShadow(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb) {
|
|
|
fb.shadow.bind();
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
shaders.shadow.use();
|
|
|
shaders.worldShadowProjView = shaders.worldShadowProj;
|
|
|
shaders.worldShadowProjView.mul(shaders.worldShadowView);
|
|
|
shaders.shadow.setMatrix("projView", shaders.worldShadowProjView.getValues());
|
|
|
-
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
@@ -331,17 +297,16 @@ static void renderShadow(float lag, Shaders& shaders, InternGame& game, Framebuf
|
|
|
|
|
|
}
|
|
|
|
|
|
-static void renderWorld(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb)
|
|
|
-{
|
|
|
+static void renderWorld(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb) {
|
|
|
fb.world.bind();
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
shaders.world.use();
|
|
|
-
|
|
|
+
|
|
|
Matrix rWorldShadowProjView;
|
|
|
rWorldShadowProjView.translate(0.5f, 0.5f, 0.5f);
|
|
|
rWorldShadowProjView.scale(0.5f, 0.5f, 0.5f);
|
|
|
rWorldShadowProjView.mul(shaders.worldShadowProjView);
|
|
|
-
|
|
|
+
|
|
|
shaders.world.setMatrix("projViewShadow", rWorldShadowProjView.getValues());
|
|
|
shaders.world.setMatrix("proj", shaders.worldProj.getValues());
|
|
|
shaders.world.setMatrix("view", shaders.worldView.getValues());
|
|
@@ -351,16 +316,15 @@ static void renderWorld(float lag, Shaders& shaders, InternGame& game, Framebuff
|
|
|
game.game.renderWorld(lag, game.model, shaders.world);
|
|
|
}
|
|
|
|
|
|
-static void renderSSAO(Shaders& shaders, InternGame& game, Framebuffers& fb)
|
|
|
-{
|
|
|
+static void renderSSAO(Shaders& shaders, InternGame& game, Framebuffers& fb) {
|
|
|
|
|
|
shaders.ssao.use();
|
|
|
-
|
|
|
+
|
|
|
Matrix rProj;
|
|
|
rProj.translate(0.5f, 0.5f, 0.5f);
|
|
|
rProj.scale(0.5f, 0.5f, 0.5f);
|
|
|
rProj.mul(shaders.worldProj);
|
|
|
-
|
|
|
+
|
|
|
shaders.ssao.setMatrix("proj", rProj.getValues());
|
|
|
shaders.ssao.setInt("width", width);
|
|
|
shaders.ssao.setInt("height", height);
|
|
@@ -378,8 +342,7 @@ static void renderSSAO(Shaders& shaders, InternGame& game, Framebuffers& fb)
|
|
|
game.rectangle.draw();
|
|
|
}
|
|
|
|
|
|
-static void renderPostWorld(Shaders& shaders, InternGame& game, Framebuffers& fb)
|
|
|
-{
|
|
|
+static void renderPostWorld(Shaders& shaders, InternGame& game, Framebuffers& fb) {
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
|
shaders.postWorld.use();
|
|
@@ -396,11 +359,10 @@ static u64 sum = 0;
|
|
|
static u64 tindex = 0;
|
|
|
static std::array<u64, 128> values;
|
|
|
|
|
|
-static void renderTextOverlay(float lag, Shaders& shaders, InternGame& game)
|
|
|
-{
|
|
|
+static void renderTextOverlay(float lag, Shaders& shaders, InternGame& game) {
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
shaders.text.use();
|
|
|
-
|
|
|
+
|
|
|
Matrix m;
|
|
|
shaders.text.setMatrix("proj", m.getValues());
|
|
|
m.translate(-1.0f, 1.0f, 0.0f);
|
|
@@ -409,7 +371,7 @@ static void renderTextOverlay(float lag, Shaders& shaders, InternGame& game)
|
|
|
game.model.clear();
|
|
|
game.model.get().scale(2.0f, 2.0f, 2.0f);
|
|
|
shaders.text.setMatrix("model", game.model.get().getValues());
|
|
|
-
|
|
|
+
|
|
|
glEnable(GL_BLEND);
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
@@ -420,61 +382,53 @@ static void renderTextOverlay(float lag, Shaders& shaders, InternGame& game)
|
|
|
glDisable(GL_BLEND);
|
|
|
}
|
|
|
|
|
|
-static void renderTick(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb)
|
|
|
-{
|
|
|
+static void renderTick(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb) {
|
|
|
u64 current = getTimeNanos();
|
|
|
sum -= values[tindex];
|
|
|
values[tindex] = current - last;
|
|
|
sum += values[tindex];
|
|
|
last = current;
|
|
|
tindex = (tindex + 1) & (127);
|
|
|
-
|
|
|
- if(resize)
|
|
|
- {
|
|
|
+
|
|
|
+ if(resize) {
|
|
|
fb.resize(width, height);
|
|
|
resize = false;
|
|
|
}
|
|
|
shaders.updateWorldProjection();
|
|
|
shaders.updateWorldView(lag, game.cam);
|
|
|
-
|
|
|
+
|
|
|
renderShadow(lag, shaders, game, fb);
|
|
|
renderWorld(lag, shaders, game, fb);
|
|
|
- if(useSSAO)
|
|
|
- {
|
|
|
+ if(useSSAO) {
|
|
|
renderSSAO(shaders, game, fb);
|
|
|
}
|
|
|
renderPostWorld(shaders, game, fb);
|
|
|
renderTextOverlay(lag, shaders, game);
|
|
|
}
|
|
|
|
|
|
-static void loop()
|
|
|
-{
|
|
|
+static void loop() {
|
|
|
Shaders shaders;
|
|
|
- if(!shaders.isValid())
|
|
|
- {
|
|
|
+ if(!shaders.isValid()) {
|
|
|
return;
|
|
|
}
|
|
|
Framebuffers fb(width, height);
|
|
|
- if(!fb.isValid())
|
|
|
- {
|
|
|
+ if(!fb.isValid()) {
|
|
|
return;
|
|
|
}
|
|
|
InternGame game;
|
|
|
-
|
|
|
+
|
|
|
last = getTimeNanos();
|
|
|
u64 lastTime = getTimeNanos();
|
|
|
u64 lag = 0;
|
|
|
- while(!glfwWindowShouldClose(client.window))
|
|
|
- {
|
|
|
+ while(!glfwWindowShouldClose(client.window)) {
|
|
|
renderTick(lag * lagFactor, shaders, game, fb);
|
|
|
glfwSwapBuffers(client.window);
|
|
|
-
|
|
|
+
|
|
|
u64 newTime = getTimeNanos();
|
|
|
lag += newTime - lastTime;
|
|
|
lastTime = newTime;
|
|
|
-
|
|
|
- while(lag >= NANOS_PER_TICK)
|
|
|
- {
|
|
|
+
|
|
|
+ while(lag >= NANOS_PER_TICK) {
|
|
|
lag -= NANOS_PER_TICK;
|
|
|
tick(game);
|
|
|
}
|
|
@@ -482,10 +436,8 @@ static void loop()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void GameClient::start(int w, int h, const char* windowName)
|
|
|
-{
|
|
|
- if(initGLFW() || initWindow(w, h, windowName) || initGLEW())
|
|
|
- {
|
|
|
+void GameClient::start(int w, int h, const char* windowName) {
|
|
|
+ if(initGLFW() || initWindow(w, h, windowName) || initGLEW()) {
|
|
|
return;
|
|
|
}
|
|
|
initCallbacks();
|