diff options
author | Elliott Hughes | 2015-04-10 15:12:05 -0500 |
---|---|---|
committer | Elliott Hughes | 2015-04-10 15:42:55 -0500 |
commit | 07cfb8fe799901948afd6af05ef4674173713bcb (patch) | |
tree | dbb3c6ea45cb910397cec50054460d46c99b454f /minui/graphics.cpp | |
parent | 5d1630a926a02ca13a66eb1e385eabba16b04cfc (diff) | |
download | platform-bootable-recovery-07cfb8fe799901948afd6af05ef4674173713bcb.tar.gz platform-bootable-recovery-07cfb8fe799901948afd6af05ef4674173713bcb.tar.xz platform-bootable-recovery-07cfb8fe799901948afd6af05ef4674173713bcb.zip |
Switch minui over to C++.
Change-Id: I59e08a304ae514a3fdb6fab58721f11670bc1b01
Diffstat (limited to 'minui/graphics.cpp')
-rw-r--r-- | minui/graphics.cpp | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/minui/graphics.cpp b/minui/graphics.cpp new file mode 100644 index 00000000..d7d6e8d5 --- /dev/null +++ b/minui/graphics.cpp | |||
@@ -0,0 +1,406 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include <stdbool.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include <unistd.h> | ||
21 | |||
22 | #include <fcntl.h> | ||
23 | #include <stdio.h> | ||
24 | |||
25 | #include <sys/ioctl.h> | ||
26 | #include <sys/mman.h> | ||
27 | #include <sys/types.h> | ||
28 | |||
29 | #include <linux/fb.h> | ||
30 | #include <linux/kd.h> | ||
31 | |||
32 | #include <time.h> | ||
33 | |||
34 | #include "font_10x18.h" | ||
35 | #include "minui.h" | ||
36 | #include "graphics.h" | ||
37 | |||
38 | struct GRFont { | ||
39 | GRSurface* texture; | ||
40 | int cwidth; | ||
41 | int cheight; | ||
42 | }; | ||
43 | |||
44 | static GRFont* gr_font = NULL; | ||
45 | static minui_backend* gr_backend = NULL; | ||
46 | |||
47 | static int overscan_percent = OVERSCAN_PERCENT; | ||
48 | static int overscan_offset_x = 0; | ||
49 | static int overscan_offset_y = 0; | ||
50 | |||
51 | static unsigned char gr_current_r = 255; | ||
52 | static unsigned char gr_current_g = 255; | ||
53 | static unsigned char gr_current_b = 255; | ||
54 | static unsigned char gr_current_a = 255; | ||
55 | |||
56 | static GRSurface* gr_draw = NULL; | ||
57 | |||
58 | static bool outside(int x, int y) | ||
59 | { | ||
60 | return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height; | ||
61 | } | ||
62 | |||
63 | int gr_measure(const char *s) | ||
64 | { | ||
65 | return gr_font->cwidth * strlen(s); | ||
66 | } | ||
67 | |||
68 | void gr_font_size(int *x, int *y) | ||
69 | { | ||
70 | *x = gr_font->cwidth; | ||
71 | *y = gr_font->cheight; | ||
72 | } | ||
73 | |||
74 | static void text_blend(unsigned char* src_p, int src_row_bytes, | ||
75 | unsigned char* dst_p, int dst_row_bytes, | ||
76 | int width, int height) | ||
77 | { | ||
78 | for (int j = 0; j < height; ++j) { | ||
79 | unsigned char* sx = src_p; | ||
80 | unsigned char* px = dst_p; | ||
81 | for (int i = 0; i < width; ++i) { | ||
82 | unsigned char a = *sx++; | ||
83 | if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255; | ||
84 | if (a == 255) { | ||
85 | *px++ = gr_current_r; | ||
86 | *px++ = gr_current_g; | ||
87 | *px++ = gr_current_b; | ||
88 | px++; | ||
89 | } else if (a > 0) { | ||
90 | *px = (*px * (255-a) + gr_current_r * a) / 255; | ||
91 | ++px; | ||
92 | *px = (*px * (255-a) + gr_current_g * a) / 255; | ||
93 | ++px; | ||
94 | *px = (*px * (255-a) + gr_current_b * a) / 255; | ||
95 | ++px; | ||
96 | ++px; | ||
97 | } else { | ||
98 | px += 4; | ||
99 | } | ||
100 | } | ||
101 | src_p += src_row_bytes; | ||
102 | dst_p += dst_row_bytes; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | void gr_text(int x, int y, const char *s, int bold) | ||
107 | { | ||
108 | GRFont* font = gr_font; | ||
109 | |||
110 | if (!font->texture || gr_current_a == 0) return; | ||
111 | |||
112 | bold = bold && (font->texture->height != font->cheight); | ||
113 | |||
114 | x += overscan_offset_x; | ||
115 | y += overscan_offset_y; | ||
116 | |||
117 | unsigned char ch; | ||
118 | while ((ch = *s++)) { | ||
119 | if (outside(x, y) || outside(x+font->cwidth-1, y+font->cheight-1)) break; | ||
120 | |||
121 | if (ch < ' ' || ch > '~') { | ||
122 | ch = '?'; | ||
123 | } | ||
124 | |||
125 | unsigned char* src_p = font->texture->data + ((ch - ' ') * font->cwidth) + | ||
126 | (bold ? font->cheight * font->texture->row_bytes : 0); | ||
127 | unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes; | ||
128 | |||
129 | text_blend(src_p, font->texture->row_bytes, | ||
130 | dst_p, gr_draw->row_bytes, | ||
131 | font->cwidth, font->cheight); | ||
132 | |||
133 | x += font->cwidth; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | void gr_texticon(int x, int y, GRSurface* icon) { | ||
138 | if (icon == NULL) return; | ||
139 | |||
140 | if (icon->pixel_bytes != 1) { | ||
141 | printf("gr_texticon: source has wrong format\n"); | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | x += overscan_offset_x; | ||
146 | y += overscan_offset_y; | ||
147 | |||
148 | if (outside(x, y) || outside(x+icon->width-1, y+icon->height-1)) return; | ||
149 | |||
150 | unsigned char* src_p = icon->data; | ||
151 | unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes; | ||
152 | |||
153 | text_blend(src_p, icon->row_bytes, | ||
154 | dst_p, gr_draw->row_bytes, | ||
155 | icon->width, icon->height); | ||
156 | } | ||
157 | |||
158 | void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) | ||
159 | { | ||
160 | #if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) | ||
161 | gr_current_r = b; | ||
162 | gr_current_g = g; | ||
163 | gr_current_b = r; | ||
164 | gr_current_a = a; | ||
165 | #else | ||
166 | gr_current_r = r; | ||
167 | gr_current_g = g; | ||
168 | gr_current_b = b; | ||
169 | gr_current_a = a; | ||
170 | #endif | ||
171 | } | ||
172 | |||
173 | void gr_clear() | ||
174 | { | ||
175 | if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) { | ||
176 | memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes); | ||
177 | } else { | ||
178 | unsigned char* px = gr_draw->data; | ||
179 | for (int y = 0; y < gr_draw->height; ++y) { | ||
180 | for (int x = 0; x < gr_draw->width; ++x) { | ||
181 | *px++ = gr_current_r; | ||
182 | *px++ = gr_current_g; | ||
183 | *px++ = gr_current_b; | ||
184 | px++; | ||
185 | } | ||
186 | px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes); | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
191 | void gr_fill(int x1, int y1, int x2, int y2) | ||
192 | { | ||
193 | x1 += overscan_offset_x; | ||
194 | y1 += overscan_offset_y; | ||
195 | |||
196 | x2 += overscan_offset_x; | ||
197 | y2 += overscan_offset_y; | ||
198 | |||
199 | if (outside(x1, y1) || outside(x2-1, y2-1)) return; | ||
200 | |||
201 | unsigned char* p = gr_draw->data + y1 * gr_draw->row_bytes + x1 * gr_draw->pixel_bytes; | ||
202 | if (gr_current_a == 255) { | ||
203 | int x, y; | ||
204 | for (y = y1; y < y2; ++y) { | ||
205 | unsigned char* px = p; | ||
206 | for (x = x1; x < x2; ++x) { | ||
207 | *px++ = gr_current_r; | ||
208 | *px++ = gr_current_g; | ||
209 | *px++ = gr_current_b; | ||
210 | px++; | ||
211 | } | ||
212 | p += gr_draw->row_bytes; | ||
213 | } | ||
214 | } else if (gr_current_a > 0) { | ||
215 | int x, y; | ||
216 | for (y = y1; y < y2; ++y) { | ||
217 | unsigned char* px = p; | ||
218 | for (x = x1; x < x2; ++x) { | ||
219 | *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255; | ||
220 | ++px; | ||
221 | *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255; | ||
222 | ++px; | ||
223 | *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255; | ||
224 | ++px; | ||
225 | ++px; | ||
226 | } | ||
227 | p += gr_draw->row_bytes; | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | |||
232 | void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) { | ||
233 | if (source == NULL) return; | ||
234 | |||
235 | if (gr_draw->pixel_bytes != source->pixel_bytes) { | ||
236 | printf("gr_blit: source has wrong format\n"); | ||
237 | return; | ||
238 | } | ||
239 | |||
240 | dx += overscan_offset_x; | ||
241 | dy += overscan_offset_y; | ||
242 | |||
243 | if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return; | ||
244 | |||
245 | unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes; | ||
246 | unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes; | ||
247 | |||
248 | int i; | ||
249 | for (i = 0; i < h; ++i) { | ||
250 | memcpy(dst_p, src_p, w * source->pixel_bytes); | ||
251 | src_p += source->row_bytes; | ||
252 | dst_p += gr_draw->row_bytes; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | unsigned int gr_get_width(GRSurface* surface) { | ||
257 | if (surface == NULL) { | ||
258 | return 0; | ||
259 | } | ||
260 | return surface->width; | ||
261 | } | ||
262 | |||
263 | unsigned int gr_get_height(GRSurface* surface) { | ||
264 | if (surface == NULL) { | ||
265 | return 0; | ||
266 | } | ||
267 | return surface->height; | ||
268 | } | ||
269 | |||
270 | static void gr_init_font(void) | ||
271 | { | ||
272 | gr_font = reinterpret_cast<GRFont*>(calloc(sizeof(*gr_font), 1)); | ||
273 | |||
274 | int res = res_create_alpha_surface("font", &(gr_font->texture)); | ||
275 | if (res == 0) { | ||
276 | // The font image should be a 96x2 array of character images. The | ||
277 | // columns are the printable ASCII characters 0x20 - 0x7f. The | ||
278 | // top row is regular text; the bottom row is bold. | ||
279 | gr_font->cwidth = gr_font->texture->width / 96; | ||
280 | gr_font->cheight = gr_font->texture->height / 2; | ||
281 | } else { | ||
282 | printf("failed to read font: res=%d\n", res); | ||
283 | |||
284 | // fall back to the compiled-in font. | ||
285 | gr_font->texture = reinterpret_cast<GRSurface*>(malloc(sizeof(*gr_font->texture))); | ||
286 | gr_font->texture->width = font.width; | ||
287 | gr_font->texture->height = font.height; | ||
288 | gr_font->texture->row_bytes = font.width; | ||
289 | gr_font->texture->pixel_bytes = 1; | ||
290 | |||
291 | unsigned char* bits = reinterpret_cast<unsigned char*>(malloc(font.width * font.height)); | ||
292 | gr_font->texture->data = reinterpret_cast<unsigned char*>(bits); | ||
293 | |||
294 | unsigned char data; | ||
295 | unsigned char* in = font.rundata; | ||
296 | while((data = *in++)) { | ||
297 | memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f); | ||
298 | bits += (data & 0x7f); | ||
299 | } | ||
300 | |||
301 | gr_font->cwidth = font.cwidth; | ||
302 | gr_font->cheight = font.cheight; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | #if 0 | ||
307 | // Exercises many of the gr_*() functions; useful for testing. | ||
308 | static void gr_test() { | ||
309 | GRSurface** images; | ||
310 | int frames; | ||
311 | int result = res_create_multi_surface("icon_installing", &frames, &images); | ||
312 | if (result < 0) { | ||
313 | printf("create surface %d\n", result); | ||
314 | gr_exit(); | ||
315 | return; | ||
316 | } | ||
317 | |||
318 | time_t start = time(NULL); | ||
319 | int x; | ||
320 | for (x = 0; x <= 1200; ++x) { | ||
321 | if (x < 400) { | ||
322 | gr_color(0, 0, 0, 255); | ||
323 | } else { | ||
324 | gr_color(0, (x-400)%128, 0, 255); | ||
325 | } | ||
326 | gr_clear(); | ||
327 | |||
328 | gr_color(255, 0, 0, 255); | ||
329 | gr_surface frame = images[x%frames]; | ||
330 | gr_blit(frame, 0, 0, frame->width, frame->height, x, 0); | ||
331 | |||
332 | gr_color(255, 0, 0, 128); | ||
333 | gr_fill(400, 150, 600, 350); | ||
334 | |||
335 | gr_color(255, 255, 255, 255); | ||
336 | gr_text(500, 225, "hello, world!", 0); | ||
337 | gr_color(255, 255, 0, 128); | ||
338 | gr_text(300+x, 275, "pack my box with five dozen liquor jugs", 1); | ||
339 | |||
340 | gr_color(0, 0, 255, 128); | ||
341 | gr_fill(gr_draw->width - 200 - x, 300, gr_draw->width - x, 500); | ||
342 | |||
343 | gr_draw = gr_backend->flip(gr_backend); | ||
344 | } | ||
345 | printf("getting end time\n"); | ||
346 | time_t end = time(NULL); | ||
347 | printf("got end time\n"); | ||
348 | printf("start %ld end %ld\n", (long)start, (long)end); | ||
349 | if (end > start) { | ||
350 | printf("%.2f fps\n", ((double)x) / (end-start)); | ||
351 | } | ||
352 | } | ||
353 | #endif | ||
354 | |||
355 | void gr_flip() { | ||
356 | gr_draw = gr_backend->flip(gr_backend); | ||
357 | } | ||
358 | |||
359 | int gr_init(void) | ||
360 | { | ||
361 | gr_init_font(); | ||
362 | |||
363 | gr_backend = open_adf(); | ||
364 | if (gr_backend) { | ||
365 | gr_draw = gr_backend->init(gr_backend); | ||
366 | if (!gr_draw) { | ||
367 | gr_backend->exit(gr_backend); | ||
368 | } | ||
369 | } | ||
370 | |||
371 | if (!gr_draw) { | ||
372 | gr_backend = open_fbdev(); | ||
373 | gr_draw = gr_backend->init(gr_backend); | ||
374 | if (gr_draw == NULL) { | ||
375 | return -1; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | overscan_offset_x = gr_draw->width * overscan_percent / 100; | ||
380 | overscan_offset_y = gr_draw->height * overscan_percent / 100; | ||
381 | |||
382 | gr_flip(); | ||
383 | gr_flip(); | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | void gr_exit(void) | ||
389 | { | ||
390 | gr_backend->exit(gr_backend); | ||
391 | } | ||
392 | |||
393 | int gr_fb_width(void) | ||
394 | { | ||
395 | return gr_draw->width - 2*overscan_offset_x; | ||
396 | } | ||
397 | |||
398 | int gr_fb_height(void) | ||
399 | { | ||
400 | return gr_draw->height - 2*overscan_offset_y; | ||
401 | } | ||
402 | |||
403 | void gr_fb_blank(bool blank) | ||
404 | { | ||
405 | gr_backend->blank(gr_backend, blank); | ||
406 | } | ||