blob: c0c67f948088393f798ce94b66490dc2bf42e2c5 [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
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
Tao Bao0ecbd762017-01-16 21:16:58 -080017#include "graphics.h"
18
Tao Baoe8020f42017-02-03 09:30:07 -080019#include <stdio.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080020#include <stdlib.h>
Elliott Hughescd3c55a2015-01-29 20:50:08 -080021#include <string.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080022
Doug Zongker6fd59ac2013-03-06 15:01:11 -080023#include "font_10x18.h"
Tao Bao0ecbd762017-01-16 21:16:58 -080024#include "minui/minui.h"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080025
Doug Zongker16f97c32014-03-06 16:16:05 -080026static GRFont* gr_font = NULL;
Doug Zongker5290f202014-03-11 13:22:04 -070027static minui_backend* gr_backend = NULL;
Doug Zongker16f97c32014-03-06 16:16:05 -080028
Doug Zongkerc560a672012-12-18 16:31:27 -080029static int overscan_percent = OVERSCAN_PERCENT;
30static int overscan_offset_x = 0;
31static int overscan_offset_y = 0;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080032
Doug Zongker16f97c32014-03-06 16:16:05 -080033static unsigned char gr_current_r = 255;
34static unsigned char gr_current_g = 255;
35static unsigned char gr_current_b = 255;
36static unsigned char gr_current_a = 255;
37
Doug Zongker5290f202014-03-11 13:22:04 -070038static GRSurface* gr_draw = NULL;
Doug Zongker16f97c32014-03-06 16:16:05 -080039
40static bool outside(int x, int y)
41{
42 return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
43}
44
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070045const GRFont* gr_sys_font()
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080046{
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070047 return gr_font;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080048}
49
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070050int gr_measure(const GRFont* font, const char *s)
Dima Zavin3c7f00e2011-08-30 11:58:24 -070051{
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070052 return font->char_width * strlen(s);
53}
54
55void gr_font_size(const GRFont* font, int *x, int *y)
56{
57 *x = font->char_width;
58 *y = font->char_height;
Dima Zavin3c7f00e2011-08-30 11:58:24 -070059}
60
Doug Zongker16f97c32014-03-06 16:16:05 -080061static void text_blend(unsigned char* src_p, int src_row_bytes,
62 unsigned char* dst_p, int dst_row_bytes,
63 int width, int height)
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080064{
Elliott Hughes01a4d082015-03-24 15:21:48 -070065 for (int j = 0; j < height; ++j) {
Doug Zongker16f97c32014-03-06 16:16:05 -080066 unsigned char* sx = src_p;
67 unsigned char* px = dst_p;
Elliott Hughes01a4d082015-03-24 15:21:48 -070068 for (int i = 0; i < width; ++i) {
Doug Zongker16f97c32014-03-06 16:16:05 -080069 unsigned char a = *sx++;
70 if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255;
71 if (a == 255) {
72 *px++ = gr_current_r;
73 *px++ = gr_current_g;
74 *px++ = gr_current_b;
75 px++;
76 } else if (a > 0) {
77 *px = (*px * (255-a) + gr_current_r * a) / 255;
78 ++px;
79 *px = (*px * (255-a) + gr_current_g * a) / 255;
80 ++px;
81 *px = (*px * (255-a) + gr_current_b * a) / 255;
82 ++px;
83 ++px;
84 } else {
85 px += 4;
86 }
87 }
88 src_p += src_row_bytes;
89 dst_p += dst_row_bytes;
90 }
91}
92
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070093void gr_text(const GRFont* font, int x, int y, const char *s, bool bold)
Doug Zongker16f97c32014-03-06 16:16:05 -080094{
Elliott Hughes01a4d082015-03-24 15:21:48 -070095 if (!font->texture || gr_current_a == 0) return;
Doug Zongker55a36ac2013-03-04 15:49:02 -080096
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070097 bold = bold && (font->texture->height != font->char_height);
Doug Zongker6fd59ac2013-03-06 15:01:11 -080098
Doug Zongkerc560a672012-12-18 16:31:27 -080099 x += overscan_offset_x;
100 y += overscan_offset_y;
101
Elliott Hughes01a4d082015-03-24 15:21:48 -0700102 unsigned char ch;
103 while ((ch = *s++)) {
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700104 if (outside(x, y) || outside(x+font->char_width-1, y+font->char_height-1)) break;
Doug Zongker16f97c32014-03-06 16:16:05 -0800105
Elliott Hughes01a4d082015-03-24 15:21:48 -0700106 if (ch < ' ' || ch > '~') {
107 ch = '?';
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800108 }
Elliott Hughes01a4d082015-03-24 15:21:48 -0700109
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700110 unsigned char* src_p = font->texture->data + ((ch - ' ') * font->char_width) +
111 (bold ? font->char_height * font->texture->row_bytes : 0);
Elliott Hughes01a4d082015-03-24 15:21:48 -0700112 unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
113
114 text_blend(src_p, font->texture->row_bytes,
115 dst_p, gr_draw->row_bytes,
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700116 font->char_width, font->char_height);
Elliott Hughes01a4d082015-03-24 15:21:48 -0700117
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700118 x += font->char_width;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800119 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800120}
121
Doug Zongker16f97c32014-03-06 16:16:05 -0800122void gr_texticon(int x, int y, GRSurface* icon) {
123 if (icon == NULL) return;
124
125 if (icon->pixel_bytes != 1) {
126 printf("gr_texticon: source has wrong format\n");
Doug Zongker52eeea4f2012-09-04 14:28:25 -0700127 return;
128 }
Doug Zongker02ec6b82012-08-22 17:26:40 -0700129
Doug Zongkerc560a672012-12-18 16:31:27 -0800130 x += overscan_offset_x;
131 y += overscan_offset_y;
132
Doug Zongker16f97c32014-03-06 16:16:05 -0800133 if (outside(x, y) || outside(x+icon->width-1, y+icon->height-1)) return;
Doug Zongker02ec6b82012-08-22 17:26:40 -0700134
Doug Zongker16f97c32014-03-06 16:16:05 -0800135 unsigned char* src_p = icon->data;
136 unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
Doug Zongker02ec6b82012-08-22 17:26:40 -0700137
Doug Zongker16f97c32014-03-06 16:16:05 -0800138 text_blend(src_p, icon->row_bytes,
139 dst_p, gr_draw->row_bytes,
140 icon->width, icon->height);
141}
142
143void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
144{
Tony Kuofd778e32015-02-05 21:25:56 +0800145#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
146 gr_current_r = b;
147 gr_current_g = g;
148 gr_current_b = r;
149 gr_current_a = a;
150#else
Doug Zongker16f97c32014-03-06 16:16:05 -0800151 gr_current_r = r;
152 gr_current_g = g;
153 gr_current_b = b;
154 gr_current_a = a;
Tony Kuofd778e32015-02-05 21:25:56 +0800155#endif
Doug Zongker16f97c32014-03-06 16:16:05 -0800156}
157
158void gr_clear()
159{
Elliott Hughes01a4d082015-03-24 15:21:48 -0700160 if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) {
Doug Zongker16f97c32014-03-06 16:16:05 -0800161 memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes);
162 } else {
Doug Zongker16f97c32014-03-06 16:16:05 -0800163 unsigned char* px = gr_draw->data;
Elliott Hughes01a4d082015-03-24 15:21:48 -0700164 for (int y = 0; y < gr_draw->height; ++y) {
165 for (int x = 0; x < gr_draw->width; ++x) {
Doug Zongker16f97c32014-03-06 16:16:05 -0800166 *px++ = gr_current_r;
167 *px++ = gr_current_g;
168 *px++ = gr_current_b;
169 px++;
170 }
171 px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes);
172 }
173 }
Doug Zongker02ec6b82012-08-22 17:26:40 -0700174}
175
Doug Zongkerc560a672012-12-18 16:31:27 -0800176void gr_fill(int x1, int y1, int x2, int y2)
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800177{
Doug Zongkerc560a672012-12-18 16:31:27 -0800178 x1 += overscan_offset_x;
179 y1 += overscan_offset_y;
180
181 x2 += overscan_offset_x;
182 y2 += overscan_offset_y;
183
Doug Zongker16f97c32014-03-06 16:16:05 -0800184 if (outside(x1, y1) || outside(x2-1, y2-1)) return;
185
186 unsigned char* p = gr_draw->data + y1 * gr_draw->row_bytes + x1 * gr_draw->pixel_bytes;
187 if (gr_current_a == 255) {
188 int x, y;
189 for (y = y1; y < y2; ++y) {
190 unsigned char* px = p;
191 for (x = x1; x < x2; ++x) {
192 *px++ = gr_current_r;
193 *px++ = gr_current_g;
194 *px++ = gr_current_b;
195 px++;
196 }
197 p += gr_draw->row_bytes;
198 }
199 } else if (gr_current_a > 0) {
200 int x, y;
201 for (y = y1; y < y2; ++y) {
202 unsigned char* px = p;
203 for (x = x1; x < x2; ++x) {
204 *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255;
205 ++px;
206 *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255;
207 ++px;
208 *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255;
209 ++px;
210 ++px;
211 }
212 p += gr_draw->row_bytes;
213 }
214 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800215}
216
Doug Zongker16f97c32014-03-06 16:16:05 -0800217void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) {
218 if (source == NULL) return;
219
220 if (gr_draw->pixel_bytes != source->pixel_bytes) {
221 printf("gr_blit: source has wrong format\n");
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800222 return;
223 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800224
Doug Zongkerc560a672012-12-18 16:31:27 -0800225 dx += overscan_offset_x;
226 dy += overscan_offset_y;
227
Doug Zongker16f97c32014-03-06 16:16:05 -0800228 if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return;
229
230 unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes;
231 unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes;
232
233 int i;
234 for (i = 0; i < h; ++i) {
235 memcpy(dst_p, src_p, w * source->pixel_bytes);
236 src_p += source->row_bytes;
237 dst_p += gr_draw->row_bytes;
238 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800239}
240
Doug Zongker16f97c32014-03-06 16:16:05 -0800241unsigned int gr_get_width(GRSurface* surface) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800242 if (surface == NULL) {
243 return 0;
244 }
Doug Zongker16f97c32014-03-06 16:16:05 -0800245 return surface->width;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800246}
247
Doug Zongker16f97c32014-03-06 16:16:05 -0800248unsigned int gr_get_height(GRSurface* surface) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800249 if (surface == NULL) {
250 return 0;
251 }
Doug Zongker16f97c32014-03-06 16:16:05 -0800252 return surface->height;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800253}
254
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700255int gr_init_font(const char* name, GRFont** dest) {
256 GRFont* font = reinterpret_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
257 if (font == nullptr) {
258 return -1;
259 }
260
261 int res = res_create_alpha_surface(name, &(font->texture));
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700262 if (res < 0) {
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700263 free(font);
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700264 return res;
265 }
266
267 // The font image should be a 96x2 array of character images. The
268 // columns are the printable ASCII characters 0x20 - 0x7f. The
269 // top row is regular text; the bottom row is bold.
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700270 font->char_width = font->texture->width / 96;
271 font->char_height = font->texture->height / 2;
272
273 *dest = font;
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700274
275 return 0;
276}
277
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800278static void gr_init_font(void)
279{
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700280 int res = gr_init_font("font", &gr_font);
Doug Zongker6fd59ac2013-03-06 15:01:11 -0800281 if (res == 0) {
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700282 return;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800283 }
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700284
285 printf("failed to read font: res=%d\n", res);
286
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700287
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700288 // fall back to the compiled-in font.
Rahul Chaudhryb29f23f2016-11-09 13:17:01 -0800289 gr_font = static_cast<GRFont*>(calloc(sizeof(*gr_font), 1));
290 gr_font->texture = static_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700291 gr_font->texture->width = font.width;
292 gr_font->texture->height = font.height;
293 gr_font->texture->row_bytes = font.width;
294 gr_font->texture->pixel_bytes = 1;
295
Rahul Chaudhryb29f23f2016-11-09 13:17:01 -0800296 unsigned char* bits = static_cast<unsigned char*>(malloc(font.width * font.height));
Rahul Chaudhry1cf93f52016-11-08 16:35:22 -0800297 gr_font->texture->data = bits;
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700298
299 unsigned char data;
300 unsigned char* in = font.rundata;
301 while((data = *in++)) {
302 memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
303 bits += (data & 0x7f);
304 }
305
306 gr_font->char_width = font.char_width;
307 gr_font->char_height = font.char_height;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800308}
309
Doug Zongker5290f202014-03-11 13:22:04 -0700310void gr_flip() {
311 gr_draw = gr_backend->flip(gr_backend);
312}
313
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800314int gr_init(void)
315{
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800316 gr_init_font();
Doug Zongker16f97c32014-03-06 16:16:05 -0800317
Greg Hackmann41909dd2014-04-25 10:39:50 -0700318 gr_backend = open_adf();
319 if (gr_backend) {
320 gr_draw = gr_backend->init(gr_backend);
321 if (!gr_draw) {
322 gr_backend->exit(gr_backend);
323 }
324 }
325
326 if (!gr_draw) {
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700327 gr_backend = open_drm();
328 gr_draw = gr_backend->init(gr_backend);
329 }
330
331 if (!gr_draw) {
Greg Hackmann41909dd2014-04-25 10:39:50 -0700332 gr_backend = open_fbdev();
333 gr_draw = gr_backend->init(gr_backend);
334 if (gr_draw == NULL) {
335 return -1;
336 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800337 }
338
Doug Zongker5290f202014-03-11 13:22:04 -0700339 overscan_offset_x = gr_draw->width * overscan_percent / 100;
340 overscan_offset_y = gr_draw->height * overscan_percent / 100;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800341
Doug Zongker16f97c32014-03-06 16:16:05 -0800342 gr_flip();
343 gr_flip();
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800344
345 return 0;
346}
347
348void gr_exit(void)
349{
Doug Zongker5290f202014-03-11 13:22:04 -0700350 gr_backend->exit(gr_backend);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800351}
352
353int gr_fb_width(void)
354{
Doug Zongker16f97c32014-03-06 16:16:05 -0800355 return gr_draw->width - 2*overscan_offset_x;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800356}
357
358int gr_fb_height(void)
359{
Doug Zongker16f97c32014-03-06 16:16:05 -0800360 return gr_draw->height - 2*overscan_offset_y;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800361}
Dima Zavin4daf48a2011-08-30 11:59:20 -0700362
363void gr_fb_blank(bool blank)
364{
Doug Zongker5290f202014-03-11 13:22:04 -0700365 gr_backend->blank(gr_backend, blank);
Dima Zavin4daf48a2011-08-30 11:59:20 -0700366}