Advertisement
Guest User

color.c

a guest
Aug 17th, 2020
2,038
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.11 KB | None | 0 0
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <event.h>
  6.  
  7. /* Conversion */
  8.  
  9. typedef struct RgbColor {
  10.     unsigned char r;
  11.     unsigned char g;
  12.     unsigned char b;
  13. }
  14. RgbColor;
  15.  
  16. typedef struct HsvColor {
  17.     unsigned char h;
  18.     unsigned char s;
  19.     unsigned char v;
  20. }
  21. HsvColor;
  22.  
  23. static HsvColor selection;
  24.  
  25. int
  26. clamp(double val, double min, double max)
  27. {
  28.     return val > max ? max : val < min ? min : val;
  29. }
  30.  
  31. unsigned int
  32. rgb2hex(RgbColor clr)
  33. {
  34.     return ((clr.r & 0xFF) << 24) + ((clr.g & 0xFF) << 16) + ((clr.b & 0xFF) << 8) + (255 & 0xFF);
  35. }
  36.  
  37. RgbColor
  38. hsv2rgb(HsvColor hsv)
  39. {
  40.     RgbColor rgb;
  41.     unsigned char region, remainder, p, q, t;
  42.  
  43.     if (hsv.s == 0) {
  44.         rgb.r = hsv.v;
  45.         rgb.g = hsv.v;
  46.         rgb.b = hsv.v;
  47.         return rgb;
  48.     }
  49.     region = hsv.h / 43;
  50.     remainder = (hsv.h - (region * 43)) * 6;
  51.     p = (hsv.v * (255 - hsv.s)) >> 8;
  52.     q = (hsv.v * (255 - ((hsv.s * remainder) >> 8))) >> 8;
  53.     t = (hsv.v * (255 - ((hsv.s * (255 - remainder)) >> 8))) >> 8;
  54.     switch (region) {
  55.     case 0:
  56.         rgb.r = hsv.v;
  57.         rgb.g = t;
  58.         rgb.b = p;
  59.         break;
  60.     case 1:
  61.         rgb.r = q;
  62.         rgb.g = hsv.v;
  63.         rgb.b = p;
  64.         break;
  65.     case 2:
  66.         rgb.r = p;
  67.         rgb.g = hsv.v;
  68.         rgb.b = t;
  69.         break;
  70.     case 3:
  71.         rgb.r = p;
  72.         rgb.g = q;
  73.         rgb.b = hsv.v;
  74.         break;
  75.     case 4:
  76.         rgb.r = t;
  77.         rgb.g = p;
  78.         rgb.b = hsv.v;
  79.         break;
  80.     default:
  81.         rgb.r = hsv.v;
  82.         rgb.g = p;
  83.         rgb.b = q;
  84.         break;
  85.     }
  86.     return rgb;
  87. }
  88.  
  89. HsvColor
  90. rgb2hsv(RgbColor rgb)
  91. {
  92.     HsvColor hsv;
  93.     unsigned char rgbMin, rgbMax;
  94.  
  95.     rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
  96.     rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
  97.     hsv.v = rgbMax;
  98.     if (hsv.v == 0) {
  99.         hsv.h = 0;
  100.         hsv.s = 0;
  101.         return hsv;
  102.     }
  103.     hsv.s = 255 * (double)(rgbMax - rgbMin) / hsv.v;
  104.     if (hsv.s == 0) {
  105.         hsv.h = 0;
  106.         return hsv;
  107.     }
  108.     if (rgbMax == rgb.r)
  109.         hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
  110.     else if (rgbMax == rgb.g)
  111.         hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
  112.     else
  113.         hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);
  114.     return hsv;
  115. }
  116.  
  117. unsigned int
  118. hsv2hex(HsvColor hsvclr)
  119. {
  120.     RgbColor clr = hsv2rgb(hsvclr);
  121.  
  122.     return ((clr.r & 0xFF) << 24) + ((clr.g & 0xFF) << 16) + ((clr.b & 0xFF) << 8) + (255 & 0xFF);
  123. }
  124.  
  125. /* Defaults */
  126.  
  127. void
  128. lineb(Image * dst, Point p0, Point p1, Image * src, Point sp)
  129. {
  130.     int dx = abs(p1.x - p0.x), sx = p0.x < p1.x ? 1 : -1;
  131.     int dy = -abs(p1.y - p0.y), sy = p0.y < p1.y ? 1 : -1;
  132.     int err = dx + dy, e2;
  133.  
  134.     for (;;) {
  135.         draw(dst, Rect(p0.x, p0.y, p0.x + 1, p0.y + 1), src, nil, sp);
  136.         if (p0.x == p1.x && p0.y == p1.y) break;
  137.         e2 = 2 * err;
  138.         if (e2 >= dy) {
  139.             err += dy;
  140.             p0.x += sx;
  141.         }
  142.         if (e2 <= dx) {
  143.             err += dx;
  144.             p0.y += sy;
  145.         }
  146.     }
  147. }
  148.  
  149. unsigned int
  150. gradeint(int a, int b, double ratio)
  151. {
  152.     return (a * ratio) + (b * (1 - ratio));
  153. }
  154.  
  155. unsigned int
  156. gradecolor(HsvColor a, HsvColor b, double ratio)
  157. {
  158.     HsvColor clr = (HsvColor) {
  159.         gradeint(a.h, b.h, ratio),
  160.             gradeint(a.s, b.s, ratio),
  161.             gradeint(a.v, b.v, ratio)
  162.     };
  163.  
  164.     return hsv2hex(clr);
  165. }
  166.  
  167. Point
  168. gradept(Point a, Point b, double ratio)
  169. {
  170.     return Pt(a.x * ratio + b.x * (1 - ratio), a.y * ratio + b.y * (1 - ratio));
  171. }
  172.  
  173. void
  174. gradeline(Image * dst, Point p0, Point p1, HsvColor clr0, HsvColor clr1, int segs, Point sp)
  175. {
  176.     for (int i = 0; i < segs; i++) {
  177.         double ratio = (double) i / segs;
  178.         Image * clrimg = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1,
  179.             gradecolor(clr0, clr1, ratio));
  180.         lineb(screen,
  181.             gradept(p0, p1, ratio),
  182.             gradept(p0, p1, (double)(i + 1) / segs), clrimg, ZP);
  183.         freeimage(clrimg);
  184.     }
  185. }
  186.  
  187. double
  188. ptangle(Point a, Point b)
  189. {
  190.     return atan2(b.y - a.y, b.x - a.x);
  191. }
  192.  
  193. double
  194. ptdistance(Point a, Point b)
  195. {
  196.     int x = a.x - b.x;
  197.     int y = a.y - b.y;
  198.  
  199.     return sqrt(x * x + y * y);
  200. }
  201.  
  202. Point
  203. circlept(Point c, int r, int degrees)
  204. {
  205.     double rad = (double) degrees * PI / 180.0;
  206.  
  207.     c.x += cos(rad) * r;
  208.     c.y -= sin(rad) * r;
  209.     return c;
  210. }
  211.  
  212. Point
  213. getcenter(Rectangle r)
  214. {
  215.     return divpt(addpt(r.min, r.max), 2);
  216. }
  217.  
  218. int
  219. within(Point p, Rectangle r)
  220. {
  221.     return p.x > r.min.x && p.x < r.max.x && p.y > r.min.y && p.y < r.max.y;
  222. }
  223.  
  224. void
  225. redraw(void)
  226. {
  227.     Rectangle r = screen -> r;
  228.     Point center = getcenter(r);
  229.     int pad = 20;
  230.     int width = (r.max.x - r.min.x) - 2 * pad;
  231.     int height = (r.max.y - r.min.y) - 2 * pad;
  232.  
  233.     int radius = ((Dx(r) < Dy(r) ? Dx(r) : Dy(r)) / 2) - pad;
  234.  
  235.     /* draw ring */
  236.     fillellipse(screen, center, radius + pad, radius + pad, display -> black, ZP);
  237.     for (int i = 0; i < 180; i++) {
  238.         Point p0 = circlept(center, radius, i * 2);
  239.         Point p1 = circlept(center, radius, (i + 1) * 2);
  240.         unsigned int angle = ptangle(center, p0) / PI / 2 * 255;
  241.         int hexclr = hsv2hex((HsvColor) {
  242.             angle,
  243.             255,
  244.             255
  245.         });
  246.         Image * imgclr = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, hexclr);
  247.         lineb(screen, p0, p1, imgclr, ZP);
  248.         freeimage(imgclr);
  249.     }
  250.  
  251.     /* draw selection */
  252.     RgbColor selrgb = hsv2rgb(selection);
  253.     HsvColor selhue = (HsvColor) {
  254.         selection.h, 255, 255
  255.     };
  256.     unsigned int selhex = rgb2hex(selrgb);
  257.  
  258.     Image * selclr = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, selhex);
  259.     Image * selhueclr = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, hsv2hex(selhue));
  260.  
  261.     /* draw hue */
  262.     double angle = (selection.h / 255.0) * -360.0;
  263.     Point huepos = circlept(center, radius, angle);
  264.     fillellipse(screen, huepos, 2, 2, selhueclr, ZP);
  265.  
  266.     /* draw sat */
  267.     double distance = (selection.s / 255.0) * radius;
  268.     Point satpos = circlept(center, distance, angle);
  269.     ellipse(screen, center, distance, distance, 0, selclr, ZP);
  270.     fillellipse(screen, satpos, 2, 2, selclr, ZP);
  271.     gradeline(screen, huepos, satpos, selhue, selection, 8, ZP);
  272.  
  273.     /* collapse if window is horizontal */
  274.     if (height > width + 2 * pad) {
  275.         Rectangle sliderect = Rect(r.min.x, r.max.y - pad * 2, r.max.x, r.max.y - pad);
  276.         draw(screen, sliderect, display -> black, nil, ZP);
  277.         gradeline(screen,
  278.             addpt(sliderect.min, Pt(pad, pad / 2)),
  279.             addpt(sliderect.max, Pt(-pad, -pad / 2)),
  280.             (HsvColor) {
  281.                 selection.h, selection.s, 0
  282.             },
  283.             (HsvColor) {
  284.                 selection.h, selection.s, 255
  285.             }, 16, ZP);
  286.         Point valpos = addpt(sliderect.min, Pt((selection.v / 255.0) * width + pad, pad / 2));
  287.         fillellipse(screen, valpos, 2, 2, selclr, ZP);
  288.     }
  289.  
  290.     /* header */
  291.     char hexstr[16];
  292.     char rgbstr[12];
  293.     sprint(hexstr, "#%02ux%02ux%02ux",
  294.         (selhex >> 24) & 0xFF,
  295.         (selhex >> 16) & 0xFF,
  296.         (selhex >> 8) & 0xFF);
  297.     sprint(rgbstr, "%ud,%ud,%ud",
  298.         selrgb.r,
  299.         selrgb.g,
  300.         selrgb.b);
  301.     Point hexstrsize = stringsize(display -> defaultfont, hexstr);
  302.     Point rgbstrsize = stringsize(display -> defaultfont, rgbstr);
  303.  
  304.     /* collapse if window is horizontal */
  305.     if (height > width + 2 * pad) {
  306.         Rectangle clearrect = (Rectangle) {
  307.             addpt(screen -> r.min, Pt(pad, pad)),
  308.                 addpt(screen -> r.min, Pt(radius * 2 + pad, pad + rgbstrsize.y))
  309.         };
  310.         draw(screen, clearrect, display -> black, nil, ZP);
  311.         string(screen,
  312.             addpt(screen -> r.min, Pt(pad, pad)),
  313.             display -> white, ZP, display -> defaultfont, hexstr);
  314.         if (hexstrsize.x + rgbstrsize.x < width)
  315.             string(screen,
  316.                 Pt(screen -> r.max.x - pad - rgbstrsize.x, screen -> r.min.y + pad),
  317.                 selclr, ZP, display -> defaultfont, rgbstr);
  318.     }
  319.  
  320.     /* cleanup */
  321.     flushimage(display, 1);
  322.     freeimage(selclr);
  323.     freeimage(selhueclr);
  324. }
  325.  
  326. void
  327. touch(Point m)
  328. {
  329.     Rectangle r = screen -> r;
  330.     Point center = getcenter(r);
  331.     int pad = 20;
  332.     int radius = ((Dx(r) < Dy(r) ? Dx(r) : Dy(r)) / 2) - pad;
  333.  
  334.     if (ptdistance(center, m) > radius) {
  335.         int width = (r.max.x - r.min.x) - pad * 2;
  336.         Rectangle sliderect = Rect(r.min.x, r.max.y - pad * 2, r.max.x, r.max.y);
  337.         if (within(m, sliderect)) {
  338.             int touchx = m.x - screen -> r.min.x - pad;
  339.             double ratio = touchx / (double) width;
  340.             selection.v = ratio > 1 ? 255.0 : ratio < 0 ? 0 : ratio * 255.0;
  341.         } else {
  342.             double angle = ptangle(center, m);
  343.             selection.h = (int)(angle / PI / 2 * 255) % 255;
  344.         }
  345.     } else {
  346.         double distance = ptdistance(center, m);
  347.         selection.s = (distance / radius) * 255.0;
  348.     }
  349.     redraw();
  350. }
  351.  
  352. void
  353. eresized(int new)
  354. {
  355.     if (new && getwindow(display, Refnone) < 0)
  356.         fprint(2, "can't reattach to window");
  357.     draw(screen, screen -> r, display -> black, nil, ZP);
  358.     redraw();
  359. }
  360.  
  361. void
  362. main(int argc, char ** argv)
  363. {
  364.     Event e;
  365.     Mouse m;
  366.     Menu menu;
  367.     char * mstr[] = {
  368.         "exit",
  369.         0
  370.     };
  371.     int key;
  372.  
  373.     if (initdraw(0, 0, "Color") < 0)
  374.         sysfatal("initdraw failed");
  375.  
  376.     eresized(0);
  377.     einit(Emouse);
  378.     menu.item = mstr;
  379.     menu.lasthit = 0;
  380.  
  381.     selection.h = 200;
  382.     selection.s = 210;
  383.     selection.v = 220;
  384.  
  385.     redraw();
  386.  
  387.     /* Break on mouse3 */
  388.     for (;;) {
  389.         key = event( & e);
  390.         if (key == Emouse) {
  391.             m = e.mouse;
  392.             if (m.buttons & 4) {
  393.                 if (emenuhit(3, & m, & menu) == 0)
  394.                     exits(0);
  395.             } else if (m.buttons & 1) {
  396.                 touch(m.xy);
  397.             }
  398.         }
  399.     }
  400. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement