olive.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  1. // Copyright 2022 Alexey Kutepov <[email protected]>
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining
  4. // a copy of this software and associated documentation files (the
  5. // "Software"), to deal in the Software without restriction, including
  6. // without limitation the rights to use, copy, modify, merge, publish,
  7. // distribute, sublicense, and/or sell copies of the Software, and to
  8. // permit persons to whom the Software is furnished to do so, subject to
  9. // the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be
  12. // included in all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #ifndef OLIVE_C_
  22. #define OLIVE_C_
  23. #include <stddef.h>
  24. #include <stdint.h>
  25. #include <stdbool.h>
  26. #ifndef OLIVECDEF
  27. #define OLIVECDEF static inline
  28. #endif
  29. #ifndef OLIVEC_AA_RES
  30. #define OLIVEC_AA_RES 2
  31. #endif
  32. #define OLIVEC_SWAP(T, a, b) do { T t = a; a = b; b = t; } while (0)
  33. #define OLIVEC_SIGN(T, x) ((T)((x) > 0) - (T)((x) < 0))
  34. #define OLIVEC_ABS(T, x) (OLIVEC_SIGN(T, x)*(x))
  35. typedef struct {
  36. size_t width, height;
  37. const char *glyphs;
  38. } Olivec_Font;
  39. #define OLIVEC_DEFAULT_FONT_HEIGHT 6
  40. #define OLIVEC_DEFAULT_FONT_WIDTH 6
  41. // TODO: allocate proper descender and acender areas for the default font
  42. static char olivec_default_glyphs[128][OLIVEC_DEFAULT_FONT_HEIGHT][OLIVEC_DEFAULT_FONT_WIDTH] = {
  43. ['a'] = {
  44. {0, 0, 0, 0, 0},
  45. {0, 1, 1, 0, 0},
  46. {0, 0, 0, 1, 0},
  47. {0, 1, 1, 1, 0},
  48. {1, 0, 0, 1, 0},
  49. {0, 1, 1, 1, 0},
  50. },
  51. ['b'] = {
  52. {1, 0, 0, 0, 0},
  53. {1, 1, 1, 0, 0},
  54. {1, 0, 0, 1, 0},
  55. {1, 0, 0, 1, 0},
  56. {1, 0, 0, 1, 0},
  57. {1, 1, 1, 0, 0},
  58. },
  59. ['c'] = {
  60. {0, 0, 0, 0, 0},
  61. {0, 1, 1, 0, 0},
  62. {1, 0, 0, 1, 0},
  63. {1, 0, 0, 0, 0},
  64. {1, 0, 0, 1, 0},
  65. {0, 1, 1, 0, 0},
  66. },
  67. ['d'] = {
  68. {0, 0, 0, 1, 0},
  69. {0, 1, 1, 1, 0},
  70. {1, 0, 0, 1, 0},
  71. {1, 0, 0, 1, 0},
  72. {1, 0, 0, 1, 0},
  73. {0, 1, 1, 1, 0},
  74. },
  75. ['e'] = {
  76. {0, 0, 0, 0, 0},
  77. {0, 1, 1, 0, 0},
  78. {1, 0, 0, 1, 0},
  79. {1, 1, 1, 1, 0},
  80. {1, 0, 0, 0, 0},
  81. {0, 1, 1, 1, 0},
  82. },
  83. ['f'] = {
  84. {0, 0, 1, 1, 0},
  85. {0, 1, 0, 0, 0},
  86. {1, 1, 1, 1, 0},
  87. {0, 1, 0, 0, 0},
  88. {0, 1, 0, 0, 0},
  89. {0, 1, 0, 0, 0},
  90. },
  91. ['g'] = {
  92. {0, 1, 1, 1, 0},
  93. {1, 0, 0, 1, 0},
  94. {1, 0, 0, 1, 0},
  95. {0, 1, 1, 1, 0},
  96. {0, 0, 0, 1, 0},
  97. {0, 1, 1, 0, 0},
  98. },
  99. ['h'] = {
  100. {1, 0, 0, 0, 0},
  101. {1, 1, 1, 0, 0},
  102. {1, 0, 0, 1, 0},
  103. {1, 0, 0, 1, 0},
  104. {1, 0, 0, 1, 0},
  105. {1, 0, 0, 1, 0},
  106. },
  107. ['i'] = {
  108. {0, 0, 1, 0, 0},
  109. {0, 0, 0, 0, 0},
  110. {0, 0, 1, 0, 0},
  111. {0, 0, 1, 0, 0},
  112. {0, 0, 1, 0, 0},
  113. {0, 0, 1, 0, 0},
  114. },
  115. ['j'] = {
  116. {0, 0, 1, 0, 0},
  117. {0, 0, 0, 0, 0},
  118. {0, 0, 1, 0, 0},
  119. {0, 0, 1, 0, 0},
  120. {1, 0, 1, 0, 0},
  121. {0, 1, 1, 0, 0},
  122. },
  123. ['k'] = {
  124. {1, 0, 0, 0, 0},
  125. {1, 0, 0, 1, 0},
  126. {1, 0, 1, 0, 0},
  127. {1, 1, 0, 0, 0},
  128. {1, 0, 1, 0, 0},
  129. {1, 0, 0, 1, 0},
  130. },
  131. ['l'] = {
  132. {0, 1, 1, 0, 0},
  133. {0, 0, 1, 0, 0},
  134. {0, 0, 1, 0, 0},
  135. {0, 0, 1, 0, 0},
  136. {0, 0, 1, 0, 0},
  137. {0, 1, 1, 1, 0},
  138. },
  139. ['m'] = {
  140. {0, 0, 0, 0, 0},
  141. {0, 1, 0, 1, 1},
  142. {1, 0, 1, 0, 1},
  143. {1, 0, 1, 0, 1},
  144. {1, 0, 1, 0, 1},
  145. {1, 0, 1, 0, 1},
  146. },
  147. ['n'] = {
  148. {0, 0, 0, 0, 0},
  149. {0, 1, 1, 1, 0},
  150. {1, 0, 0, 1, 0},
  151. {1, 0, 0, 1, 0},
  152. {1, 0, 0, 1, 0},
  153. {1, 0, 0, 1, 0},
  154. },
  155. ['o'] = {
  156. {0, 0, 0, 0, 0},
  157. {0, 1, 1, 0, 0},
  158. {1, 0, 0, 1, 0},
  159. {1, 0, 0, 1, 0},
  160. {1, 0, 0, 1, 0},
  161. {0, 1, 1, 0, 0},
  162. },
  163. ['p'] = {
  164. {1, 1, 1, 0, 0},
  165. {1, 0, 0, 1, 0},
  166. {1, 0, 0, 1, 0},
  167. {1, 1, 1, 0, 0},
  168. {1, 0, 0, 0, 0},
  169. {1, 0, 0, 0, 0},
  170. },
  171. ['q'] = {
  172. {0, 1, 1, 1, 0},
  173. {1, 0, 0, 1, 0},
  174. {1, 0, 0, 1, 0},
  175. {0, 1, 1, 1, 0},
  176. {0, 0, 0, 1, 0},
  177. {0, 0, 0, 1, 0},
  178. },
  179. ['r'] = {
  180. {0, 0, 0, 0, 0},
  181. {1, 0, 1, 1, 0},
  182. {1, 1, 0, 0, 1},
  183. {1, 0, 0, 0, 0},
  184. {1, 0, 0, 0, 0},
  185. {1, 0, 0, 0, 0},
  186. },
  187. ['s'] = {
  188. {0, 0, 0, 0, 0},
  189. {0, 1, 1, 1, 0},
  190. {1, 0, 0, 0, 0},
  191. {1, 1, 1, 1, 0},
  192. {0, 0, 0, 1, 0},
  193. {1, 1, 1, 0, 0},
  194. },
  195. ['t'] = {
  196. {0, 1, 0, 0, 0},
  197. {0, 1, 0, 0, 0},
  198. {1, 1, 1, 1, 0},
  199. {0, 1, 0, 0, 0},
  200. {0, 1, 0, 1, 0},
  201. {0, 1, 1, 0, 0},
  202. },
  203. ['u'] = {
  204. {0, 0, 0, 0, 0},
  205. {1, 0, 0, 1, 0},
  206. {1, 0, 0, 1, 0},
  207. {1, 0, 0, 1, 0},
  208. {1, 0, 0, 1, 0},
  209. {0, 1, 1, 1, 0},
  210. },
  211. ['v'] = {
  212. {0, 0, 0, 0, 0},
  213. {1, 0, 0, 1, 0},
  214. {1, 0, 0, 1, 0},
  215. {1, 0, 0, 1, 0},
  216. {1, 0, 0, 1, 0},
  217. {0, 1, 1, 0, 0},
  218. },
  219. ['w'] = {
  220. {0, 0, 0, 0, 0},
  221. {1, 0, 0, 0, 1},
  222. {1, 0, 1, 0, 1},
  223. {1, 0, 1, 0, 1},
  224. {1, 0, 1, 0, 1},
  225. {0, 1, 1, 1, 1},
  226. },
  227. ['x'] = {
  228. {0, 0, 0, 0, 0},
  229. {1, 0, 1, 0, 0},
  230. {1, 0, 1, 0, 0},
  231. {0, 1, 0, 0, 0},
  232. {1, 0, 1, 0, 0},
  233. {1, 0, 1, 0, 0},
  234. },
  235. ['y'] = {
  236. {0, 0, 0, 0, 0},
  237. {1, 0, 1, 0, 0},
  238. {1, 0, 1, 0, 0},
  239. {1, 0, 1, 0, 0},
  240. {0, 1, 0, 0, 0},
  241. {0, 1, 0, 0, 0},
  242. },
  243. ['z'] = {
  244. {0, 0, 0, 0, 0},
  245. {1, 1, 1, 1, 0},
  246. {0, 0, 0, 1, 0},
  247. {0, 1, 1, 0, 0},
  248. {1, 0, 0, 0, 0},
  249. {1, 1, 1, 1, 0},
  250. },
  251. ['A'] = {0},
  252. ['B'] = {0},
  253. ['C'] = {0},
  254. ['D'] = {0},
  255. ['E'] = {0},
  256. ['F'] = {0},
  257. ['G'] = {0},
  258. ['H'] = {0},
  259. ['I'] = {0},
  260. ['J'] = {0},
  261. ['K'] = {0},
  262. ['L'] = {0},
  263. ['M'] = {0},
  264. ['N'] = {0},
  265. ['O'] = {0},
  266. ['P'] = {0},
  267. ['Q'] = {0},
  268. ['R'] = {0},
  269. ['S'] = {0},
  270. ['T'] = {0},
  271. ['U'] = {0},
  272. ['V'] = {0},
  273. ['W'] = {0},
  274. ['X'] = {0},
  275. ['Y'] = {0},
  276. ['Z'] = {0},
  277. ['0'] = {
  278. {0, 1, 1, 0, 0},
  279. {1, 0, 0, 1, 0},
  280. {1, 0, 0, 1, 0},
  281. {1, 0, 0, 1, 0},
  282. {1, 0, 0, 1, 0},
  283. {0, 1, 1, 0, 0},
  284. },
  285. ['1'] = {
  286. {0, 0, 1, 0, 0},
  287. {0, 1, 1, 0, 0},
  288. {0, 0, 1, 0, 0},
  289. {0, 0, 1, 0, 0},
  290. {0, 0, 1, 0, 0},
  291. {0, 1, 1, 1, 0},
  292. },
  293. ['2'] = {
  294. {0, 1, 1, 0, 0},
  295. {1, 0, 0, 1, 0},
  296. {0, 0, 0, 1, 0},
  297. {0, 1, 1, 0, 0},
  298. {1, 0, 0, 0, 0},
  299. {1, 1, 1, 1, 0},
  300. },
  301. ['3'] = {
  302. {0, 1, 1, 0, 0},
  303. {1, 0, 0, 1, 0},
  304. {0, 0, 1, 0, 0},
  305. {0, 0, 0, 1, 0},
  306. {1, 0, 0, 1, 0},
  307. {0, 1, 1, 0, 0},
  308. },
  309. ['4'] = {
  310. {0, 0, 1, 1, 0},
  311. {0, 1, 0, 1, 0},
  312. {1, 0, 0, 1, 0},
  313. {1, 1, 1, 1, 1},
  314. {0, 0, 0, 1, 0},
  315. {0, 0, 0, 1, 0},
  316. },
  317. ['5'] = {
  318. {1, 1, 1, 0, 0},
  319. {1, 0, 0, 0, 0},
  320. {1, 1, 1, 0, 0},
  321. {0, 0, 0, 1, 0},
  322. {1, 0, 0, 1, 0},
  323. {0, 1, 1, 0, 0},
  324. },
  325. ['6'] = {
  326. {0, 1, 1, 0, 0},
  327. {1, 0, 0, 0, 0},
  328. {1, 1, 1, 0, 0},
  329. {1, 0, 0, 1, 0},
  330. {1, 0, 0, 1, 0},
  331. {0, 1, 1, 0, 0},
  332. },
  333. ['7'] = {
  334. {1, 1, 1, 1, 0},
  335. {0, 0, 0, 1, 0},
  336. {0, 0, 1, 0, 0},
  337. {0, 1, 0, 0, 0},
  338. {0, 1, 0, 0, 0},
  339. {0, 1, 0, 0, 0},
  340. },
  341. ['8'] = {
  342. {0, 1, 1, 0, 0},
  343. {1, 0, 0, 1, 0},
  344. {0, 1, 1, 0, 0},
  345. {1, 0, 0, 1, 0},
  346. {1, 0, 0, 1, 0},
  347. {0, 1, 1, 0, 0},
  348. },
  349. ['9'] = {
  350. {0, 1, 1, 0, 0},
  351. {1, 0, 0, 1, 0},
  352. {1, 0, 0, 1, 0},
  353. {0, 1, 1, 1, 0},
  354. {0, 0, 0, 1, 0},
  355. {0, 1, 1, 0, 0},
  356. },
  357. [','] = {
  358. {0, 0, 0, 0, 0},
  359. {0, 0, 0, 0, 0},
  360. {0, 0, 0, 0, 0},
  361. {0, 0, 0, 0, 0},
  362. {0, 0, 0, 1, 0},
  363. {0, 0, 1, 0, 0},
  364. },
  365. ['.'] = {
  366. {0, 0, 0, 0, 0},
  367. {0, 0, 0, 0, 0},
  368. {0, 0, 0, 0, 0},
  369. {0, 0, 0, 0, 0},
  370. {0, 0, 0, 0, 0},
  371. {0, 0, 1, 0, 0},
  372. },
  373. ['-'] = {
  374. {0, 0, 0, 0, 0},
  375. {0, 0, 0, 0, 0},
  376. {0, 0, 0, 0, 0},
  377. {1, 1, 1, 1, 0},
  378. {0, 0, 0, 0, 0},
  379. {0, 0, 0, 0, 0},
  380. },
  381. };
  382. static Olivec_Font olivec_default_font = {
  383. .glyphs = &olivec_default_glyphs[0][0][0],
  384. .width = OLIVEC_DEFAULT_FONT_WIDTH,
  385. .height = OLIVEC_DEFAULT_FONT_HEIGHT,
  386. };
  387. // WARNING! Always initialize your Canvas with a color that has Non-Zero Alpha Channel!
  388. // A lot of functions use `olivec_blend_color()` function to blend with the Background
  389. // which preserves the original Alpha of the Background. So you may easily end up with
  390. // a result that is perceptually transparent if the Alpha is Zero.
  391. typedef struct {
  392. uint32_t *pixels;
  393. size_t width;
  394. size_t height;
  395. size_t stride;
  396. } Olivec_Canvas;
  397. #define OLIVEC_CANVAS_NULL ((Olivec_Canvas) {0})
  398. #define OLIVEC_PIXEL(oc, x, y) (oc).pixels[(y)*(oc).stride + (x)]
  399. OLIVECDEF Olivec_Canvas olivec_canvas(uint32_t *pixels, size_t width, size_t height, size_t stride);
  400. OLIVECDEF Olivec_Canvas olivec_subcanvas(Olivec_Canvas oc, int x, int y, int w, int h);
  401. OLIVECDEF bool olivec_in_bounds(Olivec_Canvas oc, int x, int y);
  402. OLIVECDEF void olivec_blend_color(uint32_t *c1, uint32_t c2);
  403. OLIVECDEF void olivec_fill(Olivec_Canvas oc, uint32_t color);
  404. OLIVECDEF void olivec_rect(Olivec_Canvas oc, int x, int y, int w, int h, uint32_t color);
  405. OLIVECDEF void olivec_frame(Olivec_Canvas oc, int x, int y, int w, int h, size_t thiccness, uint32_t color);
  406. OLIVECDEF void olivec_circle(Olivec_Canvas oc, int cx, int cy, int r, uint32_t color);
  407. OLIVECDEF void olivec_ellipse(Olivec_Canvas oc, int cx, int cy, int rx, int ry, uint32_t color);
  408. // TODO: lines with different thiccness
  409. OLIVECDEF void olivec_line(Olivec_Canvas oc, int x1, int y1, int x2, int y2, uint32_t color);
  410. OLIVECDEF bool olivec_normalize_triangle(size_t width, size_t height, int x1, int y1, int x2, int y2, int x3, int y3, int *lx, int *hx, int *ly, int *hy);
  411. OLIVECDEF bool olivec_barycentric(int x1, int y1, int x2, int y2, int x3, int y3, int xp, int yp, int *u1, int *u2, int *det);
  412. OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t color);
  413. OLIVECDEF void olivec_triangle3c(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t c1, uint32_t c2, uint32_t c3);
  414. OLIVECDEF void olivec_triangle3z(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float z1, float z2, float z3);
  415. OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float z1, float z2, float z3, Olivec_Canvas texture);
  416. OLIVECDEF void olivec_triangle3uv_bilinear(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float z1, float z2, float z3, Olivec_Canvas texture);
  417. OLIVECDEF void olivec_text(Olivec_Canvas oc, const char *text, int x, int y, Olivec_Font font, size_t size, uint32_t color);
  418. OLIVECDEF void olivec_sprite_blend(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
  419. OLIVECDEF void olivec_sprite_copy(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
  420. OLIVECDEF void olivec_sprite_copy_bilinear(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
  421. OLIVECDEF uint32_t olivec_pixel_bilinear(Olivec_Canvas sprite, int nx, int ny, int w, int h);
  422. typedef struct {
  423. // Safe ranges to iterate over.
  424. int x1, x2;
  425. int y1, y2;
  426. // Original uncut ranges some parts of which may be outside of the canvas boundaries.
  427. int ox1, ox2;
  428. int oy1, oy2;
  429. } Olivec_Normalized_Rect;
  430. // The point of this function is to produce two ranges x1..x2 and y1..y2 that are guaranteed to be safe to iterate over the canvas of size pixels_width by pixels_height without any boundary checks.
  431. //
  432. // Olivec_Normalized_Rect nr = {0};
  433. // if (olivec_normalize_rect(x, y, w, h, WIDTH, HEIGHT, &nr)) {
  434. // for (int x = nr.x1; x <= nr.x2; ++x) {
  435. // for (int y = nr.y1; y <= nr.y2; ++y) {
  436. // OLIVEC_PIXEL(oc, x, y) = 0x69696969;
  437. // }
  438. // }
  439. // } else {
  440. // // Rectangle is invisible cause it's completely out-of-bounds
  441. // }
  442. OLIVECDEF bool olivec_normalize_rect(int x, int y, int w, int h,
  443. size_t canvas_width, size_t canvas_height,
  444. Olivec_Normalized_Rect *nr);
  445. #endif // OLIVE_C_
  446. #ifdef OLIVEC_IMPLEMENTATION
  447. OLIVECDEF Olivec_Canvas olivec_canvas(uint32_t *pixels, size_t width, size_t height, size_t stride)
  448. {
  449. Olivec_Canvas oc = {
  450. .pixels = pixels,
  451. .width = width,
  452. .height = height,
  453. .stride = stride,
  454. };
  455. return oc;
  456. }
  457. OLIVECDEF bool olivec_normalize_rect(int x, int y, int w, int h,
  458. size_t canvas_width, size_t canvas_height,
  459. Olivec_Normalized_Rect *nr)
  460. {
  461. // No need to render empty rectangle
  462. if (w == 0) return false;
  463. if (h == 0) return false;
  464. nr->ox1 = x;
  465. nr->oy1 = y;
  466. // Convert the rectangle to 2-points representation
  467. nr->ox2 = nr->ox1 + OLIVEC_SIGN(int, w)*(OLIVEC_ABS(int, w) - 1);
  468. if (nr->ox1 > nr->ox2) OLIVEC_SWAP(int, nr->ox1, nr->ox2);
  469. nr->oy2 = nr->oy1 + OLIVEC_SIGN(int, h)*(OLIVEC_ABS(int, h) - 1);
  470. if (nr->oy1 > nr->oy2) OLIVEC_SWAP(int, nr->oy1, nr->oy2);
  471. // Cull out invisible rectangle
  472. if (nr->ox1 >= (int) canvas_width) return false;
  473. if (nr->ox2 < 0) return false;
  474. if (nr->oy1 >= (int) canvas_height) return false;
  475. if (nr->oy2 < 0) return false;
  476. nr->x1 = nr->ox1;
  477. nr->y1 = nr->oy1;
  478. nr->x2 = nr->ox2;
  479. nr->y2 = nr->oy2;
  480. // Clamp the rectangle to the boundaries
  481. if (nr->x1 < 0) nr->x1 = 0;
  482. if (nr->x2 >= (int) canvas_width) nr->x2 = (int) canvas_width - 1;
  483. if (nr->y1 < 0) nr->y1 = 0;
  484. if (nr->y2 >= (int) canvas_height) nr->y2 = (int) canvas_height - 1;
  485. return true;
  486. }
  487. OLIVECDEF Olivec_Canvas olivec_subcanvas(Olivec_Canvas oc, int x, int y, int w, int h)
  488. {
  489. Olivec_Normalized_Rect nr = {0};
  490. if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &nr)) return OLIVEC_CANVAS_NULL;
  491. oc.pixels = &OLIVEC_PIXEL(oc, nr.x1, nr.y1);
  492. oc.width = nr.x2 - nr.x1 + 1;
  493. oc.height = nr.y2 - nr.y1 + 1;
  494. return oc;
  495. }
  496. // TODO: custom pixel formats
  497. // Maybe we can store pixel format info in Olivec_Canvas
  498. #define OLIVEC_RED(color) (((color)&0x000000FF)>>(8*0))
  499. #define OLIVEC_GREEN(color) (((color)&0x0000FF00)>>(8*1))
  500. #define OLIVEC_BLUE(color) (((color)&0x00FF0000)>>(8*2))
  501. #define OLIVEC_ALPHA(color) (((color)&0xFF000000)>>(8*3))
  502. #define OLIVEC_RGBA(r, g, b, a) ((((r)&0xFF)<<(8*0)) | (((g)&0xFF)<<(8*1)) | (((b)&0xFF)<<(8*2)) | (((a)&0xFF)<<(8*3)))
  503. OLIVECDEF void olivec_blend_color(uint32_t *c1, uint32_t c2)
  504. {
  505. uint32_t r1 = OLIVEC_RED(*c1);
  506. uint32_t g1 = OLIVEC_GREEN(*c1);
  507. uint32_t b1 = OLIVEC_BLUE(*c1);
  508. uint32_t a1 = OLIVEC_ALPHA(*c1);
  509. uint32_t r2 = OLIVEC_RED(c2);
  510. uint32_t g2 = OLIVEC_GREEN(c2);
  511. uint32_t b2 = OLIVEC_BLUE(c2);
  512. uint32_t a2 = OLIVEC_ALPHA(c2);
  513. r1 = (r1*(255 - a2) + r2*a2)/255; if (r1 > 255) r1 = 255;
  514. g1 = (g1*(255 - a2) + g2*a2)/255; if (g1 > 255) g1 = 255;
  515. b1 = (b1*(255 - a2) + b2*a2)/255; if (b1 > 255) b1 = 255;
  516. *c1 = OLIVEC_RGBA(r1, g1, b1, a1);
  517. }
  518. OLIVECDEF void olivec_fill(Olivec_Canvas oc, uint32_t color)
  519. {
  520. for (size_t y = 0; y < oc.height; ++y) {
  521. for (size_t x = 0; x < oc.width; ++x) {
  522. OLIVEC_PIXEL(oc, x, y) = color;
  523. }
  524. }
  525. }
  526. OLIVECDEF void olivec_rect(Olivec_Canvas oc, int x, int y, int w, int h, uint32_t color)
  527. {
  528. Olivec_Normalized_Rect nr = {0};
  529. if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &nr)) return;
  530. for (int x = nr.x1; x <= nr.x2; ++x) {
  531. for (int y = nr.y1; y <= nr.y2; ++y) {
  532. olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
  533. }
  534. }
  535. }
  536. OLIVECDEF void olivec_frame(Olivec_Canvas oc, int x, int y, int w, int h, size_t t, uint32_t color)
  537. {
  538. if (t == 0) return; // Nothing to render
  539. // Convert the rectangle to 2-points representation
  540. int x1 = x;
  541. int y1 = y;
  542. int x2 = x1 + OLIVEC_SIGN(int, w)*(OLIVEC_ABS(int, w) - 1);
  543. if (x1 > x2) OLIVEC_SWAP(int, x1, x2);
  544. int y2 = y1 + OLIVEC_SIGN(int, h)*(OLIVEC_ABS(int, h) - 1);
  545. if (y1 > y2) OLIVEC_SWAP(int, y1, y2);
  546. olivec_rect(oc, x1 - t/2, y1 - t/2, (x2 - x1 + 1) + t/2*2, t, color); // Top
  547. olivec_rect(oc, x1 - t/2, y1 - t/2, t, (y2 - y1 + 1) + t/2*2, color); // Left
  548. olivec_rect(oc, x1 - t/2, y2 + t/2, (x2 - x1 + 1) + t/2*2, -t, color); // Bottom
  549. olivec_rect(oc, x2 + t/2, y1 - t/2, -t, (y2 - y1 + 1) + t/2*2, color); // Right
  550. }
  551. OLIVECDEF void olivec_ellipse(Olivec_Canvas oc, int cx, int cy, int rx, int ry, uint32_t color)
  552. {
  553. Olivec_Normalized_Rect nr = {0};
  554. int rx1 = rx + OLIVEC_SIGN(int, rx);
  555. int ry1 = ry + OLIVEC_SIGN(int, ry);
  556. if (!olivec_normalize_rect(cx - rx1, cy - ry1, 2*rx1, 2*ry1, oc.width, oc.height, &nr)) return;
  557. for (int y = nr.y1; y <= nr.y2; ++y) {
  558. for (int x = nr.x1; x <= nr.x2; ++x) {
  559. float nx = (x + 0.5 - nr.x1)/(2.0f*rx1);
  560. float ny = (y + 0.5 - nr.y1)/(2.0f*ry1);
  561. float dx = nx - 0.5;
  562. float dy = ny - 0.5;
  563. if (dx*dx + dy*dy <= 0.5*0.5) {
  564. OLIVEC_PIXEL(oc, x, y) = color;
  565. }
  566. }
  567. }
  568. }
  569. OLIVECDEF void olivec_circle(Olivec_Canvas oc, int cx, int cy, int r, uint32_t color)
  570. {
  571. Olivec_Normalized_Rect nr = {0};
  572. int r1 = r + OLIVEC_SIGN(int, r);
  573. if (!olivec_normalize_rect(cx - r1, cy - r1, 2*r1, 2*r1, oc.width, oc.height, &nr)) return;
  574. for (int y = nr.y1; y <= nr.y2; ++y) {
  575. for (int x = nr.x1; x <= nr.x2; ++x) {
  576. int count = 0;
  577. for (int sox = 0; sox < OLIVEC_AA_RES; ++sox) {
  578. for (int soy = 0; soy < OLIVEC_AA_RES; ++soy) {
  579. // TODO: switch to 64 bits to make the overflow less likely
  580. // Also research the probability of overflow
  581. int res1 = (OLIVEC_AA_RES + 1);
  582. int dx = (x*res1*2 + 2 + sox*2 - res1*cx*2 - res1);
  583. int dy = (y*res1*2 + 2 + soy*2 - res1*cy*2 - res1);
  584. if (dx*dx + dy*dy <= res1*res1*r*r*2*2) count += 1;
  585. }
  586. }
  587. uint32_t alpha = ((color&0xFF000000)>>(3*8))*count/OLIVEC_AA_RES/OLIVEC_AA_RES;
  588. uint32_t updated_color = (color&0x00FFFFFF)|(alpha<<(3*8));
  589. olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), updated_color);
  590. }
  591. }
  592. }
  593. OLIVECDEF bool olivec_in_bounds(Olivec_Canvas oc, int x, int y)
  594. {
  595. return 0 <= x && x < (int) oc.width && 0 <= y && y < (int) oc.height;
  596. }
  597. // TODO: AA for line
  598. OLIVECDEF void olivec_line(Olivec_Canvas oc, int x1, int y1, int x2, int y2, uint32_t color)
  599. {
  600. int dx = x2 - x1;
  601. int dy = y2 - y1;
  602. // If both of the differences are 0 there will be a division by 0 below.
  603. if (dx == 0 && dy == 0) {
  604. if (olivec_in_bounds(oc, x1, y1)) {
  605. olivec_blend_color(&OLIVEC_PIXEL(oc, x1, y1), color);
  606. }
  607. return;
  608. }
  609. if (OLIVEC_ABS(int, dx) > OLIVEC_ABS(int, dy)) {
  610. if (x1 > x2) {
  611. OLIVEC_SWAP(int, x1, x2);
  612. OLIVEC_SWAP(int, y1, y2);
  613. }
  614. for (int x = x1; x <= x2; ++x) {
  615. int y = dy*(x - x1)/dx + y1;
  616. // TODO: move boundary checks out side of the loops in olivec_draw_line
  617. if (olivec_in_bounds(oc, x, y)) {
  618. olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
  619. }
  620. }
  621. } else {
  622. if (y1 > y2) {
  623. OLIVEC_SWAP(int, x1, x2);
  624. OLIVEC_SWAP(int, y1, y2);
  625. }
  626. for (int y = y1; y <= y2; ++y) {
  627. int x = dx*(y - y1)/dy + x1;
  628. // TODO: move boundary checks out side of the loops in olivec_draw_line
  629. if (olivec_in_bounds(oc, x, y)) {
  630. olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
  631. }
  632. }
  633. }
  634. }
  635. OLIVECDEF uint32_t mix_colors2(uint32_t c1, uint32_t c2, int u1, int det)
  636. {
  637. // TODO: estimate how much overflows are an issue in integer only environment
  638. int64_t r1 = OLIVEC_RED(c1);
  639. int64_t g1 = OLIVEC_GREEN(c1);
  640. int64_t b1 = OLIVEC_BLUE(c1);
  641. int64_t a1 = OLIVEC_ALPHA(c1);
  642. int64_t r2 = OLIVEC_RED(c2);
  643. int64_t g2 = OLIVEC_GREEN(c2);
  644. int64_t b2 = OLIVEC_BLUE(c2);
  645. int64_t a2 = OLIVEC_ALPHA(c2);
  646. if (det != 0) {
  647. int u2 = det - u1;
  648. int64_t r4 = (r1*u2 + r2*u1)/det;
  649. int64_t g4 = (g1*u2 + g2*u1)/det;
  650. int64_t b4 = (b1*u2 + b2*u1)/det;
  651. int64_t a4 = (a1*u2 + a2*u1)/det;
  652. return OLIVEC_RGBA(r4, g4, b4, a4);
  653. }
  654. return 0;
  655. }
  656. OLIVECDEF uint32_t mix_colors3(uint32_t c1, uint32_t c2, uint32_t c3, int u1, int u2, int det)
  657. {
  658. // TODO: estimate how much overflows are an issue in integer only environment
  659. int64_t r1 = OLIVEC_RED(c1);
  660. int64_t g1 = OLIVEC_GREEN(c1);
  661. int64_t b1 = OLIVEC_BLUE(c1);
  662. int64_t a1 = OLIVEC_ALPHA(c1);
  663. int64_t r2 = OLIVEC_RED(c2);
  664. int64_t g2 = OLIVEC_GREEN(c2);
  665. int64_t b2 = OLIVEC_BLUE(c2);
  666. int64_t a2 = OLIVEC_ALPHA(c2);
  667. int64_t r3 = OLIVEC_RED(c3);
  668. int64_t g3 = OLIVEC_GREEN(c3);
  669. int64_t b3 = OLIVEC_BLUE(c3);
  670. int64_t a3 = OLIVEC_ALPHA(c3);
  671. if (det != 0) {
  672. int u3 = det - u1 - u2;
  673. int64_t r4 = (r1*u1 + r2*u2 + r3*u3)/det;
  674. int64_t g4 = (g1*u1 + g2*u2 + g3*u3)/det;
  675. int64_t b4 = (b1*u1 + b2*u2 + b3*u3)/det;
  676. int64_t a4 = (a1*u1 + a2*u2 + a3*u3)/det;
  677. return OLIVEC_RGBA(r4, g4, b4, a4);
  678. }
  679. return 0;
  680. }
  681. // NOTE: we imply u3 = det - u1 - u2
  682. OLIVECDEF bool olivec_barycentric(int x1, int y1, int x2, int y2, int x3, int y3, int xp, int yp, int *u1, int *u2, int *det)
  683. {
  684. *det = ((x1 - x3)*(y2 - y3) - (x2 - x3)*(y1 - y3));
  685. *u1 = ((y2 - y3)*(xp - x3) + (x3 - x2)*(yp - y3));
  686. *u2 = ((y3 - y1)*(xp - x3) + (x1 - x3)*(yp - y3));
  687. int u3 = *det - *u1 - *u2;
  688. return (
  689. (OLIVEC_SIGN(int, *u1) == OLIVEC_SIGN(int, *det) || *u1 == 0) &&
  690. (OLIVEC_SIGN(int, *u2) == OLIVEC_SIGN(int, *det) || *u2 == 0) &&
  691. (OLIVEC_SIGN(int, u3) == OLIVEC_SIGN(int, *det) || u3 == 0)
  692. );
  693. }
  694. OLIVECDEF bool olivec_normalize_triangle(size_t width, size_t height, int x1, int y1, int x2, int y2, int x3, int y3, int *lx, int *hx, int *ly, int *hy)
  695. {
  696. *lx = x1;
  697. *hx = x1;
  698. if (*lx > x2) *lx = x2;
  699. if (*lx > x3) *lx = x3;
  700. if (*hx < x2) *hx = x2;
  701. if (*hx < x3) *hx = x3;
  702. if (*lx < 0) *lx = 0;
  703. if ((size_t) *lx >= width) return false;;
  704. if (*hx < 0) return false;;
  705. if ((size_t) *hx >= width) *hx = width-1;
  706. *ly = y1;
  707. *hy = y1;
  708. if (*ly > y2) *ly = y2;
  709. if (*ly > y3) *ly = y3;
  710. if (*hy < y2) *hy = y2;
  711. if (*hy < y3) *hy = y3;
  712. if (*ly < 0) *ly = 0;
  713. if ((size_t) *ly >= height) return false;;
  714. if (*hy < 0) return false;;
  715. if ((size_t) *hy >= height) *hy = height-1;
  716. return true;
  717. }
  718. OLIVECDEF void olivec_triangle3c(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3,
  719. uint32_t c1, uint32_t c2, uint32_t c3)
  720. {
  721. int lx, hx, ly, hy;
  722. if (olivec_normalize_triangle(oc.width, oc.height, x1, y1, x2, y2, x3, y3, &lx, &hx, &ly, &hy)) {
  723. for (int y = ly; y <= hy; ++y) {
  724. for (int x = lx; x <= hx; ++x) {
  725. int u1, u2, det;
  726. if (olivec_barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det)) {
  727. olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), mix_colors3(c1, c2, c3, u1, u2, det));
  728. }
  729. }
  730. }
  731. }
  732. }
  733. OLIVECDEF void olivec_triangle3z(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float z1, float z2, float z3)
  734. {
  735. int lx, hx, ly, hy;
  736. if (olivec_normalize_triangle(oc.width, oc.height, x1, y1, x2, y2, x3, y3, &lx, &hx, &ly, &hy)) {
  737. for (int y = ly; y <= hy; ++y) {
  738. for (int x = lx; x <= hx; ++x) {
  739. int u1, u2, det;
  740. if (olivec_barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det)) {
  741. float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
  742. OLIVEC_PIXEL(oc, x, y) = *(uint32_t*)&z;
  743. }
  744. }
  745. }
  746. }
  747. }
  748. OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float z1, float z2, float z3, Olivec_Canvas texture)
  749. {
  750. int lx, hx, ly, hy;
  751. if (olivec_normalize_triangle(oc.width, oc.height, x1, y1, x2, y2, x3, y3, &lx, &hx, &ly, &hy)) {
  752. for (int y = ly; y <= hy; ++y) {
  753. for (int x = lx; x <= hx; ++x) {
  754. int u1, u2, det;
  755. if (olivec_barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det)) {
  756. int u3 = det - u1 - u2;
  757. float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
  758. float tx = tx1*u1/det + tx2*u2/det + tx3*u3/det;
  759. float ty = ty1*u1/det + ty2*u2/det + ty3*u3/det;
  760. int texture_x = tx/z*texture.width;
  761. if (texture_x < 0) texture_x = 0;
  762. if ((size_t) texture_x >= texture.width) texture_x = texture.width - 1;
  763. int texture_y = ty/z*texture.height;
  764. if (texture_y < 0) texture_y = 0;
  765. if ((size_t) texture_y >= texture.height) texture_y = texture.height - 1;
  766. OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(texture, (int)texture_x, (int)texture_y);
  767. }
  768. }
  769. }
  770. }
  771. }
  772. OLIVECDEF void olivec_triangle3uv_bilinear(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float z1, float z2, float z3, Olivec_Canvas texture)
  773. {
  774. int lx, hx, ly, hy;
  775. if (olivec_normalize_triangle(oc.width, oc.height, x1, y1, x2, y2, x3, y3, &lx, &hx, &ly, &hy)) {
  776. for (int y = ly; y <= hy; ++y) {
  777. for (int x = lx; x <= hx; ++x) {
  778. int u1, u2, det;
  779. if (olivec_barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det)) {
  780. int u3 = det - u1 - u2;
  781. float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
  782. float tx = tx1*u1/det + tx2*u2/det + tx3*u3/det;
  783. float ty = ty1*u1/det + ty2*u2/det + ty3*u3/det;
  784. float texture_x = tx/z*texture.width;
  785. if (texture_x < 0) texture_x = 0;
  786. if (texture_x >= (float) texture.width) texture_x = texture.width - 1;
  787. float texture_y = ty/z*texture.height;
  788. if (texture_y < 0) texture_y = 0;
  789. if (texture_y >= (float) texture.height) texture_y = texture.height - 1;
  790. int precision = 100;
  791. OLIVEC_PIXEL(oc, x, y) = olivec_pixel_bilinear(
  792. texture,
  793. texture_x*precision, texture_y*precision,
  794. precision, precision);
  795. }
  796. }
  797. }
  798. }
  799. }
  800. // TODO: AA for triangle
  801. OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t color)
  802. {
  803. int lx, hx, ly, hy;
  804. if (olivec_normalize_triangle(oc.width, oc.height, x1, y1, x2, y2, x3, y3, &lx, &hx, &ly, &hy)) {
  805. for (int y = ly; y <= hy; ++y) {
  806. for (int x = lx; x <= hx; ++x) {
  807. int u1, u2, det;
  808. if (olivec_barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det)) {
  809. olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
  810. }
  811. }
  812. }
  813. }
  814. }
  815. OLIVECDEF void olivec_text(Olivec_Canvas oc, const char *text, int tx, int ty, Olivec_Font font, size_t glyph_size, uint32_t color)
  816. {
  817. for (size_t i = 0; *text; ++i, ++text) {
  818. int gx = tx + i*font.width*glyph_size;
  819. int gy = ty;
  820. const char *glyph = &font.glyphs[(*text)*sizeof(char)*font.width*font.height];
  821. for (int dy = 0; (size_t) dy < font.height; ++dy) {
  822. for (int dx = 0; (size_t) dx < font.width; ++dx) {
  823. int px = gx + dx*glyph_size;
  824. int py = gy + dy*glyph_size;
  825. if (0 <= px && px < (int) oc.width && 0 <= py && py < (int) oc.height) {
  826. if (glyph[dy*font.width + dx]) {
  827. olivec_rect(oc, px, py, glyph_size, glyph_size, color);
  828. }
  829. }
  830. }
  831. }
  832. }
  833. }
  834. OLIVECDEF void olivec_sprite_blend(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite)
  835. {
  836. if (sprite.width == 0) return;
  837. if (sprite.height == 0) return;
  838. Olivec_Normalized_Rect nr = {0};
  839. if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &nr)) return;
  840. int xa = nr.ox1;
  841. if (w < 0) xa = nr.ox2;
  842. int ya = nr.oy1;
  843. if (h < 0) ya = nr.oy2;
  844. for (int y = nr.y1; y <= nr.y2; ++y) {
  845. for (int x = nr.x1; x <= nr.x2; ++x) {
  846. size_t nx = (x - xa)*((int) sprite.width)/w;
  847. size_t ny = (y - ya)*((int) sprite.height)/h;
  848. olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), OLIVEC_PIXEL(sprite, nx, ny));
  849. }
  850. }
  851. }
  852. OLIVECDEF void olivec_sprite_copy(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite)
  853. {
  854. if (sprite.width == 0) return;
  855. if (sprite.height == 0) return;
  856. // TODO: consider introducing flip parameter instead of relying on negative width and height
  857. // Similar to how SDL_RenderCopyEx does that
  858. Olivec_Normalized_Rect nr = {0};
  859. if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &nr)) return;
  860. int xa = nr.ox1;
  861. if (w < 0) xa = nr.ox2;
  862. int ya = nr.oy1;
  863. if (h < 0) ya = nr.oy2;
  864. for (int y = nr.y1; y <= nr.y2; ++y) {
  865. for (int x = nr.x1; x <= nr.x2; ++x) {
  866. size_t nx = (x - xa)*((int) sprite.width)/w;
  867. size_t ny = (y - ya)*((int) sprite.height)/h;
  868. OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(sprite, nx, ny);
  869. }
  870. }
  871. }
  872. // TODO: olivec_pixel_bilinear does not check for out-of-bounds
  873. // But maybe it shouldn't. Maybe it's a responsibility of the caller of the function.
  874. OLIVECDEF uint32_t olivec_pixel_bilinear(Olivec_Canvas sprite, int nx, int ny, int w, int h)
  875. {
  876. int px = nx%w;
  877. int py = ny%h;
  878. int x1 = nx/w, x2 = nx/w;
  879. int y1 = ny/h, y2 = ny/h;
  880. if (px < w/2) {
  881. // left
  882. px += w/2;
  883. x1 -= 1;
  884. if (x1 < 0) x1 = 0;
  885. } else {
  886. // right
  887. px -= w/2;
  888. x2 += 1;
  889. if ((size_t) x2 >= sprite.width) x2 = sprite.width - 1;
  890. }
  891. if (py < h/2) {
  892. // top
  893. py += h/2;
  894. y1 -= 1;
  895. if (y1 < 0) y1 = 0;
  896. } else {
  897. // bottom
  898. py -= h/2;
  899. y2 += 1;
  900. if ((size_t) y2 >= sprite.height) y2 = sprite.height - 1;
  901. }
  902. return mix_colors2(mix_colors2(OLIVEC_PIXEL(sprite, x1, y1),
  903. OLIVEC_PIXEL(sprite, x2, y1),
  904. px, w),
  905. mix_colors2(OLIVEC_PIXEL(sprite, x1, y2),
  906. OLIVEC_PIXEL(sprite, x2, y2),
  907. px, w),
  908. py, h);
  909. }
  910. OLIVECDEF void olivec_sprite_copy_bilinear(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite)
  911. {
  912. // TODO: support negative size in olivec_sprite_copy_bilinear()
  913. if (w <= 0) return;
  914. if (h <= 0) return;
  915. Olivec_Normalized_Rect nr = {0};
  916. if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &nr)) return;
  917. for (int y = nr.y1; y <= nr.y2; ++y) {
  918. for (int x = nr.x1; x <= nr.x2; ++x) {
  919. size_t nx = (x - nr.ox1)*sprite.width;
  920. size_t ny = (y - nr.oy1)*sprite.height;
  921. OLIVEC_PIXEL(oc, x, y) = olivec_pixel_bilinear(sprite, nx, ny, w, h);
  922. }
  923. }
  924. }
  925. #endif // OLIVEC_IMPLEMENTATION
  926. // TODO: Benchmarking
  927. // TODO: SIMD implementations
  928. // TODO: bezier curves
  929. // TODO: olivec_ring
  930. // TODO: fuzzer
  931. // TODO: Stencil