blob: 3bdc33fd1811966786c692330c95c2088130507e [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
Tao Bao557fa1f2017-02-07 12:51:00 -080023#include <memory>
24
Doug Zongker6fd59ac2013-03-06 15:01:11 -080025#include "font_10x18.h"
Tao Bao557fa1f2017-02-07 12:51:00 -080026#include "graphics_adf.h"
27#include "graphics_drm.h"
28#include "graphics_fbdev.h"
Tao Bao0ecbd762017-01-16 21:16:58 -080029#include "minui/minui.h"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080030
Doug Zongker16f97c32014-03-06 16:16:05 -080031static GRFont* gr_font = NULL;
Tao Bao557fa1f2017-02-07 12:51:00 -080032static MinuiBackend* gr_backend = nullptr;
Doug Zongker16f97c32014-03-06 16:16:05 -080033
Doug Zongkerc560a672012-12-18 16:31:27 -080034static int overscan_percent = OVERSCAN_PERCENT;
35static int overscan_offset_x = 0;
36static int overscan_offset_y = 0;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080037
Doug Zongker16f97c32014-03-06 16:16:05 -080038static unsigned char gr_current_r = 255;
39static unsigned char gr_current_g = 255;
40static unsigned char gr_current_b = 255;
41static unsigned char gr_current_a = 255;
42
Doug Zongker5290f202014-03-11 13:22:04 -070043static GRSurface* gr_draw = NULL;
Doug Zongker16f97c32014-03-06 16:16:05 -080044
45static bool outside(int x, int y)
46{
47 return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
48}
49
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070050const GRFont* gr_sys_font()
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080051{
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070052 return gr_font;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080053}
54
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070055int gr_measure(const GRFont* font, const char *s)
Dima Zavin3c7f00e2011-08-30 11:58:24 -070056{
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070057 return font->char_width * strlen(s);
58}
59
60void gr_font_size(const GRFont* font, int *x, int *y)
61{
62 *x = font->char_width;
63 *y = font->char_height;
Dima Zavin3c7f00e2011-08-30 11:58:24 -070064}
65
Doug Zongker16f97c32014-03-06 16:16:05 -080066static void text_blend(unsigned char* src_p, int src_row_bytes,
67 unsigned char* dst_p, int dst_row_bytes,
68 int width, int height)
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080069{
Elliott Hughes01a4d082015-03-24 15:21:48 -070070 for (int j = 0; j < height; ++j) {
Doug Zongker16f97c32014-03-06 16:16:05 -080071 unsigned char* sx = src_p;
72 unsigned char* px = dst_p;
Elliott Hughes01a4d082015-03-24 15:21:48 -070073 for (int i = 0; i < width; ++i) {
Doug Zongker16f97c32014-03-06 16:16:05 -080074 unsigned char a = *sx++;
75 if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255;
76 if (a == 255) {
77 *px++ = gr_current_r;
78 *px++ = gr_current_g;
79 *px++ = gr_current_b;
80 px++;
81 } else if (a > 0) {
82 *px = (*px * (255-a) + gr_current_r * a) / 255;
83 ++px;
84 *px = (*px * (255-a) + gr_current_g * a) / 255;
85 ++px;
86 *px = (*px * (255-a) + gr_current_b * a) / 255;
87 ++px;
88 ++px;
89 } else {
90 px += 4;
91 }
92 }
93 src_p += src_row_bytes;
94 dst_p += dst_row_bytes;
95 }
96}
97
Damien Bargiacchid5d34d72016-08-11 15:57:03 -070098void gr_text(const GRFont* font, int x, int y, const char *s, bool bold)
Doug Zongker16f97c32014-03-06 16:16:05 -080099{
Elliott Hughes01a4d082015-03-24 15:21:48 -0700100 if (!font->texture || gr_current_a == 0) return;
Doug Zongker55a36ac2013-03-04 15:49:02 -0800101
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700102 bold = bold && (font->texture->height != font->char_height);
Doug Zongker6fd59ac2013-03-06 15:01:11 -0800103
Doug Zongkerc560a672012-12-18 16:31:27 -0800104 x += overscan_offset_x;
105 y += overscan_offset_y;
106
Elliott Hughes01a4d082015-03-24 15:21:48 -0700107 unsigned char ch;
108 while ((ch = *s++)) {
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700109 if (outside(x, y) || outside(x+font->char_width-1, y+font->char_height-1)) break;
Doug Zongker16f97c32014-03-06 16:16:05 -0800110
Elliott Hughes01a4d082015-03-24 15:21:48 -0700111 if (ch < ' ' || ch > '~') {
112 ch = '?';
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800113 }
Elliott Hughes01a4d082015-03-24 15:21:48 -0700114
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700115 unsigned char* src_p = font->texture->data + ((ch - ' ') * font->char_width) +
116 (bold ? font->char_height * font->texture->row_bytes : 0);
Elliott Hughes01a4d082015-03-24 15:21:48 -0700117 unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
118
119 text_blend(src_p, font->texture->row_bytes,
120 dst_p, gr_draw->row_bytes,
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700121 font->char_width, font->char_height);
Elliott Hughes01a4d082015-03-24 15:21:48 -0700122
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700123 x += font->char_width;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800124 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800125}
126
Doug Zongker16f97c32014-03-06 16:16:05 -0800127void gr_texticon(int x, int y, GRSurface* icon) {
128 if (icon == NULL) return;
129
130 if (icon->pixel_bytes != 1) {
131 printf("gr_texticon: source has wrong format\n");
Doug Zongker52eeea4f2012-09-04 14:28:25 -0700132 return;
133 }
Doug Zongker02ec6b82012-08-22 17:26:40 -0700134
Doug Zongkerc560a672012-12-18 16:31:27 -0800135 x += overscan_offset_x;
136 y += overscan_offset_y;
137
Doug Zongker16f97c32014-03-06 16:16:05 -0800138 if (outside(x, y) || outside(x+icon->width-1, y+icon->height-1)) return;
Doug Zongker02ec6b82012-08-22 17:26:40 -0700139
Doug Zongker16f97c32014-03-06 16:16:05 -0800140 unsigned char* src_p = icon->data;
141 unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
Doug Zongker02ec6b82012-08-22 17:26:40 -0700142
Doug Zongker16f97c32014-03-06 16:16:05 -0800143 text_blend(src_p, icon->row_bytes,
144 dst_p, gr_draw->row_bytes,
145 icon->width, icon->height);
146}
147
148void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
149{
Tony Kuofd778e32015-02-05 21:25:56 +0800150#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
151 gr_current_r = b;
152 gr_current_g = g;
153 gr_current_b = r;
154 gr_current_a = a;
155#else
Doug Zongker16f97c32014-03-06 16:16:05 -0800156 gr_current_r = r;
157 gr_current_g = g;
158 gr_current_b = b;
159 gr_current_a = a;
Tony Kuofd778e32015-02-05 21:25:56 +0800160#endif
Doug Zongker16f97c32014-03-06 16:16:05 -0800161}
162
163void gr_clear()
164{
Elliott Hughes01a4d082015-03-24 15:21:48 -0700165 if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) {
Doug Zongker16f97c32014-03-06 16:16:05 -0800166 memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes);
167 } else {
Doug Zongker16f97c32014-03-06 16:16:05 -0800168 unsigned char* px = gr_draw->data;
Elliott Hughes01a4d082015-03-24 15:21:48 -0700169 for (int y = 0; y < gr_draw->height; ++y) {
170 for (int x = 0; x < gr_draw->width; ++x) {
Doug Zongker16f97c32014-03-06 16:16:05 -0800171 *px++ = gr_current_r;
172 *px++ = gr_current_g;
173 *px++ = gr_current_b;
174 px++;
175 }
176 px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes);
177 }
178 }
Doug Zongker02ec6b82012-08-22 17:26:40 -0700179}
180
Doug Zongkerc560a672012-12-18 16:31:27 -0800181void gr_fill(int x1, int y1, int x2, int y2)
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800182{
Doug Zongkerc560a672012-12-18 16:31:27 -0800183 x1 += overscan_offset_x;
184 y1 += overscan_offset_y;
185
186 x2 += overscan_offset_x;
187 y2 += overscan_offset_y;
188
Doug Zongker16f97c32014-03-06 16:16:05 -0800189 if (outside(x1, y1) || outside(x2-1, y2-1)) return;
190
191 unsigned char* p = gr_draw->data + y1 * gr_draw->row_bytes + x1 * gr_draw->pixel_bytes;
192 if (gr_current_a == 255) {
193 int x, y;
194 for (y = y1; y < y2; ++y) {
195 unsigned char* px = p;
196 for (x = x1; x < x2; ++x) {
197 *px++ = gr_current_r;
198 *px++ = gr_current_g;
199 *px++ = gr_current_b;
200 px++;
201 }
202 p += gr_draw->row_bytes;
203 }
204 } else if (gr_current_a > 0) {
205 int x, y;
206 for (y = y1; y < y2; ++y) {
207 unsigned char* px = p;
208 for (x = x1; x < x2; ++x) {
209 *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255;
210 ++px;
211 *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255;
212 ++px;
213 *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255;
214 ++px;
215 ++px;
216 }
217 p += gr_draw->row_bytes;
218 }
219 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800220}
221
Doug Zongker16f97c32014-03-06 16:16:05 -0800222void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) {
223 if (source == NULL) return;
224
225 if (gr_draw->pixel_bytes != source->pixel_bytes) {
226 printf("gr_blit: source has wrong format\n");
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800227 return;
228 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800229
Doug Zongkerc560a672012-12-18 16:31:27 -0800230 dx += overscan_offset_x;
231 dy += overscan_offset_y;
232
Doug Zongker16f97c32014-03-06 16:16:05 -0800233 if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return;
234
235 unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes;
236 unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes;
237
238 int i;
239 for (i = 0; i < h; ++i) {
240 memcpy(dst_p, src_p, w * source->pixel_bytes);
241 src_p += source->row_bytes;
242 dst_p += gr_draw->row_bytes;
243 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800244}
245
Doug Zongker16f97c32014-03-06 16:16:05 -0800246unsigned int gr_get_width(GRSurface* surface) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800247 if (surface == NULL) {
248 return 0;
249 }
Doug Zongker16f97c32014-03-06 16:16:05 -0800250 return surface->width;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800251}
252
Doug Zongker16f97c32014-03-06 16:16:05 -0800253unsigned int gr_get_height(GRSurface* surface) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800254 if (surface == NULL) {
255 return 0;
256 }
Doug Zongker16f97c32014-03-06 16:16:05 -0800257 return surface->height;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800258}
259
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700260int gr_init_font(const char* name, GRFont** dest) {
261 GRFont* font = reinterpret_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
262 if (font == nullptr) {
263 return -1;
264 }
265
266 int res = res_create_alpha_surface(name, &(font->texture));
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700267 if (res < 0) {
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700268 free(font);
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700269 return res;
270 }
271
272 // The font image should be a 96x2 array of character images. The
273 // columns are the printable ASCII characters 0x20 - 0x7f. The
274 // top row is regular text; the bottom row is bold.
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700275 font->char_width = font->texture->width / 96;
276 font->char_height = font->texture->height / 2;
277
278 *dest = font;
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700279
280 return 0;
281}
282
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800283static void gr_init_font(void)
284{
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700285 int res = gr_init_font("font", &gr_font);
Doug Zongker6fd59ac2013-03-06 15:01:11 -0800286 if (res == 0) {
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700287 return;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800288 }
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700289
290 printf("failed to read font: res=%d\n", res);
291
Damien Bargiacchi97eda9d2016-09-09 07:14:08 -0700292
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700293 // fall back to the compiled-in font.
Rahul Chaudhryb29f23f2016-11-09 13:17:01 -0800294 gr_font = static_cast<GRFont*>(calloc(sizeof(*gr_font), 1));
295 gr_font->texture = static_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700296 gr_font->texture->width = font.width;
297 gr_font->texture->height = font.height;
298 gr_font->texture->row_bytes = font.width;
299 gr_font->texture->pixel_bytes = 1;
300
Rahul Chaudhryb29f23f2016-11-09 13:17:01 -0800301 unsigned char* bits = static_cast<unsigned char*>(malloc(font.width * font.height));
Rahul Chaudhry1cf93f52016-11-08 16:35:22 -0800302 gr_font->texture->data = bits;
Damien Bargiacchid5d34d72016-08-11 15:57:03 -0700303
304 unsigned char data;
305 unsigned char* in = font.rundata;
306 while((data = *in++)) {
307 memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
308 bits += (data & 0x7f);
309 }
310
311 gr_font->char_width = font.char_width;
312 gr_font->char_height = font.char_height;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800313}
314
Doug Zongker5290f202014-03-11 13:22:04 -0700315void gr_flip() {
Tao Bao557fa1f2017-02-07 12:51:00 -0800316 gr_draw = gr_backend->Flip();
Doug Zongker5290f202014-03-11 13:22:04 -0700317}
318
Tao Bao557fa1f2017-02-07 12:51:00 -0800319int gr_init() {
320 gr_init_font();
Doug Zongker16f97c32014-03-06 16:16:05 -0800321
Tao Bao557fa1f2017-02-07 12:51:00 -0800322 auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendAdf>() };
323 gr_draw = backend->Init();
Greg Hackmann41909dd2014-04-25 10:39:50 -0700324
Tao Bao557fa1f2017-02-07 12:51:00 -0800325 if (!gr_draw) {
326 backend = std::make_unique<MinuiBackendDrm>();
327 gr_draw = backend->Init();
328 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700329
Tao Bao557fa1f2017-02-07 12:51:00 -0800330 if (!gr_draw) {
331 backend = std::make_unique<MinuiBackendFbdev>();
332 gr_draw = backend->Init();
333 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800334
Tao Bao557fa1f2017-02-07 12:51:00 -0800335 if (!gr_draw) {
336 return -1;
337 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800338
Tao Bao557fa1f2017-02-07 12:51:00 -0800339 gr_backend = backend.release();
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800340
Tao Bao557fa1f2017-02-07 12:51:00 -0800341 overscan_offset_x = gr_draw->width * overscan_percent / 100;
342 overscan_offset_y = gr_draw->height * overscan_percent / 100;
343
344 gr_flip();
345 gr_flip();
346
347 return 0;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800348}
349
Tao Bao557fa1f2017-02-07 12:51:00 -0800350void gr_exit() {
351 delete gr_backend;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800352}
353
Tao Bao557fa1f2017-02-07 12:51:00 -0800354int gr_fb_width() {
355 return gr_draw->width - 2 * overscan_offset_x;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800356}
357
Tao Bao557fa1f2017-02-07 12:51:00 -0800358int gr_fb_height() {
359 return gr_draw->height - 2 * overscan_offset_y;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800360}
Dima Zavin4daf48a2011-08-30 11:59:20 -0700361
Tao Bao557fa1f2017-02-07 12:51:00 -0800362void gr_fb_blank(bool blank) {
363 gr_backend->Blank(blank);
Dima Zavin4daf48a2011-08-30 11:59:20 -0700364}