helper.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /**
  2. Helper code for tinyphysicsengine example programs which handle things like
  3. SDL rendering, I/O, small3dlib rendering etc.
  4. */
  5. #define TPE_LOG puts
  6. #include "../tinyphysicsengine.h"
  7. #include <SDL2/SDL.h>
  8. #include <math.h>
  9. #include <sys/time.h> // for measuring time
  10. #ifndef RES_X
  11. #define RES_X 640
  12. #endif
  13. #ifndef RES_Y
  14. #define RES_Y 480
  15. #endif
  16. #ifndef FPS
  17. #define FPS 30
  18. #endif
  19. #ifndef CAMERA_STEP
  20. #define CAMERA_STEP 100
  21. #endif
  22. #ifndef CAMERA_ROT_STEP
  23. #define CAMERA_ROT_STEP 5
  24. #endif
  25. #define MSPF (1000 / (FPS))
  26. #define S3L_RESOLUTION_X RES_X
  27. #define S3L_RESOLUTION_Y RES_Y
  28. #define S3L_PIXEL_FUNCTION s3l_drawPixel
  29. #define S3L_SORT 0
  30. #define S3L_Z_BUFFER 1
  31. #define S3L_NEAR_CROSS_STRATEGY 2
  32. #define S3L_USE_WIDER_TYPES 1
  33. #include "small3dlib.h"
  34. #define PIXELS_SIZE (S3L_RESOLUTION_X * S3L_RESOLUTION_Y * 4)
  35. S3L_Unit cubeVertices[] = { S3L_CUBE_VERTICES(TPE_FRACTIONS_PER_UNIT) };
  36. S3L_Index cubeTriangles[] = { S3L_CUBE_TRIANGLES };
  37. S3L_Model3D cubeModel;
  38. S3L_Unit triangleVertices[9];
  39. S3L_Index triangleTriangles[] = {0, 1, 2, 0, 2, 1};
  40. S3L_Model3D triangleModel;
  41. S3L_Unit planeVerices[] =
  42. {
  43. #define a S3L_FRACTIONS_PER_UNIT / 2
  44. #define b -1 * S3L_FRACTIONS_PER_UNIT / 2
  45. a,0,a,
  46. a,0,b,
  47. b,0,a,
  48. b,0,b
  49. #undef a
  50. #undef b
  51. };
  52. S3L_Index planeTriangles[] =
  53. { 0,2,1, 1,2,3 };
  54. S3L_Model3D planeModel;
  55. #define SPHERE_VERTEX_COUNT 42
  56. const S3L_Unit sphereVertices[SPHERE_VERTEX_COUNT * 3] = {
  57. 0, -512, 0, // 0
  58. 370, -228, -269, // 3
  59. -141, -228, -435, // 6
  60. -457, -228, 0, // 9
  61. -141, -228, 435, // 12
  62. 370, -228, 269, // 15
  63. 141, 228, -435, // 18
  64. -370, 228, -269, // 21
  65. -370, 228, 269, // 24
  66. 141, 228, 435, // 27
  67. 457, 228, 0, // 30
  68. 0, 512, 0, // 33
  69. -83, -435, -255, // 36
  70. 217, -435, -158, // 39
  71. 134, -269, -414, // 42
  72. 435, -269, 0, // 45
  73. 217, -435, 158, // 48
  74. -269, -435, 0, // 51
  75. -352, -269, -255, // 54
  76. -83, -435, 255, // 57
  77. -352, -269, 255, // 60
  78. 134, -269, 414, // 63
  79. 486, 0, -158, // 66
  80. 486, 0, 158, // 69
  81. 0, 0, -512, // 72
  82. 300, 0, -414, // 75
  83. -486, 0, -158, // 78
  84. -300, 0, -414, // 81
  85. -300, 0, 414, // 84
  86. -486, 0, 158, // 87
  87. 300, 0, 414, // 90
  88. 0, 0, 512, // 93
  89. 352, 269, -255, // 96
  90. -134, 269, -414, // 99
  91. -435, 269, 0, // 102
  92. -134, 269, 414, // 105
  93. 352, 269, 255, // 108
  94. 83, 435, -255, // 111
  95. 269, 435, 0, // 114
  96. -217, 435, -158, // 117
  97. -217, 435, 158, // 120
  98. 83, 435, 255 // 123
  99. }; // sphereVertices
  100. #define SPHERE_TRIANGLE_COUNT 80
  101. const S3L_Index sphereTriangleIndices[SPHERE_TRIANGLE_COUNT * 3] = {
  102. 0, 13, 12, // 0
  103. 1, 13, 15, // 3
  104. 0, 12, 17, // 6
  105. 0, 17, 19, // 9
  106. 0, 19, 16, // 12
  107. 1, 15, 22, // 15
  108. 2, 14, 24, // 18
  109. 3, 18, 26, // 21
  110. 4, 20, 28, // 24
  111. 5, 21, 30, // 27
  112. 1, 22, 25, // 30
  113. 2, 24, 27, // 33
  114. 3, 26, 29, // 36
  115. 4, 28, 31, // 39
  116. 5, 30, 23, // 42
  117. 6, 32, 37, // 45
  118. 7, 33, 39, // 48
  119. 8, 34, 40, // 51
  120. 9, 35, 41, // 54
  121. 10, 36, 38, // 57
  122. 38, 41, 11, // 60
  123. 38, 36, 41, // 63
  124. 36, 9, 41, // 66
  125. 41, 40, 11, // 69
  126. 41, 35, 40, // 72
  127. 35, 8, 40, // 75
  128. 40, 39, 11, // 78
  129. 40, 34, 39, // 81
  130. 34, 7, 39, // 84
  131. 39, 37, 11, // 87
  132. 39, 33, 37, // 90
  133. 33, 6, 37, // 93
  134. 37, 38, 11, // 96
  135. 37, 32, 38, // 99
  136. 32, 10, 38, // 102
  137. 23, 36, 10, // 105
  138. 23, 30, 36, // 108
  139. 30, 9, 36, // 111
  140. 31, 35, 9, // 114
  141. 31, 28, 35, // 117
  142. 28, 8, 35, // 120
  143. 29, 34, 8, // 123
  144. 29, 26, 34, // 126
  145. 26, 7, 34, // 129
  146. 27, 33, 7, // 132
  147. 27, 24, 33, // 135
  148. 24, 6, 33, // 138
  149. 25, 32, 6, // 141
  150. 25, 22, 32, // 144
  151. 22, 10, 32, // 147
  152. 30, 31, 9, // 150
  153. 30, 21, 31, // 153
  154. 21, 4, 31, // 156
  155. 28, 29, 8, // 159
  156. 28, 20, 29, // 162
  157. 20, 3, 29, // 165
  158. 26, 27, 7, // 168
  159. 26, 18, 27, // 171
  160. 18, 2, 27, // 174
  161. 24, 25, 6, // 177
  162. 24, 14, 25, // 180
  163. 14, 1, 25, // 183
  164. 22, 23, 10, // 186
  165. 22, 15, 23, // 189
  166. 15, 5, 23, // 192
  167. 16, 21, 5, // 195
  168. 16, 19, 21, // 198
  169. 19, 4, 21, // 201
  170. 19, 20, 4, // 204
  171. 19, 17, 20, // 207
  172. 17, 3, 20, // 210
  173. 17, 18, 3, // 213
  174. 17, 12, 18, // 216
  175. 12, 2, 18, // 219
  176. 15, 16, 5, // 222
  177. 15, 13, 16, // 225
  178. 13, 0, 16, // 228
  179. 12, 14, 2, // 231
  180. 12, 13, 14, // 234
  181. 13, 1, 14 // 237
  182. }; // sphereTriangleIndices
  183. S3L_Model3D sphereModel;
  184. #define MAX_BODIES 128
  185. #define MAX_JOINTS 1024
  186. #define MAX_CONNECTIONS 2048
  187. TPE_Body tpe_bodies[MAX_BODIES];
  188. TPE_Joint tpe_joints[MAX_JOINTS];
  189. TPE_Connection tpe_connections[MAX_CONNECTIONS];
  190. unsigned int
  191. helper_jointsUsed = 0,
  192. helper_connectionsUsed = 0;
  193. TPE_World tpe_world;
  194. uint8_t sdl_pixels[PIXELS_SIZE];
  195. SDL_Window *sdl_window;
  196. SDL_Renderer *sdl_renderer;
  197. SDL_Texture *sdl_texture;
  198. SDL_Surface *sdl_screenSurface;
  199. int helper_frameStartTime;
  200. int helper_frameMsLeft;
  201. int helper_running;
  202. int helper_frame;
  203. const uint8_t *sdl_keyboard;
  204. S3L_Scene s3l_scene;
  205. S3L_Vec4 helper_cameraForw, helper_cameraRight, helper_cameraUp;
  206. unsigned long helper_getMicroSecs(void)
  207. {
  208. struct timeval t;
  209. gettimeofday(&t,NULL);
  210. return 1000000 * t.tv_sec + t.tv_usec;
  211. }
  212. void _helper_bodyAdded(int joints, int conns, TPE_Unit mass)
  213. {
  214. TPE_bodyInit(&tpe_bodies[tpe_world.bodyCount],
  215. &tpe_joints[helper_jointsUsed],joints,
  216. &tpe_connections[helper_connectionsUsed],conns,mass);
  217. helper_jointsUsed += joints;
  218. helper_connectionsUsed += conns;
  219. tpe_world.bodyCount++;
  220. }
  221. void helper_addBox(TPE_Unit w, TPE_Unit h, TPE_Unit d, TPE_Unit jointSize, TPE_Unit mass)
  222. {
  223. TPE_makeBox(
  224. tpe_joints + helper_jointsUsed,
  225. tpe_connections + helper_connectionsUsed,w,h,d,jointSize);
  226. _helper_bodyAdded(8,16,mass);
  227. }
  228. void helper_add2Line(TPE_Unit w, TPE_Unit jointSize, TPE_Unit mass)
  229. {
  230. TPE_make2Line(
  231. tpe_joints + helper_jointsUsed,
  232. tpe_connections + helper_connectionsUsed,w,jointSize);
  233. _helper_bodyAdded(2,1,mass);
  234. }
  235. void helper_addTriangle(TPE_Unit s, TPE_Unit d, TPE_Unit mass)
  236. {
  237. TPE_makeTriangle(
  238. tpe_joints + helper_jointsUsed,
  239. tpe_connections + helper_connectionsUsed,s,d);
  240. _helper_bodyAdded(3,3,mass);
  241. }
  242. void helper_addRect(TPE_Unit w, TPE_Unit d, TPE_Unit jointSize, TPE_Unit mass)
  243. {
  244. TPE_makeRect(
  245. tpe_joints + helper_jointsUsed,
  246. tpe_connections + helper_connectionsUsed,w,d,jointSize);
  247. _helper_bodyAdded(4,6,mass);
  248. }
  249. void helper_addBall(TPE_Unit s, TPE_Unit mass)
  250. {
  251. tpe_joints[helper_jointsUsed] = TPE_joint(TPE_vec3(0,0,0),s);
  252. _helper_bodyAdded(1,0,mass);
  253. }
  254. void helper_printCamera(void)
  255. {
  256. printf("camera: %ld %ld %ld (%ld %ld %ld)\n",
  257. s3l_scene.camera.transform.translation.x,
  258. s3l_scene.camera.transform.translation.y,
  259. s3l_scene.camera.transform.translation.z,
  260. s3l_scene.camera.transform.rotation.x,
  261. s3l_scene.camera.transform.rotation.y,
  262. s3l_scene.camera.transform.rotation.z);
  263. }
  264. void helper_printCPU(void)
  265. {
  266. printf("CPU (%d FPS): %d %\n",FPS,((MSPF - helper_frameMsLeft) * 100) / MSPF);
  267. }
  268. void helper_cameraFreeMovement(void)
  269. {
  270. if (sdl_keyboard[SDL_SCANCODE_LSHIFT])
  271. {
  272. if (sdl_keyboard[SDL_SCANCODE_UP])
  273. S3L_vec3Add(&s3l_scene.camera.transform.translation,helper_cameraForw);
  274. else if (sdl_keyboard[SDL_SCANCODE_DOWN])
  275. S3L_vec3Sub(&s3l_scene.camera.transform.translation,helper_cameraForw);
  276. else if (sdl_keyboard[SDL_SCANCODE_LEFT])
  277. S3L_vec3Sub(&s3l_scene.camera.transform.translation,helper_cameraRight);
  278. else if (sdl_keyboard[SDL_SCANCODE_RIGHT])
  279. S3L_vec3Add(&s3l_scene.camera.transform.translation,helper_cameraRight);
  280. }
  281. else
  282. {
  283. if (sdl_keyboard[SDL_SCANCODE_UP])
  284. s3l_scene.camera.transform.rotation.x += CAMERA_ROT_STEP;
  285. else if (sdl_keyboard[SDL_SCANCODE_DOWN])
  286. s3l_scene.camera.transform.rotation.x -= CAMERA_ROT_STEP;
  287. else if (sdl_keyboard[SDL_SCANCODE_LEFT])
  288. s3l_scene.camera.transform.rotation.y += CAMERA_ROT_STEP;
  289. else if (sdl_keyboard[SDL_SCANCODE_RIGHT])
  290. s3l_scene.camera.transform.rotation.y -= CAMERA_ROT_STEP;
  291. else if (sdl_keyboard[SDL_SCANCODE_Q])
  292. s3l_scene.camera.transform.rotation.z += CAMERA_ROT_STEP;
  293. else if (sdl_keyboard[SDL_SCANCODE_E])
  294. s3l_scene.camera.transform.rotation.z -= CAMERA_ROT_STEP;
  295. }
  296. }
  297. void sdl_drawPixel(int x, int y, uint8_t r, uint8_t g, uint8_t b)
  298. {
  299. uint8_t *pixel = sdl_pixels + (y * S3L_RESOLUTION_X + x) * 4 + 1;
  300. *pixel = b;
  301. pixel++;
  302. *pixel = g;
  303. pixel++;
  304. *pixel = r;
  305. }
  306. void helper_drawLine2D(int x1, int y1, int x2, int y2, uint8_t r, uint8_t g,
  307. uint8_t b)
  308. {
  309. // stupid algorithm
  310. x2 -= x1;
  311. y2 -= y1;
  312. int max = (x2 * x2 > y2 * y2) ? x2 : y2;
  313. if (max < 0)
  314. max *= -1;
  315. for (int i = 0; i < max; ++i)
  316. sdl_drawPixel(x1 + (x2 * i) / max,y1 + (y2 * i) / max,r,g,b);
  317. }
  318. void helper_drawLine3D(TPE_Vec3 p1, TPE_Vec3 p2, uint8_t rr, uint8_t gg,
  319. uint8_t bb)
  320. {
  321. S3L_Vec4 a, b, c, d;
  322. a.x = p1.x; a.y = p1.y; a.z = p1.z; a.w = 0;
  323. b.x = p2.x; b.y = p2.y; b.z = p2.z; b.w = 0;
  324. S3L_project3DPointToScreen(a,s3l_scene.camera,&c);
  325. S3L_project3DPointToScreen(b,s3l_scene.camera,&d);
  326. if (c.x >= 0 && c.x < S3L_RESOLUTION_X && c.y >= 0 && c.y < S3L_RESOLUTION_Y && c.z > 0 &&
  327. d.x >= 0 && d.x < S3L_RESOLUTION_X && d.y >= 0 && d.y < S3L_RESOLUTION_Y && d.z > 0)
  328. helper_drawLine2D(c.x,c.y,d.x,d.y,rr,gg,bb);
  329. }
  330. void tpe_debugDrawPixel(uint16_t x, uint16_t y, uint8_t color)
  331. {
  332. if (x < S3L_RESOLUTION_X - 2 && y < S3L_RESOLUTION_Y - 2)
  333. {
  334. uint8_t r, g, b;
  335. switch (color)
  336. {
  337. case 0: r = 100; g = 255; b = 200; break;
  338. case 1: r = 255; g = 100; b = 100; break;
  339. case 2: r = 0; g = 50; b = 50; break;
  340. default: r = 0; g = 0; b = 0; break;
  341. }
  342. for (int i = 0; i < 3; ++i)
  343. for (int j = 0; j < 3; ++j)
  344. sdl_drawPixel(x + i,y + j,r,g,b);
  345. }
  346. }
  347. void helper_debugDraw(void)
  348. {
  349. TPE_Vec3 camPos =
  350. TPE_vec3(
  351. s3l_scene.camera.transform.translation.x,
  352. s3l_scene.camera.transform.translation.y,
  353. s3l_scene.camera.transform.translation.z);
  354. TPE_Vec3 camRot =
  355. TPE_vec3(
  356. s3l_scene.camera.transform.rotation.x,
  357. s3l_scene.camera.transform.rotation.y,
  358. s3l_scene.camera.transform.rotation.z);
  359. TPE_worldDebugDraw(&tpe_world,tpe_debugDrawPixel,camPos,camRot,
  360. TPE_vec3(S3L_RESOLUTION_X,S3L_RESOLUTION_Y,s3l_scene.camera.focalLength));
  361. }
  362. uint8_t s3l_r = 0, s3l_g = 255, s3l_b = 0;
  363. uint8_t s3l_rr = 0, s3l_gg = 255, s3l_bb = 0;
  364. int s3l_previousTriangleID = -1;
  365. void s3l_drawPixel(S3L_PixelInfo *p)
  366. {
  367. if (p->triangleIndex != s3l_previousTriangleID)
  368. {
  369. s3l_rr = s3l_r + ((p->triangleIndex * 5) % 128) * (((s3l_r < 128) * 2) - 1);
  370. s3l_gg = s3l_g + ((p->triangleIndex * 3) % 128) * (((s3l_g < 128) * 2) - 1);
  371. s3l_bb = s3l_b + ((p->triangleIndex * 7) % 128) * (((s3l_b < 128) * 2) - 1);
  372. s3l_previousTriangleID = p->triangleIndex;
  373. }
  374. sdl_drawPixel(p->x,p->y,s3l_rr,s3l_gg,s3l_bb);
  375. }
  376. void helper_set3dColor(uint8_t r, uint8_t g, uint8_t b)
  377. {
  378. s3l_r = r;
  379. s3l_g = g;
  380. s3l_b = b;
  381. }
  382. void helper_drawModel(S3L_Model3D *model, TPE_Vec3 pos, TPE_Vec3 scale,
  383. TPE_Vec3 rot)
  384. {
  385. s3l_previousTriangleID = -1;
  386. model->transform.translation.x = pos.x;
  387. model->transform.translation.y = pos.y;
  388. model->transform.translation.z = pos.z;
  389. model->transform.scale.x = scale.x;
  390. model->transform.scale.y = scale.y;
  391. model->transform.scale.z = scale.z;
  392. model->transform.rotation.x = rot.x;
  393. model->transform.rotation.y = rot.y;
  394. model->transform.rotation.z = rot.z;
  395. s3l_scene.models = model;
  396. S3L_drawScene(s3l_scene);
  397. }
  398. void helper_draw3dTriangle(TPE_Vec3 v1, TPE_Vec3 v2, TPE_Vec3 v3)
  399. {
  400. triangleVertices[0] = v1.x;
  401. triangleVertices[1] = v1.y;
  402. triangleVertices[2] = v1.z;
  403. triangleVertices[3] = v2.x;
  404. triangleVertices[4] = v2.y;
  405. triangleVertices[5] = v2.z;
  406. triangleVertices[6] = v3.x;
  407. triangleVertices[7] = v3.y;
  408. triangleVertices[8] = v3.z;
  409. helper_drawModel(&triangleModel,TPE_vec3(0,0,0),
  410. TPE_vec3(S3L_FRACTIONS_PER_UNIT,S3L_FRACTIONS_PER_UNIT,S3L_FRACTIONS_PER_UNIT),
  411. TPE_vec3(0,0,0));
  412. }
  413. void helper_draw3dCube(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
  414. {
  415. cubeModel.config.backfaceCulling = 2;
  416. helper_drawModel(&cubeModel,pos,scale,rot);
  417. }
  418. void helper_draw3dCubeInside(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
  419. {
  420. cubeModel.config.backfaceCulling = 1;
  421. helper_drawModel(&cubeModel,pos,scale,rot);
  422. }
  423. void helper_draw3dPlane(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
  424. {
  425. helper_drawModel(&planeModel,pos,scale,rot);
  426. }
  427. void helper_draw3dSphere(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
  428. {
  429. helper_drawModel(&sphereModel,pos,scale,rot);
  430. }
  431. void helper_init(void)
  432. {
  433. sdl_window = SDL_CreateWindow("program",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,S3L_RESOLUTION_X,S3L_RESOLUTION_Y,SDL_WINDOW_SHOWN);
  434. sdl_renderer = SDL_CreateRenderer(sdl_window,-1,0);
  435. sdl_texture = SDL_CreateTexture(sdl_renderer,SDL_PIXELFORMAT_RGBX8888,SDL_TEXTUREACCESS_STATIC,S3L_RESOLUTION_X,S3L_RESOLUTION_Y);
  436. sdl_screenSurface = SDL_GetWindowSurface(sdl_window);
  437. sdl_keyboard = SDL_GetKeyboardState(NULL);
  438. helper_running = 1;
  439. helper_frame = 0;
  440. helper_frameMsLeft = 0;
  441. S3L_model3DInit(cubeVertices,S3L_CUBE_VERTEX_COUNT,cubeTriangles,
  442. S3L_CUBE_TRIANGLE_COUNT,&cubeModel);
  443. S3L_model3DInit(planeVerices,4,planeTriangles,2,&planeModel);
  444. S3L_model3DInit(sphereVertices,SPHERE_VERTEX_COUNT,sphereTriangleIndices,
  445. SPHERE_TRIANGLE_COUNT,&sphereModel);
  446. S3L_model3DInit(triangleVertices,3,triangleTriangles,2,&triangleModel);
  447. S3L_sceneInit(0,1,&s3l_scene);
  448. TPE_worldInit(&tpe_world,tpe_bodies,0,0);
  449. }
  450. void helper_frameStart(void)
  451. {
  452. helper_frameStartTime = SDL_GetTicks();
  453. for (uint32_t i = 0; i < PIXELS_SIZE; ++i)
  454. sdl_pixels[i] = 0;
  455. S3L_newFrame();
  456. SDL_Event event;
  457. while (SDL_PollEvent(&event))
  458. if (
  459. (event.type == SDL_QUIT) ||
  460. ((event.type == SDL_KEYDOWN) && (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE))
  461. )
  462. helper_running = 0;
  463. S3L_rotationToDirections(s3l_scene.camera.transform.rotation,
  464. CAMERA_STEP,&helper_cameraForw,&helper_cameraRight,&helper_cameraUp);
  465. sdl_keyboard = SDL_GetKeyboardState(NULL);
  466. }
  467. void helper_frameEnd(void)
  468. {
  469. SDL_UpdateTexture(sdl_texture,NULL,sdl_pixels,S3L_RESOLUTION_X * sizeof(uint32_t));
  470. SDL_RenderClear(sdl_renderer);
  471. SDL_RenderCopy(sdl_renderer,sdl_texture,NULL,NULL);
  472. SDL_RenderPresent(sdl_renderer);
  473. helper_frame++;
  474. helper_frameMsLeft = helper_frameStartTime + MSPF - SDL_GetTicks();
  475. if (helper_frameMsLeft > 0)
  476. usleep(helper_frameMsLeft * 1000); // ofc this isn't accurate
  477. }
  478. void helper_end(void)
  479. {
  480. // TODO
  481. }