| #include <u.h> |
| #include <libc.h> |
| #include <draw.h> |
| #include <event.h> |
| #include <geometry.h> |
| |
| typedef struct Vert{ |
| Point3 world; |
| Point3 screen; |
| int color; |
| }Vert; |
| |
| int nocubes; |
| int ncolor; |
| Quaternion q = {1.,0.,0.,0.}; |
| Image *image; |
| Image *bg; |
| Image *color[256]; |
| Rectangle viewrect; |
| int prevsel; |
| |
| Point3 |
| p3(double x, double y, double z, double w) |
| { |
| Point3 p; |
| |
| p.x = x; |
| p.y = y; |
| p.z = z; |
| p.w = w; |
| return p; |
| } |
| |
| int |
| cmp(Vert *a, Vert *b) |
| { |
| if(a->screen.z>b->screen.z) |
| return -1; |
| if(a->screen.z<b->screen.z) |
| return 1; |
| return 0; |
| } |
| |
| /* crummy hack */ |
| void |
| readcolmap(Display *d, RGB *cmap) |
| { |
| int i, rgb, r, g, b; |
| |
| for(i=0; i<256; i++){ |
| rgb = cmap2rgb(i); |
| r = rgb>>16; |
| g = (rgb>>8)&0xFF; |
| b = rgb & 0xFF; |
| cmap[i].red = r|(r<<8)|(r<<16)|(r<<24); |
| cmap[i].green = g|(g<<8)|(g<<16)|(g<<24); |
| cmap[i].blue = b|(b<<8)|(b<<16)|(b<<24); |
| } |
| } |
| |
| void |
| colorspace(RGB *cmap, Vert *v) |
| { |
| Space *view; |
| int i; |
| |
| for(i=0;i!=ncolor;i++){ |
| v[i].world.x=(cmap[i].red>>24)/255.-.5; |
| v[i].world.y=(cmap[i].green>>24)/255.-.5; |
| v[i].world.z=(cmap[i].blue>>24)/255.-.5; |
| v[i].world.w=1.; |
| v[i].color=i; |
| } |
| view = pushmat(0); |
| viewport(view, viewrect, 1.); |
| persp(view, 30., 3., 7.); |
| look(view, p3(0., 0., -5., 1.), p3(0., 0., 0., 1.), |
| p3(0., 1., 0., 1.)); |
| qrot(view, q); |
| for(i=0;i!=ncolor;i++) |
| v[i].screen = xformpointd(v[i].world, 0, view); |
| popmat(view); |
| } |
| |
| void |
| line3(Vert a, Vert b) |
| { |
| line(image, Pt(a.screen.x, a.screen.y), Pt(b.screen.x, b.screen.y), 0, 0, 0, display->white, ZP); |
| } |
| |
| |
| void |
| redraw(void) |
| { |
| int i, m; |
| RGB cmap[256]; |
| Vert v[256]; |
| |
| readcolmap(display, cmap); |
| colorspace(cmap, v); |
| draw(image, image->r, bg, nil, Pt(0, 0)); |
| m = Dx(viewrect)/2; |
| if(m > Dy(viewrect)/2) |
| m = Dy(viewrect)/2; |
| ellipse(image, addpt(viewrect.min, divpt(Pt(Dx(viewrect), Dy(viewrect)), 2)), |
| m, m, 1, display->white, ZP); |
| |
| line3(v[0], v[0x36]); |
| line3(v[0x36], v[0x32]); |
| line3(v[0x32], v[0x3F]); |
| line3(v[0x3F], v[0]); |
| |
| line3(v[0xF0], v[0xF3]); |
| line3(v[0xF3], v[0xFF]); |
| line3(v[0xFF], v[0xFC]); |
| line3(v[0xFC], v[0xF0]); |
| |
| line3(v[0], v[0xF0]); |
| line3(v[0x36], v[0xF3]); |
| line3(v[0x32], v[0xFF]); |
| line3(v[0x3F], v[0xFC]); |
| |
| qsort(v, ncolor, sizeof(Vert), (int(*)(const void*, const void*))cmp); |
| if(!nocubes) |
| for(i=0; i!=ncolor; i++) |
| draw(image, rectaddpt(Rect(-3, -3, 4, 4), Pt(v[i].screen.x, v[i].screen.y)), |
| color[v[i].color], nil, Pt(0, 0)); |
| draw(screen, image->r, image, nil, image->r.min); |
| flushimage(display, 1); |
| } |
| |
| void |
| eresized(int new) |
| { |
| int dx, dy; |
| |
| if(new && getwindow(display, Refnone) < 0){ |
| fprint(2, "colors: can't reattach to window: %r\n"); |
| exits("reshaped"); |
| } |
| draw(screen, screen->r, display->black, nil, ZP); |
| replclipr(screen, 0, insetrect(screen->r, 3)); |
| viewrect = screen->clipr; |
| viewrect.min.y += stringsize(font, "0i").y + 5; |
| if(image) |
| freeimage(image); |
| image = allocimage(display, viewrect, screen->chan, 0, DNofill); |
| dx = viewrect.max.x-viewrect.min.x; |
| dy = viewrect.max.y-viewrect.min.y; |
| if(dx>dy){ |
| viewrect.min.x=(viewrect.min.x+viewrect.max.x-dy)/2; |
| viewrect.max.x=viewrect.min.x+dy; |
| } |
| else{ |
| viewrect.min.y=(viewrect.min.y+viewrect.max.y-dx)/2; |
| viewrect.max.y=viewrect.min.y+dx; |
| } |
| if(image==nil){ |
| fprint(2, "can't allocate image\n"); |
| exits("bad allocimage"); |
| } |
| prevsel = -1; |
| redraw(); |
| } |
| |
| void main(int argc, char **argv){ |
| Vert v[256]; |
| RGB cmap[256]; |
| char buf[100]; |
| Point p; |
| Mouse m; |
| int i; |
| ulong bgcol; |
| |
| bgcol = DNofill; |
| ARGBEGIN{ |
| case 'n': |
| nocubes = 1; |
| break; |
| case 'b': |
| bgcol = DBlack; |
| break; |
| case 'w': |
| bgcol = DWhite; |
| break; |
| }ARGEND |
| |
| initdraw(0,0,0); |
| ncolor=256; |
| for(i=0;i!=ncolor;i++) |
| color[i] = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, cmap2rgba(i)); |
| if(bgcol==DNofill){ |
| bg = allocimage(display, Rect(0, 0, 2, 2), screen->chan, 1, DWhite); |
| draw(bg, Rect(0, 0, 1, 1), color[0], nil, Pt(0, 0)); |
| draw(bg, Rect(1, 1, 2, 2), color[0], nil, Pt(0, 0)); |
| }else |
| bg = allocimage(display, Rect(0,0,1,1), screen->chan, 1, bgcol); |
| |
| einit(Emouse); |
| eresized(0); |
| |
| for(;;){ |
| m = emouse(); |
| if(m.buttons&1) |
| qball(viewrect, &m, &q, redraw, 0); |
| else if(m.buttons & 2){ |
| readcolmap(display, cmap); |
| colorspace(cmap, v); |
| qsort(v, ncolor, sizeof(Vert), (int(*)(const void*, const void*))cmp); |
| while(m.buttons){ |
| for(i=ncolor-1; i!=0; i--){ |
| if(ptinrect(m.xy, rectaddpt(Rect(-3, -3, 4, 4), Pt(v[i].screen.x, v[i].screen.y)))){ |
| i = v[i].color; |
| if(i == prevsel) |
| break; |
| sprint(buf, "index %3d r %3ld g %3ld b %3ld", |
| i, |
| cmap[i].red>>24, |
| cmap[i].green>>24, |
| cmap[i].blue>>24); |
| p = addpt(screen->r.min, Pt(2,2)); |
| draw(screen, Rpt(p, addpt(p, stringsize(font, buf))), display->black, nil, p); |
| string(screen, p, display->white, ZP, font, buf); |
| prevsel = i; |
| break; |
| } |
| } |
| m = emouse(); |
| } |
| }else if(m.buttons&4){ |
| do |
| m = emouse(); |
| while(m.buttons); |
| exits(0); |
| } |
| } |
| } |