main.c 9.2 KB

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