You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

mat_pixel_drawing.cpp 55 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949
  1. // Copyright 2021 Tencent
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. #include "mat.h"
  4. #include <ctype.h>
  5. #include <limits.h>
  6. #if __ARM_NEON
  7. #include <arm_neon.h>
  8. #endif // __ARM_NEON
  9. #if __SSE2__
  10. #include <emmintrin.h>
  11. #endif
  12. #include "platform.h"
  13. namespace ncnn {
  14. #if NCNN_PIXEL_DRAWING
  15. #include "mat_pixel_drawing_font.h"
  16. void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
  17. {
  18. return draw_rectangle_c1(pixels, w, h, w, rx, ry, rw, rh, color, thickness);
  19. }
  20. void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
  21. {
  22. return draw_rectangle_c2(pixels, w, h, w * 2, rx, ry, rw, rh, color, thickness);
  23. }
  24. void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
  25. {
  26. return draw_rectangle_c3(pixels, w, h, w * 3, rx, ry, rw, rh, color, thickness);
  27. }
  28. void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
  29. {
  30. return draw_rectangle_c4(pixels, w, h, w * 4, rx, ry, rw, rh, color, thickness);
  31. }
  32. void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
  33. {
  34. const unsigned char* pen_color = (const unsigned char*)&color;
  35. if (thickness == -1)
  36. {
  37. // filled
  38. for (int y = ry; y < ry + rh; y++)
  39. {
  40. if (y < 0)
  41. continue;
  42. if (y >= h)
  43. break;
  44. unsigned char* p = pixels + stride * y;
  45. for (int x = rx; x < rx + rw; x++)
  46. {
  47. if (x < 0)
  48. continue;
  49. if (x >= w)
  50. break;
  51. p[x] = pen_color[0];
  52. }
  53. }
  54. return;
  55. }
  56. const int t0 = thickness / 2;
  57. const int t1 = thickness - t0;
  58. // draw top
  59. {
  60. for (int y = ry - t0; y < ry + t1; y++)
  61. {
  62. if (y < 0)
  63. continue;
  64. if (y >= h)
  65. break;
  66. unsigned char* p = pixels + stride * y;
  67. for (int x = rx - t0; x < rx + rw + t1; x++)
  68. {
  69. if (x < 0)
  70. continue;
  71. if (x >= w)
  72. break;
  73. p[x] = pen_color[0];
  74. }
  75. }
  76. }
  77. // draw bottom
  78. {
  79. for (int y = ry + rh - t0; y < ry + rh + t1; y++)
  80. {
  81. if (y < 0)
  82. continue;
  83. if (y >= h)
  84. break;
  85. unsigned char* p = pixels + stride * y;
  86. for (int x = rx - t0; x < rx + rw + t1; x++)
  87. {
  88. if (x < 0)
  89. continue;
  90. if (x >= w)
  91. break;
  92. p[x] = pen_color[0];
  93. }
  94. }
  95. }
  96. // draw left
  97. for (int x = rx - t0; x < rx + t1; x++)
  98. {
  99. if (x < 0)
  100. continue;
  101. if (x >= w)
  102. break;
  103. for (int y = ry + t1; y < ry + rh - t0; y++)
  104. {
  105. if (y < 0)
  106. continue;
  107. if (y >= h)
  108. break;
  109. unsigned char* p = pixels + stride * y;
  110. p[x] = pen_color[0];
  111. }
  112. }
  113. // draw right
  114. for (int x = rx + rw - t0; x < rx + rw + t1; x++)
  115. {
  116. if (x < 0)
  117. continue;
  118. if (x >= w)
  119. break;
  120. for (int y = ry + t1; y < ry + rh - t0; y++)
  121. {
  122. if (y < 0)
  123. continue;
  124. if (y >= h)
  125. break;
  126. unsigned char* p = pixels + stride * y;
  127. p[x] = pen_color[0];
  128. }
  129. }
  130. }
  131. void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
  132. {
  133. const unsigned char* pen_color = (const unsigned char*)&color;
  134. if (thickness == -1)
  135. {
  136. // filled
  137. for (int y = ry; y < ry + rh; y++)
  138. {
  139. if (y < 0)
  140. continue;
  141. if (y >= h)
  142. break;
  143. unsigned char* p = pixels + stride * y;
  144. for (int x = rx; x < rx + rw; x++)
  145. {
  146. if (x < 0)
  147. continue;
  148. if (x >= w)
  149. break;
  150. p[x * 2 + 0] = pen_color[0];
  151. p[x * 2 + 1] = pen_color[1];
  152. }
  153. }
  154. return;
  155. }
  156. const int t0 = thickness / 2;
  157. const int t1 = thickness - t0;
  158. // draw top
  159. {
  160. for (int y = ry - t0; y < ry + t1; y++)
  161. {
  162. if (y < 0)
  163. continue;
  164. if (y >= h)
  165. break;
  166. unsigned char* p = pixels + stride * y;
  167. for (int x = rx - t0; x < rx + rw + t1; x++)
  168. {
  169. if (x < 0)
  170. continue;
  171. if (x >= w)
  172. break;
  173. p[x * 2 + 0] = pen_color[0];
  174. p[x * 2 + 1] = pen_color[1];
  175. }
  176. }
  177. }
  178. // draw bottom
  179. {
  180. for (int y = ry + rh - t0; y < ry + rh + t1; y++)
  181. {
  182. if (y < 0)
  183. continue;
  184. if (y >= h)
  185. break;
  186. unsigned char* p = pixels + stride * y;
  187. for (int x = rx - t0; x < rx + rw + t1; x++)
  188. {
  189. if (x < 0)
  190. continue;
  191. if (x >= w)
  192. break;
  193. p[x * 2 + 0] = pen_color[0];
  194. p[x * 2 + 1] = pen_color[1];
  195. }
  196. }
  197. }
  198. // draw left
  199. for (int x = rx - t0; x < rx + t1; x++)
  200. {
  201. if (x < 0)
  202. continue;
  203. if (x >= w)
  204. break;
  205. for (int y = ry + t1; y < ry + rh - t0; y++)
  206. {
  207. if (y < 0)
  208. continue;
  209. if (y >= h)
  210. break;
  211. unsigned char* p = pixels + stride * y;
  212. p[x * 2 + 0] = pen_color[0];
  213. p[x * 2 + 1] = pen_color[1];
  214. }
  215. }
  216. // draw right
  217. for (int x = rx + rw - t0; x < rx + rw + t1; x++)
  218. {
  219. if (x < 0)
  220. continue;
  221. if (x >= w)
  222. break;
  223. for (int y = ry + t1; y < ry + rh - t0; y++)
  224. {
  225. if (y < 0)
  226. continue;
  227. if (y >= h)
  228. break;
  229. unsigned char* p = pixels + stride * y;
  230. p[x * 2 + 0] = pen_color[0];
  231. p[x * 2 + 1] = pen_color[1];
  232. }
  233. }
  234. }
  235. void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
  236. {
  237. const unsigned char* pen_color = (const unsigned char*)&color;
  238. if (thickness == -1)
  239. {
  240. // filled
  241. for (int y = ry; y < ry + rh; y++)
  242. {
  243. if (y < 0)
  244. continue;
  245. if (y >= h)
  246. break;
  247. unsigned char* p = pixels + stride * y;
  248. for (int x = rx; x < rx + rw; x++)
  249. {
  250. if (x < 0)
  251. continue;
  252. if (x >= w)
  253. break;
  254. p[x * 3 + 0] = pen_color[0];
  255. p[x * 3 + 1] = pen_color[1];
  256. p[x * 3 + 2] = pen_color[2];
  257. }
  258. }
  259. return;
  260. }
  261. const int t0 = thickness / 2;
  262. const int t1 = thickness - t0;
  263. // draw top
  264. {
  265. for (int y = ry - t0; y < ry + t1; y++)
  266. {
  267. if (y < 0)
  268. continue;
  269. if (y >= h)
  270. break;
  271. unsigned char* p = pixels + stride * y;
  272. for (int x = rx - t0; x < rx + rw + t1; x++)
  273. {
  274. if (x < 0)
  275. continue;
  276. if (x >= w)
  277. break;
  278. p[x * 3 + 0] = pen_color[0];
  279. p[x * 3 + 1] = pen_color[1];
  280. p[x * 3 + 2] = pen_color[2];
  281. }
  282. }
  283. }
  284. // draw bottom
  285. {
  286. for (int y = ry + rh - t0; y < ry + rh + t1; y++)
  287. {
  288. if (y < 0)
  289. continue;
  290. if (y >= h)
  291. break;
  292. unsigned char* p = pixels + stride * y;
  293. for (int x = rx - t0; x < rx + rw + t1; x++)
  294. {
  295. if (x < 0)
  296. continue;
  297. if (x >= w)
  298. break;
  299. p[x * 3 + 0] = pen_color[0];
  300. p[x * 3 + 1] = pen_color[1];
  301. p[x * 3 + 2] = pen_color[2];
  302. }
  303. }
  304. }
  305. // draw left
  306. for (int x = rx - t0; x < rx + t1; x++)
  307. {
  308. if (x < 0)
  309. continue;
  310. if (x >= w)
  311. break;
  312. for (int y = ry + t1; y < ry + rh - t0; y++)
  313. {
  314. if (y < 0)
  315. continue;
  316. if (y >= h)
  317. break;
  318. unsigned char* p = pixels + stride * y;
  319. p[x * 3 + 0] = pen_color[0];
  320. p[x * 3 + 1] = pen_color[1];
  321. p[x * 3 + 2] = pen_color[2];
  322. }
  323. }
  324. // draw right
  325. for (int x = rx + rw - t0; x < rx + rw + t1; x++)
  326. {
  327. if (x < 0)
  328. continue;
  329. if (x >= w)
  330. break;
  331. for (int y = ry + t1; y < ry + rh - t0; y++)
  332. {
  333. if (y < 0)
  334. continue;
  335. if (y >= h)
  336. break;
  337. unsigned char* p = pixels + stride * y;
  338. p[x * 3 + 0] = pen_color[0];
  339. p[x * 3 + 1] = pen_color[1];
  340. p[x * 3 + 2] = pen_color[2];
  341. }
  342. }
  343. }
  344. void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
  345. {
  346. const unsigned char* pen_color = (const unsigned char*)&color;
  347. if (thickness == -1)
  348. {
  349. // filled
  350. for (int y = ry; y < ry + rh; y++)
  351. {
  352. if (y < 0)
  353. continue;
  354. if (y >= h)
  355. break;
  356. unsigned char* p = pixels + stride * y;
  357. for (int x = rx; x < rx + rw; x++)
  358. {
  359. if (x < 0)
  360. continue;
  361. if (x >= w)
  362. break;
  363. p[x * 4 + 0] = pen_color[0];
  364. p[x * 4 + 1] = pen_color[1];
  365. p[x * 4 + 2] = pen_color[2];
  366. p[x * 4 + 3] = pen_color[3];
  367. }
  368. }
  369. return;
  370. }
  371. const int t0 = thickness / 2;
  372. const int t1 = thickness - t0;
  373. // draw top
  374. {
  375. for (int y = ry - t0; y < ry + t1; y++)
  376. {
  377. if (y < 0)
  378. continue;
  379. if (y >= h)
  380. break;
  381. unsigned char* p = pixels + stride * y;
  382. for (int x = rx - t0; x < rx + rw + t1; x++)
  383. {
  384. if (x < 0)
  385. continue;
  386. if (x >= w)
  387. break;
  388. p[x * 4 + 0] = pen_color[0];
  389. p[x * 4 + 1] = pen_color[1];
  390. p[x * 4 + 2] = pen_color[2];
  391. p[x * 4 + 3] = pen_color[3];
  392. }
  393. }
  394. }
  395. // draw bottom
  396. {
  397. for (int y = ry + rh - t0; y < ry + rh + t1; y++)
  398. {
  399. if (y < 0)
  400. continue;
  401. if (y >= h)
  402. break;
  403. unsigned char* p = pixels + stride * y;
  404. for (int x = rx - t0; x < rx + rw + t1; x++)
  405. {
  406. if (x < 0)
  407. continue;
  408. if (x >= w)
  409. break;
  410. p[x * 4 + 0] = pen_color[0];
  411. p[x * 4 + 1] = pen_color[1];
  412. p[x * 4 + 2] = pen_color[2];
  413. p[x * 4 + 3] = pen_color[3];
  414. }
  415. }
  416. }
  417. // draw left
  418. for (int x = rx - t0; x < rx + t1; x++)
  419. {
  420. if (x < 0)
  421. continue;
  422. if (x >= w)
  423. break;
  424. for (int y = ry + t1; y < ry + rh - t0; y++)
  425. {
  426. if (y < 0)
  427. continue;
  428. if (y >= h)
  429. break;
  430. unsigned char* p = pixels + stride * y;
  431. p[x * 4 + 0] = pen_color[0];
  432. p[x * 4 + 1] = pen_color[1];
  433. p[x * 4 + 2] = pen_color[2];
  434. p[x * 4 + 3] = pen_color[3];
  435. }
  436. }
  437. // draw right
  438. for (int x = rx + rw - t0; x < rx + rw + t1; x++)
  439. {
  440. if (x < 0)
  441. continue;
  442. if (x >= w)
  443. break;
  444. for (int y = ry + t1; y < ry + rh - t0; y++)
  445. {
  446. if (y < 0)
  447. continue;
  448. if (y >= h)
  449. break;
  450. unsigned char* p = pixels + stride * y;
  451. p[x * 4 + 0] = pen_color[0];
  452. p[x * 4 + 1] = pen_color[1];
  453. p[x * 4 + 2] = pen_color[2];
  454. p[x * 4 + 3] = pen_color[3];
  455. }
  456. }
  457. }
  458. void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
  459. {
  460. // assert w % 2 == 0
  461. // assert h % 2 == 0
  462. // assert rx % 2 == 0
  463. // assert ry % 2 == 0
  464. // assert rw % 2 == 0
  465. // assert rh % 2 == 0
  466. // assert thickness % 2 == 0
  467. const unsigned char* pen_color = (const unsigned char*)&color;
  468. unsigned int v_y;
  469. unsigned int v_uv;
  470. unsigned char* pen_color_y = (unsigned char*)&v_y;
  471. unsigned char* pen_color_uv = (unsigned char*)&v_uv;
  472. pen_color_y[0] = pen_color[0];
  473. pen_color_uv[0] = pen_color[1];
  474. pen_color_uv[1] = pen_color[2];
  475. unsigned char* Y = yuv420sp;
  476. draw_rectangle_c1(Y, w, h, rx, ry, rw, rh, v_y, thickness);
  477. unsigned char* UV = yuv420sp + w * h;
  478. int thickness_uv = thickness == -1 ? thickness : std::max(thickness / 2, 1);
  479. draw_rectangle_c2(UV, w / 2, h / 2, rx / 2, ry / 2, rw / 2, rh / 2, v_uv, thickness_uv);
  480. }
  481. static inline bool distance_lessequal(int x0, int y0, int x1, int y1, float r)
  482. {
  483. int dx = x0 - x1;
  484. int dy = y0 - y1;
  485. int q = dx * dx + dy * dy;
  486. return q <= r * r;
  487. }
  488. static inline bool distance_inrange(int x0, int y0, int x1, int y1, float r0, float r1)
  489. {
  490. int dx = x0 - x1;
  491. int dy = y0 - y1;
  492. int q = dx * dx + dy * dy;
  493. return q >= r0 * r0 && q < r1 * r1;
  494. }
  495. void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
  496. {
  497. return draw_circle_c1(pixels, w, h, w, cx, cy, radius, color, thickness);
  498. }
  499. void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
  500. {
  501. return draw_circle_c2(pixels, w, h, w * 2, cx, cy, radius, color, thickness);
  502. }
  503. void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
  504. {
  505. return draw_circle_c3(pixels, w, h, w * 3, cx, cy, radius, color, thickness);
  506. }
  507. void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
  508. {
  509. return draw_circle_c4(pixels, w, h, w * 4, cx, cy, radius, color, thickness);
  510. }
  511. void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness)
  512. {
  513. const unsigned char* pen_color = (const unsigned char*)&color;
  514. if (thickness == -1)
  515. {
  516. // filled
  517. for (int y = cy - (radius - 1); y < cy + radius; y++)
  518. {
  519. if (y < 0)
  520. continue;
  521. if (y >= h)
  522. break;
  523. unsigned char* p = pixels + stride * y;
  524. for (int x = cx - (radius - 1); x < cx + radius; x++)
  525. {
  526. if (x < 0)
  527. continue;
  528. if (x >= w)
  529. break;
  530. // distance from cx cy
  531. if (distance_lessequal(x, y, cx, cy, radius))
  532. {
  533. p[x] = pen_color[0];
  534. }
  535. }
  536. }
  537. return;
  538. }
  539. const float t0 = thickness / 2.f;
  540. const float t1 = thickness - t0;
  541. for (int y = cy - (radius - 1) - t0; y < cy + radius + t1; y++)
  542. {
  543. if (y < 0)
  544. continue;
  545. if (y >= h)
  546. break;
  547. unsigned char* p = pixels + stride * y;
  548. for (int x = cx - (radius - 1) - t0; x < cx + radius + t1; x++)
  549. {
  550. if (x < 0)
  551. continue;
  552. if (x >= w)
  553. break;
  554. // distance from cx cy
  555. if (distance_inrange(x, y, cx, cy, radius - t0, radius + t1))
  556. {
  557. p[x] = pen_color[0];
  558. }
  559. }
  560. }
  561. }
  562. void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness)
  563. {
  564. const unsigned char* pen_color = (const unsigned char*)&color;
  565. if (thickness == -1)
  566. {
  567. // filled
  568. for (int y = cy - (radius - 1); y < cy + radius; y++)
  569. {
  570. if (y < 0)
  571. continue;
  572. if (y >= h)
  573. break;
  574. unsigned char* p = pixels + stride * y;
  575. for (int x = cx - (radius - 1); x < cx + radius; x++)
  576. {
  577. if (x < 0)
  578. continue;
  579. if (x >= w)
  580. break;
  581. // distance from cx cy
  582. if (distance_lessequal(x, y, cx, cy, radius))
  583. {
  584. p[x * 2 + 0] = pen_color[0];
  585. p[x * 2 + 1] = pen_color[1];
  586. }
  587. }
  588. }
  589. return;
  590. }
  591. const float t0 = thickness / 2.f;
  592. const float t1 = thickness - t0;
  593. for (int y = cy - radius - t0; y < cy + radius + t1; y++)
  594. {
  595. if (y < 0)
  596. continue;
  597. if (y >= h)
  598. break;
  599. unsigned char* p = pixels + stride * y;
  600. for (int x = cx - radius - t0; x < cx + radius + t1; x++)
  601. {
  602. if (x < 0)
  603. continue;
  604. if (x >= w)
  605. break;
  606. // distance from cx cy
  607. if (distance_inrange(x, y, cx, cy, radius - t0, radius + t1))
  608. {
  609. p[x * 2 + 0] = pen_color[0];
  610. p[x * 2 + 1] = pen_color[1];
  611. }
  612. }
  613. }
  614. }
  615. void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness)
  616. {
  617. const unsigned char* pen_color = (const unsigned char*)&color;
  618. if (thickness == -1)
  619. {
  620. // filled
  621. for (int y = cy - (radius - 1); y < cy + radius; y++)
  622. {
  623. if (y < 0)
  624. continue;
  625. if (y >= h)
  626. break;
  627. unsigned char* p = pixels + stride * y;
  628. for (int x = cx - (radius - 1); x < cx + radius; x++)
  629. {
  630. if (x < 0)
  631. continue;
  632. if (x >= w)
  633. break;
  634. // distance from cx cy
  635. if (distance_lessequal(x, y, cx, cy, radius))
  636. {
  637. p[x * 3 + 0] = pen_color[0];
  638. p[x * 3 + 1] = pen_color[1];
  639. p[x * 3 + 2] = pen_color[2];
  640. }
  641. }
  642. }
  643. return;
  644. }
  645. const float t0 = thickness / 2.f;
  646. const float t1 = thickness - t0;
  647. for (int y = cy - radius - t0; y < cy + radius + t1; y++)
  648. {
  649. if (y < 0)
  650. continue;
  651. if (y >= h)
  652. break;
  653. unsigned char* p = pixels + stride * y;
  654. for (int x = cx - radius - t0; x < cx + radius + t1; x++)
  655. {
  656. if (x < 0)
  657. continue;
  658. if (x >= w)
  659. break;
  660. // distance from cx cy
  661. if (distance_inrange(x, y, cx, cy, radius - t0, radius + t1))
  662. {
  663. p[x * 3 + 0] = pen_color[0];
  664. p[x * 3 + 1] = pen_color[1];
  665. p[x * 3 + 2] = pen_color[2];
  666. }
  667. }
  668. }
  669. }
  670. void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness)
  671. {
  672. const unsigned char* pen_color = (const unsigned char*)&color;
  673. if (thickness == -1)
  674. {
  675. // filled
  676. for (int y = cy - (radius - 1); y < cy + radius; y++)
  677. {
  678. if (y < 0)
  679. continue;
  680. if (y >= h)
  681. break;
  682. unsigned char* p = pixels + stride * y;
  683. for (int x = cx - (radius - 1); x < cx + radius; x++)
  684. {
  685. if (x < 0)
  686. continue;
  687. if (x >= w)
  688. break;
  689. // distance from cx cy
  690. if (distance_lessequal(x, y, cx, cy, radius))
  691. {
  692. p[x * 4 + 0] = pen_color[0];
  693. p[x * 4 + 1] = pen_color[1];
  694. p[x * 4 + 2] = pen_color[2];
  695. p[x * 4 + 3] = pen_color[3];
  696. }
  697. }
  698. }
  699. return;
  700. }
  701. const float t0 = thickness / 2.f;
  702. const float t1 = thickness - t0;
  703. for (int y = cy - (radius - 1) - t0; y < cy + radius + t1; y++)
  704. {
  705. if (y < 0)
  706. continue;
  707. if (y >= h)
  708. break;
  709. unsigned char* p = pixels + stride * y;
  710. for (int x = cx - (radius - 1) - t0; x < cx + radius + t1; x++)
  711. {
  712. if (x < 0)
  713. continue;
  714. if (x >= w)
  715. break;
  716. // distance from cx cy
  717. if (distance_inrange(x, y, cx, cy, radius - t0, radius + t1))
  718. {
  719. p[x * 4 + 0] = pen_color[0];
  720. p[x * 4 + 1] = pen_color[1];
  721. p[x * 4 + 2] = pen_color[2];
  722. p[x * 4 + 3] = pen_color[3];
  723. }
  724. }
  725. }
  726. }
  727. void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
  728. {
  729. // assert w % 2 == 0
  730. // assert h % 2 == 0
  731. // assert cx % 2 == 0
  732. // assert cy % 2 == 0
  733. // assert radius % 2 == 0
  734. // assert thickness % 2 == 0
  735. const unsigned char* pen_color = (const unsigned char*)&color;
  736. unsigned int v_y;
  737. unsigned int v_uv;
  738. unsigned char* pen_color_y = (unsigned char*)&v_y;
  739. unsigned char* pen_color_uv = (unsigned char*)&v_uv;
  740. pen_color_y[0] = pen_color[0];
  741. pen_color_uv[0] = pen_color[1];
  742. pen_color_uv[1] = pen_color[2];
  743. unsigned char* Y = yuv420sp;
  744. draw_circle_c1(Y, w, h, cx, cy, radius, v_y, thickness);
  745. unsigned char* UV = yuv420sp + w * h;
  746. int thickness_uv = thickness == -1 ? thickness : std::max(thickness / 2, 1);
  747. draw_circle_c2(UV, w / 2, h / 2, cx / 2, cy / 2, radius / 2, v_uv, thickness_uv);
  748. }
  749. static inline bool distance_lessthan(int x, int y, int x0, int y0, int x1, int y1, float t)
  750. {
  751. int dx01 = x1 - x0;
  752. int dy01 = y1 - y0;
  753. int dx0 = x - x0;
  754. int dy0 = y - y0;
  755. float r = (float)(dx0 * dx01 + dy0 * dy01) / (dx01 * dx01 + dy01 * dy01);
  756. if (r < 0 || r > 1)
  757. return false;
  758. float px = x0 + dx01 * r;
  759. float py = y0 + dy01 * r;
  760. float dx = x - px;
  761. float dy = y - py;
  762. float p = dx * dx + dy * dy;
  763. return p < t;
  764. }
  765. void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
  766. {
  767. draw_line_c1(pixels, w, h, w, x0, y0, x1, y1, color, thickness);
  768. }
  769. void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
  770. {
  771. draw_line_c2(pixels, w, h, w * 2, x0, y0, x1, y1, color, thickness);
  772. }
  773. void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
  774. {
  775. draw_line_c3(pixels, w, h, w * 3, x0, y0, x1, y1, color, thickness);
  776. }
  777. void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
  778. {
  779. draw_line_c4(pixels, w, h, w * 4, x0, y0, x1, y1, color, thickness);
  780. }
  781. void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
  782. {
  783. const unsigned char* pen_color = (const unsigned char*)&color;
  784. const float t0 = thickness / 2.f;
  785. const float t1 = thickness - t0;
  786. int x_min = std::min(x0, x1);
  787. int x_max = std::max(x0, x1);
  788. int y_min = std::min(y0, y1);
  789. int y_max = std::max(y0, y1);
  790. for (int y = y_min - t0; y < y_max + t1; y++)
  791. {
  792. if (y < 0)
  793. continue;
  794. if (y >= h)
  795. break;
  796. unsigned char* p = pixels + stride * y;
  797. for (int x = x_min - t0; x < x_max + t1; x++)
  798. {
  799. if (x < 0)
  800. continue;
  801. if (x >= w)
  802. break;
  803. // distance from line
  804. if (distance_lessthan(x, y, x0, y0, x1, y1, t1))
  805. {
  806. p[x] = pen_color[0];
  807. }
  808. }
  809. }
  810. }
  811. void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
  812. {
  813. const unsigned char* pen_color = (const unsigned char*)&color;
  814. const float t0 = thickness / 2.f;
  815. const float t1 = thickness - t0;
  816. int x_min = std::min(x0, x1);
  817. int x_max = std::max(x0, x1);
  818. int y_min = std::min(y0, y1);
  819. int y_max = std::max(y0, y1);
  820. for (int y = y_min - t0; y < y_max + t1; y++)
  821. {
  822. if (y < 0)
  823. continue;
  824. if (y >= h)
  825. break;
  826. unsigned char* p = pixels + stride * y;
  827. for (int x = x_min - t0; x < x_max + t1; x++)
  828. {
  829. if (x < 0)
  830. continue;
  831. if (x >= w)
  832. break;
  833. // distance from line
  834. if (distance_lessthan(x, y, x0, y0, x1, y1, t1))
  835. {
  836. p[x * 2 + 0] = pen_color[0];
  837. p[x * 2 + 1] = pen_color[1];
  838. }
  839. }
  840. }
  841. }
  842. void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
  843. {
  844. const unsigned char* pen_color = (const unsigned char*)&color;
  845. const float t0 = thickness / 2.f;
  846. const float t1 = thickness - t0;
  847. int x_min = std::min(x0, x1);
  848. int x_max = std::max(x0, x1);
  849. int y_min = std::min(y0, y1);
  850. int y_max = std::max(y0, y1);
  851. for (int y = y_min - t0; y < y_max + t1; y++)
  852. {
  853. if (y < 0)
  854. continue;
  855. if (y >= h)
  856. break;
  857. unsigned char* p = pixels + stride * y;
  858. for (int x = x_min - t0; x < x_max + t1; x++)
  859. {
  860. if (x < 0)
  861. continue;
  862. if (x >= w)
  863. break;
  864. // distance from line
  865. if (distance_lessthan(x, y, x0, y0, x1, y1, t1))
  866. {
  867. p[x * 3 + 0] = pen_color[0];
  868. p[x * 3 + 1] = pen_color[1];
  869. p[x * 3 + 2] = pen_color[2];
  870. }
  871. }
  872. }
  873. }
  874. void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
  875. {
  876. const unsigned char* pen_color = (const unsigned char*)&color;
  877. const float t0 = thickness / 2.f;
  878. const float t1 = thickness - t0;
  879. int x_min = std::min(x0, x1);
  880. int x_max = std::max(x0, x1);
  881. int y_min = std::min(y0, y1);
  882. int y_max = std::max(y0, y1);
  883. for (int y = y_min - t0; y < y_max + t1; y++)
  884. {
  885. if (y < 0)
  886. continue;
  887. if (y >= h)
  888. break;
  889. unsigned char* p = pixels + stride * y;
  890. for (int x = x_min - t0; x < x_max + t1; x++)
  891. {
  892. if (x < 0)
  893. continue;
  894. if (x >= w)
  895. break;
  896. // distance from line
  897. if (distance_lessthan(x, y, x0, y0, x1, y1, t1))
  898. {
  899. p[x * 4 + 0] = pen_color[0];
  900. p[x * 4 + 1] = pen_color[1];
  901. p[x * 4 + 2] = pen_color[2];
  902. p[x * 4 + 3] = pen_color[3];
  903. }
  904. }
  905. }
  906. }
  907. void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
  908. {
  909. // assert w % 2 == 0
  910. // assert h % 2 == 0
  911. // assert x0 % 2 == 0
  912. // assert y0 % 2 == 0
  913. // assert x1 % 2 == 0
  914. // assert y1 % 2 == 0
  915. // assert thickness % 2 == 0
  916. const unsigned char* pen_color = (const unsigned char*)&color;
  917. unsigned int v_y;
  918. unsigned int v_uv;
  919. unsigned char* pen_color_y = (unsigned char*)&v_y;
  920. unsigned char* pen_color_uv = (unsigned char*)&v_uv;
  921. pen_color_y[0] = pen_color[0];
  922. pen_color_uv[0] = pen_color[1];
  923. pen_color_uv[1] = pen_color[2];
  924. unsigned char* Y = yuv420sp;
  925. draw_line_c1(Y, w, h, x0, y0, x1, y1, v_y, thickness);
  926. unsigned char* UV = yuv420sp + w * h;
  927. int thickness_uv = thickness == -1 ? thickness : std::max(thickness / 2, 1);
  928. draw_line_c2(UV, w / 2, h / 2, x0 / 2, y0 / 2, x1 / 2, y1 / 2, v_uv, thickness_uv);
  929. }
  930. void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h)
  931. {
  932. *w = 0;
  933. *h = 0;
  934. const int n = strlen(text);
  935. int line_w = 0;
  936. for (int i = 0; i < n; i++)
  937. {
  938. char ch = text[i];
  939. if (ch == '\n')
  940. {
  941. // newline
  942. *w = std::max(*w, line_w);
  943. *h += fontpixelsize * 2;
  944. line_w = 0;
  945. }
  946. if (isprint(ch) != 0)
  947. {
  948. line_w += fontpixelsize;
  949. }
  950. }
  951. *w = std::max(*w, line_w);
  952. *h += fontpixelsize * 2;
  953. }
  954. void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
  955. {
  956. return draw_text_c1(pixels, w, h, w, text, x, y, fontpixelsize, color);
  957. }
  958. void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
  959. {
  960. return draw_text_c2(pixels, w, h, w * 2, text, x, y, fontpixelsize, color);
  961. }
  962. void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
  963. {
  964. return draw_text_c3(pixels, w, h, w * 3, text, x, y, fontpixelsize, color);
  965. }
  966. void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
  967. {
  968. return draw_text_c4(pixels, w, h, w * 4, text, x, y, fontpixelsize, color);
  969. }
  970. void resize_bilinear_font(const unsigned char* font_bitmap, unsigned char* resized_font_bitmap, int fontpixelsize)
  971. {
  972. const int INTER_RESIZE_COEF_BITS = 11;
  973. const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
  974. const int srcw = 20;
  975. const int srch = 40;
  976. const int w = fontpixelsize;
  977. const int h = fontpixelsize * 2;
  978. double scale = (double)srcw / w;
  979. int* buf = new int[w + h + w + h];
  980. int* xofs = buf; //new int[w];
  981. int* yofs = buf + w; //new int[h];
  982. short* ialpha = (short*)(buf + w + h); //new short[w * 2];
  983. short* ibeta = (short*)(buf + w + h + w); //new short[h * 2];
  984. float fx;
  985. float fy;
  986. int sx;
  987. int sy;
  988. #define SATURATE_CAST_SHORT(X) (short)::std::min(::std::max((int)(X + (X >= 0.f ? 0.5f : -0.5f)), SHRT_MIN), SHRT_MAX);
  989. for (int dx = 0; dx < w; dx++)
  990. {
  991. fx = (float)((dx + 0.5) * scale - 0.5);
  992. sx = static_cast<int>(floor(fx));
  993. fx -= sx;
  994. xofs[dx] = sx;
  995. float a0 = (1.f - fx) * INTER_RESIZE_COEF_SCALE;
  996. float a1 = fx * INTER_RESIZE_COEF_SCALE;
  997. ialpha[dx * 2] = SATURATE_CAST_SHORT(a0);
  998. ialpha[dx * 2 + 1] = SATURATE_CAST_SHORT(a1);
  999. }
  1000. for (int dy = 0; dy < h; dy++)
  1001. {
  1002. fy = (float)((dy + 0.5) * scale - 0.5);
  1003. sy = static_cast<int>(floor(fy));
  1004. fy -= sy;
  1005. yofs[dy] = sy;
  1006. float b0 = (1.f - fy) * INTER_RESIZE_COEF_SCALE;
  1007. float b1 = fy * INTER_RESIZE_COEF_SCALE;
  1008. ibeta[dy * 2] = SATURATE_CAST_SHORT(b0);
  1009. ibeta[dy * 2 + 1] = SATURATE_CAST_SHORT(b1);
  1010. }
  1011. #undef SATURATE_CAST_SHORT
  1012. // loop body
  1013. Mat rowsbuf0(w, (size_t)2u);
  1014. Mat rowsbuf1(w, (size_t)2u);
  1015. short* rows0 = (short*)rowsbuf0;
  1016. short* rows1 = (short*)rowsbuf1;
  1017. {
  1018. short* rows1p = rows1;
  1019. for (int dx = 0; dx < w; dx++)
  1020. {
  1021. rows1p[dx] = 0;
  1022. }
  1023. }
  1024. int prev_sy1 = -2;
  1025. for (int dy = 0; dy < h; dy++)
  1026. {
  1027. sy = yofs[dy];
  1028. if (sy == prev_sy1)
  1029. {
  1030. // reuse all rows
  1031. }
  1032. else if (sy == prev_sy1 + 1)
  1033. {
  1034. // hresize one row
  1035. short* rows0_old = rows0;
  1036. rows0 = rows1;
  1037. rows1 = rows0_old;
  1038. const unsigned char* S1 = font_bitmap + 10 * (sy + 1);
  1039. if (sy >= srch - 1)
  1040. {
  1041. short* rows1p = rows1;
  1042. for (int dx = 0; dx < w; dx++)
  1043. {
  1044. rows1p[dx] = 0;
  1045. }
  1046. }
  1047. else
  1048. {
  1049. const short* ialphap = ialpha;
  1050. short* rows1p = rows1;
  1051. for (int dx = 0; dx < w; dx++)
  1052. {
  1053. sx = xofs[dx];
  1054. short a0 = ialphap[0];
  1055. short a1 = ialphap[1];
  1056. unsigned char S1p0;
  1057. unsigned char S1p1;
  1058. if (sx < 0)
  1059. {
  1060. S1p0 = 0;
  1061. S1p1 = S1[0] & 0x0f;
  1062. }
  1063. else if (sx >= srcw - 1)
  1064. {
  1065. S1p0 = (S1[9] & 0xf0) >> 4;
  1066. S1p1 = 0;
  1067. }
  1068. else
  1069. {
  1070. S1p0 = sx % 2 == 0 ? S1[sx / 2] & 0x0f : (S1[sx / 2] & 0xf0) >> 4;
  1071. S1p1 = sx % 2 == 0 ? (S1[sx / 2] & 0xf0) >> 4 : S1[sx / 2 + 1] & 0x0f;
  1072. }
  1073. rows1p[dx] = (S1p0 * a0 + S1p1 * a1) * 17 >> 4;
  1074. ialphap += 2;
  1075. }
  1076. }
  1077. }
  1078. else
  1079. {
  1080. // hresize two rows
  1081. const unsigned char* S0 = font_bitmap + 10 * (sy);
  1082. const unsigned char* S1 = font_bitmap + 10 * (sy + 1);
  1083. if (sy >= srch - 1)
  1084. {
  1085. const short* ialphap = ialpha;
  1086. short* rows0p = rows0;
  1087. short* rows1p = rows1;
  1088. for (int dx = 0; dx < w; dx++)
  1089. {
  1090. sx = xofs[dx];
  1091. short a0 = ialphap[0];
  1092. short a1 = ialphap[1];
  1093. unsigned char S0p0;
  1094. unsigned char S0p1;
  1095. if (sx < 0)
  1096. {
  1097. S0p0 = 0;
  1098. S0p1 = S0[0] & 0x0f;
  1099. }
  1100. else if (sx >= srcw - 1)
  1101. {
  1102. S0p0 = (S0[9] & 0xf0) >> 4;
  1103. S0p1 = 0;
  1104. }
  1105. else
  1106. {
  1107. S0p0 = sx % 2 == 0 ? S0[sx / 2] & 0x0f : (S0[sx / 2] & 0xf0) >> 4;
  1108. S0p1 = sx % 2 == 0 ? (S0[sx / 2] & 0xf0) >> 4 : S0[sx / 2 + 1] & 0x0f;
  1109. }
  1110. rows0p[dx] = (S0p0 * a0 + S0p1 * a1) * 17 >> 4;
  1111. rows1p[dx] = 0;
  1112. ialphap += 2;
  1113. }
  1114. }
  1115. else
  1116. {
  1117. const short* ialphap = ialpha;
  1118. short* rows0p = rows0;
  1119. short* rows1p = rows1;
  1120. for (int dx = 0; dx < w; dx++)
  1121. {
  1122. sx = xofs[dx];
  1123. short a0 = ialphap[0];
  1124. short a1 = ialphap[1];
  1125. unsigned char S0p0;
  1126. unsigned char S0p1;
  1127. unsigned char S1p0;
  1128. unsigned char S1p1;
  1129. if (sx < 0)
  1130. {
  1131. S0p0 = 0;
  1132. S0p1 = S0[0] & 0x0f;
  1133. S1p0 = 0;
  1134. S1p1 = S1[0] & 0x0f;
  1135. }
  1136. else if (sx >= srcw - 1)
  1137. {
  1138. S0p0 = (S0[9] & 0xf0) >> 4;
  1139. S0p1 = 0;
  1140. S1p0 = (S1[9] & 0xf0) >> 4;
  1141. S1p1 = 0;
  1142. }
  1143. else
  1144. {
  1145. S0p0 = sx % 2 == 0 ? S0[sx / 2] & 0x0f : (S0[sx / 2] & 0xf0) >> 4;
  1146. S0p1 = sx % 2 == 0 ? (S0[sx / 2] & 0xf0) >> 4 : S0[sx / 2 + 1] & 0x0f;
  1147. S1p0 = sx % 2 == 0 ? S1[sx / 2] & 0x0f : (S1[sx / 2] & 0xf0) >> 4;
  1148. S1p1 = sx % 2 == 0 ? (S1[sx / 2] & 0xf0) >> 4 : S1[sx / 2 + 1] & 0x0f;
  1149. }
  1150. rows0p[dx] = (S0p0 * a0 + S0p1 * a1) * 17 >> 4;
  1151. rows1p[dx] = (S1p0 * a0 + S1p1 * a1) * 17 >> 4;
  1152. ialphap += 2;
  1153. }
  1154. }
  1155. }
  1156. prev_sy1 = sy;
  1157. if (dy + 1 < h && yofs[dy + 1] == sy)
  1158. {
  1159. // vresize for two rows
  1160. short b0 = ibeta[0];
  1161. short b1 = ibeta[1];
  1162. short b2 = ibeta[2];
  1163. short b3 = ibeta[3];
  1164. short* rows0p = rows0;
  1165. short* rows1p = rows1;
  1166. unsigned char* Dp0 = resized_font_bitmap + w * (dy);
  1167. unsigned char* Dp1 = resized_font_bitmap + w * (dy + 1);
  1168. int dx = 0;
  1169. #if __ARM_NEON
  1170. int16x8_t _b0 = vdupq_n_s16(b0);
  1171. int16x8_t _b1 = vdupq_n_s16(b1);
  1172. int16x8_t _b2 = vdupq_n_s16(b2);
  1173. int16x8_t _b3 = vdupq_n_s16(b3);
  1174. for (; dx + 15 < w; dx += 16)
  1175. {
  1176. int16x8_t _r00 = vld1q_s16(rows0p);
  1177. int16x8_t _r01 = vld1q_s16(rows0p + 8);
  1178. int16x8_t _r10 = vld1q_s16(rows1p);
  1179. int16x8_t _r11 = vld1q_s16(rows1p + 8);
  1180. int16x8_t _acc00 = vaddq_s16(vqdmulhq_s16(_r00, _b0), vqdmulhq_s16(_r10, _b1));
  1181. int16x8_t _acc01 = vaddq_s16(vqdmulhq_s16(_r01, _b0), vqdmulhq_s16(_r11, _b1));
  1182. int16x8_t _acc10 = vaddq_s16(vqdmulhq_s16(_r00, _b2), vqdmulhq_s16(_r10, _b3));
  1183. int16x8_t _acc11 = vaddq_s16(vqdmulhq_s16(_r01, _b2), vqdmulhq_s16(_r11, _b3));
  1184. uint8x16_t _Dp0 = vcombine_u8(vqrshrun_n_s16(_acc00, 3), vqrshrun_n_s16(_acc01, 3));
  1185. uint8x16_t _Dp1 = vcombine_u8(vqrshrun_n_s16(_acc10, 3), vqrshrun_n_s16(_acc11, 3));
  1186. vst1q_u8(Dp0, _Dp0);
  1187. vst1q_u8(Dp1, _Dp1);
  1188. Dp0 += 16;
  1189. Dp1 += 16;
  1190. rows0p += 16;
  1191. rows1p += 16;
  1192. }
  1193. for (; dx + 7 < w; dx += 8)
  1194. {
  1195. int16x8_t _r0 = vld1q_s16(rows0p);
  1196. int16x8_t _r1 = vld1q_s16(rows1p);
  1197. int16x8_t _acc0 = vaddq_s16(vqdmulhq_s16(_r0, _b0), vqdmulhq_s16(_r1, _b1));
  1198. int16x8_t _acc1 = vaddq_s16(vqdmulhq_s16(_r0, _b2), vqdmulhq_s16(_r1, _b3));
  1199. uint8x8_t _Dp0 = vqrshrun_n_s16(_acc0, 3);
  1200. uint8x8_t _Dp1 = vqrshrun_n_s16(_acc1, 3);
  1201. vst1_u8(Dp0, _Dp0);
  1202. vst1_u8(Dp1, _Dp1);
  1203. Dp0 += 8;
  1204. Dp1 += 8;
  1205. rows0p += 8;
  1206. rows1p += 8;
  1207. }
  1208. #endif // __ARM_NEON
  1209. #if __SSE2__
  1210. __m128i _b0 = _mm_set1_epi16(b0);
  1211. __m128i _b1 = _mm_set1_epi16(b1);
  1212. __m128i _b2 = _mm_set1_epi16(b2);
  1213. __m128i _b3 = _mm_set1_epi16(b3);
  1214. __m128i _v2 = _mm_set1_epi16(2);
  1215. for (; dx + 15 < w; dx += 16)
  1216. {
  1217. __m128i _r00 = _mm_loadu_si128((const __m128i*)rows0p);
  1218. __m128i _r01 = _mm_loadu_si128((const __m128i*)(rows0p + 8));
  1219. __m128i _r10 = _mm_loadu_si128((const __m128i*)rows1p);
  1220. __m128i _r11 = _mm_loadu_si128((const __m128i*)(rows1p + 8));
  1221. __m128i _acc00 = _mm_add_epi16(_mm_mulhi_epi16(_r00, _b0), _mm_mulhi_epi16(_r10, _b1));
  1222. __m128i _acc01 = _mm_add_epi16(_mm_mulhi_epi16(_r01, _b0), _mm_mulhi_epi16(_r11, _b1));
  1223. __m128i _acc10 = _mm_add_epi16(_mm_mulhi_epi16(_r00, _b2), _mm_mulhi_epi16(_r10, _b3));
  1224. __m128i _acc11 = _mm_add_epi16(_mm_mulhi_epi16(_r01, _b2), _mm_mulhi_epi16(_r11, _b3));
  1225. _acc00 = _mm_srai_epi16(_mm_add_epi16(_acc00, _v2), 2);
  1226. _acc01 = _mm_srai_epi16(_mm_add_epi16(_acc01, _v2), 2);
  1227. _acc10 = _mm_srai_epi16(_mm_add_epi16(_acc10, _v2), 2);
  1228. _acc11 = _mm_srai_epi16(_mm_add_epi16(_acc11, _v2), 2);
  1229. __m128i _Dp0 = _mm_packus_epi16(_acc00, _acc01);
  1230. __m128i _Dp1 = _mm_packus_epi16(_acc10, _acc11);
  1231. _mm_storeu_si128((__m128i*)Dp0, _Dp0);
  1232. _mm_storeu_si128((__m128i*)Dp1, _Dp1);
  1233. Dp0 += 16;
  1234. Dp1 += 16;
  1235. rows0p += 16;
  1236. rows1p += 16;
  1237. }
  1238. for (; dx + 7 < w; dx += 8)
  1239. {
  1240. __m128i _r0 = _mm_loadu_si128((const __m128i*)rows0p);
  1241. __m128i _r1 = _mm_loadu_si128((const __m128i*)rows1p);
  1242. __m128i _acc0 = _mm_add_epi16(_mm_mulhi_epi16(_r0, _b0), _mm_mulhi_epi16(_r1, _b1));
  1243. __m128i _acc1 = _mm_add_epi16(_mm_mulhi_epi16(_r0, _b2), _mm_mulhi_epi16(_r1, _b3));
  1244. _acc0 = _mm_srai_epi16(_mm_add_epi16(_acc0, _v2), 2);
  1245. _acc1 = _mm_srai_epi16(_mm_add_epi16(_acc1, _v2), 2);
  1246. __m128i _Dp0 = _mm_packus_epi16(_acc0, _acc0);
  1247. __m128i _Dp1 = _mm_packus_epi16(_acc1, _acc1);
  1248. _mm_storel_epi64((__m128i*)Dp0, _Dp0);
  1249. _mm_storel_epi64((__m128i*)Dp1, _Dp1);
  1250. Dp0 += 8;
  1251. Dp1 += 8;
  1252. rows0p += 8;
  1253. rows1p += 8;
  1254. }
  1255. #endif // __SSE2__
  1256. for (; dx < w; dx++)
  1257. {
  1258. short s0 = *rows0p++;
  1259. short s1 = *rows1p++;
  1260. *Dp0++ = (unsigned char)(((short)((b0 * s0) >> 16) + (short)((b1 * s1) >> 16) + 2) >> 2);
  1261. *Dp1++ = (unsigned char)(((short)((b2 * s0) >> 16) + (short)((b3 * s1) >> 16) + 2) >> 2);
  1262. }
  1263. ibeta += 4;
  1264. dy += 1;
  1265. }
  1266. else
  1267. {
  1268. // vresize
  1269. short b0 = ibeta[0];
  1270. short b1 = ibeta[1];
  1271. short* rows0p = rows0;
  1272. short* rows1p = rows1;
  1273. unsigned char* Dp = resized_font_bitmap + w * (dy);
  1274. int dx = 0;
  1275. #if __ARM_NEON
  1276. int16x8_t _b0 = vdupq_n_s16(b0);
  1277. int16x8_t _b1 = vdupq_n_s16(b1);
  1278. for (; dx + 15 < w; dx += 16)
  1279. {
  1280. int16x8_t _r00 = vld1q_s16(rows0p);
  1281. int16x8_t _r01 = vld1q_s16(rows0p + 8);
  1282. int16x8_t _r10 = vld1q_s16(rows1p);
  1283. int16x8_t _r11 = vld1q_s16(rows1p + 8);
  1284. int16x8_t _acc0 = vaddq_s16(vqdmulhq_s16(_r00, _b0), vqdmulhq_s16(_r10, _b1));
  1285. int16x8_t _acc1 = vaddq_s16(vqdmulhq_s16(_r01, _b0), vqdmulhq_s16(_r11, _b1));
  1286. uint8x16_t _Dp = vcombine_u8(vqrshrun_n_s16(_acc0, 3), vqrshrun_n_s16(_acc1, 3));
  1287. vst1q_u8(Dp, _Dp);
  1288. Dp += 16;
  1289. rows0p += 16;
  1290. rows1p += 16;
  1291. }
  1292. for (; dx + 7 < w; dx += 8)
  1293. {
  1294. int16x8_t _r0 = vld1q_s16(rows0p);
  1295. int16x8_t _r1 = vld1q_s16(rows1p);
  1296. int16x8_t _acc = vaddq_s16(vqdmulhq_s16(_r0, _b0), vqdmulhq_s16(_r1, _b1));
  1297. uint8x8_t _Dp = vqrshrun_n_s16(_acc, 3);
  1298. vst1_u8(Dp, _Dp);
  1299. Dp += 8;
  1300. rows0p += 8;
  1301. rows1p += 8;
  1302. }
  1303. #endif // __ARM_NEON
  1304. #if __SSE2__
  1305. __m128i _b0 = _mm_set1_epi16(b0);
  1306. __m128i _b1 = _mm_set1_epi16(b1);
  1307. __m128i _v2 = _mm_set1_epi16(2);
  1308. for (; dx + 15 < w; dx += 16)
  1309. {
  1310. __m128i _r00 = _mm_loadu_si128((const __m128i*)rows0p);
  1311. __m128i _r01 = _mm_loadu_si128((const __m128i*)(rows0p + 8));
  1312. __m128i _r10 = _mm_loadu_si128((const __m128i*)rows1p);
  1313. __m128i _r11 = _mm_loadu_si128((const __m128i*)(rows1p + 8));
  1314. __m128i _acc0 = _mm_add_epi16(_mm_mulhi_epi16(_r00, _b0), _mm_mulhi_epi16(_r10, _b1));
  1315. __m128i _acc1 = _mm_add_epi16(_mm_mulhi_epi16(_r01, _b0), _mm_mulhi_epi16(_r11, _b1));
  1316. _acc0 = _mm_srai_epi16(_mm_add_epi16(_acc0, _v2), 2);
  1317. _acc1 = _mm_srai_epi16(_mm_add_epi16(_acc1, _v2), 2);
  1318. __m128i _Dp = _mm_packus_epi16(_acc0, _acc1);
  1319. _mm_storeu_si128((__m128i*)Dp, _Dp);
  1320. Dp += 16;
  1321. rows0p += 16;
  1322. rows1p += 16;
  1323. }
  1324. for (; dx + 7 < w; dx += 8)
  1325. {
  1326. __m128i _r0 = _mm_loadu_si128((const __m128i*)rows0p);
  1327. __m128i _r1 = _mm_loadu_si128((const __m128i*)rows1p);
  1328. __m128i _acc = _mm_add_epi16(_mm_mulhi_epi16(_r0, _b0), _mm_mulhi_epi16(_r1, _b1));
  1329. _acc = _mm_srai_epi16(_mm_add_epi16(_acc, _v2), 2);
  1330. __m128i _Dp = _mm_packus_epi16(_acc, _acc);
  1331. _mm_storel_epi64((__m128i*)Dp, _Dp);
  1332. Dp += 8;
  1333. rows0p += 8;
  1334. rows1p += 8;
  1335. }
  1336. #endif // __SSE2__
  1337. for (; dx < w; dx++)
  1338. {
  1339. short s0 = *rows0p++;
  1340. short s1 = *rows1p++;
  1341. *Dp++ = (unsigned char)(((short)((b0 * s0) >> 16) + (short)((b1 * s1) >> 16) + 2) >> 2);
  1342. }
  1343. ibeta += 2;
  1344. }
  1345. }
  1346. delete[] buf;
  1347. }
  1348. void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color)
  1349. {
  1350. const unsigned char* pen_color = (const unsigned char*)&color;
  1351. unsigned char* resized_font_bitmap = new unsigned char[fontpixelsize * fontpixelsize * 2];
  1352. const int n = strlen(text);
  1353. int cursor_x = x;
  1354. int cursor_y = y;
  1355. for (int i = 0; i < n; i++)
  1356. {
  1357. char ch = text[i];
  1358. if (ch == '\n')
  1359. {
  1360. // newline
  1361. cursor_x = x;
  1362. cursor_y += fontpixelsize * 2;
  1363. continue;
  1364. }
  1365. if (ch == ' ')
  1366. {
  1367. cursor_x += fontpixelsize;
  1368. continue;
  1369. }
  1370. if (isprint(ch) != 0)
  1371. {
  1372. const unsigned char* font_bitmap = mono_font_data[ch - '!'];
  1373. // draw resized character
  1374. resize_bilinear_font(font_bitmap, resized_font_bitmap, fontpixelsize);
  1375. const int ystart = std::max(cursor_y, 0);
  1376. const int yend = std::min(cursor_y + fontpixelsize * 2, h);
  1377. const int xstart = std::max(cursor_x, 0);
  1378. const int xend = std::min(cursor_x + fontpixelsize, w);
  1379. for (int j = ystart; j < yend; j++)
  1380. {
  1381. const unsigned char* palpha = resized_font_bitmap + (j - cursor_y) * fontpixelsize + xstart - cursor_x;
  1382. unsigned char* p = pixels + stride * j + xstart;
  1383. for (int k = xstart; k < xend; k++)
  1384. {
  1385. unsigned char alpha = *palpha++;
  1386. p[0] = (p[0] * (255 - alpha) + pen_color[0] * alpha) / 255;
  1387. p += 1;
  1388. }
  1389. }
  1390. cursor_x += fontpixelsize;
  1391. }
  1392. }
  1393. delete[] resized_font_bitmap;
  1394. }
  1395. void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color)
  1396. {
  1397. const unsigned char* pen_color = (const unsigned char*)&color;
  1398. unsigned char* resized_font_bitmap = new unsigned char[fontpixelsize * fontpixelsize * 2];
  1399. const int n = strlen(text);
  1400. int cursor_x = x;
  1401. int cursor_y = y;
  1402. for (int i = 0; i < n; i++)
  1403. {
  1404. char ch = text[i];
  1405. if (ch == '\n')
  1406. {
  1407. // newline
  1408. cursor_x = x;
  1409. cursor_y += fontpixelsize * 2;
  1410. continue;
  1411. }
  1412. if (ch == ' ')
  1413. {
  1414. cursor_x += fontpixelsize;
  1415. continue;
  1416. }
  1417. if (isprint(ch) != 0)
  1418. {
  1419. const unsigned char* font_bitmap = mono_font_data[ch - '!'];
  1420. // draw resized character
  1421. resize_bilinear_font(font_bitmap, resized_font_bitmap, fontpixelsize);
  1422. const int ystart = std::max(cursor_y, 0);
  1423. const int yend = std::min(cursor_y + fontpixelsize * 2, h);
  1424. const int xstart = std::max(cursor_x, 0);
  1425. const int xend = std::min(cursor_x + fontpixelsize, w);
  1426. for (int j = ystart; j < yend; j++)
  1427. {
  1428. const unsigned char* palpha = resized_font_bitmap + (j - cursor_y) * fontpixelsize + xstart - cursor_x;
  1429. unsigned char* p = pixels + stride * j + xstart * 2;
  1430. for (int k = xstart; k < xend; k++)
  1431. {
  1432. unsigned char alpha = *palpha++;
  1433. p[0] = (p[0] * (255 - alpha) + pen_color[0] * alpha) / 255;
  1434. p[1] = (p[1] * (255 - alpha) + pen_color[1] * alpha) / 255;
  1435. p += 2;
  1436. }
  1437. }
  1438. cursor_x += fontpixelsize;
  1439. }
  1440. }
  1441. delete[] resized_font_bitmap;
  1442. }
  1443. void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color)
  1444. {
  1445. const unsigned char* pen_color = (const unsigned char*)&color;
  1446. unsigned char* resized_font_bitmap = new unsigned char[fontpixelsize * fontpixelsize * 2];
  1447. const int n = strlen(text);
  1448. int cursor_x = x;
  1449. int cursor_y = y;
  1450. for (int i = 0; i < n; i++)
  1451. {
  1452. char ch = text[i];
  1453. if (ch == '\n')
  1454. {
  1455. // newline
  1456. cursor_x = x;
  1457. cursor_y += fontpixelsize * 2;
  1458. continue;
  1459. }
  1460. if (ch == ' ')
  1461. {
  1462. cursor_x += fontpixelsize;
  1463. continue;
  1464. }
  1465. if (isprint(ch) != 0)
  1466. {
  1467. const unsigned char* font_bitmap = mono_font_data[ch - '!'];
  1468. // draw resized character
  1469. resize_bilinear_font(font_bitmap, resized_font_bitmap, fontpixelsize);
  1470. const int ystart = std::max(cursor_y, 0);
  1471. const int yend = std::min(cursor_y + fontpixelsize * 2, h);
  1472. const int xstart = std::max(cursor_x, 0);
  1473. const int xend = std::min(cursor_x + fontpixelsize, w);
  1474. for (int j = ystart; j < yend; j++)
  1475. {
  1476. const unsigned char* palpha = resized_font_bitmap + (j - cursor_y) * fontpixelsize + xstart - cursor_x;
  1477. unsigned char* p = pixels + stride * j + xstart * 3;
  1478. for (int k = xstart; k < xend; k++)
  1479. {
  1480. unsigned char alpha = *palpha++;
  1481. p[0] = (p[0] * (255 - alpha) + pen_color[0] * alpha) / 255;
  1482. p[1] = (p[1] * (255 - alpha) + pen_color[1] * alpha) / 255;
  1483. p[2] = (p[2] * (255 - alpha) + pen_color[2] * alpha) / 255;
  1484. p += 3;
  1485. }
  1486. }
  1487. cursor_x += fontpixelsize;
  1488. }
  1489. }
  1490. delete[] resized_font_bitmap;
  1491. }
  1492. void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color)
  1493. {
  1494. const unsigned char* pen_color = (const unsigned char*)&color;
  1495. unsigned char* resized_font_bitmap = new unsigned char[fontpixelsize * fontpixelsize * 2];
  1496. const int n = strlen(text);
  1497. int cursor_x = x;
  1498. int cursor_y = y;
  1499. for (int i = 0; i < n; i++)
  1500. {
  1501. char ch = text[i];
  1502. if (ch == '\n')
  1503. {
  1504. // newline
  1505. cursor_x = x;
  1506. cursor_y += fontpixelsize * 2;
  1507. continue;
  1508. }
  1509. if (ch == ' ')
  1510. {
  1511. cursor_x += fontpixelsize;
  1512. continue;
  1513. }
  1514. if (isprint(ch) != 0)
  1515. {
  1516. const unsigned char* font_bitmap = mono_font_data[ch - '!'];
  1517. // draw resized character
  1518. resize_bilinear_font(font_bitmap, resized_font_bitmap, fontpixelsize);
  1519. const int ystart = std::max(cursor_y, 0);
  1520. const int yend = std::min(cursor_y + fontpixelsize * 2, h);
  1521. const int xstart = std::max(cursor_x, 0);
  1522. const int xend = std::min(cursor_x + fontpixelsize, w);
  1523. for (int j = ystart; j < yend; j++)
  1524. {
  1525. const unsigned char* palpha = resized_font_bitmap + (j - cursor_y) * fontpixelsize + xstart - cursor_x;
  1526. unsigned char* p = pixels + stride * j + xstart * 4;
  1527. for (int k = xstart; k < xend; k++)
  1528. {
  1529. unsigned char alpha = *palpha++;
  1530. p[0] = (p[0] * (255 - alpha) + pen_color[0] * alpha) / 255;
  1531. p[1] = (p[1] * (255 - alpha) + pen_color[1] * alpha) / 255;
  1532. p[2] = (p[2] * (255 - alpha) + pen_color[2] * alpha) / 255;
  1533. p[3] = (p[3] * (255 - alpha) + pen_color[3] * alpha) / 255;
  1534. p += 4;
  1535. }
  1536. }
  1537. cursor_x += fontpixelsize;
  1538. }
  1539. }
  1540. delete[] resized_font_bitmap;
  1541. }
  1542. void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
  1543. {
  1544. // assert w % 2 == 0
  1545. // assert h % 2 == 0
  1546. // assert x % 2 == 0
  1547. // assert y % 2 == 0
  1548. // assert fontpixelsize % 2 == 0
  1549. const unsigned char* pen_color = (const unsigned char*)&color;
  1550. unsigned int v_y;
  1551. unsigned int v_uv;
  1552. unsigned char* pen_color_y = (unsigned char*)&v_y;
  1553. unsigned char* pen_color_uv = (unsigned char*)&v_uv;
  1554. pen_color_y[0] = pen_color[0];
  1555. pen_color_uv[0] = pen_color[1];
  1556. pen_color_uv[1] = pen_color[2];
  1557. unsigned char* Y = yuv420sp;
  1558. draw_text_c1(Y, w, h, text, x, y, fontpixelsize, v_y);
  1559. unsigned char* UV = yuv420sp + w * h;
  1560. draw_text_c2(UV, w / 2, h / 2, text, x / 2, y / 2, std::max(fontpixelsize / 2, 1), v_uv);
  1561. }
  1562. #endif // NCNN_PIXEL_DRAWING
  1563. } // namespace ncnn