Engine.cpp 9.2 KB

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