drawtest.c 23 KB

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