main.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. typedef enum displayMode_t
  22. {
  23. DISPLAY_MODE_WIREFRAME,
  24. DISPLAY_MODE_SOLID,
  25. DISPLAY_MODE_BOTH,
  26. } displayMode_t;
  27. bool displayVertex = false;
  28. bool doNotCull = false;
  29. enum displayMode_t currentDisplayMode = DISPLAY_MODE_SOLID;
  30. vec3_t cameraPosition =
  31. {
  32. .x = 0,
  33. .y = 0,
  34. .z = 0,
  35. };
  36. triangle_t *projectedTriangles = NULL;
  37. double fovFactor = 640;
  38. void setup()
  39. {
  40. frameBuffer = (uint32_t *)calloc(windowWidth * windowHeight, sizeof(uint32_t));
  41. if (!frameBuffer)
  42. {
  43. Log(TLOG_PANIC, NULL, "Memory allocation error.");
  44. goto exit;
  45. }
  46. frameBufferTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, windowWidth,
  47. windowHeight);
  48. if (frameBufferTexture == NULL)
  49. {
  50. Log(TLOG_PANIC, NULL, "SDL Texture creation error: %s", SDL_GetError());
  51. goto exit;
  52. }
  53. //loadOBJFile("assets/cube.obj");
  54. loadCubeMeshData();
  55. exit:
  56. return;
  57. }
  58. void processInput()
  59. {
  60. SDL_Event event;
  61. SDL_PollEvent(&event);
  62. switch (event.type)
  63. {
  64. case SDL_QUIT:isRunning = false;
  65. break;
  66. case SDL_KEYDOWN:
  67. switch(event.key.keysym.sym)
  68. {
  69. case SDLK_ESCAPE:
  70. isRunning = false;
  71. break;
  72. case SDLK_1:
  73. displayVertex = true;
  74. currentDisplayMode = DISPLAY_MODE_WIREFRAME;
  75. break;
  76. case SDLK_2:
  77. displayVertex = false;
  78. currentDisplayMode = DISPLAY_MODE_WIREFRAME;
  79. break;
  80. case SDLK_3:
  81. displayVertex = false;
  82. currentDisplayMode = DISPLAY_MODE_SOLID;
  83. break;
  84. case SDLK_4:
  85. displayVertex = false;
  86. currentDisplayMode = DISPLAY_MODE_BOTH;
  87. break;
  88. case SDLK_c:
  89. doNotCull = false;
  90. break;
  91. case SDLK_d:
  92. doNotCull = true;
  93. break;
  94. }
  95. break;
  96. default:
  97. break;
  98. }
  99. }
  100. vec2_t orthographicPointProjection(vec3_t point)
  101. {
  102. vec2_t ret;
  103. ret.x = point.x * fovFactor;
  104. ret.y = point.y * fovFactor;
  105. return ret;
  106. }
  107. vec2_t perspectivePointProjection(vec3_t point)
  108. {
  109. vec2_t ret;
  110. double divisor = point.z;
  111. if (divisor == 0) { divisor += 0.00001; }
  112. ret.x = (point.x / divisor) * (fovFactor/2.);
  113. ret.y = (point.y / divisor) * (fovFactor/2.);
  114. return ret;
  115. }
  116. void update()
  117. {
  118. uint32_t i, j;
  119. uint32_t faceCount;
  120. uint32_t timeToWait = FRAME_TARGET_TIME - (SDL_GetTicks() - previousFrameTime);
  121. if (timeToWait <= FRAME_TARGET_TIME)
  122. {
  123. SDL_Delay(timeToWait);
  124. }
  125. previousFrameTime = SDL_GetTicks();
  126. mesh.rotation.x += 0.01;
  127. mesh.rotation.y += 0.01;
  128. mesh.rotation.z += 0.02;
  129. arrayEmpty(projectedTriangles);
  130. faceCount = arrayGetSize(mesh.faces);
  131. for(i = 0; i < faceCount; i++)
  132. {
  133. triangle_t currentTriangle;
  134. vec3_t transformedVertices[3];
  135. vec3_t vertices[3] =
  136. {
  137. mesh.vertices[mesh.faces[i].a - 1],
  138. mesh.vertices[mesh.faces[i].b - 1],
  139. mesh.vertices[mesh.faces[i].c - 1],
  140. };
  141. for(j = 0; j < 3; j++)
  142. {
  143. transformedVertices[j] = vertices[j];
  144. transformedVertices[j] = vec3RotateX(transformedVertices[j], mesh.rotation.x);
  145. transformedVertices[j] = vec3RotateY(transformedVertices[j], mesh.rotation.y);
  146. transformedVertices[j] = vec3RotateZ(transformedVertices[j], mesh.rotation.z);
  147. transformed[j].z += 5;
  148. }
  149. if (!doNotCull)
  150. {
  151. vec3_t vectorBA = vec3SubVectors(transformedVertices[1], transformedVertices[0]);
  152. vec3_t vectorCA = vec3SubVectors(transformedVertices[2], transformedVertices[0]);
  153. vec3Normalize(&vectorBA);
  154. vec3Normalize(&vectorCA);
  155. vec3_t triangleNormal = vec3Cross(vectorBA, vectorCA);
  156. vec3Normalize(&triangleNormal);
  157. vec3_t cameraRay = vec3SubVectors(cameraPosition, transformedVertices[0]);
  158. vec3Normalize(&cameraRay);
  159. double cameraDotTriangle = vec3Dot(triangleNormal, cameraRay);
  160. if (cameraDotTriangle < 0)
  161. {
  162. continue;
  163. }
  164. }
  165. for (j = 0 ; j < 3 ; j++)
  166. {
  167. vec2_t projected = perspectivePointProjection(transformedVertices[j]);
  168. projected.x += (windowWidth / 2);
  169. projected.y += (windowHeight / 2);
  170. currentTriangle.points[j] = projected;
  171. }
  172. currentTriangle.colour = mesh.faces[i].colour;
  173. currentTriangle.averageDepth = (transformedVertices[0].z +
  174. transformedVertices[1].z +
  175. transformedVertices[2].z) / 3.0;
  176. arrayAdd(projectedTriangles, currentTriangle);
  177. }
  178. }
  179. void render()
  180. {
  181. int i;
  182. SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
  183. SDL_RenderClear(renderer);
  184. #if 1
  185. int triangleCount = arrayGetSize(projectedTriangles);
  186. for(i = 0; i < triangleCount; i++)
  187. {
  188. switch(currentDisplayMode)
  189. {
  190. case DISPLAY_MODE_SOLID:
  191. drawFilledTriangle(projectedTriangles[i].points[0].x, projectedTriangles[i].points[0].y,
  192. projectedTriangles[i].points[1].x, projectedTriangles[i].points[1].y,
  193. projectedTriangles[i].points[2].x, projectedTriangles[i].points[2].y,
  194. projectedTriangles[i].colour);
  195. break;
  196. case DISPLAY_MODE_WIREFRAME:
  197. drawTriangle(projectedTriangles[i].points[0].x, projectedTriangles[i].points[0].y,
  198. projectedTriangles[i].points[1].x, projectedTriangles[i].points[1].y,
  199. projectedTriangles[i].points[2].x, projectedTriangles[i].points[2].y,
  200. projectedTriangles[i].colour);
  201. break;
  202. case DISPLAY_MODE_BOTH:
  203. drawFilledTriangle(projectedTriangles[i].points[0].x, projectedTriangles[i].points[0].y,
  204. projectedTriangles[i].points[1].x, projectedTriangles[i].points[1].y,
  205. projectedTriangles[i].points[2].x, projectedTriangles[i].points[2].y,
  206. projectedTriangles[i].colour);
  207. drawTriangle(projectedTriangles[i].points[0].x, projectedTriangles[i].points[0].y,
  208. projectedTriangles[i].points[1].x, projectedTriangles[i].points[1].y,
  209. projectedTriangles[i].points[2].x, projectedTriangles[i].points[2].y,
  210. 0xFF000000 | ~projectedTriangles[i].colour);
  211. break;
  212. }
  213. if (displayVertex)
  214. {
  215. int j;
  216. for(j = 0; j < 3; j++)
  217. {
  218. drawRectangle(projectedTriangles[i].points[j].x - 1,
  219. projectedTriangles[i].points[j].y - 1,
  220. 3, 3,
  221. 0xFFFF0000);
  222. }
  223. }
  224. }
  225. #else
  226. drawTriangle(300, 100, 50, 400, 500, 700, 0xFF00FF00);
  227. drawFilledTriangle(300, 100, 50, 400, 500, 700, 0xFFFF0000);
  228. #endif
  229. renderFrameBuffer();
  230. clearFrameBuffer(0xFF000000);
  231. SDL_RenderPresent(renderer);
  232. }
  233. int main(int argc, char *argv[])
  234. {
  235. int param_i;
  236. bool fullScreen = false;
  237. MAX_DEBUG_LEVEL = TLOG_DEBUG;
  238. Log(TLOG_ALWAYS, NULL, "Booting 3D Engine (version %s)!", VERSION);
  239. for (param_i = 1 ; (param_i < argc) && (argv[param_i][0] == '-') ; param_i++)
  240. {
  241. switch (argv[param_i][1])
  242. {
  243. default: exit(-1); /* Option not recognized */
  244. case 'f': fullScreen = true; break;
  245. case 'w': windowWidth = atoi(argv[++param_i]);
  246. case 'h': windowHeight = atoi(argv[++param_i]); break;
  247. #ifdef DYNA_LOG_LEVEL
  248. case 'l': MAX_DEBUG_LEVEL = atoi(argv[++param_i]); break;
  249. #endif
  250. case '-': goto no_more_params; /* Could use break, but this is more clear */
  251. }
  252. }
  253. no_more_params:
  254. isRunning = initialiseWindow(fullScreen);
  255. setup();
  256. while (isRunning)
  257. {
  258. processInput();
  259. update();
  260. render();
  261. }
  262. arrayFree(projectedTriangles);
  263. meshFree();
  264. destroyWindow();
  265. return 0;
  266. }