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