mug.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <event.h>
  5. #include <cursor.h>
  6. #define initstate muginitstate
  7. typedef struct State State;
  8. struct State {
  9. double black;
  10. double white;
  11. double stretch;
  12. double gamma;
  13. int depth;
  14. int gtab[1001];
  15. Rectangle selr;
  16. };
  17. typedef struct Face Face;
  18. struct Face {
  19. Rectangle r;
  20. State state;
  21. Image *small;
  22. };
  23. double GAMMA = 1.0; /* theory tells me this should be 2.2, but 1.0 sure looks better */
  24. enum {
  25. Left=0,
  26. Right,
  27. Top,
  28. Bottom,
  29. RTopLeft=0,
  30. RTop,
  31. RTopRight,
  32. RLeft,
  33. RMiddle,
  34. RRight,
  35. RBotLeft,
  36. RBot,
  37. RBotRight,
  38. };
  39. void*
  40. emalloc(ulong sz)
  41. {
  42. void *v;
  43. v = malloc(sz);
  44. if(v == nil)
  45. sysfatal("malloc %lud fails\n", sz);
  46. memset(v, 0, sz);
  47. return v;
  48. }
  49. Face *face[8];
  50. int nface;
  51. uchar grey2cmap[256];
  52. Image *bkgd;
  53. Image *orig;
  54. Image *ramp, *small, *osmall, *tmp8, *red, *green, *blue;
  55. State state, ostate;
  56. uchar val2cmap[256];
  57. uchar clamp[3*256];
  58. Rectangle rbig, rramp, rface[nelem(face)], rsmall;
  59. double *rdata;
  60. int sdy, sdx;
  61. void
  62. geometry(Rectangle r)
  63. {
  64. int i;
  65. Rectangle fr[9];
  66. rramp.min = addpt(r.min, Pt(4,4));
  67. rramp.max = addpt(rramp.min, Pt(256,256));
  68. rbig.min = Pt(rramp.max.x+6, rramp.min.y);
  69. rbig.max = addpt(rbig.min, Pt(Dx(orig->r), Dy(orig->r)));
  70. for(i=0; i<9; i++)
  71. fr[i] = rectaddpt(Rect(0,0,48,48), Pt(rramp.min.x+48+56*(i%3), rramp.max.y+6+56*(i/3)));
  72. rsmall = fr[4];
  73. for(i=0; i<4; i++)
  74. rface[i] = fr[i];
  75. for(i=4; i<8; i++)
  76. rface[i] = fr[i+1];
  77. }
  78. double
  79. y2gamma(int y)
  80. {
  81. double g;
  82. g = (double)y / 128.0;
  83. return 0.5+g*g; /* gamma from 0.5 to 4.5, with 1.0 near the middle */
  84. }
  85. int
  86. gamma2y(double g)
  87. {
  88. g -= 0.5;
  89. return (int)(128.0*sqrt(g)+0.5);
  90. }
  91. void
  92. drawface(int i)
  93. {
  94. if(i==-1){
  95. border(screen, rsmall, -3, blue, ZP);
  96. draw(screen, rsmall, small, nil, ZP);
  97. return;
  98. }
  99. border(screen, rface[i], -1, display->black, ZP);
  100. if(face[i])
  101. draw(screen, rface[i], face[i]->small, nil, ZP);
  102. else
  103. draw(screen, rface[i], display->white, nil, ZP);
  104. }
  105. void
  106. drawrampbar(Image *color, State *s)
  107. {
  108. Rectangle liner, r;
  109. static Rectangle br;
  110. if(Dx(br))
  111. draw(screen, br, ramp, nil, subpt(br.min, rramp.min));
  112. r = rramp;
  113. r.max.x = r.min.x + (int)(s->white*255.0);
  114. r.min.x += (int)(s->black*255.0);
  115. r.min.y += gamma2y(s->gamma);
  116. r.max.y = r.min.y+1;
  117. rectclip(&r, rramp);
  118. draw(screen, r, color, nil, ZP);
  119. br = r;
  120. r.min.y -= 2;
  121. r.max.y += 2;
  122. liner = r;
  123. r.min.x += Dx(liner)/3;
  124. r.max.x -= Dx(liner)/3;
  125. rectclip(&r, rramp);
  126. draw(screen, r, color, nil, ZP);
  127. combinerect(&br, r);
  128. r = liner;
  129. r.max.x = r.min.x+3;
  130. rectclip(&r, rramp);
  131. draw(screen, r, color, nil, ZP);
  132. combinerect(&br, r);
  133. r = liner;
  134. r.min.x = r.max.x-3;
  135. rectclip(&r, rramp);
  136. draw(screen, r, color, nil, ZP);
  137. combinerect(&br, r);
  138. }
  139. void
  140. drawscreen(int clear)
  141. {
  142. int i;
  143. if(clear){
  144. geometry(screen->r);
  145. draw(screen, screen->r, bkgd, nil, ZP);
  146. }
  147. border(screen, rbig, -1, display->black, ZP);
  148. draw(screen, rbig, orig, nil, orig->r.min);
  149. border(screen, rramp, -1, display->black, ZP);
  150. draw(screen, rramp, ramp, nil, ramp->r.min);
  151. drawrampbar(red, &state);
  152. border(screen, rectaddpt(state.selr, subpt(rbig.min, orig->r.min)), -2, red, ZP);
  153. if(clear){
  154. drawface(-1);
  155. for(i=0; i<nelem(face); i++)
  156. drawface(i);
  157. }
  158. }
  159. void
  160. moveframe(Rectangle old, Rectangle new)
  161. {
  162. border(screen, rectaddpt(old, subpt(rbig.min, orig->r.min)), -2, orig, old.min);
  163. border(screen, rectaddpt(new, subpt(rbig.min, orig->r.min)), -2, red, ZP);
  164. }
  165. /*
  166. * Initialize gamma ramp; should dither for
  167. * benefit of non-true-color displays.
  168. */
  169. void
  170. initramp(void)
  171. {
  172. int k, x, y;
  173. uchar dat[256*256];
  174. double g;
  175. k = 0;
  176. for(y=0; y<256; y++) {
  177. g = y2gamma(y);
  178. for(x=0; x<256; x++)
  179. dat[k++] = 255.0 * pow(x/255.0, g);
  180. }
  181. assert(k == sizeof dat);
  182. ramp = allocimage(display, Rect(0,0,256,256), GREY8, 0, DNofill);
  183. if(ramp == nil)
  184. sysfatal("allocimage: %r");
  185. if(loadimage(ramp, ramp->r, dat, sizeof dat) != sizeof dat)
  186. sysfatal("loadimage: %r");
  187. }
  188. void
  189. initclamp(void)
  190. {
  191. int i;
  192. for(i=0; i<256; i++) {
  193. clamp[i] = 0;
  194. clamp[256+i] = i;
  195. clamp[512+i] = 255;
  196. }
  197. }
  198. void
  199. changestretch(double stretch)
  200. {
  201. state.stretch = stretch;
  202. }
  203. /*
  204. * There is greyscale data for the rectangle datar in data;
  205. * extract square r and write it into the 48x48 pixel image small.
  206. */
  207. void
  208. process(double *data, Rectangle datar, Rectangle r, Image *small)
  209. {
  210. double black, center, delta, *k, shrink, sum, *tmp[48], *tt, w, white, x;
  211. int datadx, dp, dx, dy, error, i, ii, j, jj;
  212. int ksize, ksizeby2, sdata[48*48], sd, sh, sm, sv, u, uu, uuu, v, vv;
  213. uchar bdata[48*48];
  214. datadx = Dx(datar);
  215. dx = Dx(r);
  216. dy = Dy(r);
  217. shrink = dx/48.0;
  218. ksize = 1+2*(int)(shrink/2.0);
  219. if(ksize <= 2)
  220. return;
  221. k = emalloc(ksize*sizeof(k[0]));
  222. /* center of box */
  223. for(i=1; i<ksize-1; i++)
  224. k[i] = 1.0;
  225. /* edges */
  226. x = shrink - floor(shrink);
  227. k[0] = x;
  228. k[ksize-1] = x;
  229. sum = 0.0;
  230. for(i=0; i<ksize; i++)
  231. sum += k[i];
  232. for(i=0; i<ksize; i++)
  233. k[i] /= sum;
  234. ksizeby2 = ksize/2;
  235. for(i=0; i<48; i++)
  236. tmp[i] = emalloc(datadx*sizeof(tmp[i][0]));
  237. /* squeeze vertically */
  238. for(i=0; i<48; i++) {
  239. ii = r.min.y+i*dy/48;
  240. tt = tmp[i];
  241. uu = ii - ksizeby2;
  242. for(j=r.min.x-ksize; j<r.max.x+ksize; j++) {
  243. if(j<datar.min.x || j>=datar.max.x)
  244. continue;
  245. w = 0.0;
  246. uuu = uu*datadx+j;
  247. if(uu>=datar.min.y && uu+ksize<datar.max.y)
  248. for(u=0; u<ksize; u++){
  249. w += k[u]*data[uuu];
  250. uuu += datadx;
  251. }
  252. else
  253. for(u=0; u<ksize; u++){
  254. if(uu+u>=datar.min.y && uu+u<datar.max.y)
  255. w += k[u]*data[uuu];
  256. uuu+=datadx;
  257. }
  258. tt[j-datar.min.x] = w;
  259. }
  260. }
  261. /* stretch value scale */
  262. center = (state.black+state.white)/2;
  263. delta = state.stretch*(state.white-state.black)/2;
  264. black = center - delta;
  265. white = center + delta;
  266. /* squeeze horizontally */
  267. for(i=0; i<48; i++) {
  268. tt = tmp[i];
  269. for(j=0; j<48; j++) {
  270. jj = r.min.x+j*dx/48;
  271. w = 0.0;
  272. for(v=0; v<ksize; v++) {
  273. vv = jj - ksizeby2 + v;
  274. if(vv<datar.min.x || vv>=datar.max.x) {
  275. w += k[v]; /* assume white surround */
  276. continue;
  277. }
  278. w += k[v]*tt[vv-datar.min.x];
  279. }
  280. if(w < black || black==white)
  281. w = 0.0;
  282. else if(w > white)
  283. w = 1.0;
  284. else
  285. w = (w-black)/(white-black);
  286. sdata[i*48+j] = state.gtab[(int)(1000.0*w)];
  287. }
  288. }
  289. /* dither to lower depth before copying into GREY8 version */
  290. if(small->chan != GREY8) {
  291. u = 0;
  292. dp = small->depth;
  293. for(i=0; i<48; i++) {
  294. sm = 0xFF ^ (0xFF>>dp);
  295. sh = 0;
  296. v = 0;
  297. for(j=0; j<48; j++) {
  298. ii = 48*i+j;
  299. sd = clamp[sdata[ii]+256];
  300. sv = sd&sm;
  301. v |= sv>>sh;
  302. sh += dp;
  303. if(sh == 8) {
  304. bdata[u++] = v;
  305. v = 0;
  306. sh = 0;
  307. }
  308. /* propagate error, with decay (sum errors < 1) */
  309. error = sd - sv;
  310. if(ii+49 < 48*48) { /* one test is enough, really */
  311. sdata[ii+1] = sdata[ii+1]+((3*error)>>4);
  312. sdata[ii+48] = sdata[ii+48]+((3*error)>>4);
  313. sdata[ii+49] = sdata[ii+49]+((3*error)>>3);
  314. }
  315. /* produce correct color map value by copying bits */
  316. switch(dp){
  317. case 1:
  318. sv |= sv>>1;
  319. case 2:
  320. sv |= sv>>2;
  321. case 4:
  322. sv |= sv>>4;
  323. }
  324. sdata[ii] = sv;
  325. }
  326. }
  327. for(i=0; i<nelem(bdata); i++)
  328. bdata[i] = sdata[i];
  329. if(loadimage(tmp8, tmp8->r, bdata, sizeof bdata) != sizeof bdata)
  330. sysfatal("loadimage: %r");
  331. draw(small, small->r, tmp8, nil, tmp8->r.min);
  332. } else {
  333. for(i=0; i<nelem(bdata); i++)
  334. bdata[i] = sdata[i];
  335. if(loadimage(small, small->r, bdata, sizeof bdata) != sizeof bdata)
  336. sysfatal("loadimage: %r");
  337. }
  338. free(k);
  339. for(i=0; i<48; i++)
  340. free(tmp[i]);
  341. }
  342. void
  343. initval2cmap(void)
  344. {
  345. int i;
  346. for(i=0; i<256; i++)
  347. val2cmap[i] = rgb2cmap(i, i, i);
  348. }
  349. void
  350. setgtab(State *s)
  351. {
  352. int i;
  353. for(i=0; i<=1000; i++)
  354. s->gtab[i] = val2cmap[(int)(255.0*pow((i/1000.0), 1.0/s->gamma))];
  355. }
  356. int
  357. section(int x)
  358. {
  359. int ib, iw;
  360. ib = state.black * 255.0;
  361. iw = state.white * 255.0;
  362. if(x<ib-5 || iw+5<x)
  363. return -1;
  364. iw -= ib;
  365. x -= ib;
  366. if(x < iw/3)
  367. return 0;
  368. if(x < 2*iw/3)
  369. return 1;
  370. return 2;
  371. }
  372. Image*
  373. copyimage(Image *i)
  374. {
  375. Image *n;
  376. if(i == nil)
  377. return nil;
  378. n = allocimage(display, i->r, i->chan, 0, DNofill);
  379. if(n == nil)
  380. sysfatal("allocimage: %r");
  381. draw(n, n->r, i, nil, i->r.min);
  382. return n;
  383. }
  384. Image*
  385. grey8image(Image *i)
  386. {
  387. Image *n;
  388. if(i->chan == GREY8)
  389. return i;
  390. n = allocimage(display, i->r, GREY8, 0, DNofill);
  391. if(n == nil)
  392. sysfatal("allocimage: %r");
  393. draw(n, n->r, i, nil, i->r.min);
  394. freeimage(i);
  395. return n;
  396. }
  397. void
  398. mark(void)
  399. {
  400. if(osmall != small){
  401. freeimage(osmall);
  402. osmall = small;
  403. }
  404. ostate = state;
  405. }
  406. void
  407. undo(void)
  408. {
  409. if(small != osmall){
  410. freeimage(small);
  411. small = osmall;
  412. }
  413. state = ostate;
  414. process(rdata, orig->r, state.selr, small);
  415. drawface(-1);
  416. drawscreen(0);
  417. }
  418. void
  419. saveface(Face *f, int slot)
  420. {
  421. if(slot == -1){
  422. mark();
  423. state = f->state;
  424. small = copyimage(f->small);
  425. drawface(-1);
  426. drawscreen(0);
  427. return;
  428. }
  429. if(face[slot]==nil)
  430. face[slot] = emalloc(sizeof(*face[slot]));
  431. else{
  432. freeimage(face[slot]->small);
  433. face[slot]->small = nil;
  434. }
  435. if(f == nil){
  436. face[slot]->small = copyimage(small);
  437. face[slot]->state = state;
  438. }else{
  439. face[slot]->small = copyimage(f->small);
  440. face[slot]->state = f->state;
  441. }
  442. drawface(slot);
  443. }
  444. int
  445. writeface(char *outfile, Image *image)
  446. {
  447. int i, fd, rv, y;
  448. uchar data[48*48/2];
  449. if(outfile == nil)
  450. fd = 1;
  451. else{
  452. if((fd = create(outfile, OWRITE, 0666)) < 0)
  453. return -1;
  454. }
  455. switch(image->chan) {
  456. default:
  457. rv = -1;
  458. break;
  459. case GREY1:
  460. if(unloadimage(image, image->r, data, 48*48/8) != 48*48/8)
  461. sysfatal("unloadimage: %r");
  462. for(y=0; y<48; y++) {
  463. for(i=0; i<3; i++)
  464. fprint(fd, "0x%.2x%.2x,", data[y*6+i*2+0], data[y*6+i*2+1]);
  465. fprint(fd, "\n");
  466. }
  467. rv = 0;
  468. break;
  469. case GREY2:
  470. if(unloadimage(image, image->r, data, 48*48/4) != 48*48/4)
  471. sysfatal("unloadimage: %r");
  472. for(y=0; y<48; y++) {
  473. for(i=0; i<3; i++)
  474. fprint(fd, "0x%.2x%.2x,%.2x%.2x,",
  475. data[y*12+i*4+0], data[y*12+i*4+1],
  476. data[y*12+i*4+2], data[y*12+i*4+3]);
  477. fprint(fd, "\n");
  478. }
  479. rv = 0;
  480. break;
  481. case GREY4:
  482. case GREY8:
  483. rv = writeimage(fd, image, 0); /* dolock? */
  484. break;
  485. }
  486. if(outfile)
  487. close(fd);
  488. return rv;
  489. }
  490. void
  491. room(Rectangle out, Rectangle in, int *a)
  492. {
  493. a[Left] = out.min.x - in.min.x;
  494. a[Right] = out.max.x - in.max.x;
  495. a[Top] = out.min.y - in.min.y;
  496. a[Bottom] = out.max.y - in.max.y;
  497. }
  498. int
  499. min(int a, int b)
  500. {
  501. if(a < b)
  502. return a;
  503. return b;
  504. }
  505. int
  506. max(int a, int b)
  507. {
  508. if(a > b)
  509. return a;
  510. return b;
  511. }
  512. int
  513. move(Rectangle r, Rectangle picr, Point d, int k, Rectangle *rp)
  514. {
  515. int a[4], i;
  516. Rectangle oldr;
  517. static int toggle;
  518. oldr = r;
  519. room(picr, r, a);
  520. switch(k){
  521. case RTopLeft:
  522. i = (d.x+d.y)/2;
  523. if(i>=Dx(r) || i>=Dy(r))
  524. break;
  525. i = max(i, a[Left]);
  526. i = max(i, a[Top]);
  527. r.min.x += i;
  528. r.min.y += i;
  529. break;
  530. case RTop:
  531. i = d.y;
  532. if(i < 0){
  533. /*
  534. * should really check i/2, but this is safe and feedback
  535. * makes the control feel right
  536. */
  537. i = -min(-i, a[Right]);
  538. i = max(i, a[Left]);
  539. }
  540. i = max(i, a[Top]);
  541. if(i >= Dy(r))
  542. break;
  543. r.min.y += i;
  544. /* divide the half bit equally */
  545. toggle = 1-toggle;
  546. if(toggle){
  547. r.min.x += i/2;
  548. r.max.x = r.min.x+Dy(r);
  549. }else{
  550. r.max.x -= i/2;
  551. r.min.x = r.max.x-Dy(r);
  552. }
  553. break;
  554. case RTopRight:
  555. i = (-d.x+d.y)/2;
  556. if(i>=Dx(r) || i>=Dy(r))
  557. break;
  558. i = -min(-i, a[Right]);
  559. i = max(i, a[Top]);
  560. r.max.x -= i;
  561. r.min.y += i;
  562. break;
  563. case RLeft:
  564. i = d.x;
  565. if(i < 0){
  566. i = -min(-i, a[Bottom]);
  567. i = max(i, a[Top]);
  568. }
  569. i = max(i, a[Left]);
  570. if(i >= Dx(r))
  571. break;
  572. r.min.x += i;
  573. /* divide the half bit equally */
  574. toggle = 1-toggle;
  575. if(toggle){
  576. r.min.y += i/2;
  577. r.max.y = r.min.y+Dx(r);
  578. }else{
  579. r.max.y -= i/2;
  580. r.min.y = r.max.y-Dx(r);
  581. }
  582. break;
  583. case RMiddle:
  584. if(d.x >= 0)
  585. d.x = min(d.x, a[Right]);
  586. else
  587. d.x = max(d.x, a[Left]);
  588. if(d.y >= 0)
  589. d.y = min(d.y, a[Bottom]);
  590. else
  591. d.y = max(d.y, a[Top]);
  592. r = rectaddpt(r, d);
  593. break;
  594. case RRight:
  595. i = d.x;
  596. if(i > 0){
  597. i = min(i, a[Bottom]);
  598. i = -max(-i, a[Top]);
  599. }
  600. i = min(i, a[Right]);
  601. if(-i >= Dx(r))
  602. break;
  603. r.max.x += i;
  604. /* divide the half bit equally */
  605. toggle = 1-toggle;
  606. if(toggle){
  607. r.min.y -= i/2;
  608. r.max.y = r.min.y+Dx(r);
  609. }else{
  610. r.max.y += i/2;
  611. r.min.y = r.max.y-Dx(r);
  612. }
  613. break;
  614. case RBotLeft:
  615. i = (d.x+-d.y)/2;
  616. if(i>=Dx(r) || i>=Dy(r))
  617. break;
  618. i = max(i, a[Left]);
  619. i = -min(-i, a[Bottom]);
  620. r.min.x += i;
  621. r.max.y -= i;
  622. break;
  623. case RBot:
  624. i = d.y;
  625. if(i > 0){
  626. i = min(i, a[Right]);
  627. i = -max(-i, a[Left]);
  628. }
  629. i = min(i, a[Bottom]);
  630. if(i >= Dy(r))
  631. break;
  632. r.max.y += i;
  633. /* divide the half bit equally */
  634. toggle = 1-toggle;
  635. if(toggle){
  636. r.min.x -= i/2;
  637. r.max.x = r.min.x+Dy(r);
  638. }else{
  639. r.max.x += i/2;
  640. r.min.x = r.max.x-Dy(r);
  641. }
  642. break;
  643. case RBotRight:
  644. i = (-d.x+-d.y)/2;
  645. if(i>=Dx(r) || i>=Dy(r))
  646. break;
  647. i = -min(-i, a[Right]);
  648. i = -min(-i, a[Bottom]);
  649. r.max.x -= i;
  650. r.max.y -= i;
  651. break;
  652. }
  653. if(Dx(r)<3 || Dy(r)<3){
  654. *rp = oldr;
  655. return 0;
  656. }
  657. *rp = r;
  658. return !eqrect(r, oldr);
  659. }
  660. void
  661. rlist(Rectangle r, Rectangle *ra)
  662. {
  663. Rectangle tr;
  664. tr = r;
  665. tr.max.y = r.min.y+Dy(r)/4;
  666. ra[0] = tr;
  667. ra[0].max.x = tr.min.x+Dx(tr)/4;
  668. ra[1] = tr;
  669. ra[1].min.x = ra[0].max.x;
  670. ra[1].max.x = tr.max.x-Dx(tr)/4;
  671. ra[2] = tr;
  672. ra[2].min.x = ra[1].max.x;
  673. tr.min.y = tr.max.y;
  674. tr.max.y = r.max.y-Dy(r)/4;
  675. ra[3] = tr;
  676. ra[3].max.x = tr.min.x+Dx(tr)/4;
  677. ra[4] = tr;
  678. ra[4].min.x = ra[3].max.x;
  679. ra[4].max.x = tr.max.x-Dx(tr)/4;
  680. ra[5] = tr;
  681. ra[5].min.x = ra[4].max.x;
  682. tr.min.y = tr.max.y;
  683. tr.max.y = r.max.y;
  684. ra[6] = tr;
  685. ra[6].max.x = tr.min.x+Dx(tr)/4;
  686. ra[7] = tr;
  687. ra[7].min.x = ra[6].max.x;
  688. ra[7].max.x = tr.max.x-Dx(tr)/4;
  689. ra[8] = tr;
  690. ra[8].min.x = ra[7].max.x;
  691. }
  692. int
  693. abs(int a)
  694. {
  695. if(a < 0)
  696. return -a;
  697. return a;
  698. }
  699. void
  700. usage(void)
  701. {
  702. fprint(2, "usage: mug [file.bit]\n");
  703. exits("usage");
  704. }
  705. void
  706. eresized(int new)
  707. {
  708. if(new && getwindow(display, Refmesg) < 0)
  709. fprint(2,"can't reattach to window");
  710. drawscreen(1);
  711. }
  712. /*
  713. interface notes
  714. cursor changes while in rbig to indicate region.
  715. only button 1 works for resizing region
  716. only button 1 works for moving thingy in ramp
  717. button-3 menu: Reset, Depth, Undo, Save, Write
  718. */
  719. Cursor tl = {
  720. {-4, -4},
  721. {0xfe, 0x00, 0x82, 0x00, 0x8c, 0x00, 0x87, 0xff,
  722. 0xa0, 0x01, 0xb0, 0x01, 0xd0, 0x01, 0x11, 0xff,
  723. 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00,
  724. 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x1f, 0x00, },
  725. {0x00, 0x00, 0x7c, 0x00, 0x70, 0x00, 0x78, 0x00,
  726. 0x5f, 0xfe, 0x4f, 0xfe, 0x0f, 0xfe, 0x0e, 0x00,
  727. 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
  728. 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, }
  729. };
  730. Cursor t = {
  731. {-7, -8},
  732. {0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x06, 0xc0,
  733. 0x1c, 0x70, 0x10, 0x10, 0x0c, 0x60, 0xfc, 0x7f,
  734. 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff,
  735. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
  736. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
  737. 0x03, 0x80, 0x0f, 0xe0, 0x03, 0x80, 0x03, 0x80,
  738. 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x00, 0x00,
  739. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
  740. };
  741. Cursor tr = {
  742. {-11, -4},
  743. {0x00, 0x7f, 0x00, 0x41, 0x00, 0x31, 0xff, 0xe1,
  744. 0x80, 0x05, 0x80, 0x0d, 0x80, 0x0b, 0xff, 0x88,
  745. 0x00, 0x88, 0x0, 0x88, 0x00, 0x88, 0x00, 0x88,
  746. 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xf8, },
  747. {0x00, 0x00, 0x00, 0x3e, 0x00, 0x0e, 0x00, 0x1e,
  748. 0x7f, 0xfa, 0x7f, 0xf2, 0x7f, 0xf0, 0x00, 0x70,
  749. 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
  750. 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, }
  751. };
  752. Cursor r = {
  753. {-8, -7},
  754. {0x07, 0xc0, 0x04, 0x40, 0x04, 0x40, 0x04, 0x58,
  755. 0x04, 0x68, 0x04, 0x6c, 0x04, 0x06, 0x04, 0x02,
  756. 0x04, 0x06, 0x04, 0x6c, 0x04, 0x68, 0x04, 0x58,
  757. 0x04, 0x40, 0x04, 0x40, 0x04, 0x40, 0x07, 0xc0, },
  758. {0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
  759. 0x03, 0x90, 0x03, 0x90, 0x03, 0xf8, 0x03, 0xfc,
  760. 0x03, 0xf8, 0x03, 0x90, 0x03, 0x90, 0x03, 0x80,
  761. 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, }
  762. };
  763. Cursor br = {
  764. {-11, -11},
  765. {0x00, 0xf8, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88,
  766. 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88,
  767. 0xff, 0x88, 0x80, 0x0b, 0x80, 0x0d, 0x80, 0x05,
  768. 0xff, 0xe1, 0x00, 0x31, 0x00, 0x41, 0x00, 0x7f, },
  769. {0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
  770. 0x0, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
  771. 0x00, 0x70, 0x7f, 0xf0, 0x7f, 0xf2, 0x7f, 0xfa,
  772. 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x3e, 0x00, 0x00, }
  773. };
  774. Cursor b = {
  775. {-7, -7},
  776. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  777. 0xff, 0xff, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
  778. 0xfc, 0x7f, 0x0c, 0x60, 0x10, 0x10, 0x1c, 0x70,
  779. 0x06, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, },
  780. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  781. 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe,
  782. 0x03, 0x80, 0x03, 0x80, 0x0f, 0xe0, 0x03, 0x80,
  783. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
  784. };
  785. Cursor bl = {
  786. {-4, -11},
  787. {0x1f, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00,
  788. 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00,
  789. 0x11, 0xff, 0xd0, 0x01, 0xb0, 0x01, 0xa0, 0x01,
  790. 0x87, 0xff, 0x8c, 0x00, 0x82, 0x00, 0xfe, 0x00, },
  791. {0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
  792. 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
  793. 0x0e, 0x00, 0x0f, 0xfe, 0x4f, 0xfe, 0x5f, 0xfe,
  794. 0x78, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x00, 0x0, }
  795. };
  796. Cursor l = {
  797. {-7, -7},
  798. {0x03, 0xe0, 0x02, 0x20, 0x02, 0x20, 0x1a, 0x20,
  799. 0x16, 0x20, 0x36, 0x20, 0x60, 0x20, 0x40, 0x20,
  800. 0x60, 0x20, 0x36, 0x20, 0x16, 0x20, 0x1a, 0x20,
  801. 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x03, 0xe0, },
  802. {0x00, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
  803. 0x09, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x3f, 0xc0,
  804. 0x1f, 0xc0, 0x09, 0xc0, 0x09, 0xc0, 0x01, 0xc0,
  805. 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, }
  806. };
  807. Cursor boxcursor = {
  808. {-7, -7},
  809. {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  810. 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
  811. 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF,
  812. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
  813. {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE,
  814. 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
  815. 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
  816. 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00, }
  817. };
  818. Cursor clearcursor;
  819. Cursor *corners[10] = {
  820. &tl, &t, &tr,
  821. &l, &boxcursor, &r,
  822. &bl, &b, &br,
  823. nil, /* default arrow */
  824. };
  825. char *item[] = {
  826. "Reset",
  827. "Depth",
  828. "Undo",
  829. "Write",
  830. "Exit",
  831. nil
  832. };
  833. Menu menu = {
  834. item,
  835. nil,
  836. 2
  837. };
  838. /*BUG make less flashy */
  839. void
  840. moveface(Image *back, Point lastp, Image *face, Point p, Point d)
  841. {
  842. draw(screen, rectaddpt(back->r, subpt(lastp, d)), back, nil, back->r.min);
  843. draw(back, back->r, screen, nil, addpt(back->r.min, subpt(p, d)));
  844. border(screen, rectaddpt(face->r, subpt(p, d)),
  845. -1, display->black, ZP);
  846. draw(screen, rectaddpt(face->r, subpt(p, d)),
  847. face, nil, face->r.min);
  848. }
  849. int
  850. dragface(Mouse *m, Image *im, Point d, int x)
  851. {
  852. int i;
  853. Point lastp;
  854. static Image *back;
  855. if(back == nil){
  856. back = allocimage(display, Rect(-1,-1,49,49), display->image->chan, 0, DNofill);
  857. if(back == nil)
  858. sysfatal("dragface backing store: %r");
  859. }
  860. lastp = m->xy;
  861. draw(back, back->r, screen, nil, addpt(back->r.min, subpt(lastp, d)));
  862. esetcursor(&clearcursor);
  863. do{
  864. moveface(back, lastp, im, m->xy, d);
  865. lastp = m->xy;
  866. }while(*m=emouse(), m->buttons==1);
  867. draw(screen, rectaddpt(back->r, subpt(lastp, d)), back, nil, back->r.min);
  868. esetcursor(nil);
  869. if(m->buttons==0){
  870. for(i=0; i<nelem(face); i++)
  871. if(ptinrect(m->xy, rface[i]))
  872. return i;
  873. if(ptinrect(m->xy, rsmall))
  874. return -1;
  875. return x;
  876. }
  877. while(*m=emouse(), m->buttons)
  878. ;
  879. return x;
  880. }
  881. void
  882. initstate(void)
  883. {
  884. state.black = 0.0;
  885. state.white = 1.0;
  886. state.stretch = 1.0;
  887. state.depth = 4;
  888. state.gamma = 1.0;
  889. setgtab(&state);
  890. state.selr = insetrect(orig->r, 5);
  891. sdx = Dx(state.selr);
  892. sdy = Dy(state.selr);
  893. if(sdx > sdy)
  894. state.selr.max.x = state.selr.min.x+sdy;
  895. else
  896. state.selr.max.y = state.selr.min.y+sdx;
  897. }
  898. void
  899. main(int argc, char **argv)
  900. {
  901. int ccursor, i, fd, k, n, y;
  902. uchar *data;
  903. double gammatab[256];
  904. Event e;
  905. Mouse m;
  906. Point lastp, p;
  907. Rectangle nselr, rbig9[9];
  908. ARGBEGIN{
  909. default:
  910. usage();
  911. }ARGEND
  912. if(argc > 1)
  913. usage();
  914. if(argc == 1){
  915. if((fd = open(argv[0], OREAD)) < 0)
  916. sysfatal("open %s: %r", argv[0]);
  917. }else
  918. fd = 0;
  919. initdraw(0, 0, "mug");
  920. if((orig = readimage(display, fd, 0)) == nil)
  921. sysfatal("readimage: %r");
  922. orig = grey8image(orig);
  923. initramp();
  924. initclamp();
  925. initval2cmap();
  926. bkgd = allocimagemix(display, DPaleyellow, DWhite);
  927. small = allocimage(display, Rect(0,0,48,48), GREY4, 0, DWhite);
  928. tmp8 = allocimage(display, Rect(0,0,48,48), GREY8, 0, DWhite);
  929. red = allocimage(display, Rect(0,0,1,1), display->image->chan, 1, DRed);
  930. green = allocimage(display, Rect(0,0,1,1), display->image->chan, 1, DGreen);
  931. blue = allocimage(display, Rect(0,0,1,1), display->image->chan, 1, DBlue);
  932. if(bkgd==nil || small==nil || tmp8==nil || red==nil || green==nil || blue==nil)
  933. sysfatal("allocimage: %r");
  934. n = Dx(orig->r)*Dy(orig->r);
  935. data = emalloc(n*sizeof data[0]);
  936. rdata = emalloc(n*sizeof rdata[0]);
  937. if(unloadimage(orig, orig->r, data, n) != n)
  938. sysfatal("unloadimage: %r");
  939. for(i=0; i<256; i++)
  940. gammatab[i] = pow((255-i)/(double)255.0, GAMMA);
  941. for(i=0; i<n; i++)
  942. rdata[i] = gammatab[255-data[i]];
  943. initstate();
  944. process(rdata, orig->r, state.selr, small);
  945. drawscreen(1);
  946. flushimage(display, 1);
  947. einit(Emouse|Ekeyboard);
  948. ccursor = 9;
  949. for(;;){
  950. if((n=eread(Emouse|Ekeyboard, &e))==Ekeyboard)
  951. continue;
  952. if(n != Emouse)
  953. break;
  954. m = e.mouse;
  955. if(m.buttons&4){
  956. ccursor = 9;
  957. esetcursor(corners[ccursor]);
  958. switch(emenuhit(3, &m, &menu)){
  959. case -1:
  960. continue;
  961. case 0: /* Reset */
  962. mark();
  963. initstate();
  964. small = allocimage(display, Rect(0,0,48,48), CHAN1(CGrey, state.depth), 0, DWhite);
  965. if(small == nil)
  966. sysfatal("allocimage: %r");
  967. process(rdata, orig->r, state.selr, small);
  968. drawface(-1);
  969. drawscreen(0);
  970. break;
  971. case 1: /* Depth */
  972. mark();
  973. /* osmall = small, so no freeimage */
  974. state.depth /= 2;
  975. if(state.depth == 0)
  976. state.depth = 8;
  977. small = allocimage(display, Rect(0,0,48,48), CHAN1(CGrey, state.depth), 0, DWhite);
  978. if(small == nil)
  979. sysfatal("allocimage: %r");
  980. process(rdata, orig->r, state.selr, small);
  981. drawface(-1);
  982. break;
  983. case 2: /* Undo */
  984. undo();
  985. break;
  986. case 3: /* Write */
  987. writeface(nil, small);
  988. break;
  989. case 4: /* Exit */
  990. exits(nil);
  991. break;
  992. }
  993. }
  994. if(ptinrect(m.xy, rbig)){
  995. rlist(rectaddpt(state.selr, subpt(rbig.min, orig->r.min)), rbig9);
  996. for(i=0; i<9; i++)
  997. if(ptinrect(m.xy, rbig9[i]))
  998. break;
  999. if(i != ccursor){
  1000. ccursor = i;
  1001. esetcursor(corners[ccursor]);
  1002. }
  1003. if(i==9)
  1004. continue;
  1005. if(m.buttons & 1){
  1006. mark();
  1007. lastp = m.xy;
  1008. while(m=emouse(), m.buttons&1){
  1009. if(move(state.selr, orig->r, subpt(m.xy, lastp), i, &nselr)){
  1010. moveframe(state.selr, nselr);
  1011. state.selr = nselr;
  1012. lastp = m.xy;
  1013. process(rdata, orig->r, state.selr, small);
  1014. drawface(-1);
  1015. }
  1016. }
  1017. }
  1018. continue;
  1019. }
  1020. if(ccursor != 9){ /* default cursor */
  1021. ccursor = 9;
  1022. esetcursor(corners[ccursor]);
  1023. }
  1024. if(ptinrect(m.xy, rramp)){
  1025. if(m.buttons != 1)
  1026. continue;
  1027. mark();
  1028. y = gamma2y(state.gamma);
  1029. if(abs(y-(m.xy.y-rramp.min.y)) > 5)
  1030. continue;
  1031. k = section(m.xy.x-rramp.min.x);
  1032. drawrampbar(green, &state);
  1033. lastp = m.xy;
  1034. while(m=emouse(), m.buttons&1){
  1035. if(!ptinrect(m.xy, rramp))
  1036. continue;
  1037. switch(k){
  1038. case -1:
  1039. continue;
  1040. case 0:
  1041. if((m.xy.x-rramp.min.x)/255.0 < state.white){
  1042. state.black = (m.xy.x-rramp.min.x)/255.0;
  1043. break;
  1044. }
  1045. continue;
  1046. case 1:
  1047. state.gamma = y2gamma(m.xy.y-rramp.min.y);
  1048. setgtab(&state);
  1049. break;
  1050. case 2:
  1051. if((m.xy.x-rramp.min.x)/255.0 > state.black){
  1052. state.white = (m.xy.x-rramp.min.x)/255.0;
  1053. break;
  1054. }
  1055. continue;
  1056. case 10:
  1057. state.black += (m.xy.x-lastp.x)/255.0;
  1058. state.white += (m.xy.x-lastp.x)/255.0;
  1059. state.gamma = y2gamma(p.y);
  1060. break;
  1061. }
  1062. process(rdata, orig->r, state.selr, small);
  1063. drawface(-1);
  1064. drawrampbar(green, &state);
  1065. }
  1066. if(m.buttons == 0){
  1067. process(rdata, orig->r, state.selr, small);
  1068. drawface(-1);
  1069. drawrampbar(red, &state);
  1070. }else
  1071. undo();
  1072. continue;
  1073. }
  1074. if(ptinrect(m.xy, rsmall)){
  1075. if(m.buttons != 1)
  1076. continue;
  1077. n=dragface(&m, small, subpt(m.xy, rsmall.min), -1);
  1078. if(n == -1)
  1079. continue;
  1080. saveface(nil, n);
  1081. }
  1082. for(i=0; i<nelem(face); i++)
  1083. if(ptinrect(m.xy, rface[i]))
  1084. break;
  1085. if(i<nelem(face) && face[i] != nil){
  1086. if(m.buttons != 1)
  1087. continue;
  1088. n=dragface(&m, face[i]->small, subpt(m.xy, rface[i].min), i);
  1089. if(n == i)
  1090. continue;
  1091. saveface(face[i], n);
  1092. continue;
  1093. }
  1094. do
  1095. m = emouse();
  1096. while(m.buttons==1);
  1097. }
  1098. exits(nil);
  1099. }