Engine.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. #include "client/rendering/Engine.h"
  2. #include "client/Game.h"
  3. #include "client/rendering/Mesh.h"
  4. #include "math/Frustum.h"
  5. #include "rendering/Framebuffer.h"
  6. #include "rendering/Window.h"
  7. #include "utils/Logger.h"
  8. #include "utils/Random.h"
  9. #include "wrapper/GL.h"
  10. static Shader worldShader;
  11. static Shader ssaoShader;
  12. static Shader ssaoBlurShader;
  13. static Shader shadowShader;
  14. static Shader postWorldShader;
  15. static Shader overlayShader;
  16. static Framebuffer<5> worldBuffer;
  17. static Framebuffer<1> ssaoBuffer;
  18. static Framebuffer<1> ssaoBlurBuffer;
  19. static Framebuffer<1> shadowBuffer;
  20. static Frustum frustum{60.0f, 0.1f, 1000.0f, Window::getSize()};
  21. static MatrixStack<16> model;
  22. Renderer Engine::renderer;
  23. ShaderMatrix Engine::matrix{nullptr, model, nullptr};
  24. float Engine::lag = 0.0f;
  25. static Texture ssaoNoise;
  26. static Mesh rectangle;
  27. static Matrix worldProj;
  28. static Matrix worldView;
  29. static Matrix worldShadowProj;
  30. static Matrix worldShadowView;
  31. static Matrix worldShadowProjView;
  32. static bool useSsao = true;
  33. static bool useShadows = false;
  34. static float shadowRadius = 0.01f;
  35. static float shadowBias = 0.0002f;
  36. static bool running = true;
  37. static Error compileShader(Shader& s, const char* name) {
  38. constexpr const char* prefix = "resources/shader/";
  39. return s.compile(StringBuffer<50>(prefix).append(name).append(".vs"),
  40. StringBuffer<50>(prefix).append(name).append(".fs"));
  41. }
  42. static Error initShaders() {
  43. Error error = compileShader(worldShader, "world");
  44. if(error.has()) {
  45. return error;
  46. }
  47. error = compileShader(ssaoShader, "ssao");
  48. if(error.has()) {
  49. return error;
  50. }
  51. error = compileShader(ssaoBlurShader, "ssaoBlur");
  52. if(error.has()) {
  53. return error;
  54. }
  55. error = compileShader(shadowShader, "worldShadow");
  56. if(error.has()) {
  57. return error;
  58. }
  59. error = compileShader(postWorldShader, "worldPost");
  60. if(error.has()) {
  61. return error;
  62. }
  63. return compileShader(overlayShader, "overlay");
  64. }
  65. static void resizeFramebuffers(const Size& size) {
  66. worldBuffer.resize(size);
  67. ssaoBuffer.resize(size);
  68. ssaoBlurBuffer.resize(size);
  69. shadowBuffer.resize(size);
  70. }
  71. static Error initFramebuffers(const Size& size) {
  72. Error error = worldBuffer.init(
  73. size, TextureFormat::float32(3), TextureFormat::float32(3),
  74. TextureFormat::color8(4), TextureFormat::float32(1),
  75. TextureFormat::depth32(true));
  76. if(error.has()) {
  77. return error;
  78. }
  79. error = ssaoBuffer.init(size, TextureFormat::float32(1));
  80. if(error.has()) {
  81. return error;
  82. }
  83. error = ssaoBlurBuffer.init(size, TextureFormat::float32(1));
  84. if(error.has()) {
  85. return error;
  86. }
  87. return shadowBuffer.init(size, TextureFormat::depth32());
  88. }
  89. static bool initRectangle() {
  90. if(rectangle.init()) {
  91. return true;
  92. }
  93. rectangle.build(TypedBuffer<Mesh::Triangle>(2)
  94. .add({{{-1.0f, -1.0f, +0.0f}, {0.0f, 0.0f}},
  95. {{+1.0f, +1.0f, +0.0f}, {1.0f, 1.0f}},
  96. {{-1.0f, +1.0f, +0.0f}, {0.0f, 1.0f}}})
  97. .add({{{-1.0f, -1.0f, +0.0f}, {0.0f, 0.0f}},
  98. {{+1.0f, -1.0f, +0.0f}, {1.0f, 0.0f}},
  99. {{+1.0f, +1.0f, +0.0f}, {1.0f, 1.0f}}}));
  100. return false;
  101. }
  102. static void initNoise() {
  103. ssaoNoise.init(TextureFormat::float32(3), 0);
  104. Random r(1);
  105. Array<float, 48> data;
  106. for(int i = 0; i < 48; i++) {
  107. data[i] = r.nextFloat() * 2.0f - 1.0f;
  108. }
  109. ssaoNoise.setData(4, 4, data.begin());
  110. }
  111. bool Engine::init() {
  112. WindowOptions options(4, 0, {1024, 620}, false, "test");
  113. Error error = Window::open(options);
  114. if(error.has()) {
  115. LOG_ERROR(error.message);
  116. return true;
  117. }
  118. Window::show();
  119. error = initShaders();
  120. if(error.has()) {
  121. LOG_ERROR(error.message);
  122. return true;
  123. }
  124. error = initFramebuffers(Window::getSize());
  125. if(error.has()) {
  126. LOG_ERROR(error.message);
  127. return true;
  128. }
  129. initNoise();
  130. if(renderer.init() || initRectangle()) {
  131. return true;
  132. }
  133. return false;
  134. }
  135. static void renderShadow() {
  136. shadowBuffer.bindAndClear();
  137. GL::enableDepthTesting();
  138. shadowShader.use();
  139. worldShadowProjView = worldShadowProj;
  140. worldShadowProjView *= worldShadowView;
  141. shadowShader.setMatrix("projView", worldShadowProjView.getValues());
  142. model.clear();
  143. shadowShader.setMatrix("model", model.peek().getValues());
  144. Engine::matrix = {&shadowShader, model, &worldView};
  145. Game::renderWorld();
  146. }
  147. static void renderWorld() {
  148. worldBuffer.bindAndClear();
  149. GL::enableDepthTesting();
  150. worldShader.use();
  151. Matrix rWorldShadowProjView;
  152. rWorldShadowProjView.scale(0.5f).translate(Vector3(0.5f, 0.5f, 0.5f));
  153. rWorldShadowProjView *= worldShadowProjView;
  154. worldShader.setMatrix("projViewShadow", rWorldShadowProjView.getValues());
  155. worldShader.setMatrix("proj", worldProj.getValues());
  156. worldView = Matrix();
  157. worldShader.setMatrix("view", worldView.getValues());
  158. model.clear();
  159. worldShader.setMatrix("model", model.peek().getValues());
  160. shadowBuffer.bindTextureTo(0, 1);
  161. worldShader.setInt("shadows", useShadows);
  162. worldShader.setFloat("radius", shadowRadius);
  163. worldShader.setFloat("zbias", shadowBias);
  164. Engine::matrix = {&worldShader, model, &worldView};
  165. Game::renderWorld();
  166. }
  167. static void renderSSAO() {
  168. ssaoShader.use();
  169. Matrix rProj;
  170. rProj.scale(0.5f).translate(Vector3(0.5f, 0.5f, 0.5f));
  171. rProj *= worldProj;
  172. ssaoShader.setMatrix("proj", rProj.getValues());
  173. ssaoShader.setInt("width", Window::getSize().width);
  174. ssaoShader.setInt("height", Window::getSize().height);
  175. worldBuffer.bindTextureTo(0, 0);
  176. worldBuffer.bindTextureTo(4, 1);
  177. ssaoNoise.bindTo(2);
  178. ssaoBuffer.bindAndClear();
  179. rectangle.draw();
  180. ssaoBlurShader.use();
  181. ssaoBuffer.bindTextureTo(0, 0);
  182. ssaoBlurBuffer.bindAndClear();
  183. rectangle.draw();
  184. }
  185. static void renderPostWorld() {
  186. GL::bindMainFramebuffer();
  187. GL::clear();
  188. postWorldShader.use();
  189. worldBuffer.bindTextureTo(2, 0);
  190. ssaoBlurBuffer.bindTextureTo(0, 1);
  191. worldBuffer.bindTextureTo(3, 2);
  192. worldBuffer.bindTextureTo(1, 3);
  193. postWorldShader.setInt("ssao", useSsao);
  194. postWorldShader.setInt("shadows", useShadows);
  195. rectangle.draw();
  196. }
  197. static void renderOverlay() {
  198. GL::disableDepthTesting();
  199. overlayShader.use();
  200. Matrix m;
  201. m.scale(Vector3(2.0f / Window::getSize().width,
  202. -2.0f / Window::getSize().height, 1.0f))
  203. .translate(Vector3(-1.0f, 1.0f, 0.0f));
  204. overlayShader.setMatrix("view", m.getValues());
  205. model.clear();
  206. overlayShader.setMatrix("model", model.peek().getValues());
  207. GL::enableBlending();
  208. Engine::matrix = {&overlayShader, model, &m};
  209. Game::renderOverlay();
  210. GL::disableBlending();
  211. }
  212. static void updateWorldProjection() {
  213. worldProj = frustum.updateProjection();
  214. if(!useShadows) {
  215. return;
  216. }
  217. worldShadowProj.set(0, Vector4(2.0f / 40.0f, 0.0f, 0.0f, 0.0f));
  218. worldShadowProj.set(1, Vector4(0.0f, 2.0f / 30.0f, 0.0f, 0.0f));
  219. worldShadowProj.set(2, Vector4(0.0f, 0.0f, -2.0f / (1000.0f - 0.1f), 0.0f));
  220. worldShadowProj.set(3, Vector4(0.0f, 0.0f, 0.0f, 1.0f));
  221. }
  222. static void updateWorldView() {
  223. if(!useShadows) {
  224. return;
  225. }
  226. Vector3 right(0.939693f, 0.0f, -0.34202f);
  227. Vector3 back(0.280166f, 0.573576f, 0.769751f);
  228. Vector3 up(-0.196175f, 0.819152f, -0.538986f);
  229. Vector3 center(16.0f, 24.0f, 24.0f);
  230. worldShadowView.set(
  231. 0, Vector4(right[0], right[1], right[2], right.dot(-center)));
  232. worldShadowView.set(1, Vector4(up[0], up[1], up[2], up.dot(-center)));
  233. worldShadowView.set(2,
  234. Vector4(back[0], back[1], back[2], back.dot(-center)));
  235. worldShadowView.set(3, Vector4(0.0f, 0.0f, 0.0f, 1.0f));
  236. }
  237. static void startRender() {
  238. if(Window::hasSizeChanged()) {
  239. GL::setViewport(Window::getSize().width, Window::getSize().height);
  240. resizeFramebuffers(Window::getSize());
  241. }
  242. GL::printError("loop error");
  243. updateWorldProjection();
  244. updateWorldView();
  245. if(useShadows) {
  246. renderShadow();
  247. }
  248. renderWorld();
  249. if(useSsao) {
  250. renderSSAO();
  251. }
  252. renderPostWorld();
  253. renderOverlay();
  254. }
  255. static void render(float lag) {
  256. Engine::lag = lag;
  257. startRender();
  258. }
  259. static void tick() {
  260. Game::tick();
  261. }
  262. static bool isRunning() {
  263. return running && !Window::shouldClose();
  264. }
  265. void Engine::run() {
  266. Window::run<isRunning, tick, render>(50'000'000);
  267. }
  268. void Engine::stop() {
  269. running = false;
  270. }