drawtest.c 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <draw.h>
  5. #include <memdraw.h>
  6. #define DBG if(0)
  7. #define RGB2K(r,g,b) ((299*((ulong)(r))+587*((ulong)(g))+114*((ulong)(b)))/1000)
  8. /*
  9. * This program tests the 'memimagedraw' primitive stochastically.
  10. * It tests the combination aspects of it thoroughly, but since the
  11. * three images it uses are disjoint, it makes no check of the
  12. * correct behavior when images overlap. That is, however, much
  13. * easier to get right and to test.
  14. */
  15. void drawonepixel(Memimage*, Point, Memimage*, Point, Memimage*, Point);
  16. void verifyone(void);
  17. void verifyline(void);
  18. void verifyrect(void);
  19. void verifyrectrepl(int, int);
  20. void putpixel(Memimage *img, Point pt, ulong nv);
  21. ulong rgbatopix(uchar, uchar, uchar, uchar);
  22. char *dchan, *schan, *mchan;
  23. int dbpp, sbpp, mbpp;
  24. int drawdebug=0;
  25. int seed;
  26. int niters = 100;
  27. int dbpp; /* bits per pixel in destination */
  28. int sbpp; /* bits per pixel in src */
  29. int mbpp; /* bits per pixel in mask */
  30. int dpm; /* pixel mask at high part of byte, in destination */
  31. int nbytes; /* in destination */
  32. int Xrange = 64;
  33. int Yrange = 8;
  34. Memimage *dst;
  35. Memimage *src;
  36. Memimage *mask;
  37. Memimage *stmp;
  38. Memimage *mtmp;
  39. Memimage *ones;
  40. uchar *dstbits;
  41. uchar *srcbits;
  42. uchar *maskbits;
  43. ulong *savedstbits;
  44. void
  45. rdb(void)
  46. {
  47. }
  48. int
  49. iprint(char *fmt, ...)
  50. {
  51. int n;
  52. va_list va;
  53. char buf[1024];
  54. va_start(va, fmt);
  55. n = doprint(buf, buf+sizeof buf, fmt, va) - buf;
  56. va_end(va);
  57. write(1,buf,n);
  58. return 1;
  59. }
  60. void
  61. main(int argc, char *argv[])
  62. {
  63. memimageinit();
  64. seed = time(0);
  65. ARGBEGIN{
  66. case 'x':
  67. Xrange = atoi(ARGF());
  68. break;
  69. case 'y':
  70. Yrange = atoi(ARGF());
  71. break;
  72. case 'n':
  73. niters = atoi(ARGF());
  74. break;
  75. case 's':
  76. seed = atoi(ARGF());
  77. break;
  78. }ARGEND
  79. dchan = "r8g8b8";
  80. schan = "r8g8b8";
  81. mchan = "r8g8b8";
  82. switch(argc){
  83. case 3: mchan = argv[2];
  84. case 2: schan = argv[1];
  85. case 1: dchan = argv[0];
  86. case 0: break;
  87. default: goto Usage;
  88. Usage:
  89. fprint(2, "usage: dtest [dchan [schan [mchan]]]\n");
  90. exits("usage");
  91. }
  92. fmtinstall('b', numbconv); /* binary! */
  93. fprint(2, "%s -x %d -y %d -s 0x%x %s %s %s\n", argv0, Xrange, Yrange, seed, dchan, schan, mchan);
  94. srand(seed);
  95. dst = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(dchan));
  96. src = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
  97. mask = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
  98. stmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
  99. mtmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
  100. ones = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
  101. // print("chan %lux %lux %lux %lux %lux %lux\n", dst->chan, src->chan, mask->chan, stmp->chan, mtmp->chan, ones->chan);
  102. if(dst==0 || src==0 || mask==0 || mtmp==0 || ones==0) {
  103. Alloc:
  104. fprint(2, "dtest: allocation failed: %r\n");
  105. exits("alloc");
  106. }
  107. nbytes = (4*Xrange+4)*Yrange;
  108. srcbits = malloc(nbytes);
  109. dstbits = malloc(nbytes);
  110. maskbits = malloc(nbytes);
  111. savedstbits = malloc(nbytes);
  112. if(dstbits==0 || srcbits==0 || maskbits==0 || savedstbits==0)
  113. goto Alloc;
  114. dbpp = dst->depth;
  115. sbpp = src->depth;
  116. mbpp = mask->depth;
  117. dpm = 0xFF ^ (0xFF>>dbpp);
  118. memset(ones->data->bdata, 0xFF, ones->width*sizeof(ulong)*Yrange);
  119. fprint(2, "dtest: verify single pixel operation\n");
  120. verifyone();
  121. fprint(2, "dtest: verify full line non-replicated\n");
  122. verifyline();
  123. fprint(2, "dtest: verify full rectangle non-replicated\n");
  124. verifyrect();
  125. fprint(2, "dtest: verify full rectangle source replicated\n");
  126. verifyrectrepl(1, 0);
  127. fprint(2, "dtest: verify full rectangle mask replicated\n");
  128. verifyrectrepl(0, 1);
  129. fprint(2, "dtest: verify full rectangle source and mask replicated\n");
  130. verifyrectrepl(1, 1);
  131. exits(0);
  132. }
  133. /*
  134. * Dump out an ASCII representation of an image. The label specifies
  135. * a list of characters to put at various points in the picture.
  136. */
  137. static void
  138. Bprintr5g6b5(Biobuf *bio, char*, ulong v)
  139. {
  140. int r,g,b;
  141. r = (v>>11)&31;
  142. g = (v>>5)&63;
  143. b = v&31;
  144. Bprint(bio, "%.2x%.2x%.2x", r,g,b);
  145. }
  146. static void
  147. Bprintr5g5b5a1(Biobuf *bio, char*, ulong v)
  148. {
  149. int r,g,b,a;
  150. r = (v>>11)&31;
  151. g = (v>>6)&31;
  152. b = (v>>1)&31;
  153. a = v&1;
  154. Bprint(bio, "%.2x%.2x%.2x%.2x", r,g,b,a);
  155. }
  156. void
  157. dumpimage(char *name, Memimage *img, void *vdata, Point labelpt)
  158. {
  159. Biobuf b;
  160. uchar *data;
  161. uchar *p;
  162. char *arg;
  163. void (*fmt)(Biobuf*, char*, ulong);
  164. int npr, x, y, nb, bpp;
  165. ulong v, mask;
  166. Rectangle r;
  167. fmt = nil;
  168. arg = nil;
  169. switch(img->depth){
  170. case 1:
  171. case 2:
  172. case 4:
  173. fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
  174. arg = "%.1ux";
  175. break;
  176. case 8:
  177. fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
  178. arg = "%.2ux";
  179. break;
  180. case 16:
  181. arg = nil;
  182. if(img->chan == RGB16)
  183. fmt = Bprintr5g6b5;
  184. else{
  185. fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
  186. arg = "%.4ux";
  187. }
  188. break;
  189. case 24:
  190. fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
  191. arg = "%.6lux";
  192. break;
  193. case 32:
  194. fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
  195. arg = "%.8lux";
  196. break;
  197. }
  198. if(fmt == nil){
  199. fprint(2, "bad format\n");
  200. abort();
  201. }
  202. r = img->r;
  203. Binit(&b, 2, OWRITE);
  204. data = vdata;
  205. bpp = img->depth;
  206. Bprint(&b, "%s\t%d\tr %R clipr %R repl %d data %p *%P\n", name, r.min.x, r, img->clipr, (img->flags&Frepl) ? 1 : 0, vdata, labelpt);
  207. mask = (1ULL<<bpp)-1;
  208. // for(y=r.min.y; y<r.max.y; y++){
  209. for(y=0; y<Yrange; y++){
  210. nb = 0;
  211. v = 0;
  212. p = data+(byteaddr(img, Pt(0,y))-(uchar*)img->data->bdata);
  213. Bprint(&b, "%-4d\t", y);
  214. // for(x=r.min.x; x<r.max.x; x++){
  215. for(x=0; x<Xrange; x++){
  216. if(x==0)
  217. Bprint(&b, "\t");
  218. if(x != 0 && (x%8)==0)
  219. Bprint(&b, " ");
  220. npr = 0;
  221. if(x==labelpt.x && y==labelpt.y){
  222. Bprint(&b, "*");
  223. npr++;
  224. }
  225. if(npr == 0)
  226. Bprint(&b, " ");
  227. while(nb < bpp){
  228. v &= (1<<nb)-1;
  229. v |= (ulong)(*p++) << nb;
  230. nb += 8;
  231. }
  232. nb -= bpp;
  233. // print("bpp %d v %.8lux mask %.8lux nb %d\n", bpp, v, mask, nb);
  234. fmt(&b, arg, (v>>nb)&mask);
  235. }
  236. Bprint(&b, "\n");
  237. }
  238. Bterm(&b);
  239. }
  240. /*
  241. * Verify that the destination pixel has the specified value.
  242. * The value is in the high bits of v, suitably masked, but must
  243. * be extracted from the destination Memimage.
  244. */
  245. void
  246. checkone(Point p, Point sp, Point mp)
  247. {
  248. int delta;
  249. uchar *dp, *sdp;
  250. delta = (uchar*)byteaddr(dst, p)-(uchar*)dst->data->bdata;
  251. dp = (uchar*)dst->data->bdata+delta;
  252. sdp = (uchar*)savedstbits+delta;
  253. if(memcmp(dp, sdp, (dst->depth+7)/8) != 0) {
  254. fprint(2, "dtest: one bad pixel drawing at dst %P from source %P mask %P\n", p, sp, mp);
  255. fprint(2, " %.2ux %.2ux %.2ux %.2ux should be %.2ux %.2ux %.2ux %.2ux\n",
  256. dp[0], dp[1], dp[2], dp[3], sdp[0], sdp[1], sdp[2], sdp[3]);
  257. fprint(2, "addresses dst %p src %p mask %p\n", dp, byteaddr(src, sp), byteaddr(mask, mp));
  258. dumpimage("src", src, src->data->bdata, sp);
  259. dumpimage("mask", mask, mask->data->bdata, mp);
  260. dumpimage("origdst", dst, dstbits, p);
  261. dumpimage("dst", dst, dst->data->bdata, p);
  262. dumpimage("gooddst", dst, savedstbits, p);
  263. abort();
  264. }
  265. }
  266. /*
  267. * Verify that the destination line has the same value as the saved line.
  268. */
  269. #define RECTPTS(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y
  270. void
  271. checkline(Rectangle r, Point sp, Point mp, int y, Memimage *stmp, Memimage *mtmp)
  272. {
  273. ulong *dp;
  274. int nb;
  275. ulong *saved;
  276. dp = wordaddr(dst, Pt(0, y));
  277. saved = savedstbits + y*dst->width;
  278. if(dst->depth < 8)
  279. nb = Xrange/(8/dst->depth);
  280. else
  281. nb = Xrange*(dst->depth/8);
  282. if(memcmp(dp, saved, nb) != 0){
  283. fprint(2, "dtest: bad line at y=%d; saved %p dp %p\n", y, saved, dp);
  284. fprint(2, "draw dst %R src %P mask %P\n", r, sp, mp);
  285. dumpimage("src", src, src->data->bdata, sp);
  286. if(stmp) dumpimage("stmp", stmp, stmp->data->bdata, sp);
  287. dumpimage("mask", mask, mask->data->bdata, mp);
  288. if(mtmp) dumpimage("mtmp", mtmp, mtmp->data->bdata, mp);
  289. dumpimage("origdst", dst, dstbits, r.min);
  290. dumpimage("dst", dst, dst->data->bdata, r.min);
  291. dumpimage("gooddst", dst, savedstbits, r.min);
  292. abort();
  293. }
  294. }
  295. /*
  296. * Fill the bits of an image with random data.
  297. * The Memimage parameter is used only to make sure
  298. * the data is well formatted: only ucbits is written.
  299. */
  300. void
  301. fill(Memimage *img, uchar *ucbits)
  302. {
  303. int i, x, y;
  304. ushort *up;
  305. uchar alpha, r, g, b;
  306. void *data;
  307. if((img->flags&Falpha) == 0){
  308. up = (ushort*)ucbits;
  309. for(i=0; i<nbytes/2; i++)
  310. *up++ = lrand() >> 7;
  311. if(i+i != nbytes)
  312. *(uchar*)up = lrand() >> 7;
  313. }else{
  314. data = img->data->bdata;
  315. img->data->bdata = ucbits;
  316. for(x=img->r.min.x; x<img->r.max.x; x++)
  317. for(y=img->r.min.y; y<img->r.max.y; y++){
  318. alpha = rand() >> 4;
  319. r = rand()%(alpha+1);
  320. g = rand()%(alpha+1);
  321. b = rand()%(alpha+1);
  322. putpixel(img, Pt(x,y), rgbatopix(r,g,b,alpha));
  323. }
  324. img->data->bdata = data;
  325. }
  326. }
  327. /*
  328. * Mask is preset; do the rest
  329. */
  330. void
  331. verifyonemask(void)
  332. {
  333. Point dp, sp, mp;
  334. fill(dst, dstbits);
  335. fill(src, srcbits);
  336. memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
  337. memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
  338. memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
  339. dp.x = nrand(Xrange);
  340. dp.y = nrand(Yrange);
  341. sp.x = nrand(Xrange);
  342. sp.y = nrand(Yrange);
  343. mp.x = nrand(Xrange);
  344. mp.y = nrand(Yrange);
  345. drawonepixel(dst, dp, src, sp, mask, mp);
  346. memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
  347. memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
  348. memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
  349. memimagedraw(dst, Rect(dp.x, dp.y, dp.x+1, dp.y+1), src, sp, mask, mp, SoverD);
  350. memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
  351. checkone(dp, sp, mp);
  352. }
  353. void
  354. verifyone(void)
  355. {
  356. int i;
  357. /* mask all zeros */
  358. memset(maskbits, 0, nbytes);
  359. for(i=0; i<niters; i++)
  360. verifyonemask();
  361. /* mask all ones */
  362. memset(maskbits, 0xFF, nbytes);
  363. for(i=0; i<niters; i++)
  364. verifyonemask();
  365. /* random mask */
  366. for(i=0; i<niters; i++){
  367. fill(mask, maskbits);
  368. verifyonemask();
  369. }
  370. }
  371. /*
  372. * Mask is preset; do the rest
  373. */
  374. void
  375. verifylinemask(void)
  376. {
  377. Point sp, mp, tp, up;
  378. Rectangle dr;
  379. int x;
  380. fill(dst, dstbits);
  381. fill(src, srcbits);
  382. memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
  383. memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
  384. memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
  385. dr.min.x = nrand(Xrange-1);
  386. dr.min.y = nrand(Yrange-1);
  387. dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
  388. dr.max.y = dr.min.y + 1;
  389. sp.x = nrand(Xrange);
  390. sp.y = nrand(Yrange);
  391. mp.x = nrand(Xrange);
  392. mp.y = nrand(Yrange);
  393. tp = sp;
  394. up = mp;
  395. for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
  396. memimagedraw(dst, Rect(x, dr.min.y, x+1, dr.min.y+1), src, tp, mask, up, SoverD);
  397. memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
  398. memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
  399. memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
  400. checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), dr.min.y, nil, nil);
  401. }
  402. void
  403. verifyline(void)
  404. {
  405. int i;
  406. /* mask all ones */
  407. memset(maskbits, 0xFF, nbytes);
  408. for(i=0; i<niters; i++)
  409. verifylinemask();
  410. /* mask all zeros */
  411. memset(maskbits, 0, nbytes);
  412. for(i=0; i<niters; i++)
  413. verifylinemask();
  414. /* random mask */
  415. for(i=0; i<niters; i++){
  416. fill(mask, maskbits);
  417. verifylinemask();
  418. }
  419. }
  420. /*
  421. * Mask is preset; do the rest
  422. */
  423. void
  424. verifyrectmask(void)
  425. {
  426. Point sp, mp, tp, up;
  427. Rectangle dr;
  428. int x, y;
  429. fill(dst, dstbits);
  430. fill(src, srcbits);
  431. memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
  432. memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
  433. memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
  434. dr.min.x = nrand(Xrange-1);
  435. dr.min.y = nrand(Yrange-1);
  436. dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
  437. dr.max.y = dr.min.y + 1 + nrand(Yrange-1-dr.min.y);
  438. sp.x = nrand(Xrange);
  439. sp.y = nrand(Yrange);
  440. mp.x = nrand(Xrange);
  441. mp.y = nrand(Yrange);
  442. tp = sp;
  443. up = mp;
  444. for(y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++){
  445. for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
  446. memimagedraw(dst, Rect(x, y, x+1, y+1), src, tp, mask, up, SoverD);
  447. tp.x = sp.x;
  448. up.x = mp.x;
  449. }
  450. memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
  451. memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
  452. memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
  453. for(y=0; y<Yrange; y++)
  454. checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, nil, nil);
  455. }
  456. void
  457. verifyrect(void)
  458. {
  459. int i;
  460. /* mask all zeros */
  461. memset(maskbits, 0, nbytes);
  462. for(i=0; i<niters; i++)
  463. verifyrectmask();
  464. /* mask all ones */
  465. memset(maskbits, 0xFF, nbytes);
  466. for(i=0; i<niters; i++)
  467. verifyrectmask();
  468. /* random mask */
  469. for(i=0; i<niters; i++){
  470. fill(mask, maskbits);
  471. verifyrectmask();
  472. }
  473. }
  474. Rectangle
  475. randrect(void)
  476. {
  477. Rectangle r;
  478. r.min.x = nrand(Xrange-1);
  479. r.min.y = nrand(Yrange-1);
  480. r.max.x = r.min.x + 1 + nrand(Xrange-1-r.min.x);
  481. r.max.y = r.min.y + 1 + nrand(Yrange-1-r.min.y);
  482. return r;
  483. }
  484. /*
  485. * Return coordinate corresponding to x withing range [minx, maxx)
  486. */
  487. int
  488. tilexy(int minx, int maxx, int x)
  489. {
  490. int sx;
  491. sx = (x-minx) % (maxx-minx);
  492. if(sx < 0)
  493. sx += maxx-minx;
  494. return sx+minx;
  495. }
  496. void
  497. replicate(Memimage *i, Memimage *tmp)
  498. {
  499. Rectangle r, r1;
  500. int x, y, nb;
  501. /* choose the replication window (i->r) */
  502. r.min.x = nrand(Xrange-1);
  503. r.min.y = nrand(Yrange-1);
  504. /* make it trivial more often than pure chance allows */
  505. switch(lrand()&0){
  506. case 1:
  507. r.max.x = r.min.x + 2;
  508. r.max.y = r.min.y + 2;
  509. if(r.max.x < Xrange && r.max.y < Yrange)
  510. break;
  511. /* fall through */
  512. case 0:
  513. r.max.x = r.min.x + 1;
  514. r.max.y = r.min.y + 1;
  515. break;
  516. default:
  517. if(r.min.x+3 >= Xrange)
  518. r.max.x = Xrange;
  519. else
  520. r.max.x = r.min.x+3 + nrand(Xrange-(r.min.x+3));
  521. if(r.min.y+3 >= Yrange)
  522. r.max.y = Yrange;
  523. else
  524. r.max.y = r.min.y+3 + nrand(Yrange-(r.min.y+3));
  525. }
  526. assert(r.min.x >= 0);
  527. assert(r.max.x <= Xrange);
  528. assert(r.min.y >= 0);
  529. assert(r.max.y <= Yrange);
  530. /* copy from i to tmp so we have just the replicated bits */
  531. nb = tmp->width*sizeof(ulong)*Yrange;
  532. memset(tmp->data->bdata, 0, nb);
  533. memimagedraw(tmp, r, i, r.min, ones, r.min, SoverD);
  534. memmove(i->data->bdata, tmp->data->bdata, nb);
  535. /* i is now a non-replicated instance of the replication */
  536. /* replicate it by hand through tmp */
  537. memset(tmp->data->bdata, 0, nb);
  538. x = -(tilexy(r.min.x, r.max.x, 0)-r.min.x);
  539. for(; x<Xrange; x+=Dx(r)){
  540. y = -(tilexy(r.min.y, r.max.y, 0)-r.min.y);
  541. for(; y<Yrange; y+=Dy(r)){
  542. /* set r1 to instance of tile by translation */
  543. r1.min.x = x;
  544. r1.min.y = y;
  545. r1.max.x = r1.min.x+Dx(r);
  546. r1.max.y = r1.min.y+Dy(r);
  547. memimagedraw(tmp, r1, i, r.min, ones, r.min, SoverD);
  548. }
  549. }
  550. i->flags |= Frepl;
  551. i->r = r;
  552. i->clipr = randrect();
  553. // fprint(2, "replicate [[%d %d] [%d %d]] [[%d %d][%d %d]]\n", r.min.x, r.min.y, r.max.x, r.max.y,
  554. // i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
  555. tmp->clipr = i->clipr;
  556. }
  557. /*
  558. * Mask is preset; do the rest
  559. */
  560. void
  561. verifyrectmaskrepl(int srcrepl, int maskrepl)
  562. {
  563. Point sp, mp, tp, up;
  564. Rectangle dr;
  565. int x, y;
  566. Memimage *s, *m;
  567. // print("verfrect %d %d\n", srcrepl, maskrepl);
  568. src->flags &= ~Frepl;
  569. src->r = Rect(0, 0, Xrange, Yrange);
  570. src->clipr = src->r;
  571. stmp->flags &= ~Frepl;
  572. stmp->r = Rect(0, 0, Xrange, Yrange);
  573. stmp->clipr = src->r;
  574. mask->flags &= ~Frepl;
  575. mask->r = Rect(0, 0, Xrange, Yrange);
  576. mask->clipr = mask->r;
  577. mtmp->flags &= ~Frepl;
  578. mtmp->r = Rect(0, 0, Xrange, Yrange);
  579. mtmp->clipr = mask->r;
  580. fill(dst, dstbits);
  581. fill(src, srcbits);
  582. memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
  583. memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
  584. memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
  585. if(srcrepl){
  586. replicate(src, stmp);
  587. s = stmp;
  588. }else
  589. s = src;
  590. if(maskrepl){
  591. replicate(mask, mtmp);
  592. m = mtmp;
  593. }else
  594. m = mask;
  595. dr = randrect();
  596. sp.x = nrand(Xrange);
  597. sp.y = nrand(Yrange);
  598. mp.x = nrand(Xrange);
  599. mp.y = nrand(Yrange);
  600. DBG print("smalldraws\n");
  601. for(tp.y=sp.y,up.y=mp.y,y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++)
  602. for(tp.x=sp.x,up.x=mp.x,x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
  603. memimagedraw(dst, Rect(x, y, x+1, y+1), s, tp, m, up, SoverD);
  604. memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
  605. memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
  606. DBG print("bigdraw\n");
  607. memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
  608. for(y=0; y<Yrange; y++)
  609. checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, srcrepl?stmp:nil, maskrepl?mtmp:nil);
  610. }
  611. void
  612. verifyrectrepl(int srcrepl, int maskrepl)
  613. {
  614. int i;
  615. /* mask all ones */
  616. memset(maskbits, 0xFF, nbytes);
  617. for(i=0; i<niters; i++)
  618. verifyrectmaskrepl(srcrepl, maskrepl);
  619. /* mask all zeros */
  620. memset(maskbits, 0, nbytes);
  621. for(i=0; i<niters; i++)
  622. verifyrectmaskrepl(srcrepl, maskrepl);
  623. /* random mask */
  624. for(i=0; i<niters; i++){
  625. fill(mask, maskbits);
  626. verifyrectmaskrepl(srcrepl, maskrepl);
  627. }
  628. }
  629. /*
  630. * Trivial draw implementation.
  631. * Color values are passed around as ulongs containing ααRRGGBB
  632. */
  633. /*
  634. * Convert v, which is nhave bits wide, into its nwant bits wide equivalent.
  635. * Replicates to widen the value, truncates to narrow it.
  636. */
  637. ulong
  638. replbits(ulong v, int nhave, int nwant)
  639. {
  640. v &= (1<<nhave)-1;
  641. for(; nhave<nwant; nhave*=2)
  642. v |= v<<nhave;
  643. v >>= (nhave-nwant);
  644. return v & ((1<<nwant)-1);
  645. }
  646. /*
  647. * Decode a pixel into the uchar* values.
  648. */
  649. void
  650. pixtorgba(ulong v, uchar *r, uchar *g, uchar *b, uchar *a)
  651. {
  652. *a = v>>24;
  653. *r = v>>16;
  654. *g = v>>8;
  655. *b = v;
  656. }
  657. /*
  658. * Convert uchar channels into ulong pixel.
  659. */
  660. ulong
  661. rgbatopix(uchar r, uchar g, uchar b, uchar a)
  662. {
  663. return (a<<24)|(r<<16)|(g<<8)|b;
  664. }
  665. /*
  666. * Retrieve the pixel value at pt in the image.
  667. */
  668. ulong
  669. getpixel(Memimage *img, Point pt)
  670. {
  671. uchar r, g, b, a, *p;
  672. int nbits, npack, bpp;
  673. ulong v, c, rbits, bits;
  674. r = g = b = 0;
  675. a = ~0; /* default alpha is full */
  676. p = byteaddr(img, pt);
  677. v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
  678. bpp = img->depth;
  679. if(bpp<8){
  680. /*
  681. * Sub-byte greyscale pixels.
  682. *
  683. * We want to throw away the top pt.x%npack pixels and then use the next bpp bits
  684. * in the bottom byte of v. This madness is due to having big endian bits
  685. * but little endian bytes.
  686. */
  687. npack = 8/bpp;
  688. v >>= 8 - bpp*(pt.x%npack+1);
  689. v &= (1<<bpp)-1;
  690. r = g = b = replbits(v, bpp, 8);
  691. }else{
  692. /*
  693. * General case. We need to parse the channel descriptor and do what it says.
  694. * In all channels but the color map, we replicate to 8 bits because that's the
  695. * precision that all calculations are done at.
  696. *
  697. * In the case of the color map, we leave the bits alone, in case a color map
  698. * with less than 8 bits of index is used. This is currently disallowed, so it's
  699. * sort of silly.
  700. */
  701. for(c=img->chan; c; c>>=8){
  702. nbits = NBITS(c);
  703. bits = v & ((1<<nbits)-1);
  704. rbits = replbits(bits, nbits, 8);
  705. v >>= nbits;
  706. switch(TYPE(c)){
  707. case CRed:
  708. r = rbits;
  709. break;
  710. case CGreen:
  711. g = rbits;
  712. break;
  713. case CBlue:
  714. b = rbits;
  715. break;
  716. case CGrey:
  717. r = g = b = rbits;
  718. break;
  719. case CAlpha:
  720. a = rbits;
  721. break;
  722. case CMap:
  723. p = img->cmap->cmap2rgb + 3*bits;
  724. r = p[0];
  725. g = p[1];
  726. b = p[2];
  727. break;
  728. case CIgnore:
  729. break;
  730. default:
  731. fprint(2, "unknown channel type %lud\n", TYPE(c));
  732. abort();
  733. }
  734. }
  735. }
  736. return rgbatopix(r, g, b, a);
  737. }
  738. /*
  739. * Return the greyscale equivalent of a pixel.
  740. */
  741. uchar
  742. getgrey(Memimage *img, Point pt)
  743. {
  744. uchar r, g, b, a;
  745. pixtorgba(getpixel(img, pt), &r, &g, &b, &a);
  746. return RGB2K(r, g, b);
  747. }
  748. /*
  749. * Return the value at pt in image, if image is interpreted
  750. * as a mask. This means the alpha channel if present, else
  751. * the greyscale or its computed equivalent.
  752. */
  753. uchar
  754. getmask(Memimage *img, Point pt)
  755. {
  756. if(img->flags&Falpha)
  757. return getpixel(img, pt)>>24;
  758. else
  759. return getgrey(img, pt);
  760. }
  761. #undef DBG
  762. #define DBG if(0)
  763. /*
  764. * Write a pixel to img at point pt.
  765. *
  766. * We do this by reading a 32-bit little endian
  767. * value from p and then writing it back
  768. * after tweaking the appropriate bits. Because
  769. * the data is little endian, we don't have to worry
  770. * about what the actual depth is, as long as it is
  771. * less than 32 bits.
  772. */
  773. void
  774. putpixel(Memimage *img, Point pt, ulong nv)
  775. {
  776. uchar r, g, b, a, *p, *q;
  777. ulong c, mask, bits, v;
  778. int bpp, sh, npack, nbits;
  779. pixtorgba(nv, &r, &g, &b, &a);
  780. p = byteaddr(img, pt);
  781. v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
  782. bpp = img->depth;
  783. DBG print("v %.8lux...", v);
  784. if(bpp < 8){
  785. /*
  786. * Sub-byte greyscale pixels. We need to skip the leftmost pt.x%npack pixels,
  787. * which is equivalent to skipping the rightmost npack - pt.x%npack - 1 pixels.
  788. */
  789. npack = 8/bpp;
  790. sh = bpp*(npack - pt.x%npack - 1);
  791. bits = RGB2K(r,g,b);
  792. DBG print("repl %lux 8 %d = %lux...", bits, bpp, replbits(bits, 8, bpp));
  793. bits = replbits(bits, 8, bpp);
  794. mask = (1<<bpp)-1;
  795. DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
  796. mask <<= sh;
  797. bits <<= sh;
  798. DBG print("(%lux & %lux) | (%lux & %lux)", v, ~mask, bits, mask);
  799. v = (v & ~mask) | (bits & mask);
  800. } else {
  801. /*
  802. * General case. We need to parse the channel descriptor again.
  803. */
  804. sh = 0;
  805. for(c=img->chan; c; c>>=8){
  806. nbits = NBITS(c);
  807. switch(TYPE(c)){
  808. case CRed:
  809. bits = r;
  810. break;
  811. case CGreen:
  812. bits = g;
  813. break;
  814. case CBlue:
  815. bits = b;
  816. break;
  817. case CGrey:
  818. bits = RGB2K(r, g, b);
  819. break;
  820. case CAlpha:
  821. bits = a;
  822. break;
  823. case CIgnore:
  824. bits = 0;
  825. break;
  826. case CMap:
  827. q = img->cmap->rgb2cmap;
  828. bits = q[(r>>4)*16*16+(g>>4)*16+(b>>4)];
  829. break;
  830. default:
  831. SET(bits);
  832. fprint(2, "unknown channel type %lud\n", TYPE(c));
  833. abort();
  834. }
  835. DBG print("repl %lux 8 %d = %lux...", bits, nbits, replbits(bits, 8, nbits));
  836. if(TYPE(c) != CMap)
  837. bits = replbits(bits, 8, nbits);
  838. mask = (1<<nbits)-1;
  839. DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
  840. bits <<= sh;
  841. mask <<= sh;
  842. v = (v & ~mask) | (bits & mask);
  843. sh += nbits;
  844. }
  845. }
  846. DBG print("v %.8lux\n", v);
  847. p[0] = v;
  848. p[1] = v>>8;
  849. p[2] = v>>16;
  850. p[3] = v>>24;
  851. }
  852. #undef DBG
  853. #define DBG if(0)
  854. void
  855. drawonepixel(Memimage *dst, Point dp, Memimage *src, Point sp, Memimage *mask, Point mp)
  856. {
  857. uchar m, M, sr, sg, sb, sa, sk, dr, dg, db, da, dk;
  858. pixtorgba(getpixel(dst, dp), &dr, &dg, &db, &da);
  859. pixtorgba(getpixel(src, sp), &sr, &sg, &sb, &sa);
  860. m = getmask(mask, mp);
  861. M = 255-(sa*m)/255;
  862. DBG print("dst %x %x %x %x src %x %x %x %x m %x = ", dr,dg,db,da, sr,sg,sb,sa, m);
  863. if(dst->flags&Fgrey){
  864. /*
  865. * We need to do the conversion to grey before the alpha calculation
  866. * because the draw operator does this, and we need to be operating
  867. * at the same precision so we get exactly the same answers.
  868. */
  869. sk = RGB2K(sr, sg, sb);
  870. dk = RGB2K(dr, dg, db);
  871. dk = (sk*m + dk*M)/255;
  872. dr = dg = db = dk;
  873. da = (sa*m + da*M)/255;
  874. }else{
  875. /*
  876. * True color alpha calculation treats all channels (including alpha)
  877. * the same. It might have been nice to use an array, but oh well.
  878. */
  879. dr = (sr*m + dr*M)/255;
  880. dg = (sg*m + dg*M)/255;
  881. db = (sb*m + db*M)/255;
  882. da = (sa*m + da*M)/255;
  883. }
  884. DBG print("%x %x %x %x\n", dr,dg,db,da);
  885. putpixel(dst, dp, rgbatopix(dr, dg, db, da));
  886. }