1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <event.h>
5 #include <geometry.h>
6
7 typedef struct Vert{
8 Point3 world;
9 Point3 screen;
10 int color;
11 }Vert;
12
13 int nocubes;
14 int ncolor;
15 Quaternion q = {1.,0.,0.,0.};
16 Image *image;
17 Image *bg;
18 Image *color[256];
19 Rectangle viewrect;
20 int prevsel;
21
22 Point3
p3(double x,double y,double z,double w)23 p3(double x, double y, double z, double w)
24 {
25 Point3 p;
26
27 p.x = x;
28 p.y = y;
29 p.z = z;
30 p.w = w;
31 return p;
32 }
33
34 int
cmp(Vert * a,Vert * b)35 cmp(Vert *a, Vert *b)
36 {
37 if(a->screen.z>b->screen.z)
38 return -1;
39 if(a->screen.z<b->screen.z)
40 return 1;
41 return 0;
42 }
43
44 /* crummy hack */
45 void
readcolmap(Display * d,RGB * cmap)46 readcolmap(Display *d, RGB *cmap)
47 {
48 int i, rgb, r, g, b;
49
50 for(i=0; i<256; i++){
51 rgb = cmap2rgb(i);
52 r = rgb>>16;
53 g = (rgb>>8)&0xFF;
54 b = rgb & 0xFF;
55 cmap[i].red = r|(r<<8)|(r<<16)|(r<<24);
56 cmap[i].green = g|(g<<8)|(g<<16)|(g<<24);
57 cmap[i].blue = b|(b<<8)|(b<<16)|(b<<24);
58 }
59 }
60
61 void
colorspace(RGB * cmap,Vert * v)62 colorspace(RGB *cmap, Vert *v)
63 {
64 Space *view;
65 int i;
66
67 for(i=0;i!=ncolor;i++){
68 v[i].world.x=(cmap[i].red>>24)/255.-.5;
69 v[i].world.y=(cmap[i].green>>24)/255.-.5;
70 v[i].world.z=(cmap[i].blue>>24)/255.-.5;
71 v[i].world.w=1.;
72 v[i].color=i;
73 }
74 view = pushmat(0);
75 viewport(view, viewrect, 1.);
76 persp(view, 30., 3., 7.);
77 look(view, p3(0., 0., -5., 1.), p3(0., 0., 0., 1.),
78 p3(0., 1., 0., 1.));
79 qrot(view, q);
80 for(i=0;i!=ncolor;i++)
81 v[i].screen = xformpointd(v[i].world, 0, view);
82 popmat(view);
83 }
84
85 void
line3(Vert a,Vert b)86 line3(Vert a, Vert b)
87 {
88 line(image, Pt(a.screen.x, a.screen.y), Pt(b.screen.x, b.screen.y), 0, 0, 0, display->white, ZP);
89 }
90
91
92 void
redraw(void)93 redraw(void)
94 {
95 int i, m;
96 RGB cmap[256];
97 Vert v[256];
98
99 readcolmap(display, cmap);
100 colorspace(cmap, v);
101 draw(image, image->r, bg, nil, Pt(0, 0));
102 m = Dx(viewrect)/2;
103 if(m > Dy(viewrect)/2)
104 m = Dy(viewrect)/2;
105 ellipse(image, addpt(viewrect.min, divpt(Pt(Dx(viewrect), Dy(viewrect)), 2)),
106 m, m, 1, display->white, ZP);
107
108 line3(v[0], v[0x36]);
109 line3(v[0x36], v[0x32]);
110 line3(v[0x32], v[0x3F]);
111 line3(v[0x3F], v[0]);
112
113 line3(v[0xF0], v[0xF3]);
114 line3(v[0xF3], v[0xFF]);
115 line3(v[0xFF], v[0xFC]);
116 line3(v[0xFC], v[0xF0]);
117
118 line3(v[0], v[0xF0]);
119 line3(v[0x36], v[0xF3]);
120 line3(v[0x32], v[0xFF]);
121 line3(v[0x3F], v[0xFC]);
122
123 qsort(v, ncolor, sizeof(Vert), (int(*)(const void*, const void*))cmp);
124 if(!nocubes)
125 for(i=0; i!=ncolor; i++)
126 draw(image, rectaddpt(Rect(-3, -3, 4, 4), Pt(v[i].screen.x, v[i].screen.y)),
127 color[v[i].color], nil, Pt(0, 0));
128 draw(screen, image->r, image, nil, image->r.min);
129 flushimage(display, 1);
130 }
131
132 void
eresized(int new)133 eresized(int new)
134 {
135 int dx, dy;
136
137 if(new && getwindow(display, Refnone) < 0){
138 fprint(2, "colors: can't reattach to window: %r\n");
139 exits("reshaped");
140 }
141 draw(screen, screen->r, display->black, nil, ZP);
142 replclipr(screen, 0, insetrect(screen->r, 3));
143 viewrect = screen->clipr;
144 viewrect.min.y += stringsize(font, "0i").y + 5;
145 if(image)
146 freeimage(image);
147 image = allocimage(display, viewrect, screen->chan, 0, DNofill);
148 dx = viewrect.max.x-viewrect.min.x;
149 dy = viewrect.max.y-viewrect.min.y;
150 if(dx>dy){
151 viewrect.min.x=(viewrect.min.x+viewrect.max.x-dy)/2;
152 viewrect.max.x=viewrect.min.x+dy;
153 }
154 else{
155 viewrect.min.y=(viewrect.min.y+viewrect.max.y-dx)/2;
156 viewrect.max.y=viewrect.min.y+dx;
157 }
158 if(image==nil){
159 fprint(2, "can't allocate image\n");
160 exits("bad allocimage");
161 }
162 prevsel = -1;
163 redraw();
164 }
165
main(int argc,char ** argv)166 void main(int argc, char **argv){
167 Vert v[256];
168 RGB cmap[256];
169 char buf[100];
170 Point p;
171 Mouse m;
172 int i;
173 ulong bgcol;
174
175 bgcol = DNofill;
176 ARGBEGIN{
177 case 'n':
178 nocubes = 1;
179 break;
180 case 'b':
181 bgcol = DBlack;
182 break;
183 case 'w':
184 bgcol = DWhite;
185 break;
186 }ARGEND
187
188 if(initdraw(0,0,0) < 0)
189 sysfatal("initdraw: %r");
190 ncolor=256;
191 for(i=0;i!=ncolor;i++)
192 color[i] = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, cmap2rgba(i));
193 if(bgcol==DNofill){
194 bg = allocimage(display, Rect(0, 0, 2, 2), screen->chan, 1, DWhite);
195 draw(bg, Rect(0, 0, 1, 1), color[0], nil, Pt(0, 0));
196 draw(bg, Rect(1, 1, 2, 2), color[0], nil, Pt(0, 0));
197 }else
198 bg = allocimage(display, Rect(0,0,1,1), screen->chan, 1, bgcol);
199
200 einit(Emouse);
201 eresized(0);
202
203 for(;;){
204 m = emouse();
205 if(m.buttons&1)
206 qball(viewrect, &m, &q, redraw, 0);
207 else if(m.buttons & 2){
208 readcolmap(display, cmap);
209 colorspace(cmap, v);
210 qsort(v, ncolor, sizeof(Vert), (int(*)(const void*, const void*))cmp);
211 while(m.buttons){
212 for(i=ncolor-1; i!=0; i--){
213 if(ptinrect(m.xy, rectaddpt(Rect(-3, -3, 4, 4), Pt(v[i].screen.x, v[i].screen.y)))){
214 i = v[i].color;
215 if(i == prevsel)
216 break;
217 sprint(buf, "index %3d r %3ld g %3ld b %3ld",
218 i,
219 cmap[i].red>>24,
220 cmap[i].green>>24,
221 cmap[i].blue>>24);
222 p = addpt(screen->r.min, Pt(2,2));
223 draw(screen, Rpt(p, addpt(p, stringsize(font, buf))), display->black, nil, p);
224 string(screen, p, display->white, ZP, font, buf);
225 prevsel = i;
226 break;
227 }
228 }
229 m = emouse();
230 }
231 }else if(m.buttons&4){
232 do
233 m = emouse();
234 while(m.buttons);
235 exits(0);
236 }
237 }
238 }
239