main.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * 3D Engine
  3. * main.c:
  4. * Based on pikuma.com 3D software renderer in C
  5. * Copyright (c) 2021 986-Studio. All rights reserved.
  6. *
  7. * Created by Manoël Trapier on 01/03/2021.
  8. */
  9. #include <stdio.h>
  10. #include <stdint.h>
  11. #include <stdbool.h>
  12. #include <SDL.h>
  13. #include <log.h>
  14. #include <array.h>
  15. #include <triangle.h>
  16. #include <display.h>
  17. #include <vector.h>
  18. #include <mesh.h>
  19. bool isRunning = true;
  20. int previousFrameTime = 0;
  21. vec3_t cameraPosition =
  22. {
  23. .x = 0,
  24. .y = 0,
  25. .z = 0,
  26. };
  27. triangle_t *projectedTriangles = NULL;
  28. double fovFactor = 640;
  29. void setup()
  30. {
  31. frameBuffer = (uint32_t *)calloc(windowWidth * windowHeight, sizeof(uint32_t));
  32. if (!frameBuffer)
  33. {
  34. log(TLOG_PANIC, NULL, "Memory allocation error.");
  35. goto exit;
  36. }
  37. frameBufferTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, windowWidth,
  38. windowHeight);
  39. if (frameBufferTexture == NULL)
  40. {
  41. log(TLOG_PANIC, NULL, "SDL Texture creation error: %s", SDL_GetError());
  42. goto exit;
  43. }
  44. //loadCubeMeshData();
  45. loadOBJFile("assets/cube.obj");
  46. exit:
  47. return;
  48. }
  49. void processInput()
  50. {
  51. SDL_Event event;
  52. SDL_PollEvent(&event);
  53. switch (event.type)
  54. {
  55. case SDL_QUIT:isRunning = false;
  56. break;
  57. case SDL_KEYDOWN:
  58. if (event.key.keysym.sym == SDLK_ESCAPE)
  59. {
  60. isRunning = false;
  61. }
  62. break;
  63. default:
  64. break;
  65. }
  66. }
  67. vec2_t orthographicPointProjection(vec3_t point)
  68. {
  69. vec2_t ret;
  70. ret.x = point.x * fovFactor;
  71. ret.y = point.y * fovFactor;
  72. return ret;
  73. }
  74. vec2_t perspectivePointProjection(vec3_t point)
  75. {
  76. vec2_t ret;
  77. double divisor = point.z;
  78. if (divisor == 0) { divisor += 0.00001; }
  79. ret.x = (point.x / divisor) * (fovFactor/2.);
  80. ret.y = (point.y / divisor) * (fovFactor/2.);
  81. return ret;
  82. }
  83. void update()
  84. {
  85. uint32_t i, j;
  86. uint32_t faceCount;
  87. uint32_t timeToWait = FRAME_TARGET_TIME - (SDL_GetTicks() - previousFrameTime);
  88. if (timeToWait <= FRAME_TARGET_TIME)
  89. {
  90. SDL_Delay(timeToWait);
  91. }
  92. previousFrameTime = SDL_GetTicks();
  93. mesh.rotation.x += 0.01;
  94. mesh.rotation.y += 0.01;
  95. mesh.rotation.z += 0.02;
  96. arrayEmpty(projectedTriangles);
  97. faceCount = arrayGetSize(mesh.faces);
  98. for(i = 0; i < faceCount; i++)
  99. {
  100. triangle_t currentTriangle;
  101. vec3_t transformed[3];
  102. vec3_t vertices[3] =
  103. {
  104. mesh.vertices[mesh.faces[i].a - 1],
  105. mesh.vertices[mesh.faces[i].b - 1],
  106. mesh.vertices[mesh.faces[i].c - 1],
  107. };
  108. for(j = 0; j < 3; j++)
  109. {
  110. transformed[j] = vertices[j];
  111. transformed[j] = vec3RotateX(transformed[j], mesh.rotation.x);
  112. transformed[j] = vec3RotateY(transformed[j], mesh.rotation.y);
  113. transformed[j] = vec3RotateZ(transformed[j], mesh.rotation.z);
  114. transformed[j].z += 5;
  115. }
  116. vec3_t vectorBA = vec3SubVectors(transformed[1], transformed[0]);
  117. vec3_t vectorCA = vec3SubVectors(transformed[2], transformed[0]);
  118. vec3Normalize(&vectorBA);
  119. vec3Normalize(&vectorCA);
  120. vec3_t triangleNormal = vec3Cross(vectorBA, vectorCA);
  121. vec3Normalize(&triangleNormal);
  122. vec3_t cameraRay = vec3SubVectors(cameraPosition, transformed[0]);
  123. vec3Normalize(&cameraRay);
  124. double cameraDotTriangle = vec3Dot(triangleNormal, cameraRay);
  125. if (cameraDotTriangle < 0)
  126. {
  127. continue;
  128. }
  129. for (j = 0 ; j < 3 ; j++)
  130. {
  131. vec2_t projected = perspectivePointProjection(transformed[j]);
  132. projected.x += (windowWidth / 2);
  133. projected.y += (windowHeight / 2);
  134. currentTriangle.points[j] = projected;
  135. }
  136. arrayAdd(projectedTriangles, currentTriangle);
  137. }
  138. }
  139. void render()
  140. {
  141. int i;
  142. SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
  143. SDL_RenderClear(renderer);
  144. #if 1
  145. int triangleCount = arrayGetSize(projectedTriangles);
  146. for(i = 0; i < triangleCount; i++)
  147. {
  148. drawFilledTriangle(projectedTriangles[i].points[0].x, projectedTriangles[i].points[0].y,
  149. projectedTriangles[i].points[1].x, projectedTriangles[i].points[1].y,
  150. projectedTriangles[i].points[2].x, projectedTriangles[i].points[2].y,
  151. 0xFFFFFFFF);
  152. drawTriangle(projectedTriangles[i].points[0].x, projectedTriangles[i].points[0].y,
  153. projectedTriangles[i].points[1].x, projectedTriangles[i].points[1].y,
  154. projectedTriangles[i].points[2].x, projectedTriangles[i].points[2].y,
  155. 0xFF000000);
  156. }
  157. #else
  158. drawTriangle(300, 100, 50, 400, 500, 700, 0xFF00FF00);
  159. drawFilledTriangle(300, 100, 50, 400, 500, 700, 0xFFFF0000);
  160. #endif
  161. renderFrameBuffer();
  162. clearFrameBuffer(0xFF000000);
  163. SDL_RenderPresent(renderer);
  164. }
  165. int main(int argc, char *argv[])
  166. {
  167. int param_i;
  168. bool fullScreen = false;
  169. MAX_DEBUG_LEVEL = TLOG_DEBUG;
  170. log(TLOG_ALWAYS, NULL, "Booting 3D Engine (version %s)!", VERSION);
  171. for (param_i = 1 ; (param_i < argc) && (argv[param_i][0] == '-') ; param_i++)
  172. {
  173. switch (argv[param_i][1])
  174. {
  175. default: exit(-1); /* Option not recognized */
  176. case 'f': fullScreen = true; break;
  177. case 'w': windowWidth = atoi(argv[++param_i]);
  178. case 'h': windowHeight = atoi(argv[++param_i]); break;
  179. #ifdef DYNA_LOG_LEVEL
  180. case 'l': MAX_DEBUG_LEVEL = atoi(argv[++param_i]); break;
  181. #endif
  182. case '-': goto no_more_params; /* Could use break, but this is more clear */
  183. }
  184. }
  185. no_more_params:
  186. isRunning = initialiseWindow(fullScreen);
  187. setup();
  188. while (isRunning)
  189. {
  190. processInput();
  191. update();
  192. render();
  193. }
  194. arrayFree(projectedTriangles);
  195. meshFree();
  196. destroyWindow();
  197. return 0;
  198. }