GameClient.cpp 13 KB

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