Game.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. #include "Game.h"
  2. #include "LayeredFramebuffer.h"
  3. #include "Texture3D.h"
  4. #include "math/Frustum.h"
  5. #include "rendering/FileTexture.h"
  6. #include "rendering/Framebuffer.h"
  7. #include "rendering/Shader.h"
  8. #include "rendering/VertexBuffer.h"
  9. #include "rendering/Window.h"
  10. #include "utils/Array.h"
  11. #include "utils/List.h"
  12. #include "utils/Random.h"
  13. #include "utils/Utils.h"
  14. #include "wrapper/GL.h"
  15. static constexpr float STEP = 1.0f / 31.5f;
  16. static Window window;
  17. static Shader cubeShader;
  18. static Shader noiseShader;
  19. static Shader particleShader;
  20. static Shader backgroundShader;
  21. static Shader postShader;
  22. static Framebuffer<1> shadowBuffer;
  23. static LayeredFramebuffer noiceBuffer;
  24. static FileTexture bricks;
  25. static FileTexture bricksBump;
  26. static FileTexture bricksNormal;
  27. static VertexBuffer rectangleBuffer;
  28. static VertexBuffer emptyBuffer;
  29. static Frustum frustum{60.0f, 0.1f, 1000.0f, window.getSize()};
  30. static Matrix projection;
  31. static Matrix view;
  32. static Matrix shadowView;
  33. static Matrix shadowProjectionView;
  34. static Matrix model;
  35. static Button up{GLFW_KEY_SPACE, "Up"};
  36. static Button down{GLFW_KEY_LEFT_SHIFT, "Down"};
  37. static Button left{GLFW_KEY_A, "left"};
  38. static Button right{GLFW_KEY_D, "right"};
  39. static Button front{GLFW_KEY_W, "front"};
  40. static Button back{GLFW_KEY_S, "back"};
  41. static Button toggle{GLFW_KEY_T, "toggle"};
  42. static Button scaleUp{GLFW_KEY_G, "scale up"};
  43. static Button scaleDown{GLFW_KEY_H, "scale down"};
  44. static Button stepsUp{GLFW_KEY_Y, "steps up"};
  45. static Button stepsDown{GLFW_KEY_U, "steps down"};
  46. static Button fineStepsUp{GLFW_KEY_I, "fine steps up"};
  47. static Button fineStepsDown{GLFW_KEY_O, "fine steps down"};
  48. static Button modeToggle{GLFW_KEY_C, "mode toggle"};
  49. static Button primaryMouse{GLFW_MOUSE_BUTTON_1, "primary click"};
  50. static Button timeUp{GLFW_KEY_N, "time up"};
  51. static Button timeDown{GLFW_KEY_M, "time down"};
  52. static Vector3 oldPosition;
  53. static Vector3 position{-32.0f, 0.0f, -120.0f};
  54. static float oldHeight = 0.0f;
  55. static float height = 0.0f;
  56. static float heightScale = 0.01f;
  57. static int steps = 1;
  58. static int fineSteps = 1;
  59. static bool mode = false;
  60. static float timeTicks = 0.0f;
  61. static Vector3 emitterPos;
  62. static float emitterAge = 999999.0f;
  63. static float timeFactor = 1.0f;
  64. static void tickTimeFactors() {
  65. if(timeUp.isDown()) {
  66. timeFactor *= 1.05f;
  67. }
  68. if(timeDown.isDown()) {
  69. timeFactor /= 1.05f;
  70. }
  71. timeTicks++;
  72. }
  73. static void tickMovement() {
  74. oldHeight = height;
  75. oldPosition = position;
  76. if(up.isDown()) {
  77. height += 1.0f;
  78. }
  79. if(down.isDown()) {
  80. height -= 1.0f;
  81. }
  82. constexpr float speed = 5.5f;
  83. if(left.isDown()) {
  84. position += Vector3(speed, 0.0f, 0.0f);
  85. }
  86. if(right.isDown()) {
  87. position -= Vector3(speed, 0.0f, 0.0f);
  88. }
  89. if(front.isDown()) {
  90. position += Vector3(0.0f, 0.0f, speed);
  91. }
  92. if(back.isDown()) {
  93. position -= Vector3(0.0f, 0.0f, speed);
  94. }
  95. }
  96. static void tickParallaxSettings() {
  97. if(scaleUp.isDown()) {
  98. heightScale += 0.005f;
  99. }
  100. if(scaleDown.isDown()) {
  101. heightScale -= 0.005f;
  102. if(heightScale < 0.0f) {
  103. heightScale = 0.0f;
  104. }
  105. }
  106. if(stepsUp.wasReleased()) {
  107. steps++;
  108. }
  109. if(stepsDown.wasReleased() && steps > 1) {
  110. steps--;
  111. }
  112. if(fineStepsUp.wasReleased()) {
  113. fineSteps++;
  114. }
  115. if(fineStepsDown.wasReleased() && fineSteps > 1) {
  116. fineSteps--;
  117. }
  118. if(modeToggle.wasReleased()) {
  119. mode = !mode;
  120. }
  121. }
  122. static void tickGame() {
  123. tickTimeFactors();
  124. tickMovement();
  125. tickParallaxSettings();
  126. }
  127. static void prepareMatrices(float lag) {
  128. projection = frustum.updateProjection();
  129. view.translateTo(Vector3(0.0f, 0.0f, 0.0f));
  130. view.translate(Utils::interpolate(oldPosition, position, lag));
  131. float h = -32.0f + (oldHeight - height) * lag;
  132. view.translateY(h);
  133. shadowView.translateTo(Vector3(-32.0f - 180.0f, h, -340.0f));
  134. shadowProjectionView.translateTo(Vector3(0.0f, 0.0f, 0.0f));
  135. shadowProjectionView.scale(0.5f);
  136. shadowProjectionView.translate(Vector3(0.5f, 0.5f, 0.5f));
  137. shadowProjectionView *= projection;
  138. shadowProjectionView *= shadowView;
  139. }
  140. static void renderNoise() {
  141. GL::setViewport(64, 64);
  142. noiseShader.use();
  143. noiceBuffer.bindAndClear();
  144. noiseShader.setFloat("height", oldHeight * STEP);
  145. for(int i = 0; i < 64; i++) {
  146. noiseShader.setFloat("layer", i * STEP - 1.0f);
  147. noiceBuffer.bindLayer(i);
  148. rectangleBuffer.draw(6);
  149. }
  150. }
  151. static void renderCubes(Matrix& view) {
  152. GL::setViewport(window.getSize().width, window.getSize().height);
  153. cubeShader.use();
  154. cubeShader.setMatrix("proj", projection.getValues());
  155. cubeShader.setMatrix("view", view.getValues());
  156. cubeShader.setMatrix("shadow", shadowProjectionView.getValues());
  157. cubeShader.setFloat("height", oldHeight * STEP * 0.5f);
  158. cubeShader.setVector("viewPos", -position + Vector3(0.0f, 32.0f, 0.0f));
  159. cubeShader.setVector("lightPos", Vector3());
  160. cubeShader.setFloat("heightScale", heightScale);
  161. cubeShader.setInt("steps", steps);
  162. cubeShader.setInt("fineSteps", fineSteps);
  163. cubeShader.setInt("kajetan", mode);
  164. if(toggle.isDown()) {
  165. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  166. }
  167. noiceBuffer.bindTextureTo(0);
  168. bricks.bindTo(1);
  169. bricksBump.bindTo(2);
  170. bricksNormal.bindTo(3);
  171. shadowBuffer.bindTextureTo(0, 4);
  172. for(int i = 0; i < 3; i++) {
  173. model.translateTo(Vector3(80.0f * i, 0.0f, 0.0f));
  174. cubeShader.setMatrix("model", model.getValues());
  175. emptyBuffer.drawPoints(64 * 64 * 64);
  176. }
  177. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  178. }
  179. static void pickParticleCenter() {
  180. if(!primaryMouse.wasReleased()) {
  181. return;
  182. }
  183. noiceBuffer.bindTextureTo(0);
  184. static float buffer[64][64][64];
  185. glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, buffer);
  186. float hWidth = window.getSize().width * 0.5f;
  187. float hHeight = window.getSize().height * 0.5f;
  188. float x = (window.buttons.getMouseX() - hWidth) / hWidth;
  189. float y = -(window.buttons.getMouseY() - hHeight) / hHeight;
  190. float aspect = hWidth / hHeight;
  191. float tan = tanf((0.5f * frustum.fieldOfView) * M_PI / 180.0f);
  192. float q = 1.0f / tan;
  193. Vector3 direction(x / (q / aspect), y / q, 1.0f);
  194. direction[2] = -direction[2];
  195. direction.normalize();
  196. Vector3 pos = -position;
  197. pos[1] = 32.0f;
  198. pos[1] = 32.0f;
  199. for(int i = 0; i < 150; i++) {
  200. int x = pos[0] + 0.5f;
  201. int y = pos[1] + 0.5f;
  202. int z = pos[2] + 0.5f;
  203. if(x >= 0 && x < 64 && y >= 0 && y < 64 && z >= 0 && z < 64 &&
  204. buffer[x][y][z] > 0.5f) {
  205. emitterPos = pos + Vector3(0.0f, height, 0.0f);
  206. emitterAge = timeTicks;
  207. break;
  208. }
  209. pos += direction;
  210. }
  211. }
  212. static void renderParticles(float lag) {
  213. glPointSize(5.0f);
  214. particleShader.use();
  215. particleShader.setMatrix("proj", projection.getValues());
  216. Matrix m;
  217. m.translateTo(Utils::interpolate(oldPosition, position, lag));
  218. m.translateY(-32.0f - (oldHeight + (height - oldHeight) * lag));
  219. particleShader.setMatrix("view", m.getValues());
  220. particleShader.setFloat("time", timeTicks + lag);
  221. GL::enableBlending();
  222. glDepthMask(false);
  223. pickParticleCenter();
  224. particleShader.setFloat("timeFactor", timeFactor);
  225. particleShader.setVector("position", emitterPos);
  226. particleShader.setFloat("age", emitterAge);
  227. particleShader.setVector("color", Vector4(1.0f, 0.0f, 0.0f, 1.0f));
  228. particleShader.setInt("seedBase", 0);
  229. emptyBuffer.drawPoints(2000000);
  230. particleShader.setVector("position", emitterPos);
  231. particleShader.setFloat("age", emitterAge + 5);
  232. particleShader.setVector("color", Vector4(0.0f, 1.0f, 0.0f, 1.0f));
  233. particleShader.setInt("seedBase", 1);
  234. emptyBuffer.drawPoints(10000);
  235. particleShader.setVector("position", emitterPos);
  236. particleShader.setFloat("age", emitterAge + 10);
  237. particleShader.setVector("color", Vector4(0.0f, 0.0f, 1.0f, 1.0f));
  238. particleShader.setInt("seedBase", 2);
  239. emptyBuffer.drawPoints(5000);
  240. particleShader.setVector("position", emitterPos);
  241. particleShader.setFloat("age", emitterAge + 20);
  242. particleShader.setVector("color", Vector4(0.0f, 1.0f, 1.0f, 1.0f));
  243. particleShader.setInt("seedBase", 2);
  244. emptyBuffer.drawPoints(5000);
  245. glDepthMask(true);
  246. GL::disableBlending();
  247. }
  248. static void renderBackground(Matrix& view) {
  249. backgroundShader.use();
  250. shadowBuffer.bindTextureTo(0, 0);
  251. backgroundShader.setMatrix("proj", frustum.updateProjection().getValues());
  252. backgroundShader.setMatrix("view", view.getValues());
  253. model.translateTo(Vector3(0.0f, 0.0f, 0.0f));
  254. model.scale(Vector3(260.0f, 120.0f, 1.0f));
  255. model.translate(Vector3(0.0f, 20.0f, -200.0f));
  256. backgroundShader.setMatrix("model", model.getValues());
  257. backgroundShader.setMatrix("shadow", shadowProjectionView.getValues());
  258. rectangleBuffer.draw(6);
  259. }
  260. static void renderGame(float lag) {
  261. GL::enableDepthTesting();
  262. prepareMatrices(lag);
  263. renderNoise();
  264. shadowBuffer.bindAndClear();
  265. renderCubes(shadowView);
  266. renderBackground(shadowView);
  267. GL::bindMainFramebuffer();
  268. GL::clear();
  269. renderCubes(view);
  270. renderBackground(view);
  271. renderParticles(lag);
  272. // postShader.use();
  273. // shadowBuffer.bindTextureTo(0, 0);
  274. // rectangleBuffer.draw(6);
  275. }
  276. void Game::init() {
  277. WindowOptions options(4, 0, {1024, 620}, false, "test");
  278. Error error = window.open(options);
  279. if(error.has()) {
  280. error.message.printLine();
  281. return;
  282. }
  283. error = cubeShader.compile("resources/cubes.vs", "resources/cubes.gs",
  284. "resources/cubes.fs");
  285. if(error.has()) {
  286. error.message.printLine();
  287. return;
  288. }
  289. error = noiseShader.compile("resources/noise.vs", nullptr,
  290. "resources/noise.fs");
  291. if(error.has()) {
  292. error.message.printLine();
  293. return;
  294. }
  295. error = particleShader.compile("resources/particles.vs",
  296. "resources/particles.gs",
  297. "resources/particles.fs");
  298. if(error.has()) {
  299. error.message.printLine();
  300. return;
  301. }
  302. error = backgroundShader.compile("resources/background.vs", nullptr,
  303. "resources/background.fs");
  304. if(error.has()) {
  305. error.message.printLine();
  306. return;
  307. }
  308. error =
  309. postShader.compile("resources/post.vs", nullptr, "resources/post.fs");
  310. if(error.has()) {
  311. error.message.printLine();
  312. return;
  313. }
  314. error = shadowBuffer.init(window.getSize(), TextureFormat::depth32());
  315. if(error.has()) {
  316. error.message.printLine();
  317. return;
  318. }
  319. error = bricks.load("resources/bricks.png", 0);
  320. if(error.has()) {
  321. error.message.printLine();
  322. return;
  323. }
  324. error = bricksBump.load("resources/bricks_bump.png", 0);
  325. if(error.has()) {
  326. error.message.printLine();
  327. return;
  328. }
  329. error = bricksNormal.load("resources/bricks_normal.png", 0);
  330. if(error.has()) {
  331. error.message.printLine();
  332. return;
  333. }
  334. noiceBuffer.init(64, 64, 64);
  335. window.buttons.add(up);
  336. window.buttons.add(down);
  337. window.buttons.add(left);
  338. window.buttons.add(right);
  339. window.buttons.add(front);
  340. window.buttons.add(back);
  341. window.buttons.add(toggle);
  342. window.buttons.add(scaleUp);
  343. window.buttons.add(scaleDown);
  344. window.buttons.add(stepsUp);
  345. window.buttons.add(stepsDown);
  346. window.buttons.add(fineStepsUp);
  347. window.buttons.add(fineStepsDown);
  348. window.buttons.add(modeToggle);
  349. window.buttons.add(timeUp);
  350. window.buttons.add(timeDown);
  351. window.buttons.addMouse(primaryMouse);
  352. bricks.setLinearFilter();
  353. bricksBump.setLinearFilter();
  354. bricksNormal.setLinearFilter();
  355. rectangleBuffer.init(Attributes().addFloat(2));
  356. float recData[6][2] = {{-1.0f, -1.0f}, {-1.0, 1.0}, {1.0, -1.0},
  357. {1.0f, 1.0f}, {-1.0, 1.0}, {1.0, -1.0}};
  358. rectangleBuffer.setStaticData(sizeof(recData), recData);
  359. emptyBuffer.init(Attributes());
  360. struct Intern {
  361. void tick() {
  362. tickGame();
  363. }
  364. void render(float lag) {
  365. renderGame(lag);
  366. }
  367. bool isRunning() const {
  368. return true;
  369. }
  370. };
  371. Intern intern;
  372. window.run(intern, 50'000'000);
  373. }