1 /* 2 * Common font-related functions. 3 * 4 * Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <stdlib.h> 21 22 #include "display.h" 23 #include "font.h" 24 25 26 27 /* Space is a special case. */ 28 29 static char_definition_t space = { 30 .width = 3, .height = 9, .data = {0, 0, 0, 0, 0, 0, 0, 0, 0} 31 }; 32 33 34 35 /* Initialise a font configuration. */ 36 37 void init_font(font_config_t *cfg, uint8_t *chars, uint32_t *table, 38 uint32_t base, uint32_t limit) 39 { 40 cfg->chars = (char_definition_t *) chars; 41 cfg->table = table; 42 cfg->base = base; 43 cfg->limit = limit; 44 } 45 46 47 48 /* Return the character definition for the given character. */ 49 50 char_definition_t *get_char_definition(font_config_t *fcfg, char c) 51 { 52 /* Obtain the offset from the table and combine it with the character 53 definitions base address. */ 54 55 if ((c >= fcfg->base) && (c < fcfg->limit)) 56 return (char_definition_t *) ((uint8_t *) fcfg->chars + fcfg->table[c - fcfg->base]); 57 else 58 return &space; 59 } 60 61 /* Write a character to the screen, returning the next character position. */ 62 63 int write_char(display_config_t *cfg, font_config_t *fcfg, char c, 64 int x, int y, uint8_t colour) 65 { 66 int sy, dx, dy; 67 char_definition_t *chardef = get_char_definition(fcfg, c); 68 uint8_t *imagerow = chardef->data, 69 *displayline = cfg->screen_start + y * cfg->line_length, 70 bitmap, mask; 71 72 for (sy = 0, dy = y; (sy < chardef->height) && (dy < cfg->line_count); sy++, dy++) 73 { 74 if (displayline >= cfg->screen_limit) 75 displayline -= cfg->screen_size; 76 77 bitmap = *imagerow; 78 79 for (dx = x, mask = 1 << (chardef->width - 1); (mask) && (dx < cfg->line_length); dx++, mask >>= 1) 80 { 81 if (bitmap & mask) 82 displayline[display_get_position(cfg, dx)] = colour; 83 } 84 85 imagerow += 1; 86 displayline += cfg->line_length; 87 } 88 89 return x + chardef->width; 90 } 91 92 /* Write a string to the screen, updating the coordinates to indicate the next 93 character position. */ 94 95 void write_string(display_config_t *cfg, font_config_t *fcfg, const char *s, 96 int *x, int *y, uint8_t colour) 97 { 98 const int line_height = 9; 99 100 while (*s) 101 { 102 if (*x + get_char_definition(fcfg, *s)->width > cfg->line_length) 103 { 104 *x = 0; *y += line_height; 105 } 106 107 if (*y + line_height >= cfg->line_count) 108 break; 109 110 *x = write_char(cfg, fcfg, *s, *x, *y, colour); 111 s++; 112 } 113 }