xref: /plan9/sys/src/cmd/vnc/color.c (revision f8e525ac91e3a7fae3f104837a69862dc348aa81)
1 #include "vnc.h"
2 #include "vncv.h"
3 
4 enum {
5 	RGB12 = CHAN4(CIgnore, 4, CRed, 4, CGreen, 4, CBlue, 4),
6 	BGR12 = CHAN4(CIgnore, 4, CBlue, 4, CGreen, 4, CRed, 4),
7 	BGR8 = CHAN3(CBlue, 2, CGreen, 3, CRed, 3),
8 };
9 
10 void (*cvtpixels)(uchar*, uchar*, int);
11 
12 static void
chan2fmt(Pixfmt * fmt,ulong chan)13 chan2fmt(Pixfmt *fmt, ulong chan)
14 {
15 	ulong c, rc, shift;
16 
17 	shift = 0;
18 	for(rc = chan; rc; rc >>=8){
19 		c = rc & 0xFF;
20 		switch(TYPE(c)){
21 		case CRed:
22 			fmt->red = (Colorfmt){(1<<NBITS(c))-1, shift};
23 			break;
24 		case CBlue:
25 			fmt->blue = (Colorfmt){(1<<NBITS(c))-1, shift};
26 			break;
27 		case CGreen:
28 			fmt->green = (Colorfmt){(1<<NBITS(c))-1, shift};
29 			break;
30 		}
31 		shift += NBITS(c);
32 	}
33 }
34 
35 /*
36  * convert 32-bit data to 24-bit data by skipping
37  * the last of every four bytes.  we skip the last
38  * because we keep the server in little endian mode.
39  */
40 static void
cvt32to24(uchar * dst,uchar * src,int npixel)41 cvt32to24(uchar *dst, uchar *src, int npixel)
42 {
43 	int i;
44 
45 	for(i=0; i<npixel; i++){
46 		*dst++ = *src++;
47 		*dst++ = *src++;
48 		*dst++ = *src++;
49 		src++;
50 	}
51 }
52 
53 /*
54  * convert RGB12 (x4r4g4b4) into CMAP8
55  */
56 static uchar rgb12[16*16*16];
57 static void
mkrgbtab(void)58 mkrgbtab(void)
59 {
60 	int r, g, b;
61 
62 	for(r=0; r<16; r++)
63 	for(g=0; g<16; g++)
64 	for(b=0; b<16; b++)
65 		rgb12[r*256+g*16+b] = rgb2cmap(r*0x11, g*0x11, b*0x11);
66 }
67 
68 static void
cvtrgb12tocmap8(uchar * dst,uchar * src,int npixel)69 cvtrgb12tocmap8(uchar *dst, uchar *src, int npixel)
70 {
71 	int i, s;
72 
73 	for(i=0; i<npixel; i++){
74 		s = (src[0] | (src[1]<<8)) & 0xFFF;
75 		*dst++ = rgb12[s];
76 		src += 2;
77 	}
78 }
79 
80 /*
81  * convert BGR8 (b2g3r3, default VNC format) to CMAP8
82  * some bits are lost.
83  */
84 static uchar bgr8[256];
85 static void
mkbgrtab(void)86 mkbgrtab(void)
87 {
88 	int i, r, g, b;
89 
90 	for(i=0; i<256; i++){
91 		b = i>>6;
92 		b = (b<<6)|(b<<4)|(b<<2)|b;
93 		g = (i>>3) & 7;
94 		g = (g<<5)|(g<<2)|(g>>1);
95 		r = i & 7;
96 		r = (r<<5)|(r<<2)|(r>>1);
97 		bgr8[i] = rgb2cmap(r, g, b);
98 	}
99 }
100 
101 static void
cvtbgr332tocmap8(uchar * dst,uchar * src,int npixel)102 cvtbgr332tocmap8(uchar *dst, uchar *src, int npixel)
103 {
104 	uchar *ed;
105 
106 	ed = dst+npixel;
107 	while(dst < ed)
108 		*dst++ = bgr8[*src++];
109 }
110 
111 void
choosecolor(Vnc * v)112 choosecolor(Vnc *v)
113 {
114 	int bpp, depth;
115 	ulong chan;
116 
117 	bpp = screen->depth;
118 	if((bpp / 8) * 8 != bpp)
119 		sysfatal("screen not supported");
120 
121 	depth = screen->depth;
122 	chan = screen->chan;
123 
124 	if(bpp == 24){
125 		if(verbose)
126 			fprint(2, "24bit emulation using 32bpp\n");
127 		bpp = 32;
128 		cvtpixels = cvt32to24;
129 	}
130 
131 	if(chan == CMAP8){
132 		if(bpp12){
133 			if(verbose)
134 				fprint(2, "8bit emulation using 12bpp\n");
135 			bpp = 16;
136 			depth = 12;
137 			chan = RGB12;
138 			cvtpixels = cvtrgb12tocmap8;
139 			mkrgbtab();
140 		}else{
141 			if(verbose)
142 				fprint(2, "8bit emulation using 6bpp\n");	/* 6: we throw away 1 r, g bit */
143 			bpp = 8;
144 			depth = 8;
145 			chan = BGR8;
146 			cvtpixels = cvtbgr332tocmap8;
147 			mkbgrtab();
148 		}
149 	}
150 
151 	v->bpp = bpp;
152 	v->depth = depth;
153 	v->truecolor = 1;
154 	v->bigendian = 0;
155 	chan2fmt(v, chan);
156 	if(v->red.max == 0 || v->green.max == 0 || v->blue.max == 0)
157 		sysfatal("screen not supported");
158 
159 	if(verbose)
160 		fprint(2, "%d bpp, %d depth, 0x%lx chan, %d truecolor, %d bigendian\n",
161 			v->bpp, v->depth, screen->chan, v->truecolor, v->bigendian);
162 
163 	/* send information to server */
164 	vncwrchar(v, MPixFmt);
165 	vncwrchar(v, 0);	/* padding */
166 	vncwrshort(v, 0);
167 	vncwrpixfmt(v, &v->Pixfmt);
168 	vncflush(v);
169 }
170