1 | #define CONCAT_I(a, b) a ## b |
2 | #define CONCAT(a, b) CONCAT_I(a, b) |
3 | #define pixel_t CONCAT(uint, CONCAT(BPP, _t)) |
4 | #ifdef GENERIC |
5 | #define NAME CONCAT(generic_, BPP) |
6 | #else |
7 | #define NAME BPP |
8 | #endif |
9 | |
10 | static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, |
11 | int x, int y, int w, int h, |
12 | void *last_bg_, |
13 | void *last_fg_, |
14 | int *has_bg, int *has_fg) |
15 | { |
16 | VncDisplay *vd = vs->vd; |
17 | uint8_t *row = vnc_server_fb_ptr(vd, x, y); |
18 | pixel_t *irow = (pixel_t *)row; |
19 | int j, i; |
20 | pixel_t *last_bg = (pixel_t *)last_bg_; |
21 | pixel_t *last_fg = (pixel_t *)last_fg_; |
22 | pixel_t bg = 0; |
23 | pixel_t fg = 0; |
24 | int n_colors = 0; |
25 | int bg_count = 0; |
26 | int fg_count = 0; |
27 | int flags = 0; |
28 | uint8_t data[(vs->client_pf.bytes_per_pixel + 2) * 16 * 16]; |
29 | int n_data = 0; |
30 | int n_subtiles = 0; |
31 | |
32 | for (j = 0; j < h; j++) { |
33 | for (i = 0; i < w; i++) { |
34 | switch (n_colors) { |
35 | case 0: |
36 | bg = irow[i]; |
37 | n_colors = 1; |
38 | break; |
39 | case 1: |
40 | if (irow[i] != bg) { |
41 | fg = irow[i]; |
42 | n_colors = 2; |
43 | } |
44 | break; |
45 | case 2: |
46 | if (irow[i] != bg && irow[i] != fg) { |
47 | n_colors = 3; |
48 | } else { |
49 | if (irow[i] == bg) |
50 | bg_count++; |
51 | else if (irow[i] == fg) |
52 | fg_count++; |
53 | } |
54 | break; |
55 | default: |
56 | break; |
57 | } |
58 | } |
59 | if (n_colors > 2) |
60 | break; |
61 | irow += vnc_server_fb_stride(vd) / sizeof(pixel_t); |
62 | } |
63 | |
64 | if (n_colors > 1 && fg_count > bg_count) { |
65 | pixel_t tmp = fg; |
66 | fg = bg; |
67 | bg = tmp; |
68 | } |
69 | |
70 | if (!*has_bg || *last_bg != bg) { |
71 | flags |= 0x02; |
72 | *has_bg = 1; |
73 | *last_bg = bg; |
74 | } |
75 | |
76 | if (n_colors < 3 && (!*has_fg || *last_fg != fg)) { |
77 | flags |= 0x04; |
78 | *has_fg = 1; |
79 | *last_fg = fg; |
80 | } |
81 | |
82 | switch (n_colors) { |
83 | case 1: |
84 | n_data = 0; |
85 | break; |
86 | case 2: |
87 | flags |= 0x08; |
88 | |
89 | irow = (pixel_t *)row; |
90 | |
91 | for (j = 0; j < h; j++) { |
92 | int min_x = -1; |
93 | for (i = 0; i < w; i++) { |
94 | if (irow[i] == fg) { |
95 | if (min_x == -1) |
96 | min_x = i; |
97 | } else if (min_x != -1) { |
98 | hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); |
99 | n_data += 2; |
100 | n_subtiles++; |
101 | min_x = -1; |
102 | } |
103 | } |
104 | if (min_x != -1) { |
105 | hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); |
106 | n_data += 2; |
107 | n_subtiles++; |
108 | } |
109 | irow += vnc_server_fb_stride(vd) / sizeof(pixel_t); |
110 | } |
111 | break; |
112 | case 3: |
113 | flags |= 0x18; |
114 | |
115 | irow = (pixel_t *)row; |
116 | |
117 | if (!*has_bg || *last_bg != bg) |
118 | flags |= 0x02; |
119 | |
120 | for (j = 0; j < h; j++) { |
121 | int has_color = 0; |
122 | int min_x = -1; |
123 | pixel_t color = 0; /* shut up gcc */ |
124 | |
125 | for (i = 0; i < w; i++) { |
126 | if (!has_color) { |
127 | if (irow[i] == bg) |
128 | continue; |
129 | color = irow[i]; |
130 | min_x = i; |
131 | has_color = 1; |
132 | } else if (irow[i] != color) { |
133 | has_color = 0; |
134 | #ifdef GENERIC |
135 | vnc_convert_pixel(vs, data + n_data, color); |
136 | n_data += vs->client_pf.bytes_per_pixel; |
137 | #else |
138 | memcpy(data + n_data, &color, sizeof(color)); |
139 | n_data += sizeof(pixel_t); |
140 | #endif |
141 | hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); |
142 | n_data += 2; |
143 | n_subtiles++; |
144 | |
145 | min_x = -1; |
146 | if (irow[i] != bg) { |
147 | color = irow[i]; |
148 | min_x = i; |
149 | has_color = 1; |
150 | } |
151 | } |
152 | } |
153 | if (has_color) { |
154 | #ifdef GENERIC |
155 | vnc_convert_pixel(vs, data + n_data, color); |
156 | n_data += vs->client_pf.bytes_per_pixel; |
157 | #else |
158 | memcpy(data + n_data, &color, sizeof(color)); |
159 | n_data += sizeof(pixel_t); |
160 | #endif |
161 | hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); |
162 | n_data += 2; |
163 | n_subtiles++; |
164 | } |
165 | irow += vnc_server_fb_stride(vd) / sizeof(pixel_t); |
166 | } |
167 | |
168 | /* A SubrectsColoured subtile invalidates the foreground color */ |
169 | *has_fg = 0; |
170 | if (n_data > (w * h * sizeof(pixel_t))) { |
171 | n_colors = 4; |
172 | flags = 0x01; |
173 | *has_bg = 0; |
174 | |
175 | /* we really don't have to invalidate either the bg or fg |
176 | but we've lost the old values. oh well. */ |
177 | } |
178 | break; |
179 | default: |
180 | break; |
181 | } |
182 | |
183 | if (n_colors > 3) { |
184 | flags = 0x01; |
185 | *has_fg = 0; |
186 | *has_bg = 0; |
187 | n_colors = 4; |
188 | } |
189 | |
190 | vnc_write_u8(vs, flags); |
191 | if (n_colors < 4) { |
192 | if (flags & 0x02) |
193 | vs->write_pixels(vs, last_bg, sizeof(pixel_t)); |
194 | if (flags & 0x04) |
195 | vs->write_pixels(vs, last_fg, sizeof(pixel_t)); |
196 | if (n_subtiles) { |
197 | vnc_write_u8(vs, n_subtiles); |
198 | vnc_write(vs, data, n_data); |
199 | } |
200 | } else { |
201 | for (j = 0; j < h; j++) { |
202 | vs->write_pixels(vs, row, w * 4); |
203 | row += vnc_server_fb_stride(vd); |
204 | } |
205 | } |
206 | } |
207 | |
208 | #undef NAME |
209 | #undef pixel_t |
210 | #undef CONCAT_I |
211 | #undef CONCAT |
212 | |