GameClient.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. #include <iostream>
  2. #include <GL/glew.h>
  3. #include <GLFW/glfw3.h>
  4. #include <unordered_map>
  5. #include <cmath>
  6. #include "common/utils/Types.h"
  7. #include "client/GameClient.h"
  8. #include "client/input/Keys.h"
  9. #include "client/input/MouseButtons.h"
  10. #include "client/rendering/Shader.h"
  11. #include "client/rendering/FontRenderer.h"
  12. #include "client/rendering/Mesh.h"
  13. #include "client/rendering/Framebuffer.h"
  14. #include "client/Utils.h"
  15. #include "client/math/Camera.h"
  16. #include "client/math/Matrix.h"
  17. #include "client/math/MatrixStack.h"
  18. #include "client/Game.h"
  19. #include "rendering/NoiseTexture.h"
  20. struct InternGameClient
  21. {
  22. ~InternGameClient()
  23. {
  24. if(window != nullptr)
  25. {
  26. glfwDestroyWindow(window);
  27. }
  28. if(glfwInitDone)
  29. {
  30. glfwTerminate();
  31. }
  32. }
  33. bool glfwInitDone = false;
  34. GLFWwindow* window = nullptr;
  35. };
  36. static const u64 NANOS_PER_TICK = 50000000;
  37. static const float lagFactor = 1.0f / NANOS_PER_TICK;
  38. static u64 timeFactor = 1;
  39. static int width = 0;
  40. static int height = 0;
  41. static bool resize = false;
  42. static float fovY = 60.0f;
  43. static float nearClip = 0.1f;
  44. static float farClip = 1000.0f;
  45. static InternGameClient client;
  46. static Keys keys;
  47. static MouseButtons mButtons;
  48. struct Shaders
  49. {
  50. Shaders() :
  51. world("resources/shader/worldVertex.vs", "resources/shader/worldFragment.fs"),
  52. ssao("resources/shader/ssaoVertex.vs", "resources/shader/ssaoFragment.fs"),
  53. ssaoBlur("resources/shader/ssaoBlurVertex.vs", "resources/shader/ssaoBlurFragment.fs"),
  54. text("resources/shader/textVertex.vs", "resources/shader/textFragment.fs")
  55. {
  56. }
  57. Shader world;
  58. Shader ssao;
  59. Shader ssaoBlur;
  60. Shader text;
  61. bool isValid() const
  62. {
  63. return world.isValid() && ssao.isValid() && ssaoBlur.isValid() && text.isValid();
  64. }
  65. };
  66. struct Framebuffers
  67. {
  68. Framebuffers(u32 w, u32 h) : worldBuffer(w, h, Framebuffer::POSITION |
  69. Framebuffer::NORMAL | Framebuffer::COLOR | Framebuffer::DEPTH24_STENCIL8),
  70. ssaoBuffer(w, h, Framebuffer::RED), ssaoBlurBuffer(w, h, Framebuffer::RED)
  71. {
  72. }
  73. void resize(u32 w, u32 h) const
  74. {
  75. worldBuffer.resize(w, h);
  76. ssaoBuffer.resize(w, h);
  77. ssaoBlurBuffer.resize(w, h);
  78. }
  79. bool isValid() const
  80. {
  81. return worldBuffer.isValid() && ssaoBuffer.isValid() && ssaoBlurBuffer.isValid();
  82. }
  83. Framebuffer worldBuffer;
  84. Framebuffer ssaoBuffer;
  85. Framebuffer ssaoBlurBuffer;
  86. };
  87. struct InternGame
  88. {
  89. InternGame() : ssaoNoise(4, 4)
  90. {
  91. }
  92. Game game;
  93. Camera cam;
  94. MatrixStack model;
  95. FontRenderer fontRenderer;
  96. NoiseTexture ssaoNoise;
  97. };
  98. static u64 getTimeNanos()
  99. {
  100. return glfwGetTimerValue() * timeFactor;
  101. }
  102. static bool initGLFW()
  103. {
  104. client.glfwInitDone = glfwInit();
  105. if(!client.glfwInitDone)
  106. {
  107. std::cout << "could not initialize GLFW\n";
  108. return true;
  109. }
  110. timeFactor = 1000000000 / glfwGetTimerFrequency();
  111. return false;
  112. }
  113. static bool initWindow(int w, int h, const char* windowName)
  114. {
  115. width = w;
  116. height = h;
  117. glfwDefaultWindowHints();
  118. glfwWindowHint(GLFW_VISIBLE, 0);
  119. glfwWindowHint(GLFW_RESIZABLE, 1);
  120. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
  121. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
  122. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  123. client.window = glfwCreateWindow(width, height, windowName, nullptr, nullptr);
  124. if(client.window == nullptr)
  125. {
  126. std::cout << "could not create window\n";
  127. return true;
  128. }
  129. glfwMakeContextCurrent(client.window);
  130. glfwSwapInterval(1);
  131. return false;
  132. }
  133. static bool initGLEW()
  134. {
  135. GLenum err = glewInit();
  136. if(err != GLEW_OK)
  137. {
  138. std::cout << "could not initialize GLEW: " << glewGetErrorString(err) << "\n";
  139. return true;
  140. }
  141. std::cout << "using GLEW " << glewGetString(GLEW_VERSION) << "\n";
  142. return false;
  143. }
  144. static void initCallbacks()
  145. {
  146. // GLFWwindow* w, int key, int scancode, int action, int mod
  147. glfwSetKeyCallback(client.window, [](GLFWwindow*, int key, int, int action, int)
  148. {
  149. if(action == GLFW_PRESS)
  150. {
  151. keys.press(key);
  152. }
  153. else if(action == GLFW_RELEASE)
  154. {
  155. keys.release(key);
  156. }
  157. });
  158. // GLFWwindow* w, int button, int action, int mods
  159. glfwSetMouseButtonCallback(client.window, [](GLFWwindow*, int button, int action, int)
  160. {
  161. if(action == GLFW_PRESS)
  162. {
  163. mButtons.press(button);
  164. }
  165. else if(action == GLFW_RELEASE)
  166. {
  167. mButtons.release(button);
  168. }
  169. });
  170. // GLFWwindow* w, double xpos, double ypos
  171. glfwSetCursorPosCallback(client.window, [](GLFWwindow*, double x, double y)
  172. {
  173. mButtons.move(x, y);
  174. });
  175. // GLFWwindow* w, int width, int height
  176. glfwSetFramebufferSizeCallback(client.window, [](GLFWwindow*, int w, int h)
  177. {
  178. glViewport(0, 0, w, h);
  179. width = w;
  180. height = h;
  181. resize = true;
  182. });
  183. }
  184. static void tick(InternGame& game)
  185. {
  186. keys.tick();
  187. mButtons.tick();
  188. game.game.tick(keys, mButtons, game.cam);
  189. mButtons.postTick();
  190. }
  191. static void renderWorld(float lag, Shaders& shaders, InternGame& game)
  192. {
  193. glEnable(GL_DEPTH_TEST);
  194. // use world program
  195. shaders.world.use();
  196. // send projection matrix
  197. float tan = tanf((0.5f * fovY) * M_PI / 180.0f);
  198. float q = 1.0f / tan;
  199. float aspect = (float) width / height;
  200. float proj[] =
  201. {
  202. q / aspect, 0.0f, 0.0f, 0.0f,
  203. 0.0f, q, 0.0f, 0.0f,
  204. 0.0f, 0.0f, (nearClip + farClip) / (nearClip - farClip), -1.0f,
  205. 0.0f, 0.0f, (2.0f * nearClip * farClip) / (nearClip - farClip), 0.0f
  206. };
  207. shaders.world.setMatrix("proj", proj);
  208. // send view matrix
  209. game.cam.update(lag);
  210. const Vector right = game.cam.getRight();
  211. const Vector up = game.cam.getUp();
  212. const Vector back = game.cam.getBack();
  213. const Vector pos = game.cam.getPosition();
  214. float view[] =
  215. {
  216. right.getX(), up.getX(), back.getX(), 0.0f,
  217. right.getY(), up.getY(), back.getY(), 0.0f,
  218. right.getZ(), up.getZ(), back.getZ(), 0.0f,
  219. right.dotInverse(pos), up.dotInverse(pos), back.dotInverse(pos), 1.0f
  220. };
  221. shaders.world.setMatrix("view", view);
  222. // clear and send model matrix
  223. game.model.clear();
  224. shaders.world.setMatrix("model", game.model.get().getValues());
  225. // call high level world renderer
  226. game.game.renderWorld(lag, game.model, shaders.world);
  227. shaders.ssao.use();
  228. shaders.ssao.setMatrix("view", view);
  229. shaders.ssao.setMatrix("proj", proj);
  230. shaders.ssao.setInt("width", width);
  231. shaders.ssao.setInt("height", height);
  232. }
  233. /*static void renderTextOverlay(float lag, Shaders& shaders, InternGame& game)
  234. {
  235. glDisable(GL_DEPTH_TEST);
  236. shaders.text.use();
  237. Matrix m;
  238. shaders.text.setMatrix("proj", m.getValues());
  239. m.translate(-1.0f, 1.0f, 0.0f);
  240. m.scale(2.0f / width, -2.0f / height, 1.0f);
  241. shaders.text.setMatrix("view", m.getValues());
  242. game.model.clear();
  243. game.model.get().scale(2.0f, 2.0f, 2.0f);
  244. shaders.text.setMatrix("model", game.model.get().getValues());
  245. glEnable(GL_BLEND);
  246. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  247. glBlendEquation(GL_FUNC_ADD);
  248. game.game.renderTextOverlay(lag, game.model, shaders.text, game.fontRenderer);
  249. glDisable(GL_BLEND);
  250. }*/
  251. static void renderTick(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb)
  252. {
  253. if(resize)
  254. {
  255. fb.resize(width, height);
  256. resize = false;
  257. }
  258. fb.worldBuffer.bind();
  259. renderWorld(lag, shaders, game);
  260. }
  261. static void loop()
  262. {
  263. Shaders shaders;
  264. if(!shaders.isValid())
  265. {
  266. return;
  267. }
  268. Framebuffers fb(width, height);
  269. if(!fb.isValid())
  270. {
  271. return;
  272. }
  273. InternGame game;
  274. Shader sh("resources/shader/test2Vertex.vs", "resources/shader/test2Fragment.fs");
  275. Mesh m;
  276. m.add({-1, -1, 0, 0, 0, 0, 0, 0});
  277. m.add({ 1, 1, 0, 1, 1, 0, 0, 0});
  278. m.add({-1, 1, 0, 0, 1, 0, 0, 0});
  279. m.add({-1, -1, 0, 0, 0, 0, 0, 0});
  280. m.add({ 1, -1, 0, 1, 0, 0, 0, 0});
  281. m.add({ 1, 1, 0, 1, 1, 0, 0, 0});
  282. m.build();
  283. u64 lastTime = getTimeNanos();
  284. u64 lag = 0;
  285. while(!glfwWindowShouldClose(client.window))
  286. {
  287. renderTick(lag * lagFactor, shaders, game, fb);
  288. fb.worldBuffer.bindPositionTexture(0);
  289. fb.worldBuffer.bindNormalTexture(1);
  290. fb.worldBuffer.bindColorTexture(2);
  291. fb.worldBuffer.bindDepthTexture(3);
  292. game.ssaoNoise.bind(4);
  293. fb.ssaoBuffer.bind();
  294. m.draw();
  295. shaders.ssaoBlur.use();
  296. fb.ssaoBuffer.bindRedTexture(0);
  297. fb.worldBuffer.bindColorTexture(1);
  298. fb.ssaoBlurBuffer.bind();
  299. m.draw();
  300. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  301. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  302. fb.ssaoBlurBuffer.bindRedTexture(1);
  303. sh.use();
  304. //glDisable(GL_CULL_FACE);
  305. glDisable(GL_DEPTH_TEST);
  306. glEnable(GL_BLEND);
  307. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  308. glBlendEquation(GL_FUNC_ADD);
  309. m.draw();
  310. glDisable(GL_BLEND);
  311. glfwSwapBuffers(client.window);
  312. u64 newTime = getTimeNanos();
  313. lag += newTime - lastTime;
  314. lastTime = newTime;
  315. while(lag >= NANOS_PER_TICK)
  316. {
  317. lag -= NANOS_PER_TICK;
  318. tick(game);
  319. }
  320. glfwPollEvents();
  321. }
  322. }
  323. void GameClient::start(int w, int h, const char* windowName)
  324. {
  325. if(initGLFW() || initWindow(w, h, windowName) || initGLEW())
  326. {
  327. return;
  328. }
  329. initCallbacks();
  330. glfwShowWindow(client.window);
  331. loop();
  332. }