main.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. * Voxel-a-tord
  3. * main.c:
  4. * Copyright (c) 2022 986-Studio. All rights reserved.
  5. *
  6. * Created by Manoël Trapier on 28/09/2022.
  7. */
  8. #include <stdio.h>
  9. #include <stdint.h>
  10. #include <stdbool.h>
  11. #include <sys/time.h>
  12. #include <SDL.h>
  13. #include <log.h>
  14. #include <display.h>
  15. #include <texture.h>
  16. #include <fpmath.h>
  17. bool isRunning = false;
  18. int previousFrameTime = 0;
  19. double deltaTime = 0;
  20. static double updateTime, renderTime, waitTime;
  21. static int32_t windowHeight;
  22. static int32_t windowWidth;
  23. static texture_t heightMap;
  24. static texture_t colourMap;
  25. static int32_t *yBuffer;
  26. static int32_t playerHeight = 70;
  27. static fp_num_t playerX = FP_SET_INT(444);
  28. static fp_num_t playerY = FP_SET_INT(299);
  29. static int32_t playerRot = 0;
  30. static int32_t cameraHorizon = 55;
  31. static int32_t scaleFactor = 90;
  32. static int32_t renderDistance = 300;
  33. uint32_t getMicroSecTime()
  34. {
  35. struct timeval curTime;
  36. gettimeofday(&curTime, NULL);
  37. return ((curTime.tv_sec) * 1000 * 1000) + (curTime.tv_usec);
  38. }
  39. void processInput()
  40. {
  41. SDL_Event event;
  42. double direction = FP_GET_INT(1);
  43. fp_num_t dx, dy;
  44. while(SDL_PollEvent(&event))
  45. {
  46. switch (event.type)
  47. {
  48. case SDL_QUIT:
  49. isRunning = false;
  50. break;
  51. case SDL_KEYDOWN:
  52. switch (event.key.keysym.sym)
  53. {
  54. case SDLK_ESCAPE: isRunning = false; break;
  55. case SDLK_LEFT: playerRot = playerRot + 1; break;
  56. case SDLK_RIGHT: playerRot = playerRot - 1; break;
  57. case SDLK_DOWN:
  58. direction = FP_GET_INT(-1);
  59. /* fall-trough */
  60. case SDLK_UP:
  61. dx = FP_MUL(FP_MUL(fpcos(playerRot), 75), FP_SET_FLT(deltaTime));
  62. dy = FP_MUL(FP_MUL(fpsin(playerRot), 75), FP_SET_FLT(deltaTime));
  63. playerX += FP_MUL(dx, direction);
  64. playerY += FP_MUL(dy, direction);
  65. break;
  66. case SDLK_KP_4: playerX -= FP_SET_INT(1); break;
  67. case SDLK_KP_6: playerX += FP_SET_INT(1); break;
  68. case SDLK_KP_8: playerY += FP_SET_INT(1); break;
  69. case SDLK_KP_2: playerY -= FP_SET_INT(1); break;
  70. case SDLK_PAGEUP: playerHeight = playerHeight + 5; break;
  71. case SDLK_PAGEDOWN: playerHeight = playerHeight - 5; break;
  72. case SDLK_HOME: cameraHorizon = cameraHorizon + 5; break;
  73. case SDLK_END: cameraHorizon = cameraHorizon - 5; break;
  74. case SDLK_KP_MULTIPLY: scaleFactor = scaleFactor + 3; break;
  75. case SDLK_KP_DIVIDE: scaleFactor = scaleFactor - 3; break;
  76. case SDLK_KP_PLUS: renderDistance = renderDistance + 3; break;
  77. case SDLK_KP_MINUS: renderDistance = renderDistance - 3; break;
  78. }
  79. break;
  80. default:
  81. break;
  82. }
  83. }
  84. }
  85. void setup()
  86. {
  87. loadTextureDateFromPng(&heightMap, "assets/D1.png");
  88. loadTextureDateFromPng(&colourMap, "assets/C1W.png");
  89. yBuffer = (int32_t *)calloc(windowWidth, sizeof(int32_t));
  90. isRunning = true;
  91. }
  92. void update()
  93. {
  94. uint32_t timeToWait = FRAME_TARGET_TIME - (SDL_GetTicks() - previousFrameTime);
  95. uint32_t ticks = getMicroSecTime();
  96. if (timeToWait <= FRAME_TARGET_TIME)
  97. {
  98. SDL_Delay(timeToWait);
  99. }
  100. deltaTime = (SDL_GetTicks() - previousFrameTime) / 1000.0;
  101. previousFrameTime = SDL_GetTicks();
  102. waitTime = (waitTime + (getMicroSecTime() - ticks) / 1000.) / 2.0;
  103. ticks = getMicroSecTime();
  104. /* [...] */
  105. updateTime = (updateTime + (getMicroSecTime() - ticks) / 1000.) / 2.0;
  106. }
  107. void renderVoxels(tex2_t *p, int32_t angle, int32_t height, int32_t horizon, int32_t scaleHeight, int32_t renderDistance)
  108. {
  109. fp_num_t angleSin = fpsin(angle);
  110. fp_num_t angleCos = fpcos(angle);
  111. fp_num_t dz = FP_SET_INT(1), z = FP_SET_INT(1);
  112. int i;
  113. for(i = 0; i < windowWidth; i++)
  114. {
  115. yBuffer[i] = FP_SET_INT(windowHeight);
  116. }
  117. while( FP_GET_INT(z) < renderDistance)
  118. {
  119. tex2_t pleft;
  120. pleft.u = -FP_MUL(angleCos, z) - FP_MUL(angleSin, z) + p->u;
  121. pleft.v = FP_MUL(angleSin, z) - FP_MUL(angleCos, z) + p->v;
  122. tex2_t pright;
  123. pright.u = FP_MUL(angleCos, z) - FP_MUL(angleSin, z) + p->u;
  124. pright.v = -FP_MUL(angleSin, z) - FP_MUL(angleCos, z) + p->v;
  125. fp_num_t dx = (pright.u - pleft.u);
  126. dx = FP_DIV(dx, FP_SET_INT(windowWidth));
  127. fp_num_t dy = (pright.v - pleft.v);
  128. dy = FP_DIV(dy, FP_SET_INT(windowWidth));
  129. for(i = 0; i < windowWidth; i++)
  130. {
  131. int32_t voxelHeight2 = getTextureColour(&heightMap, &pleft);
  132. voxelHeight2 = height - voxelHeight2;
  133. fp_num_t temp = FP_MUL(FP_DIV(FP_SET_INT(1), z), FP_SET_INT(scaleHeight));
  134. voxelHeight2 = FP_GET_INT(FP_MUL(temp, FP_SET_INT(voxelHeight2)));
  135. int32_t heightOnScreen = voxelHeight2 + horizon;
  136. if (heightOnScreen > 0 && heightOnScreen < yBuffer[i])
  137. {
  138. colour_t voxelColour = getTextureColour(&colourMap, &pleft);
  139. drawVLine(i, yBuffer[i], heightOnScreen, voxelColour);
  140. yBuffer[i] = heightOnScreen;
  141. }
  142. pleft.u += dx;
  143. pleft.v += dy;
  144. }
  145. z += dz;
  146. #ifdef USE_FLOATING_POINT
  147. dz += 0.01;
  148. #else
  149. dz += 1; // (fp_num_t)(0.1 * FP_DIVISOR);
  150. #endif
  151. }
  152. }
  153. void render()
  154. {
  155. uint32_t ticks = getMicroSecTime();
  156. tex2_t origin = { .u = playerX, .v = playerY };
  157. clearFrameBuffer(MAKE_RGB(0, 0, 0));
  158. drawGrid(20, MAKE_RGB(27, 2, 27));
  159. renderVoxels(& origin, playerRot, playerHeight, cameraHorizon, scaleFactor, renderDistance);
  160. renderFrameBuffer();
  161. renderTime = (renderTime + (getMicroSecTime() - ticks) / 1000.) / 2.0;
  162. drawText(5, 5, 0x11FF22, "Wait time: %02.2f ms", waitTime);
  163. drawText(5, 17, 0x11FF22, "Update time: %02.2f ms", updateTime);
  164. drawText(5, 29, 0x11FF22, "Render time: %02.2f ms", renderTime);
  165. drawText(5, 41, 0x11FF22, "FPS: %.1f | dT: %.3f", 1000 / (waitTime + updateTime + renderTime), deltaTime);
  166. #ifdef USE_FLOATING_POINT
  167. drawText(5, 53, 0x11FF22, "P: (%.1f;%.1f) | PH: %.1f | CH: %.1f | SF: %.1f | RD: %.1f", playerX, playerY, playerHeight, cameraHorizon, scaleFactor, renderDistance);
  168. #else
  169. drawText(5, 53, 0x11FF22, "P: (%d;%d) | PH: %d | CH: %d | SF: %d | RD: %d", FP_GET_INT(playerX),
  170. FP_GET_INT(playerY),
  171. playerHeight,
  172. cameraHorizon,
  173. scaleFactor,
  174. renderDistance);
  175. #endif
  176. displayWindowRender();
  177. }
  178. int main(int argc, char *argv[])
  179. {
  180. int param_i;
  181. bool fullScreen = false;
  182. MAX_DEBUG_LEVEL = TLOG_DEBUG;
  183. Log(TLOG_ALWAYS, NULL, "Starting Voxel Engine (version %s)!", VERSION);
  184. windowWidth = 800;
  185. windowHeight = 600;
  186. for (param_i = 1 ; (param_i < argc) && (argv[param_i][0] == '-') ; param_i++)
  187. {
  188. switch (argv[param_i][1])
  189. {
  190. default: exit(-1); /* Option not recognized */
  191. case 'f': fullScreen = true; break;
  192. case 'w': windowWidth = atoi(argv[++param_i]); break;
  193. case 'h': windowHeight = atoi(argv[++param_i]); break;
  194. #ifdef DYNA_LOG_LEVEL
  195. case 'l': MAX_DEBUG_LEVEL = atoi(argv[++param_i]); break;
  196. #endif
  197. case '-': goto no_more_params; /* Could use break, but this is more clear */
  198. }
  199. }
  200. no_more_params:
  201. isRunning = initialiseWindow(windowWidth, windowHeight, fullScreen);
  202. setup();
  203. while (isRunning)
  204. {
  205. processInput();
  206. update();
  207. render();
  208. }
  209. destroyWindow();
  210. return 0;
  211. }