draw.c 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519
  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 <draw.h>
  12. #include <memdraw.h>
  13. #include <pool.h>
  14. int drawdebug;
  15. static int tablesbuilt;
  16. /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
  17. #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
  18. /*
  19. * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation.
  20. * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation.
  21. * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole.
  22. */
  23. /* #define DIV255(x) (((x)*257+256)>>16) */
  24. #define DIV255(x) ((((x)+1)*257)>>16)
  25. /* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */
  26. #define MUL(x, y, t) (t = (x)*(y)+128, (t+(t>>8))>>8)
  27. #define MASK13 0xFF00FF00
  28. #define MASK02 0x00FF00FF
  29. #define MUL13(a, x, t) (t = (a)*(((x)&MASK13)>>8)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)
  30. #define MUL02(a, x, t) (t = (a)*(((x)&MASK02)>>0)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)
  31. #define MUL0123(a, x, s, t) ((MUL13(a, x, s)<<8)|MUL02(a, x, t))
  32. #define MUL2(u, v, x, y) (t = (u)*(v)+(x)*(y)+256, (t+(t>>8))>>8)
  33. static void mktables(void);
  34. typedef int Subdraw(Memdrawparam*);
  35. static Subdraw chardraw, alphadraw, memoptdraw;
  36. static Memimage* memones;
  37. static Memimage* memzeros;
  38. Memimage *memwhite;
  39. Memimage *memblack;
  40. Memimage *memtransparent;
  41. Memimage *memopaque;
  42. int _ifmt(Fmt*);
  43. void
  44. memimageinit(void)
  45. {
  46. static int didinit = 0;
  47. if(didinit)
  48. return;
  49. didinit = 1;
  50. mktables();
  51. _memmkcmap();
  52. fmtinstall('R', Rfmt);
  53. fmtinstall('P', Pfmt);
  54. fmtinstall('b', _ifmt);
  55. memones = allocmemimage(Rect(0,0,1,1), GREY1);
  56. memones->flags |= Frepl;
  57. memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
  58. *byteaddr(memones, ZP) = ~0;
  59. memzeros = allocmemimage(Rect(0,0,1,1), GREY1);
  60. memzeros->flags |= Frepl;
  61. memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
  62. *byteaddr(memzeros, ZP) = 0;
  63. if(memones == nil || memzeros == nil)
  64. assert(0 /*cannot initialize memimage library */); /* RSC BUG */
  65. memwhite = memones;
  66. memblack = memzeros;
  67. memopaque = memones;
  68. memtransparent = memzeros;
  69. }
  70. static uint32_t imgtorgba(Memimage*, uint32_t);
  71. static uint32_t rgbatoimg(Memimage*, uint32_t);
  72. static uint32_t pixelbits(Memimage*, Point);
  73. #define DBG if(0)
  74. void
  75. memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
  76. {
  77. static int n = 0;
  78. Memdrawparam par;
  79. if(mask == nil)
  80. mask = memopaque;
  81. DBG print("memimagedraw %p/%lX %R @ %p %p/%lX %P %p/%lX %P... ", dst, dst->chan, r, dst->data->bdata, src, src->chan, p0, mask, mask->chan, p1);
  82. if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){
  83. // if(drawdebug)
  84. // iprint("empty clipped rectangle\n");
  85. return;
  86. }
  87. if(op < Clear || op > SoverD){
  88. // if(drawdebug)
  89. // iprint("op out of range: %d\n", op);
  90. return;
  91. }
  92. par.op = op;
  93. par.dst = dst;
  94. par.r = r;
  95. par.src = src;
  96. /* par.sr set by drawclip */
  97. par.mask = mask;
  98. /* par.mr set by drawclip */
  99. par.state = 0;
  100. if(src->flags&Frepl){
  101. par.state |= Replsrc;
  102. if(Dx(src->r)==1 && Dy(src->r)==1){
  103. par.sval = pixelbits(src, src->r.min);
  104. par.state |= Simplesrc;
  105. par.srgba = imgtorgba(src, par.sval);
  106. par.sdval = rgbatoimg(dst, par.srgba);
  107. if((par.srgba&0xFF) == 0 && (op&DoutS)){
  108. // if (drawdebug) iprint("fill with transparent source\n");
  109. return; /* no-op successfully handled */
  110. }
  111. }
  112. }
  113. if(mask->flags & Frepl){
  114. par.state |= Replmask;
  115. if(Dx(mask->r)==1 && Dy(mask->r)==1){
  116. par.mval = pixelbits(mask, mask->r.min);
  117. if(par.mval == 0 && (op&DoutS)){
  118. // if(drawdebug) iprint("fill with zero mask\n");
  119. return; /* no-op successfully handled */
  120. }
  121. par.state |= Simplemask;
  122. if(par.mval == ~0)
  123. par.state |= Fullmask;
  124. par.mrgba = imgtorgba(mask, par.mval);
  125. }
  126. }
  127. DBG print("draw dr %R sr %R mr %R %lx\n", r, par.sr, par.mr, par.state);
  128. /*
  129. * Now that we've clipped the parameters down to be consistent, we
  130. * simply try sub-drawing routines in order until we find one that was able
  131. * to handle us. If the sub-drawing routine returns zero, it means it was
  132. * unable to satisfy the request, so we do not return.
  133. */
  134. /*
  135. * Hardware support. Each video driver provides this function,
  136. * which checks to see if there is anything it can help with.
  137. * There could be an if around this checking to see if dst is in video memory.
  138. */
  139. DBG print("test hwdraw\n");
  140. if(hwdraw(&par)){
  141. //if(drawdebug) iprint("hw handled\n");
  142. DBG print("hwdraw handled\n");
  143. return;
  144. }
  145. /*
  146. * Optimizations using memmove and memset.
  147. */
  148. DBG print("test memoptdraw\n");
  149. if(memoptdraw(&par)){
  150. //if(drawdebug) iprint("memopt handled\n");
  151. DBG print("memopt handled\n");
  152. return;
  153. }
  154. /*
  155. * Character drawing.
  156. * Solid source color being painted through a boolean mask onto a high res image.
  157. */
  158. DBG print("test chardraw\n");
  159. if(chardraw(&par)){
  160. //if(drawdebug) iprint("chardraw handled\n");
  161. DBG print("chardraw handled\n");
  162. return;
  163. }
  164. /*
  165. * General calculation-laden case that does alpha for each pixel.
  166. */
  167. DBG print("do alphadraw\n");
  168. alphadraw(&par);
  169. //if(drawdebug) iprint("alphadraw handled\n");
  170. DBG print("alphadraw handled\n");
  171. }
  172. #undef DBG
  173. /*
  174. * Clip the destination rectangle further based on the properties of the
  175. * source and mask rectangles. Once the destination rectangle is properly
  176. * clipped, adjust the source and mask rectangles to be the same size.
  177. * Then if source or mask is replicated, move its clipped rectangle
  178. * so that its minimum point falls within the repl rectangle.
  179. *
  180. * Return zero if the final rectangle is null.
  181. */
  182. int
  183. drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr)
  184. {
  185. Point rmin, delta;
  186. int splitcoords;
  187. Rectangle omr;
  188. if(r->min.x>=r->max.x || r->min.y>=r->max.y)
  189. return 0;
  190. splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y);
  191. /* clip to destination */
  192. rmin = r->min;
  193. if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr))
  194. return 0;
  195. /* move mask point */
  196. p1->x += r->min.x-rmin.x;
  197. p1->y += r->min.y-rmin.y;
  198. /* move source point */
  199. p0->x += r->min.x-rmin.x;
  200. p0->y += r->min.y-rmin.y;
  201. /* map destination rectangle into source */
  202. sr->min = *p0;
  203. sr->max.x = p0->x+Dx(*r);
  204. sr->max.y = p0->y+Dy(*r);
  205. /* sr is r in source coordinates; clip to source */
  206. if(!(src->flags&Frepl) && !rectclip(sr, src->r))
  207. return 0;
  208. if(!rectclip(sr, src->clipr))
  209. return 0;
  210. /* compute and clip rectangle in mask */
  211. if(splitcoords){
  212. /* move mask point with source */
  213. p1->x += sr->min.x-p0->x;
  214. p1->y += sr->min.y-p0->y;
  215. mr->min = *p1;
  216. mr->max.x = p1->x+Dx(*sr);
  217. mr->max.y = p1->y+Dy(*sr);
  218. omr = *mr;
  219. /* mr is now rectangle in mask; clip it */
  220. if(!(mask->flags&Frepl) && !rectclip(mr, mask->r))
  221. return 0;
  222. if(!rectclip(mr, mask->clipr))
  223. return 0;
  224. /* reflect any clips back to source */
  225. sr->min.x += mr->min.x-omr.min.x;
  226. sr->min.y += mr->min.y-omr.min.y;
  227. sr->max.x += mr->max.x-omr.max.x;
  228. sr->max.y += mr->max.y-omr.max.y;
  229. *p1 = mr->min;
  230. }else{
  231. if(!(mask->flags&Frepl) && !rectclip(sr, mask->r))
  232. return 0;
  233. if(!rectclip(sr, mask->clipr))
  234. return 0;
  235. *p1 = sr->min;
  236. }
  237. /* move source clipping back to destination */
  238. delta.x = r->min.x - p0->x;
  239. delta.y = r->min.y - p0->y;
  240. r->min.x = sr->min.x + delta.x;
  241. r->min.y = sr->min.y + delta.y;
  242. r->max.x = sr->max.x + delta.x;
  243. r->max.y = sr->max.y + delta.y;
  244. /* move source rectangle so sr->min is in src->r */
  245. if(src->flags&Frepl) {
  246. delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x;
  247. delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y;
  248. sr->min.x += delta.x;
  249. sr->min.y += delta.y;
  250. sr->max.x += delta.x;
  251. sr->max.y += delta.y;
  252. }
  253. *p0 = sr->min;
  254. /* move mask point so it is in mask->r */
  255. *p1 = drawrepl(mask->r, *p1);
  256. mr->min = *p1;
  257. mr->max.x = p1->x+Dx(*sr);
  258. mr->max.y = p1->y+Dy(*sr);
  259. assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r));
  260. assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r));
  261. assert(ptinrect(*p0, src->r));
  262. assert(ptinrect(*p1, mask->r));
  263. assert(ptinrect(r->min, dst->r));
  264. return 1;
  265. }
  266. /*
  267. * Conversion tables.
  268. */
  269. static uint8_t replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */
  270. static uint8_t conv18[256][8]; /* conv18[x][y] is the yth pixel in the depth-1 pixel x */
  271. static uint8_t conv28[256][4]; /* ... */
  272. static uint8_t conv48[256][2];
  273. /*
  274. * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8.
  275. * the X's are where to put the bottom (ones) bit of the n-bit pattern.
  276. * only the top 8 bits of the result are actually used.
  277. * (the lower 8 bits are needed to get bits in the right place
  278. * when n is not a divisor of 8.)
  279. *
  280. * Should check to see if its easier to just refer to replmul than
  281. * use the precomputed values in replbit. On PCs it may well
  282. * be; on machines with slow multiply instructions it probably isn't.
  283. */
  284. #define a ((((((((((((((((0
  285. #define X *2+1)
  286. #define _ *2)
  287. static int replmul[1+8] = {
  288. 0,
  289. a X X X X X X X X X X X X X X X X,
  290. a _ X _ X _ X _ X _ X _ X _ X _ X,
  291. a _ _ X _ _ X _ _ X _ _ X _ _ X _,
  292. a _ _ _ X _ _ _ X _ _ _ X _ _ _ X,
  293. a _ _ _ _ X _ _ _ _ X _ _ _ _ X _,
  294. a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _,
  295. a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _,
  296. a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X,
  297. };
  298. #undef a
  299. #undef X
  300. #undef _
  301. static void
  302. mktables(void)
  303. {
  304. int i, j, mask, sh, small;
  305. if(tablesbuilt)
  306. return;
  307. fmtinstall('R', Rfmt);
  308. fmtinstall('P', Pfmt);
  309. tablesbuilt = 1;
  310. /* bit replication up to 8 bits */
  311. for(i=0; i<256; i++){
  312. for(j=0; j<=8; j++){ /* j <= 8 [sic] */
  313. small = i & ((1<<j)-1);
  314. replbit[j][i] = (small*replmul[j])>>8;
  315. }
  316. }
  317. /* bit unpacking up to 8 bits, only powers of 2 */
  318. for(i=0; i<256; i++){
  319. for(j=0, sh=7, mask=1; j<8; j++, sh--)
  320. conv18[i][j] = replbit[1][(i>>sh)&mask];
  321. for(j=0, sh=6, mask=3; j<4; j++, sh-=2)
  322. conv28[i][j] = replbit[2][(i>>sh)&mask];
  323. for(j=0, sh=4, mask=15; j<2; j++, sh-=4)
  324. conv48[i][j] = replbit[4][(i>>sh)&mask];
  325. }
  326. }
  327. static uint8_t ones = 0xff;
  328. /*
  329. * General alpha drawing case. Can handle anything.
  330. */
  331. typedef struct Buffer Buffer;
  332. struct Buffer {
  333. /* used by most routines */
  334. uint8_t *red;
  335. uint8_t *grn;
  336. uint8_t *blu;
  337. uint8_t *alpha;
  338. uint8_t *grey;
  339. uint32_t *rgba;
  340. int delta; /* number of bytes to add to pointer to get next pixel to the right */
  341. /* used by boolcalc* for mask data */
  342. uint8_t *m; /* ptr to mask data r.min byte; like p->bytermin */
  343. int mskip; /* no. of left bits to skip in *m */
  344. uint8_t *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */
  345. int bmskip; /* no. of left bits to skip in *bm */
  346. uint8_t *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */
  347. int emskip; /* no. of right bits to skip in *em */
  348. };
  349. typedef struct Param Param;
  350. typedef Buffer Readfn(Param*, uint8_t*, int);
  351. typedef void Writefn(Param*, uint8_t*, Buffer);
  352. typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int, int);
  353. enum {
  354. MAXBCACHE = 16
  355. };
  356. /* giant rathole to customize functions with */
  357. struct Param {
  358. Readfn *replcall;
  359. Readfn *greymaskcall;
  360. Readfn *convreadcall;
  361. Writefn *convwritecall;
  362. Memimage *img;
  363. Rectangle r;
  364. int dx; /* of r */
  365. int needbuf;
  366. int convgrey;
  367. int alphaonly;
  368. uint8_t *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */
  369. uint8_t *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */
  370. uint8_t *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */
  371. int bwidth;
  372. int replcache; /* if set, cache buffers */
  373. Buffer bcache[MAXBCACHE];
  374. uint32_t bfilled;
  375. uint8_t *bufbase;
  376. int bufoff;
  377. int bufdelta;
  378. int dir;
  379. int convbufoff;
  380. uint8_t *convbuf;
  381. Param *convdpar;
  382. int convdx;
  383. };
  384. static uint8_t *drawbuf;
  385. static int ndrawbuf;
  386. static int mdrawbuf;
  387. static Readfn greymaskread, replread, readptr;
  388. static Writefn nullwrite;
  389. static Calcfn alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;
  390. static Calcfn boolcalc14, boolcalc236789, boolcalc1011;
  391. static Readfn* readfn(Memimage*);
  392. static Readfn* readalphafn(Memimage*);
  393. static Writefn* writefn(Memimage*);
  394. static Calcfn* boolcopyfn(Memimage*, Memimage*);
  395. static Readfn* convfn(Memimage*, Param*, Memimage*, Param*, int*);
  396. static Readfn* ptrfn(Memimage*);
  397. static Calcfn *alphacalc[Ncomp] =
  398. {
  399. alphacalc0, /* Clear */
  400. alphacalc14, /* DoutS */
  401. alphacalc2810, /* SoutD */
  402. alphacalc3679, /* DxorS */
  403. alphacalc14, /* DinS */
  404. alphacalc5, /* D */
  405. alphacalc3679, /* DatopS */
  406. alphacalc3679, /* DoverS */
  407. alphacalc2810, /* SinD */
  408. alphacalc3679, /* SatopD */
  409. alphacalc2810, /* S */
  410. alphacalc11, /* SoverD */
  411. };
  412. static Calcfn *boolcalc[Ncomp] =
  413. {
  414. alphacalc0, /* Clear */
  415. boolcalc14, /* DoutS */
  416. boolcalc236789, /* SoutD */
  417. boolcalc236789, /* DxorS */
  418. boolcalc14, /* DinS */
  419. alphacalc5, /* D */
  420. boolcalc236789, /* DatopS */
  421. boolcalc236789, /* DoverS */
  422. boolcalc236789, /* SinD */
  423. boolcalc236789, /* SatopD */
  424. boolcalc1011, /* S */
  425. boolcalc1011, /* SoverD */
  426. };
  427. /*
  428. * Avoid standard Lock, QLock so that can be used in kernel.
  429. */
  430. typedef struct Dbuf Dbuf;
  431. struct Dbuf
  432. {
  433. uint8_t *p;
  434. int n;
  435. Param spar, mpar, dpar;
  436. int inuse;
  437. };
  438. static Dbuf dbuf[10];
  439. static Dbuf*
  440. allocdbuf(void)
  441. {
  442. int i;
  443. for(i=0; i<nelem(dbuf); i++){
  444. if(dbuf[i].inuse)
  445. continue;
  446. if(!_tas(&dbuf[i].inuse))
  447. return &dbuf[i];
  448. }
  449. return nil;
  450. }
  451. static void
  452. getparam(Param *p, Memimage *img, Rectangle r, int convgrey, int needbuf, int *ndrawbuf)
  453. {
  454. int nbuf;
  455. memset(p, 0, sizeof *p);
  456. p->img = img;
  457. p->r = r;
  458. p->dx = Dx(r);
  459. p->needbuf = needbuf;
  460. p->convgrey = convgrey;
  461. assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x);
  462. p->bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y));
  463. p->bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y));
  464. p->bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y));
  465. p->bwidth = sizeof(uint32_t)*img->width;
  466. assert(p->bytey0s <= p->bytermin && p->bytermin <= p->bytey0e);
  467. if(p->r.min.x == p->img->r.min.x)
  468. assert(p->bytermin == p->bytey0s);
  469. nbuf = 1;
  470. if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){
  471. p->replcache = 1;
  472. nbuf = Dy(img->r);
  473. }
  474. p->bufdelta = 4*p->dx;
  475. p->bufoff = *ndrawbuf;
  476. *ndrawbuf += p->bufdelta*nbuf;
  477. }
  478. static void
  479. clipy(Memimage *img, int *y)
  480. {
  481. int dy;
  482. dy = Dy(img->r);
  483. if(*y == dy)
  484. *y = 0;
  485. else if(*y == -1)
  486. *y = dy-1;
  487. assert(0 <= *y && *y < dy);
  488. }
  489. static void
  490. dumpbuf(char *s, Buffer b, int n)
  491. {
  492. int i;
  493. uint8_t *p;
  494. print("%s", s);
  495. for(i=0; i<n; i++){
  496. print(" ");
  497. if(p=b.grey){
  498. print(" k%.2uX", *p);
  499. b.grey += b.delta;
  500. }else{
  501. if(p=b.red){
  502. print(" r%.2uX", *p);
  503. b.red += b.delta;
  504. }
  505. if(p=b.grn){
  506. print(" g%.2uX", *p);
  507. b.grn += b.delta;
  508. }
  509. if(p=b.blu){
  510. print(" b%.2uX", *p);
  511. b.blu += b.delta;
  512. }
  513. }
  514. if((p=b.alpha) != &ones){
  515. print(" α%.2uX", *p);
  516. b.alpha += b.delta;
  517. }
  518. }
  519. print("\n");
  520. }
  521. /*
  522. * For each scan line, we expand the pixels from source, mask, and destination
  523. * into byte-aligned red, green, blue, alpha, and grey channels. If buffering is not
  524. * needed and the channels were already byte-aligned (grey8, rgb24, rgba32, rgb32),
  525. * the readers need not copy the data: they can simply return pointers to the data.
  526. * If the destination image is grey and the source is not, it is converted using the NTSC
  527. * formula.
  528. *
  529. * Once we have all the channels, we call either rgbcalc or greycalc, depending on
  530. * whether the destination image is color. This is allowed to overwrite the dst buffer (perhaps
  531. * the actual data, perhaps a copy) with its result. It should only overwrite the dst buffer
  532. * with the same format (i.e. red bytes with red bytes, etc.) A new buffer is returned from
  533. * the calculator, and that buffer is passed to a function to write it to the destination.
  534. * If the buffer is already pointing at the destination, the writing function is a no-op.
  535. */
  536. #define DBG if(0)
  537. static int
  538. alphadraw(Memdrawparam *par)
  539. {
  540. int isgrey, starty, endy, op;
  541. int needbuf, dsty, srcy, masky;
  542. int y, dir, dx, dy, ndrawbuf;
  543. uint8_t *drawbuf;
  544. Buffer bsrc, bdst, bmask;
  545. Readfn *rdsrc, *rdmask, *rddst;
  546. Calcfn *calc;
  547. Writefn *wrdst;
  548. Memimage *src, *mask, *dst;
  549. Rectangle r, sr, mr;
  550. Dbuf *z;
  551. r = par->r;
  552. dx = Dx(r);
  553. dy = Dy(r);
  554. z = allocdbuf();
  555. if(z == nil)
  556. return 0;
  557. src = par->src;
  558. mask = par->mask;
  559. dst = par->dst;
  560. sr = par->sr;
  561. mr = par->mr;
  562. op = par->op;
  563. isgrey = dst->flags&Fgrey;
  564. /*
  565. * Buffering when src and dst are the same bitmap is sufficient but not
  566. * necessary. There are stronger conditions we could use. We could
  567. * check to see if the rectangles intersect, and if simply moving in the
  568. * correct y direction can avoid the need to buffer.
  569. */
  570. needbuf = (src->data == dst->data);
  571. ndrawbuf = 0;
  572. getparam(&z->spar, src, sr, isgrey, needbuf, &ndrawbuf);
  573. getparam(&z->dpar, dst, r, isgrey, needbuf, &ndrawbuf);
  574. getparam(&z->mpar, mask, mr, 0, needbuf, &ndrawbuf);
  575. dir = (needbuf && byteaddr(dst, r.min) > byteaddr(src, sr.min)) ? -1 : 1;
  576. z->spar.dir = z->mpar.dir = z->dpar.dir = dir;
  577. /*
  578. * If the mask is purely boolean, we can convert from src to dst format
  579. * when we read src, and then just copy it to dst where the mask tells us to.
  580. * This requires a boolean (1-bit grey) mask and lack of a source alpha channel.
  581. *
  582. * The computation is accomplished by assigning the function pointers as follows:
  583. * rdsrc - read and convert source into dst format in a buffer
  584. * rdmask - convert mask to bytes, set pointer to it
  585. * rddst - fill with pointer to real dst data, but do no reads
  586. * calc - copy src onto dst when mask says to.
  587. * wrdst - do nothing
  588. * This is slightly sleazy, since things aren't doing exactly what their names say,
  589. * but it avoids a fair amount of code duplication to make this a case here
  590. * rather than have a separate booldraw.
  591. */
  592. DBG print("flag %lu mchan %lx=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth);
  593. if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8 && op == SoverD){
  594. //if(drawdebug) iprint("boolcopy...");
  595. rdsrc = convfn(dst, &z->dpar, src, &z->spar, &ndrawbuf);
  596. rddst = readptr;
  597. rdmask = readfn(mask);
  598. calc = boolcopyfn(dst, mask);
  599. wrdst = nullwrite;
  600. }else{
  601. /* usual alphadraw parameter fetching */
  602. rdsrc = readfn(src);
  603. rddst = readfn(dst);
  604. wrdst = writefn(dst);
  605. calc = alphacalc[op];
  606. /*
  607. * If there is no alpha channel, we'll ask for a grey channel
  608. * and pretend it is the alpha.
  609. */
  610. if(mask->flags&Falpha){
  611. rdmask = readalphafn(mask);
  612. z->mpar.alphaonly = 1;
  613. }else{
  614. z->mpar.greymaskcall = readfn(mask);
  615. z->mpar.convgrey = 1;
  616. rdmask = greymaskread;
  617. /*
  618. * Should really be above, but then boolcopyfns would have
  619. * to deal with bit alignment, and I haven't written that.
  620. *
  621. * This is a common case for things like ellipse drawing.
  622. * When there's no alpha involved and the mask is boolean,
  623. * we can avoid all the division and multiplication.
  624. */
  625. if(mask->chan == GREY1 && !(src->flags&Falpha))
  626. calc = boolcalc[op];
  627. else if(op == SoverD && !(src->flags&Falpha))
  628. calc = alphacalcS;
  629. }
  630. }
  631. /*
  632. * If the image has a small enough repl rectangle,
  633. * we can just read each line once and cache them.
  634. */
  635. if(z->spar.replcache){
  636. z->spar.replcall = rdsrc;
  637. rdsrc = replread;
  638. }
  639. if(z->mpar.replcache){
  640. z->mpar.replcall = rdmask;
  641. rdmask = replread;
  642. }
  643. if(z->n < ndrawbuf){
  644. free(z->p);
  645. if((z->p = mallocz(ndrawbuf, 0)) == nil){
  646. z->inuse = 0;
  647. return 0;
  648. }
  649. z->n = ndrawbuf;
  650. }
  651. drawbuf = z->p;
  652. /*
  653. * Before we were saving only offsets from drawbuf in the parameter
  654. * structures; now that drawbuf has been grown to accomodate us,
  655. * we can fill in the pointers.
  656. */
  657. z->spar.bufbase = drawbuf+z->spar.bufoff;
  658. z->mpar.bufbase = drawbuf+z->mpar.bufoff;
  659. z->dpar.bufbase = drawbuf+z->dpar.bufoff;
  660. z->spar.convbuf = drawbuf+z->spar.convbufoff;
  661. if(dir == 1){
  662. starty = 0;
  663. endy = dy;
  664. }else{
  665. starty = dy-1;
  666. endy = -1;
  667. }
  668. /*
  669. * srcy, masky, and dsty are offsets from the top of their
  670. * respective Rectangles. they need to be contained within
  671. * the rectangles, so clipy can keep them there without division.
  672. */
  673. srcy = (starty + sr.min.y - src->r.min.y)%Dy(src->r);
  674. masky = (starty + mr.min.y - mask->r.min.y)%Dy(mask->r);
  675. dsty = starty + r.min.y - dst->r.min.y;
  676. assert(0 <= srcy && srcy < Dy(src->r));
  677. assert(0 <= masky && masky < Dy(mask->r));
  678. assert(0 <= dsty && dsty < Dy(dst->r));
  679. for(y=starty; y!=endy; y+=dir, srcy+=dir, masky+=dir, dsty+=dir){
  680. clipy(src, &srcy);
  681. clipy(dst, &dsty);
  682. clipy(mask, &masky);
  683. bsrc = rdsrc(&z->spar, z->spar.bufbase, srcy);
  684. DBG print("[");
  685. bmask = rdmask(&z->mpar, z->mpar.bufbase, masky);
  686. DBG print("]\n");
  687. bdst = rddst(&z->dpar, z->dpar.bufbase, dsty);
  688. DBG dumpbuf("src", bsrc, dx);
  689. DBG dumpbuf("mask", bmask, dx);
  690. DBG dumpbuf("dst", bdst, dx);
  691. bdst = calc(bdst, bsrc, bmask, dx, isgrey, op);
  692. wrdst(&z->dpar, z->dpar.bytermin+dsty*z->dpar.bwidth, bdst);
  693. }
  694. z->inuse = 0;
  695. return 1;
  696. }
  697. #undef DBG
  698. static Buffer
  699. alphacalc0(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
  700. {
  701. USED(grey);
  702. USED(op);
  703. USED(b1);
  704. USED(b2);
  705. memset(bdst.rgba, 0, dx*bdst.delta);
  706. return bdst;
  707. }
  708. static Buffer
  709. alphacalc14(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
  710. {
  711. Buffer obdst;
  712. int fd, sadelta;
  713. int i, sa, ma, q;
  714. uint32_t s, t;
  715. obdst = bdst;
  716. sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
  717. q = bsrc.delta == 4 && bdst.delta == 4;
  718. for(i=0; i<dx; i++){
  719. sa = *bsrc.alpha;
  720. ma = *bmask.alpha;
  721. fd = MUL(sa, ma, t);
  722. if(op == DoutS)
  723. fd = 255-fd;
  724. if(grey){
  725. *bdst.grey = MUL(fd, *bdst.grey, t);
  726. bsrc.grey += bsrc.delta;
  727. bdst.grey += bdst.delta;
  728. }else{
  729. if(q){
  730. *bdst.rgba = MUL0123(fd, *bdst.rgba, s, t);
  731. bsrc.rgba++;
  732. bdst.rgba++;
  733. bsrc.alpha += sadelta;
  734. bmask.alpha += bmask.delta;
  735. continue;
  736. }
  737. *bdst.red = MUL(fd, *bdst.red, t);
  738. *bdst.grn = MUL(fd, *bdst.grn, t);
  739. *bdst.blu = MUL(fd, *bdst.blu, t);
  740. bsrc.red += bsrc.delta;
  741. bsrc.blu += bsrc.delta;
  742. bsrc.grn += bsrc.delta;
  743. bdst.red += bdst.delta;
  744. bdst.blu += bdst.delta;
  745. bdst.grn += bdst.delta;
  746. }
  747. if(bdst.alpha != &ones){
  748. *bdst.alpha = MUL(fd, *bdst.alpha, t);
  749. bdst.alpha += bdst.delta;
  750. }
  751. bmask.alpha += bmask.delta;
  752. bsrc.alpha += sadelta;
  753. }
  754. return obdst;
  755. }
  756. static Buffer
  757. alphacalc2810(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
  758. {
  759. Buffer obdst;
  760. int fs, sadelta;
  761. int i, ma, da, q;
  762. uint32_t s, t;
  763. obdst = bdst;
  764. sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
  765. q = bsrc.delta == 4 && bdst.delta == 4;
  766. for(i=0; i<dx; i++){
  767. ma = *bmask.alpha;
  768. da = *bdst.alpha;
  769. if(op == SoutD)
  770. da = 255-da;
  771. fs = ma;
  772. if(op != S)
  773. fs = MUL(fs, da, t);
  774. if(grey){
  775. *bdst.grey = MUL(fs, *bsrc.grey, t);
  776. bsrc.grey += bsrc.delta;
  777. bdst.grey += bdst.delta;
  778. }else{
  779. if(q){
  780. *bdst.rgba = MUL0123(fs, *bsrc.rgba, s, t);
  781. bsrc.rgba++;
  782. bdst.rgba++;
  783. bmask.alpha += bmask.delta;
  784. bdst.alpha += bdst.delta;
  785. continue;
  786. }
  787. *bdst.red = MUL(fs, *bsrc.red, t);
  788. *bdst.grn = MUL(fs, *bsrc.grn, t);
  789. *bdst.blu = MUL(fs, *bsrc.blu, t);
  790. bsrc.red += bsrc.delta;
  791. bsrc.blu += bsrc.delta;
  792. bsrc.grn += bsrc.delta;
  793. bdst.red += bdst.delta;
  794. bdst.blu += bdst.delta;
  795. bdst.grn += bdst.delta;
  796. }
  797. if(bdst.alpha != &ones){
  798. *bdst.alpha = MUL(fs, *bsrc.alpha, t);
  799. bdst.alpha += bdst.delta;
  800. }
  801. bmask.alpha += bmask.delta;
  802. bsrc.alpha += sadelta;
  803. }
  804. return obdst;
  805. }
  806. static Buffer
  807. alphacalc3679(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
  808. {
  809. Buffer obdst;
  810. int fs, fd, sadelta;
  811. int i, sa, ma, da, q;
  812. uint32_t s, t, u, v;
  813. obdst = bdst;
  814. sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
  815. q = bsrc.delta == 4 && bdst.delta == 4;
  816. for(i=0; i<dx; i++){
  817. sa = *bsrc.alpha;
  818. ma = *bmask.alpha;
  819. da = *bdst.alpha;
  820. if(op == SatopD)
  821. fs = MUL(ma, da, t);
  822. else
  823. fs = MUL(ma, 255-da, t);
  824. if(op == DoverS)
  825. fd = 255;
  826. else{
  827. fd = MUL(sa, ma, t);
  828. if(op != DatopS)
  829. fd = 255-fd;
  830. }
  831. if(grey){
  832. *bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
  833. bsrc.grey += bsrc.delta;
  834. bdst.grey += bdst.delta;
  835. }else{
  836. if(q){
  837. *bdst.rgba = MUL0123(fs, *bsrc.rgba, s, t)+MUL0123(fd, *bdst.rgba, u, v);
  838. bsrc.rgba++;
  839. bdst.rgba++;
  840. bsrc.alpha += sadelta;
  841. bmask.alpha += bmask.delta;
  842. bdst.alpha += bdst.delta;
  843. continue;
  844. }
  845. *bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
  846. *bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
  847. *bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
  848. bsrc.red += bsrc.delta;
  849. bsrc.blu += bsrc.delta;
  850. bsrc.grn += bsrc.delta;
  851. bdst.red += bdst.delta;
  852. bdst.blu += bdst.delta;
  853. bdst.grn += bdst.delta;
  854. }
  855. if(bdst.alpha != &ones){
  856. *bdst.alpha = MUL(fs, sa, s)+MUL(fd, da, t);
  857. bdst.alpha += bdst.delta;
  858. }
  859. bmask.alpha += bmask.delta;
  860. bsrc.alpha += sadelta;
  861. }
  862. return obdst;
  863. }
  864. static Buffer
  865. alphacalc5(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
  866. {
  867. USED(dx);
  868. USED(grey);
  869. USED(op);
  870. USED(b1);
  871. USED(b2);
  872. return bdst;
  873. }
  874. static Buffer
  875. alphacalc11(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
  876. {
  877. Buffer obdst;
  878. int fd, sadelta;
  879. int i, sa, ma, q;
  880. uint32_t s, t, u, v;
  881. USED(op);
  882. obdst = bdst;
  883. sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
  884. q = bsrc.delta == 4 && bdst.delta == 4;
  885. for(i=0; i<dx; i++){
  886. sa = *bsrc.alpha;
  887. ma = *bmask.alpha;
  888. fd = 255-MUL(sa, ma, t);
  889. if(grey){
  890. *bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
  891. bsrc.grey += bsrc.delta;
  892. bdst.grey += bdst.delta;
  893. }else{
  894. if(q){
  895. *bdst.rgba = MUL0123(ma, *bsrc.rgba, s, t)+MUL0123(fd, *bdst.rgba, u, v);
  896. bsrc.rgba++;
  897. bdst.rgba++;
  898. bsrc.alpha += sadelta;
  899. bmask.alpha += bmask.delta;
  900. continue;
  901. }
  902. *bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
  903. *bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
  904. *bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
  905. bsrc.red += bsrc.delta;
  906. bsrc.blu += bsrc.delta;
  907. bsrc.grn += bsrc.delta;
  908. bdst.red += bdst.delta;
  909. bdst.blu += bdst.delta;
  910. bdst.grn += bdst.delta;
  911. }
  912. if(bdst.alpha != &ones){
  913. *bdst.alpha = MUL(ma, sa, s)+MUL(fd, *bdst.alpha, t);
  914. bdst.alpha += bdst.delta;
  915. }
  916. bmask.alpha += bmask.delta;
  917. bsrc.alpha += sadelta;
  918. }
  919. return obdst;
  920. }
  921. /*
  922. not used yet
  923. source and mask alpha 1
  924. static Buffer
  925. alphacalcS0(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
  926. {
  927. Buffer obdst;
  928. int i;
  929. USED(op);
  930. obdst = bdst;
  931. if(bsrc.delta == bdst.delta){
  932. memmove(bdst.rgba, bsrc.rgba, dx*bdst.delta);
  933. return obdst;
  934. }
  935. for(i=0; i<dx; i++){
  936. if(grey){
  937. *bdst.grey = *bsrc.grey;
  938. bsrc.grey += bsrc.delta;
  939. bdst.grey += bdst.delta;
  940. }else{
  941. *bdst.red = *bsrc.red;
  942. *bdst.grn = *bsrc.grn;
  943. *bdst.blu = *bsrc.blu;
  944. bsrc.red += bsrc.delta;
  945. bsrc.blu += bsrc.delta;
  946. bsrc.grn += bsrc.delta;
  947. bdst.red += bdst.delta;
  948. bdst.blu += bdst.delta;
  949. bdst.grn += bdst.delta;
  950. }
  951. if(bdst.alpha != &ones){
  952. *bdst.alpha = 255;
  953. bdst.alpha += bdst.delta;
  954. }
  955. }
  956. return obdst;
  957. }
  958. */
  959. /* source alpha 1 */
  960. static Buffer
  961. alphacalcS(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
  962. {
  963. Buffer obdst;
  964. int fd;
  965. int i, ma;
  966. uint32_t s, t;
  967. USED(op);
  968. obdst = bdst;
  969. for(i=0; i<dx; i++){
  970. ma = *bmask.alpha;
  971. fd = 255-ma;
  972. if(grey){
  973. *bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
  974. bsrc.grey += bsrc.delta;
  975. bdst.grey += bdst.delta;
  976. }else{
  977. *bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
  978. *bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
  979. *bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
  980. bsrc.red += bsrc.delta;
  981. bsrc.blu += bsrc.delta;
  982. bsrc.grn += bsrc.delta;
  983. bdst.red += bdst.delta;
  984. bdst.blu += bdst.delta;
  985. bdst.grn += bdst.delta;
  986. }
  987. if(bdst.alpha != &ones){
  988. *bdst.alpha = ma+MUL(fd, *bdst.alpha, t);
  989. bdst.alpha += bdst.delta;
  990. }
  991. bmask.alpha += bmask.delta;
  992. }
  993. return obdst;
  994. }
  995. static Buffer
  996. boolcalc14(Buffer bdst, Buffer b1, Buffer bmask, int dx, int grey, int op)
  997. {
  998. Buffer obdst;
  999. int i, ma, zero;
  1000. USED(b1);
  1001. obdst = bdst;
  1002. for(i=0; i<dx; i++){
  1003. ma = *bmask.alpha;
  1004. zero = ma ? op == DoutS : op == DinS;
  1005. if(grey){
  1006. if(zero)
  1007. *bdst.grey = 0;
  1008. bdst.grey += bdst.delta;
  1009. }else{
  1010. if(zero)
  1011. *bdst.red = *bdst.grn = *bdst.blu = 0;
  1012. bdst.red += bdst.delta;
  1013. bdst.blu += bdst.delta;
  1014. bdst.grn += bdst.delta;
  1015. }
  1016. bmask.alpha += bmask.delta;
  1017. if(bdst.alpha != &ones){
  1018. if(zero)
  1019. *bdst.alpha = 0;
  1020. bdst.alpha += bdst.delta;
  1021. }
  1022. }
  1023. return obdst;
  1024. }
  1025. static Buffer
  1026. boolcalc236789(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
  1027. {
  1028. Buffer obdst;
  1029. int fs, fd;
  1030. int i, ma, da, zero;
  1031. uint32_t s, t;
  1032. obdst = bdst;
  1033. zero = !(op&1);
  1034. for(i=0; i<dx; i++){
  1035. ma = *bmask.alpha;
  1036. da = *bdst.alpha;
  1037. fs = da;
  1038. if(op&2)
  1039. fs = 255-da;
  1040. fd = 0;
  1041. if(op&4)
  1042. fd = 255;
  1043. if(grey){
  1044. if(ma)
  1045. *bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
  1046. else if(zero)
  1047. *bdst.grey = 0;
  1048. bsrc.grey += bsrc.delta;
  1049. bdst.grey += bdst.delta;
  1050. }else{
  1051. if(ma){
  1052. *bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
  1053. *bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
  1054. *bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
  1055. }
  1056. else if(zero)
  1057. *bdst.red = *bdst.grn = *bdst.blu = 0;
  1058. bsrc.red += bsrc.delta;
  1059. bsrc.blu += bsrc.delta;
  1060. bsrc.grn += bsrc.delta;
  1061. bdst.red += bdst.delta;
  1062. bdst.blu += bdst.delta;
  1063. bdst.grn += bdst.delta;
  1064. }
  1065. bmask.alpha += bmask.delta;
  1066. if(bdst.alpha != &ones){
  1067. if(ma)
  1068. *bdst.alpha = fs+MUL(fd, da, t);
  1069. else if(zero)
  1070. *bdst.alpha = 0;
  1071. bdst.alpha += bdst.delta;
  1072. }
  1073. }
  1074. return obdst;
  1075. }
  1076. static Buffer
  1077. boolcalc1011(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
  1078. {
  1079. Buffer obdst;
  1080. int i, ma, zero;
  1081. obdst = bdst;
  1082. zero = !(op&1);
  1083. for(i=0; i<dx; i++){
  1084. ma = *bmask.alpha;
  1085. if(grey){
  1086. if(ma)
  1087. *bdst.grey = *bsrc.grey;
  1088. else if(zero)
  1089. *bdst.grey = 0;
  1090. bsrc.grey += bsrc.delta;
  1091. bdst.grey += bdst.delta;
  1092. }else{
  1093. if(ma){
  1094. *bdst.red = *bsrc.red;
  1095. *bdst.grn = *bsrc.grn;
  1096. *bdst.blu = *bsrc.blu;
  1097. }
  1098. else if(zero)
  1099. *bdst.red = *bdst.grn = *bdst.blu = 0;
  1100. bsrc.red += bsrc.delta;
  1101. bsrc.blu += bsrc.delta;
  1102. bsrc.grn += bsrc.delta;
  1103. bdst.red += bdst.delta;
  1104. bdst.blu += bdst.delta;
  1105. bdst.grn += bdst.delta;
  1106. }
  1107. bmask.alpha += bmask.delta;
  1108. if(bdst.alpha != &ones){
  1109. if(ma)
  1110. *bdst.alpha = 255;
  1111. else if(zero)
  1112. *bdst.alpha = 0;
  1113. bdst.alpha += bdst.delta;
  1114. }
  1115. }
  1116. return obdst;
  1117. }
  1118. /*
  1119. * Replicated cached scan line read. Call the function listed in the Param,
  1120. * but cache the result so that for replicated images we only do the work once.
  1121. */
  1122. static Buffer
  1123. replread(Param *p, uint8_t *s, int y)
  1124. {
  1125. Buffer *b;
  1126. USED(s);
  1127. b = &p->bcache[y];
  1128. if((p->bfilled & (1<<y)) == 0){
  1129. p->bfilled |= 1<<y;
  1130. *b = p->replcall(p, p->bufbase+y*p->bufdelta, y);
  1131. }
  1132. return *b;
  1133. }
  1134. /*
  1135. * Alpha reading function that simply relabels the grey pointer.
  1136. */
  1137. static Buffer
  1138. greymaskread(Param *p, uint8_t *buf, int y)
  1139. {
  1140. Buffer b;
  1141. b = p->greymaskcall(p, buf, y);
  1142. b.alpha = b.grey;
  1143. return b;
  1144. }
  1145. #define DBG if(0)
  1146. static Buffer
  1147. readnbit(Param *p, uint8_t *buf, int y)
  1148. {
  1149. Buffer b;
  1150. Memimage *img;
  1151. uint8_t *repl, *r, *w, *ow, bits;
  1152. int i, n, sh, depth, x, dx, npack, nbits;
  1153. b.rgba = (uint32_t*)buf;
  1154. b.grey = w = buf;
  1155. b.red = b.blu = b.grn = w;
  1156. b.alpha = &ones;
  1157. b.delta = 1;
  1158. dx = p->dx;
  1159. img = p->img;
  1160. depth = img->depth;
  1161. repl = &replbit[depth][0];
  1162. npack = 8/depth;
  1163. sh = 8-depth;
  1164. /* copy from p->r.min.x until end of repl rectangle */
  1165. x = p->r.min.x;
  1166. n = dx;
  1167. if(n > p->img->r.max.x - x)
  1168. n = p->img->r.max.x - x;
  1169. r = p->bytermin + y*p->bwidth;
  1170. DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n);
  1171. bits = *r++;
  1172. nbits = 8;
  1173. if(i=x&(npack-1)){
  1174. DBG print("throwaway %d...", i);
  1175. bits <<= depth*i;
  1176. nbits -= depth*i;
  1177. }
  1178. for(i=0; i<n; i++){
  1179. if(nbits == 0){
  1180. DBG print("(%.2ux)...", *r);
  1181. bits = *r++;
  1182. nbits = 8;
  1183. }
  1184. *w++ = repl[bits>>sh];
  1185. DBG print("bit %x...", repl[bits>>sh]);
  1186. bits <<= depth;
  1187. nbits -= depth;
  1188. }
  1189. dx -= n;
  1190. if(dx == 0)
  1191. return b;
  1192. assert(x+i == p->img->r.max.x);
  1193. /* copy from beginning of repl rectangle until where we were before. */
  1194. x = p->img->r.min.x;
  1195. n = dx;
  1196. if(n > p->r.min.x - x)
  1197. n = p->r.min.x - x;
  1198. r = p->bytey0s + y*p->bwidth;
  1199. DBG print("x=%d r=%p...", x, r);
  1200. bits = *r++;
  1201. nbits = 8;
  1202. if(i=x&(npack-1)){
  1203. bits <<= depth*i;
  1204. nbits -= depth*i;
  1205. }
  1206. DBG print("nbits=%d...", nbits);
  1207. for(i=0; i<n; i++){
  1208. if(nbits == 0){
  1209. bits = *r++;
  1210. nbits = 8;
  1211. }
  1212. *w++ = repl[bits>>sh];
  1213. DBG print("bit %x...", repl[bits>>sh]);
  1214. bits <<= depth;
  1215. nbits -= depth;
  1216. DBG print("bits %x nbits %d...", bits, nbits);
  1217. }
  1218. dx -= n;
  1219. if(dx == 0)
  1220. return b;
  1221. assert(dx > 0);
  1222. /* now we have exactly one full scan line: just replicate the buffer itself until we are done */
  1223. ow = buf;
  1224. while(dx--)
  1225. *w++ = *ow++;
  1226. return b;
  1227. }
  1228. #undef DBG
  1229. #define DBG if(0)
  1230. static void
  1231. writenbit(Param *p, uint8_t *w, Buffer src)
  1232. {
  1233. uint8_t *r;
  1234. uint32_t bits;
  1235. int i, sh, depth, npack, nbits, x, ex;
  1236. assert(src.grey != nil && src.delta == 1);
  1237. x = p->r.min.x;
  1238. ex = x+p->dx;
  1239. depth = p->img->depth;
  1240. npack = 8/depth;
  1241. i=x&(npack-1);
  1242. bits = i ? (*w >> (8-depth*i)) : 0;
  1243. nbits = depth*i;
  1244. sh = 8-depth;
  1245. r = src.grey;
  1246. for(; x<ex; x++){
  1247. bits <<= depth;
  1248. DBG print(" %x", *r);
  1249. bits |= (*r++ >> sh);
  1250. nbits += depth;
  1251. if(nbits == 8){
  1252. *w++ = bits;
  1253. nbits = 0;
  1254. }
  1255. }
  1256. if(nbits){
  1257. sh = 8-nbits;
  1258. bits <<= sh;
  1259. bits |= *w & ((1<<sh)-1);
  1260. *w = bits;
  1261. }
  1262. DBG print("\n");
  1263. return;
  1264. }
  1265. #undef DBG
  1266. static Buffer
  1267. readcmap(Param *p, unsigned char *buf, int y)
  1268. {
  1269. Buffer b;
  1270. int a, convgrey, copyalpha, dx, i, m;
  1271. unsigned char *q, *cmap, *begin, *end, *r, *w;
  1272. begin = p->bytey0s + y*p->bwidth;
  1273. r = p->bytermin + y*p->bwidth;
  1274. end = p->bytey0e + y*p->bwidth;
  1275. cmap = p->img->cmap->cmap2rgb;
  1276. convgrey = p->convgrey;
  1277. copyalpha = (p->img->flags&Falpha) ? 1 : 0;
  1278. w = buf;
  1279. dx = p->dx;
  1280. if(copyalpha){
  1281. b.alpha = buf++;
  1282. a = p->img->shift[CAlpha]/8;
  1283. m = p->img->shift[CMap]/8;
  1284. for(i=0; i<dx; i++){
  1285. *w++ = r[a];
  1286. q = cmap+r[m]*3;
  1287. r += 2;
  1288. if(r == end)
  1289. r = begin;
  1290. if(convgrey){
  1291. *w++ = RGB2K(q[0], q[1], q[2]);
  1292. }else{
  1293. *w++ = q[2]; /* blue */
  1294. *w++ = q[1]; /* green */
  1295. *w++ = q[0]; /* red */
  1296. }
  1297. }
  1298. }else{
  1299. b.alpha = &ones;
  1300. for(i=0; i<dx; i++){
  1301. q = cmap+*r++*3;
  1302. if(r == end)
  1303. r = begin;
  1304. if(convgrey){
  1305. *w++ = RGB2K(q[0], q[1], q[2]);
  1306. }else{
  1307. *w++ = q[2]; /* blue */
  1308. *w++ = q[1]; /* green */
  1309. *w++ = q[0]; /* red */
  1310. }
  1311. }
  1312. }
  1313. b.rgba = (uint32_t*)(buf-copyalpha);
  1314. if(convgrey){
  1315. b.grey = buf;
  1316. b.red = b.blu = b.grn = buf;
  1317. b.delta = 1+copyalpha;
  1318. }else{
  1319. b.blu = buf;
  1320. b.grn = buf+1;
  1321. b.red = buf+2;
  1322. b.grey = nil;
  1323. b.delta = 3+copyalpha;
  1324. }
  1325. return b;
  1326. }
  1327. static void
  1328. writecmap(Param *p, uint8_t *w, Buffer src)
  1329. {
  1330. uint8_t *cmap, *red, *grn, *blu;
  1331. int i, dx, delta;
  1332. cmap = p->img->cmap->rgb2cmap;
  1333. delta = src.delta;
  1334. red= src.red;
  1335. grn = src.grn;
  1336. blu = src.blu;
  1337. dx = p->dx;
  1338. for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta)
  1339. *w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)];
  1340. }
  1341. #define DBG if(0)
  1342. static Buffer
  1343. readbyte(Param *p, uint8_t *buf, int y)
  1344. {
  1345. Buffer b;
  1346. Memimage *img;
  1347. int dx, isgrey, convgrey, alphaonly, copyalpha, i, nb;
  1348. uint8_t *begin, *end, *r, *w, *rrepl, *grepl, *brepl, *arepl, *krepl;
  1349. uint8_t ured, ugrn, ublu;
  1350. uint32_t u;
  1351. img = p->img;
  1352. begin = p->bytey0s + y*p->bwidth;
  1353. r = p->bytermin + y*p->bwidth;
  1354. end = p->bytey0e + y*p->bwidth;
  1355. w = buf;
  1356. dx = p->dx;
  1357. nb = img->depth/8;
  1358. convgrey = p->convgrey; /* convert rgb to grey */
  1359. isgrey = img->flags&Fgrey;
  1360. alphaonly = p->alphaonly;
  1361. copyalpha = (img->flags&Falpha) ? 1 : 0;
  1362. DBG print("copyalpha %d alphaonly %d convgrey %d isgrey %d\n", copyalpha, alphaonly, convgrey, isgrey);
  1363. /* if we can, avoid processing everything */
  1364. if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){
  1365. memset(&b, 0, sizeof b);
  1366. if(p->needbuf){
  1367. memmove(buf, r, dx*nb);
  1368. r = buf;
  1369. }
  1370. b.rgba = (uint32_t*)r;
  1371. if(copyalpha)
  1372. b.alpha = r+img->shift[CAlpha]/8;
  1373. else
  1374. b.alpha = &ones;
  1375. if(isgrey){
  1376. b.grey = r+img->shift[CGrey]/8;
  1377. b.red = b.grn = b.blu = b.grey;
  1378. }else{
  1379. b.red = r+img->shift[CRed]/8;
  1380. b.grn = r+img->shift[CGreen]/8;
  1381. b.blu = r+img->shift[CBlue]/8;
  1382. }
  1383. b.delta = nb;
  1384. return b;
  1385. }
  1386. DBG print("2\n");
  1387. rrepl = replbit[img->nbits[CRed]];
  1388. grepl = replbit[img->nbits[CGreen]];
  1389. brepl = replbit[img->nbits[CBlue]];
  1390. arepl = replbit[img->nbits[CAlpha]];
  1391. krepl = replbit[img->nbits[CGrey]];
  1392. for(i=0; i<dx; i++){
  1393. u = r[0] | (r[1]<<8) | (r[2]<<16) | (r[3]<<24);
  1394. if(copyalpha) {
  1395. *w++ = arepl[(u>>img->shift[CAlpha]) & img->mask[CAlpha]];
  1396. DBG print("a %x\n", w[-1]);
  1397. }
  1398. if(isgrey)
  1399. *w++ = krepl[(u >> img->shift[CGrey]) & img->mask[CGrey]];
  1400. else if(!alphaonly){
  1401. ured = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
  1402. ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
  1403. ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
  1404. if(convgrey){
  1405. DBG print("g %x %x %x\n", ured, ugrn, ublu);
  1406. *w++ = RGB2K(ured, ugrn, ublu);
  1407. DBG print("%x\n", w[-1]);
  1408. }else{
  1409. *w++ = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
  1410. *w++ = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
  1411. *w++ = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
  1412. }
  1413. }
  1414. r += nb;
  1415. if(r == end)
  1416. r = begin;
  1417. }
  1418. b.alpha = copyalpha ? buf : &ones;
  1419. b.rgba = (uint32_t*)buf;
  1420. if(alphaonly){
  1421. b.red = b.grn = b.blu = b.grey = nil;
  1422. if(!copyalpha)
  1423. b.rgba = nil;
  1424. b.delta = 1;
  1425. }else if(isgrey || convgrey){
  1426. b.grey = buf+copyalpha;
  1427. b.red = b.grn = b.blu = buf+copyalpha;
  1428. b.delta = copyalpha+1;
  1429. DBG print("alpha %x grey %x\n", b.alpha ? *b.alpha : 0xFF, *b.grey);
  1430. }else{
  1431. b.blu = buf+copyalpha;
  1432. b.grn = buf+copyalpha+1;
  1433. b.grey = nil;
  1434. b.red = buf+copyalpha+2;
  1435. b.delta = copyalpha+3;
  1436. }
  1437. return b;
  1438. }
  1439. #undef DBG
  1440. #define DBG if(0)
  1441. static void
  1442. writebyte(Param *p, uint8_t *w, Buffer src)
  1443. {
  1444. Memimage *img;
  1445. int i, isalpha, isgrey, nb, delta, dx, adelta;
  1446. uint8_t ff, *red, *grn, *blu, *grey, *alpha;
  1447. uint32_t u, mask;
  1448. img = p->img;
  1449. red = src.red;
  1450. grn = src.grn;
  1451. blu = src.blu;
  1452. alpha = src.alpha;
  1453. delta = src.delta;
  1454. grey = src.grey;
  1455. dx = p->dx;
  1456. nb = img->depth/8;
  1457. mask = (nb==4) ? 0 : ~((1<<img->depth)-1);
  1458. isalpha = img->flags&Falpha;
  1459. isgrey = img->flags&Fgrey;
  1460. adelta = src.delta;
  1461. if(isalpha && (alpha == nil || alpha == &ones)){
  1462. ff = 0xFF;
  1463. alpha = &ff;
  1464. adelta = 0;
  1465. }
  1466. for(i=0; i<dx; i++){
  1467. u = w[0] | (w[1]<<8) | (w[2]<<16) | (w[3]<<24);
  1468. DBG print("u %.8lux...", u);
  1469. u &= mask;
  1470. DBG print("&mask %.8lux...", u);
  1471. if(isgrey){
  1472. u |= ((*grey >> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey];
  1473. DBG print("|grey %.8lux...", u);
  1474. grey += delta;
  1475. }else{
  1476. u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed];
  1477. u |= ((*grn >> (8-img->nbits[CGreen])) & img->mask[CGreen]) << img->shift[CGreen];
  1478. u |= ((*blu >> (8-img->nbits[CBlue])) & img->mask[CBlue]) << img->shift[CBlue];
  1479. red += delta;
  1480. grn += delta;
  1481. blu += delta;
  1482. DBG print("|rgb %.8lux...", u);
  1483. }
  1484. if(isalpha){
  1485. u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha];
  1486. alpha += adelta;
  1487. DBG print("|alpha %.8lux...", u);
  1488. }
  1489. w[0] = u;
  1490. w[1] = u>>8;
  1491. w[2] = u>>16;
  1492. w[3] = u>>24;
  1493. w += nb;
  1494. }
  1495. }
  1496. #undef DBG
  1497. static Readfn*
  1498. readfn(Memimage *img)
  1499. {
  1500. if(img->depth < 8)
  1501. return readnbit;
  1502. if(img->nbits[CMap] == 8)
  1503. return readcmap;
  1504. return readbyte;
  1505. }
  1506. static Readfn*
  1507. readalphafn(Memimage *m)
  1508. {
  1509. USED(m);
  1510. return readbyte;
  1511. }
  1512. static Writefn*
  1513. writefn(Memimage *img)
  1514. {
  1515. if(img->depth < 8)
  1516. return writenbit;
  1517. if(img->chan == CMAP8)
  1518. return writecmap;
  1519. return writebyte;
  1520. }
  1521. static void
  1522. nullwrite(Param *p, uint8_t *s, Buffer b)
  1523. {
  1524. USED(p);
  1525. USED(s);
  1526. USED(b);
  1527. }
  1528. static Buffer
  1529. readptr(Param *p, uint8_t *s, int y)
  1530. {
  1531. Buffer b;
  1532. uint8_t *q;
  1533. USED(s);
  1534. q = p->bytermin + y*p->bwidth;
  1535. b.red = q; /* ptr to data */
  1536. b.grn = b.blu = b.grey = b.alpha = nil;
  1537. b.rgba = (uint32_t*)q;
  1538. b.delta = p->img->depth/8;
  1539. return b;
  1540. }
  1541. static Buffer
  1542. boolmemmove(Buffer bdst, Buffer bsrc, Buffer b1, int dx, int i, int o)
  1543. {
  1544. USED(i);
  1545. USED(o);
  1546. USED(b1);
  1547. USED(bsrc);
  1548. memmove(bdst.red, bsrc.red, dx*bdst.delta);
  1549. return bdst;
  1550. }
  1551. static Buffer
  1552. boolcopy8(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
  1553. {
  1554. uint8_t *m, *r, *w, *ew;
  1555. USED(i);
  1556. USED(o);
  1557. m = bmask.grey;
  1558. w = bdst.red;
  1559. r = bsrc.red;
  1560. ew = w+dx;
  1561. for(; w < ew; w++,r++)
  1562. if(*m++)
  1563. *w = *r;
  1564. return bdst; /* not used */
  1565. }
  1566. static Buffer
  1567. boolcopy16(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
  1568. {
  1569. uint8_t *m;
  1570. uint16_t *r, *w, *ew;
  1571. USED(i);
  1572. USED(o);
  1573. m = bmask.grey;
  1574. w = (uint16_t*)bdst.red;
  1575. r = (uint16_t*)bsrc.red;
  1576. ew = w+dx;
  1577. for(; w < ew; w++,r++)
  1578. if(*m++)
  1579. *w = *r;
  1580. return bdst; /* not used */
  1581. }
  1582. static Buffer
  1583. boolcopy24(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
  1584. {
  1585. uint8_t *m;
  1586. uint8_t *r, *w, *ew;
  1587. USED(i);
  1588. USED(o);
  1589. m = bmask.grey;
  1590. w = bdst.red;
  1591. r = bsrc.red;
  1592. ew = w+dx*3;
  1593. while(w < ew){
  1594. if(*m++){
  1595. *w++ = *r++;
  1596. *w++ = *r++;
  1597. *w++ = *r++;
  1598. }else{
  1599. w += 3;
  1600. r += 3;
  1601. }
  1602. }
  1603. return bdst; /* not used */
  1604. }
  1605. static Buffer
  1606. boolcopy32(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
  1607. {
  1608. uint8_t *m;
  1609. uint32_t *r, *w, *ew;
  1610. USED(i);
  1611. USED(o);
  1612. m = bmask.grey;
  1613. w = (uint32_t*)bdst.red;
  1614. r = (uint32_t*)bsrc.red;
  1615. ew = w+dx;
  1616. for(; w < ew; w++,r++)
  1617. if(*m++)
  1618. *w = *r;
  1619. return bdst; /* not used */
  1620. }
  1621. static Buffer
  1622. genconv(Param *p, uint8_t *buf, int y)
  1623. {
  1624. Buffer b;
  1625. int nb;
  1626. uint8_t *r, *w, *ew;
  1627. /* read from source into RGB format in convbuf */
  1628. b = p->convreadcall(p, p->convbuf, y);
  1629. /* write RGB format into dst format in buf */
  1630. p->convwritecall(p->convdpar, buf, b);
  1631. if(p->convdx){
  1632. nb = p->convdpar->img->depth/8;
  1633. r = buf;
  1634. w = buf+nb*p->dx;
  1635. ew = buf+nb*p->convdx;
  1636. while(w<ew)
  1637. *w++ = *r++;
  1638. }
  1639. b.red = buf;
  1640. b.blu = b.grn = b.grey = b.alpha = nil;
  1641. b.rgba = (uint32_t*)buf;
  1642. b.delta = 0;
  1643. return b;
  1644. }
  1645. static Readfn*
  1646. convfn(Memimage *dst, Param *dpar, Memimage *src, Param *spar, int *ndrawbuf)
  1647. {
  1648. if(dst->chan == src->chan && !(src->flags&Frepl)){
  1649. //if(drawdebug) iprint("readptr...");
  1650. return readptr;
  1651. }
  1652. if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){
  1653. /* cheat because we know the replicated value is exactly the color map entry. */
  1654. //if(drawdebug) iprint("Readnbit...");
  1655. return readnbit;
  1656. }
  1657. spar->convreadcall = readfn(src);
  1658. spar->convwritecall = writefn(dst);
  1659. spar->convdpar = dpar;
  1660. /* allocate a conversion buffer */
  1661. spar->convbufoff = *ndrawbuf;
  1662. *ndrawbuf += spar->dx*4;
  1663. if(spar->dx > Dx(spar->img->r)){
  1664. spar->convdx = spar->dx;
  1665. spar->dx = Dx(spar->img->r);
  1666. }
  1667. //if(drawdebug) iprint("genconv...");
  1668. return genconv;
  1669. }
  1670. static uint32_t
  1671. pixelbits(Memimage *i, Point pt)
  1672. {
  1673. uint8_t *p;
  1674. uint32_t val;
  1675. int off, bpp, npack;
  1676. val = 0;
  1677. p = byteaddr(i, pt);
  1678. switch(bpp=i->depth){
  1679. case 1:
  1680. case 2:
  1681. case 4:
  1682. npack = 8/bpp;
  1683. off = pt.x%npack;
  1684. val = p[0] >> bpp*(npack-1-off);
  1685. val &= (1<<bpp)-1;
  1686. break;
  1687. case 8:
  1688. val = p[0];
  1689. break;
  1690. case 16:
  1691. val = p[0]|(p[1]<<8);
  1692. break;
  1693. case 24:
  1694. val = p[0]|(p[1]<<8)|(p[2]<<16);
  1695. break;
  1696. case 32:
  1697. val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
  1698. break;
  1699. }
  1700. while(bpp<32){
  1701. val |= val<<bpp;
  1702. bpp *= 2;
  1703. }
  1704. return val;
  1705. }
  1706. static Calcfn*
  1707. boolcopyfn(Memimage *img, Memimage *mask)
  1708. {
  1709. if(mask->flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && pixelbits(mask, mask->r.min)==~0)
  1710. return boolmemmove;
  1711. switch(img->depth){
  1712. case 8:
  1713. return boolcopy8;
  1714. case 16:
  1715. return boolcopy16;
  1716. case 24:
  1717. return boolcopy24;
  1718. case 32:
  1719. return boolcopy32;
  1720. default:
  1721. assert(0 /* boolcopyfn */);
  1722. }
  1723. return nil;
  1724. }
  1725. /*
  1726. * Optimized draw for filling and scrolling; uses memset and memmove.
  1727. */
  1728. static void
  1729. memsetb(void *vp, uint8_t val, int n)
  1730. {
  1731. uint8_t *p, *ep;
  1732. p = vp;
  1733. ep = p+n;
  1734. while(p<ep)
  1735. *p++ = val;
  1736. }
  1737. static void
  1738. memsets(void *vp, uint16_t val, int n)
  1739. {
  1740. uint16_t *p, *ep;
  1741. p = vp;
  1742. ep = p+n;
  1743. while(p<ep)
  1744. *p++ = val;
  1745. }
  1746. static void
  1747. memsetl(void *vp, uint32_t val, int n)
  1748. {
  1749. uint32_t *p, *ep;
  1750. p = vp;
  1751. ep = p+n;
  1752. while(p<ep)
  1753. *p++ = val;
  1754. }
  1755. static void
  1756. memset24(void *vp, unsigned long val, int n)
  1757. {
  1758. unsigned char *p, *ep;
  1759. unsigned char a,b,c;
  1760. p = vp;
  1761. ep = p+3*n;
  1762. a = val;
  1763. b = val>>8;
  1764. c = val>>16;
  1765. while(p<ep){
  1766. *p++ = a;
  1767. *p++ = b;
  1768. *p++ = c;
  1769. }
  1770. }
  1771. static uint32_t
  1772. imgtorgba(Memimage *img, uint32_t val)
  1773. {
  1774. unsigned char r, g, b, a;
  1775. int nb, ov, v;
  1776. unsigned long chan;
  1777. unsigned char *p;
  1778. a = 0xFF;
  1779. r = g = b = 0xAA; /* garbage */
  1780. for(chan=img->chan; chan; chan>>=8){
  1781. nb = NBITS(chan);
  1782. ov = v = val&((1<<nb)-1);
  1783. val >>= nb;
  1784. while(nb < 8){
  1785. v |= v<<nb;
  1786. nb *= 2;
  1787. }
  1788. v >>= (nb-8);
  1789. switch(TYPE(chan)){
  1790. case CRed:
  1791. r = v;
  1792. break;
  1793. case CGreen:
  1794. g = v;
  1795. break;
  1796. case CBlue:
  1797. b = v;
  1798. break;
  1799. case CAlpha:
  1800. a = v;
  1801. break;
  1802. case CGrey:
  1803. r = g = b = v;
  1804. break;
  1805. case CMap:
  1806. p = img->cmap->cmap2rgb+3*ov;
  1807. r = *p++;
  1808. g = *p++;
  1809. b = *p;
  1810. break;
  1811. }
  1812. }
  1813. return (r<<24)|(g<<16)|(b<<8)|a;
  1814. }
  1815. static uint32_t
  1816. rgbatoimg(Memimage *img, uint32_t rgba)
  1817. {
  1818. unsigned long chan;
  1819. int d, nb;
  1820. unsigned long v;
  1821. unsigned char *p, r, g, b, a, m;
  1822. v = 0;
  1823. r = rgba>>24;
  1824. g = rgba>>16;
  1825. b = rgba>>8;
  1826. a = rgba;
  1827. d = 0;
  1828. for(chan=img->chan; chan; chan>>=8){
  1829. nb = NBITS(chan);
  1830. switch(TYPE(chan)){
  1831. case CRed:
  1832. v |= (r>>(8-nb))<<d;
  1833. break;
  1834. case CGreen:
  1835. v |= (g>>(8-nb))<<d;
  1836. break;
  1837. case CBlue:
  1838. v |= (b>>(8-nb))<<d;
  1839. break;
  1840. case CAlpha:
  1841. v |= (a>>(8-nb))<<d;
  1842. break;
  1843. case CMap:
  1844. p = img->cmap->rgb2cmap;
  1845. m = p[(r>>4)*256+(g>>4)*16+(b>>4)];
  1846. v |= (m>>(8-nb))<<d;
  1847. break;
  1848. case CGrey:
  1849. m = RGB2K(r,g,b);
  1850. v |= (m>>(8-nb))<<d;
  1851. break;
  1852. }
  1853. d += nb;
  1854. }
  1855. // print("rgba2img %.8lux = %.*lux\n", rgba, 2*d/8, v);
  1856. return v;
  1857. }
  1858. #define DBG if(0)
  1859. static int
  1860. memoptdraw(Memdrawparam *par)
  1861. {
  1862. int m, y, dy, dx, op;
  1863. uint32_t v;
  1864. Memimage *src;
  1865. Memimage *dst;
  1866. dx = Dx(par->r);
  1867. dy = Dy(par->r);
  1868. src = par->src;
  1869. dst = par->dst;
  1870. op = par->op;
  1871. DBG print("state %lx mval %lx dd %d\n", par->state, par->mval, dst->depth);
  1872. /*
  1873. * If we have an opaque mask and source is one opaque pixel we can convert to the
  1874. * destination format and just replicate with memset.
  1875. */
  1876. m = Simplesrc|Simplemask|Fullmask;
  1877. if((par->state&m)==m && (par->srgba&0xFF) == 0xFF && (op ==S || op == SoverD)){
  1878. unsigned char *dp, p[4];
  1879. int d, dwid, ppb, np, nb;
  1880. unsigned char lm, rm;
  1881. DBG print("memopt, dst %p, dst->data->bdata %p\n", dst, dst->data->bdata);
  1882. dwid = dst->width*sizeof(uint32_t);
  1883. dp = byteaddr(dst, par->r.min);
  1884. v = par->sdval;
  1885. DBG print("sdval %lu, depth %d\n", v, dst->depth);
  1886. switch(dst->depth){
  1887. case 1:
  1888. case 2:
  1889. case 4:
  1890. for(d=dst->depth; d<8; d*=2)
  1891. v |= (v<<d);
  1892. ppb = 8/dst->depth; /* pixels per byte */
  1893. m = ppb-1;
  1894. /* left edge */
  1895. np = par->r.min.x&m; /* no. pixels unused on left side of word */
  1896. dx -= (ppb-np);
  1897. nb = 8 - np * dst->depth; /* no. bits used on right side of word */
  1898. lm = (1<<nb)-1;
  1899. DBG print("np %d x %d nb %d lm %x ppb %d m %x\n", np, par->r.min.x, nb, lm, ppb, m);
  1900. /* right edge */
  1901. np = par->r.max.x&m; /* no. pixels used on left side of word */
  1902. dx -= np;
  1903. nb = 8 - np * dst->depth; /* no. bits unused on right side of word */
  1904. rm = ~((1<<nb)-1);
  1905. DBG print("np %d x %d nb %d rm %x ppb %d m %x\n", np, par->r.max.x, nb, rm, ppb, m);
  1906. DBG print("dx %d Dx %d\n", dx, Dx(par->r));
  1907. /* lm, rm are masks that are 1 where we should touch the bits */
  1908. if(dx < 0){ /* just one byte */
  1909. lm &= rm;
  1910. for(y=0; y<dy; y++, dp+=dwid)
  1911. *dp ^= (v ^ *dp) & lm;
  1912. }else if(dx == 0){ /* no full bytes */
  1913. if(lm)
  1914. dwid--;
  1915. for(y=0; y<dy; y++, dp+=dwid){
  1916. if(lm){
  1917. DBG print("dp %p v %lx lm %x (v ^ *dp) & lm %lx\n", dp, v, lm, (v^*dp)&lm);
  1918. *dp ^= (v ^ *dp) & lm;
  1919. dp++;
  1920. }
  1921. *dp ^= (v ^ *dp) & rm;
  1922. }
  1923. }else{ /* full bytes in middle */
  1924. dx /= ppb;
  1925. if(lm)
  1926. dwid--;
  1927. dwid -= dx;
  1928. for(y=0; y<dy; y++, dp+=dwid){
  1929. if(lm){
  1930. *dp ^= (v ^ *dp) & lm;
  1931. dp++;
  1932. }
  1933. memset(dp, v, dx);
  1934. dp += dx;
  1935. *dp ^= (v ^ *dp) & rm;
  1936. }
  1937. }
  1938. return 1;
  1939. case 8:
  1940. for(y=0; y<dy; y++, dp+=dwid)
  1941. memset(dp, v, dx);
  1942. return 1;
  1943. case 16:
  1944. p[0] = v; /* make little endian */
  1945. p[1] = v>>8;
  1946. v = *(uint16_t*)p;
  1947. DBG print("dp=%p; dx=%d; for(y=0; y<%d; y++, dp+=%d)\nmemsets(dp, v, dx);\n",
  1948. dp, dx, dy, dwid);
  1949. for(y=0; y<dy; y++, dp+=dwid)
  1950. memsets(dp, v, dx);
  1951. return 1;
  1952. case 24:
  1953. for(y=0; y<dy; y++, dp+=dwid)
  1954. memset24(dp, v, dx);
  1955. return 1;
  1956. case 32:
  1957. p[0] = v; /* make little endian */
  1958. p[1] = v>>8;
  1959. p[2] = v>>16;
  1960. p[3] = v>>24;
  1961. v = *(uint32_t*)p;
  1962. for(y=0; y<dy; y++, dp+=dwid)
  1963. memsetl(dp, v, dx);
  1964. return 1;
  1965. default:
  1966. assert(0 /* bad dest depth in memoptdraw */);
  1967. }
  1968. }
  1969. /*
  1970. * If no source alpha, an opaque mask, we can just copy the
  1971. * source onto the destination. If the channels are the same and
  1972. * the source is not replicated, memmove suffices.
  1973. */
  1974. m = Simplemask|Fullmask;
  1975. if((par->state&(m|Replsrc))==m && src->depth >= 8
  1976. && src->chan == dst->chan && !(src->flags&Falpha) && (op == S || op == SoverD)){
  1977. unsigned char *sp, *dp;
  1978. int32_t swid, dwid, nb;
  1979. int dir;
  1980. if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min))
  1981. dir = -1;
  1982. else
  1983. dir = 1;
  1984. swid = src->width*sizeof(uint32_t);
  1985. dwid = dst->width*sizeof(uint32_t);
  1986. sp = byteaddr(src, par->sr.min);
  1987. dp = byteaddr(dst, par->r.min);
  1988. if(dir == -1){
  1989. sp += (dy-1)*swid;
  1990. dp += (dy-1)*dwid;
  1991. swid = -swid;
  1992. dwid = -dwid;
  1993. }
  1994. nb = (dx*src->depth)/8;
  1995. for(y=0; y<dy; y++, sp+=swid, dp+=dwid)
  1996. memmove(dp, sp, nb);
  1997. return 1;
  1998. }
  1999. /*
  2000. * If we have a 1-bit mask, 1-bit source, and 1-bit destination, and
  2001. * they're all bit aligned, we can just use bit operators. This happens
  2002. * when we're manipulating boolean masks, e.g. in the arc code.
  2003. */
  2004. if((par->state&(Simplemask|Simplesrc|Replmask|Replsrc))==0
  2005. && dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1
  2006. && (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){
  2007. unsigned char *sp, *dp, *mp;
  2008. unsigned char lm, rm;
  2009. int32_t swid, dwid, mwid;
  2010. int i, x, dir;
  2011. sp = byteaddr(src, par->sr.min);
  2012. dp = byteaddr(dst, par->r.min);
  2013. mp = byteaddr(par->mask, par->mr.min);
  2014. swid = src->width*sizeof(uint32_t);
  2015. dwid = dst->width*sizeof(uint32_t);
  2016. mwid = par->mask->width*sizeof(uint32_t);
  2017. if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){
  2018. dir = -1;
  2019. }else
  2020. dir = 1;
  2021. lm = 0xFF>>(par->r.min.x&7);
  2022. rm = 0xFF<<(8-(par->r.max.x&7));
  2023. dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7);
  2024. if(dx < 0){ /* one byte wide */
  2025. lm &= rm;
  2026. if(dir == -1){
  2027. dp += dwid*(dy-1);
  2028. sp += swid*(dy-1);
  2029. mp += mwid*(dy-1);
  2030. dwid = -dwid;
  2031. swid = -swid;
  2032. mwid = -mwid;
  2033. }
  2034. for(y=0; y<dy; y++){
  2035. *dp ^= (*dp ^ *sp) & *mp & lm;
  2036. dp += dwid;
  2037. sp += swid;
  2038. mp += mwid;
  2039. }
  2040. return 1;
  2041. }
  2042. dx /= 8;
  2043. if(dir == 1){
  2044. i = (lm!=0)+dx+(rm!=0);
  2045. mwid -= i;
  2046. swid -= i;
  2047. dwid -= i;
  2048. for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
  2049. if(lm){
  2050. *dp ^= (*dp ^ *sp++) & *mp++ & lm;
  2051. dp++;
  2052. }
  2053. for(x=0; x<dx; x++){
  2054. *dp ^= (*dp ^ *sp++) & *mp++;
  2055. dp++;
  2056. }
  2057. if(rm){
  2058. *dp ^= (*dp ^ *sp++) & *mp++ & rm;
  2059. dp++;
  2060. }
  2061. }
  2062. return 1;
  2063. }else{
  2064. /* dir == -1 */
  2065. i = (lm!=0)+dx+(rm!=0);
  2066. dp += dwid*(dy-1)+i-1;
  2067. sp += swid*(dy-1)+i-1;
  2068. mp += mwid*(dy-1)+i-1;
  2069. dwid = -dwid+i;
  2070. swid = -swid+i;
  2071. mwid = -mwid+i;
  2072. for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
  2073. if(rm){
  2074. *dp ^= (*dp ^ *sp--) & *mp-- & rm;
  2075. dp--;
  2076. }
  2077. for(x=0; x<dx; x++){
  2078. *dp ^= (*dp ^ *sp--) & *mp--;
  2079. dp--;
  2080. }
  2081. if(lm){
  2082. *dp ^= (*dp ^ *sp--) & *mp-- & lm;
  2083. dp--;
  2084. }
  2085. }
  2086. }
  2087. return 1;
  2088. }
  2089. return 0;
  2090. }
  2091. #undef DBG
  2092. /*
  2093. * Boolean character drawing.
  2094. * Solid opaque color through a 1-bit greyscale mask.
  2095. */
  2096. #define DBG if(0)
  2097. static int
  2098. chardraw(Memdrawparam *par)
  2099. {
  2100. uint32_t bits;
  2101. int i, ddepth, dy, dx, x, bx, ex, y, npack, bsh, depth, op;
  2102. uint32_t v, maskwid, dstwid;
  2103. unsigned char *wp, *rp, *q, *wc;
  2104. uint16_t *ws;
  2105. uint32_t *wl;
  2106. unsigned char sp[4];
  2107. Rectangle r, mr;
  2108. Memimage *mask, *src, *dst;
  2109. DBG print("chardraw? mf %lx md %d sf %lx dxs %d dys %d dd %d ddat %p sdat %p\n",
  2110. par->mask->flags, par->mask->depth, par->src->flags,
  2111. Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data);
  2112. mask = par->mask;
  2113. src = par->src;
  2114. dst = par->dst;
  2115. r = par->r;
  2116. mr = par->mr;
  2117. op = par->op;
  2118. if((par->state&(Replsrc|Simplesrc|Replmask)) != (Replsrc|Simplesrc)
  2119. || mask->depth != 1 || src->flags&Falpha || dst->depth<8 || dst->data==src->data
  2120. || op != SoverD)
  2121. return 0;
  2122. //if(drawdebug) iprint("chardraw...");
  2123. depth = mask->depth;
  2124. maskwid = mask->width*sizeof(uint32_t);
  2125. rp = byteaddr(mask, mr.min);
  2126. npack = 8/depth;
  2127. bsh = (mr.min.x % npack) * depth;
  2128. wp = byteaddr(dst, r.min);
  2129. dstwid = dst->width*sizeof(uint32_t);
  2130. DBG print("bsh %d\n", bsh);
  2131. dy = Dy(r);
  2132. dx = Dx(r);
  2133. ddepth = dst->depth;
  2134. /*
  2135. * for loop counts from bsh to bsh+dx
  2136. *
  2137. * we want the bottom bits to be the amount
  2138. * to shift the pixels down, so for n≡0 (mod 8) we want
  2139. * bottom bits 7. for n≡1, 6, etc.
  2140. * the bits come from -n-1.
  2141. */
  2142. bx = -bsh-1;
  2143. ex = -bsh-1-dx;
  2144. SET(bits);
  2145. v = par->sdval;
  2146. /* make little endian */
  2147. sp[0] = v;
  2148. sp[1] = v>>8;
  2149. sp[2] = v>>16;
  2150. sp[3] = v>>24;
  2151. //print("sp %x %x %x %x\n", sp[0], sp[1], sp[2], sp[3]);
  2152. for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){
  2153. q = rp;
  2154. if(bsh)
  2155. bits = *q++;
  2156. switch(ddepth){
  2157. case 8:
  2158. //if(drawdebug) iprint("8loop...");
  2159. wc = wp;
  2160. for(x=bx; x>ex; x--, wc++){
  2161. i = x&7;
  2162. if(i == 8-1)
  2163. bits = *q++;
  2164. DBG print("bits %lx sh %d...", bits, i);
  2165. if((bits>>i)&1)
  2166. *wc = v;
  2167. }
  2168. break;
  2169. case 16:
  2170. ws = (uint16_t*)wp;
  2171. v = *(uint16_t*)sp;
  2172. for(x=bx; x>ex; x--, ws++){
  2173. i = x&7;
  2174. if(i == 8-1)
  2175. bits = *q++;
  2176. DBG print("bits %lx sh %d...", bits, i);
  2177. if((bits>>i)&1)
  2178. *ws = v;
  2179. }
  2180. break;
  2181. case 24:
  2182. wc = wp;
  2183. for(x=bx; x>ex; x--, wc+=3){
  2184. i = x&7;
  2185. if(i == 8-1)
  2186. bits = *q++;
  2187. DBG print("bits %lx sh %d...", bits, i);
  2188. if((bits>>i)&1){
  2189. wc[0] = sp[0];
  2190. wc[1] = sp[1];
  2191. wc[2] = sp[2];
  2192. }
  2193. }
  2194. break;
  2195. case 32:
  2196. wl = (uint32_t*)wp;
  2197. v = *(uint32_t*)sp;
  2198. for(x=bx; x>ex; x--, wl++){
  2199. i = x&7;
  2200. if(i == 8-1)
  2201. bits = *q++;
  2202. DBG iprint("bits %lx sh %d...", bits, i);
  2203. if((bits>>i)&1)
  2204. *wl = v;
  2205. }
  2206. break;
  2207. }
  2208. }
  2209. DBG print("\n");
  2210. return 1;
  2211. }
  2212. #undef DBG
  2213. /*
  2214. * Fill entire byte with replicated (if necessary) copy of source pixel,
  2215. * assuming destination ldepth is >= source ldepth.
  2216. *
  2217. * This code is just plain wrong for >8bpp.
  2218. *
  2219. ulong
  2220. membyteval(Memimage *src)
  2221. {
  2222. int i, val, bpp;
  2223. uchar uc;
  2224. unloadmemimage(src, src->r, &uc, 1);
  2225. bpp = src->depth;
  2226. uc <<= (src->r.min.x&(7/src->depth))*src->depth;
  2227. uc &= ~(0xFF>>bpp);
  2228. /* pixel value is now in high part of byte. repeat throughout byte
  2229. val = uc;
  2230. for(i=bpp; i<8; i<<=1)
  2231. val |= val>>i;
  2232. return val;
  2233. }
  2234. *
  2235. */
  2236. void
  2237. memfillcolor(Memimage *i, uint32_t val)
  2238. {
  2239. uint32_t bits;
  2240. int d, y;
  2241. if(val == DNofill)
  2242. return;
  2243. bits = rgbatoimg(i, val);
  2244. switch(i->depth){
  2245. case 24: /* 24-bit images suck */
  2246. for(y=i->r.min.y; y<i->r.max.y; y++)
  2247. memset24(byteaddr(i, Pt(i->r.min.x, y)), bits, Dx(i->r));
  2248. break;
  2249. default: /* 1, 2, 4, 8, 16, 32 */
  2250. for(d=i->depth; d<32; d*=2)
  2251. bits = (bits << d) | bits;
  2252. memsetl(wordaddr(i, i->r.min), bits, i->width*Dy(i->r));
  2253. break;
  2254. }
  2255. }