Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,319 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/stream.h"
#include "common/memstream.h"
#include "common/textconsole.h"
#include "graphics/surface.h"
#include "graphics/fonts/amigafont.h"
namespace Graphics {
// For the data source and license look into gui/themes/fonts/topaz in ScummVM distribution
static const byte amigaTopazFont[2600] = {
0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79,
0x70, 0xff, 0x4e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x00, 0x1a, 0x0f, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x45, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x74, 0x00, 0x08,
0x00, 0x40, 0x00, 0x08, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x00, 0x6e,
0x00, 0xbe, 0x00, 0x00, 0x06, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x6c, 0x6c, 0x18, 0x00, 0x38, 0x18, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x18,
0x3c, 0x3c, 0x1c, 0x7e, 0x1c, 0x7e, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7c, 0x3c,
0x7c, 0x1e, 0x78, 0x7e, 0x7e, 0x3c, 0x66, 0x3c, 0x06, 0xc6, 0x60, 0xc6, 0xc6, 0x3c, 0x7c, 0x78,
0x7c, 0x3c, 0x7e, 0x66, 0x66, 0xc6, 0xc3, 0xc3, 0xfe, 0x3c, 0xc0, 0x3c, 0x10, 0x00, 0x18, 0x00,
0x60, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x60, 0x18, 0x0c, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x18, 0x70, 0x72, 0x0f, 0x00, 0x18,
0x00, 0x1c, 0x42, 0xc3, 0x18, 0x3c, 0x66, 0x7e, 0x1c, 0x00, 0x3e, 0x7e, 0x7e, 0x3c, 0x18, 0x78,
0x78, 0x18, 0x00, 0x3e, 0x00, 0x00, 0x30, 0x38, 0x00, 0x40, 0x40, 0xc0, 0x18, 0x3c, 0x3c, 0x7e,
0x06, 0x66, 0x18, 0x7e, 0x7e, 0x36, 0x0c, 0x0c, 0x18, 0x3c, 0xc6, 0x3c, 0x60, 0x76, 0x18, 0x00,
0x0c, 0x7e, 0x71, 0x66, 0x00, 0x66, 0x60, 0x0e, 0x7e, 0x66, 0x18, 0x6e, 0x3c, 0x00, 0x18, 0x7e,
0x06, 0x66, 0x18, 0x00, 0x7e, 0x34, 0x0c, 0x0c, 0x18, 0x0c, 0x60, 0x00, 0x18, 0x3c, 0x0c, 0x00,
0x0c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x7e, 0x00, 0x18, 0x3c, 0x00, 0x18, 0x6c, 0x6c,
0x3e, 0x66, 0x6c, 0x18, 0x18, 0x18, 0x66, 0x18, 0x00, 0x00, 0x00, 0x06, 0x66, 0x38, 0x66, 0x66,
0x3c, 0x60, 0x30, 0x06, 0x66, 0x66, 0x18, 0x18, 0x06, 0x00, 0x60, 0x66, 0xc6, 0x66, 0x66, 0x30,
0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x06, 0xcc, 0x60, 0xee, 0xe6, 0x66, 0x66, 0xcc, 0x66, 0x66,
0x18, 0x66, 0x66, 0xc6, 0x66, 0x66, 0x0c, 0x30, 0x60, 0x0c, 0x38, 0x00, 0x18, 0x00, 0x60, 0x00,
0x06, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x9c, 0x3c, 0x7e, 0x00, 0x0c, 0x36,
0x3c, 0x66, 0x18, 0x60, 0x66, 0x81, 0x24, 0x33, 0x06, 0x81, 0x00, 0x66, 0x18, 0x0c, 0x0c, 0x30,
0x00, 0x7a, 0x00, 0x00, 0x70, 0x44, 0xcc, 0xc6, 0xc6, 0x23, 0x00, 0x66, 0x18, 0x00, 0x1c, 0x00,
0x24, 0x60, 0x00, 0x1c, 0x18, 0x18, 0x00, 0x66, 0xcc, 0x00, 0x60, 0x3c, 0x30, 0xc6, 0x18, 0x00,
0x8e, 0x00, 0xc6, 0x66, 0x60, 0x38, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x0c, 0x00,
0x24, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x7e,
0x8e, 0x66, 0x18, 0x00, 0x18, 0x18, 0x00, 0x66, 0x00, 0x18, 0x00, 0x18, 0x00, 0xfe, 0x60, 0xac,
0x68, 0x30, 0x30, 0x0c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x78, 0x06, 0x06, 0x6c, 0x7c,
0x60, 0x06, 0x66, 0x66, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x06, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60,
0x60, 0x60, 0x66, 0x18, 0x06, 0xd8, 0x60, 0xfe, 0xf6, 0x66, 0x66, 0xcc, 0x66, 0x70, 0x18, 0x66,
0x66, 0xc6, 0x3c, 0x3c, 0x18, 0x30, 0x30, 0x0c, 0x6c, 0x00, 0x0c, 0x3c, 0x7c, 0x3c, 0x3e, 0x3c,
0x7c, 0x3e, 0x7c, 0x18, 0x0c, 0x66, 0x18, 0xec, 0x7c, 0x3c, 0x7c, 0x3e, 0x7c, 0x3c, 0x7c, 0x66,
0x66, 0xc6, 0xc6, 0x66, 0x7e, 0x18, 0x18, 0x18, 0x00, 0xf0, 0x66, 0x18, 0x3e, 0x30, 0x66, 0x3c,
0x18, 0x3c, 0x00, 0x9d, 0x44, 0x66, 0x00, 0xb9, 0x00, 0x3c, 0x7e, 0x18, 0x18, 0x60, 0x66, 0x7a,
0x18, 0x00, 0x30, 0x44, 0x66, 0x4c, 0x4c, 0x66, 0x18, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x60,
0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x60, 0xd8, 0x3c, 0x60, 0x66, 0xc6, 0xe6, 0x3c, 0x3c, 0x3c, 0x3c,
0x6c, 0x66, 0x6c, 0x66, 0x66, 0x66, 0x7e, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0x3c, 0x3c, 0x3c,
0x3c, 0x18, 0x3c, 0x7e, 0x3c, 0x3e, 0x6c, 0x00, 0x18, 0x3c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x66, 0x1e, 0x3c, 0x66, 0x00, 0x7e, 0x7e, 0x00, 0x18, 0x00, 0x6c, 0x3c, 0xd8, 0x76, 0x00,
0x30, 0x0c, 0xff, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x7e, 0x18, 0x0c, 0x1c, 0xcc, 0x06, 0x7c, 0x0c,
0x3c, 0x3e, 0x00, 0x00, 0x60, 0x00, 0x06, 0x0c, 0xd6, 0x7e, 0x7c, 0x60, 0x66, 0x78, 0x78, 0x6e,
0x7e, 0x18, 0x06, 0xf0, 0x60, 0xd6, 0xde, 0x66, 0x7c, 0xcc, 0x7c, 0x3c, 0x18, 0x66, 0x66, 0xd6,
0x18, 0x18, 0x30, 0x30, 0x18, 0x0c, 0xc6, 0x00, 0x00, 0x06, 0x66, 0x60, 0x66, 0x66, 0x30, 0x66,
0x66, 0x18, 0x0c, 0x6c, 0x18, 0xfe, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x30, 0x66, 0x66, 0xc6,
0x6c, 0x66, 0x0c, 0x70, 0x18, 0x0e, 0x00, 0xc3, 0x66, 0x18, 0x6c, 0x78, 0x3c, 0x18, 0x00, 0x66,
0x00, 0xb1, 0x3c, 0xcc, 0x00, 0xa5, 0x00, 0x00, 0x18, 0x30, 0x0c, 0x00, 0x66, 0x3a, 0x18, 0x00,
0x30, 0x38, 0x33, 0x58, 0x58, 0x2c, 0x30, 0x7e, 0x18, 0x66, 0x66, 0x66, 0x66, 0x78, 0x60, 0x66,
0x60, 0x4c, 0x60, 0x6e, 0xf0, 0x18, 0x60, 0x30, 0xe6, 0xf6, 0x66, 0x66, 0x66, 0x66, 0x38, 0x66,
0x70, 0x30, 0x66, 0x66, 0x4c, 0x4c, 0x6c, 0x06, 0x18, 0x06, 0x3c, 0x06, 0x06, 0x66, 0x66, 0x3c,
0x66, 0x0c, 0x66, 0x66, 0x78, 0x18, 0x18, 0x60, 0x7c, 0x66, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x66,
0x78, 0x60, 0x66, 0x66, 0x0c, 0x0c, 0x00, 0x18, 0x00, 0xfe, 0x06, 0x36, 0xdc, 0x00, 0x30, 0x0c,
0x3c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x76, 0x18, 0x18, 0x06, 0xfe, 0x06, 0x66, 0x18, 0x66, 0x06,
0x00, 0x00, 0x18, 0x7e, 0x18, 0x18, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60, 0x60, 0x66, 0x66, 0x18,
0x06, 0xd8, 0x60, 0xc6, 0xce, 0x66, 0x60, 0xcc, 0x6c, 0x0e, 0x18, 0x66, 0x3c, 0xfe, 0x3c, 0x18,
0x60, 0x30, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x60, 0x66, 0x7e, 0x30, 0x66, 0x66, 0x18,
0x0c, 0x78, 0x18, 0xd6, 0x66, 0x66, 0x66, 0x66, 0x60, 0x3c, 0x30, 0x66, 0x66, 0xd6, 0x38, 0x66,
0x18, 0x18, 0x18, 0x18, 0x00, 0x0f, 0x66, 0x18, 0x3e, 0x30, 0x42, 0x3c, 0x18, 0x3c, 0x00, 0x9d,
0x00, 0x66, 0x00, 0xb9, 0x00, 0x00, 0x18, 0x7c, 0x78, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x30, 0x00,
0x66, 0x32, 0x3e, 0xd9, 0x60, 0x66, 0x18, 0x7e, 0x40, 0x7e, 0x7e, 0x60, 0x78, 0x40, 0x78, 0x18,
0x78, 0x66, 0xd8, 0x18, 0x60, 0x0c, 0xf6, 0xde, 0x66, 0x66, 0x66, 0x66, 0x6c, 0x66, 0xe0, 0x0c,
0x66, 0x66, 0x18, 0x18, 0x66, 0x3e, 0x18, 0x3e, 0x60, 0x3e, 0x3e, 0x7e, 0x7e, 0x60, 0x7e, 0x18,
0x7e, 0x66, 0x6c, 0x18, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x18, 0x3c,
0x66, 0x66, 0x18, 0x18, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x6a, 0xce, 0x00, 0x18, 0x18, 0x66, 0x18,
0x18, 0x00, 0x18, 0x60, 0x66, 0x18, 0x30, 0x66, 0x0c, 0x66, 0x66, 0x18, 0x66, 0x0c, 0x18, 0x18,
0x06, 0x00, 0x60, 0x00, 0xc0, 0x66, 0x66, 0x30, 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x66, 0xcc,
0x60, 0xc6, 0xc6, 0x66, 0x60, 0xdc, 0x66, 0x66, 0x18, 0x66, 0x3c, 0xee, 0x66, 0x18, 0xc0, 0x30,
0x06, 0x0c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x60, 0x66, 0x60, 0x30, 0x3e, 0x66, 0x18, 0x0c, 0x6c,
0x18, 0xc6, 0x66, 0x66, 0x7c, 0x3e, 0x60, 0x06, 0x30, 0x66, 0x3c, 0xfe, 0x6c, 0x3c, 0x30, 0x18,
0x18, 0x18, 0x00, 0x3c, 0x66, 0x18, 0x0c, 0x30, 0x00, 0x18, 0x18, 0x06, 0x00, 0x81, 0x7e, 0x33,
0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x00, 0x7c, 0xcc, 0x66,
0x62, 0x33, 0x66, 0x66, 0x18, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0x66, 0x60, 0x32, 0x60, 0x3e,
0xcc, 0x18, 0x7e, 0x66, 0xde, 0xce, 0x66, 0x66, 0x66, 0x66, 0xc6, 0x66, 0x60, 0x66, 0x66, 0x66,
0x32, 0x32, 0x66, 0x66, 0x18, 0x66, 0x60, 0x66, 0x66, 0x60, 0x60, 0x60, 0x60, 0x30, 0x60, 0x3e,
0x66, 0x18, 0x18, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x18, 0x66, 0x18, 0x06, 0x66, 0x66,
0x30, 0x30, 0x00, 0x18, 0x00, 0x6c, 0x18, 0xcc, 0x7b, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x18, 0x00,
0x18, 0xc0, 0x3c, 0x18, 0x7e, 0x3c, 0x0c, 0x3c, 0x3c, 0x18, 0x3c, 0x38, 0x18, 0x18, 0x00, 0x00,
0x00, 0x18, 0x78, 0x66, 0x7c, 0x1e, 0x78, 0x7e, 0x60, 0x3e, 0x66, 0x3c, 0x3c, 0xc6, 0x7e, 0xc6,
0xc6, 0x3c, 0x60, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0xc6, 0xc3, 0x18, 0xfe, 0x3c, 0x03, 0x3c,
0x00, 0x00, 0x00, 0x3e, 0x7c, 0x3c, 0x3e, 0x3c, 0x30, 0x06, 0x66, 0x0c, 0x0c, 0x66, 0x0c, 0xc6,
0x66, 0x3c, 0x60, 0x06, 0x60, 0x7c, 0x1c, 0x3e, 0x18, 0x6c, 0xc6, 0x18, 0x7e, 0x0e, 0x18, 0x70,
0x00, 0xf0, 0x7e, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x3c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x81,
0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00, 0xcf, 0xc4, 0x67,
0x3c, 0x67, 0x3e, 0x66, 0x3c, 0x66, 0x66, 0x7f, 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x18, 0x30, 0x3c,
0x18, 0x3c, 0xce, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x7e, 0x3c, 0x3c, 0x3c, 0x7e, 0x7e,
0x6c, 0x3f, 0x1e, 0x3e, 0x3c, 0x3e, 0x3e, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x3c, 0x06, 0x18, 0x0c,
0x0c, 0x7c, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x0c, 0x7c, 0x3e, 0x3e, 0x7e, 0x7e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x01, 0x00, 0x03,
0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x00, 0x30, 0x00,
0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03,
0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x18, 0x00,
0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x18, 0x00, 0x08, 0x00, 0x20,
0x00, 0x08, 0x00, 0x28, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x00, 0x40,
0x00, 0x08, 0x00, 0x48, 0x00, 0x08, 0x00, 0x50, 0x00, 0x08, 0x00, 0x58, 0x00, 0x08, 0x00, 0x60,
0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x00, 0x70, 0x00, 0x08, 0x00, 0x78, 0x00, 0x08, 0x00, 0x80,
0x00, 0x08, 0x00, 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0x98, 0x00, 0x08, 0x00, 0xa0,
0x00, 0x08, 0x00, 0xa8, 0x00, 0x08, 0x00, 0xb0, 0x00, 0x08, 0x00, 0xb8, 0x00, 0x08, 0x00, 0xc0,
0x00, 0x08, 0x00, 0xc8, 0x00, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x00, 0xd8, 0x00, 0x08, 0x00, 0xe0,
0x00, 0x08, 0x00, 0xe8, 0x00, 0x08, 0x00, 0xf0, 0x00, 0x08, 0x00, 0xf8, 0x00, 0x08, 0x01, 0x00,
0x00, 0x08, 0x01, 0x08, 0x00, 0x08, 0x01, 0x10, 0x00, 0x08, 0x01, 0x18, 0x00, 0x08, 0x01, 0x20,
0x00, 0x08, 0x01, 0x28, 0x00, 0x08, 0x01, 0x30, 0x00, 0x08, 0x01, 0x38, 0x00, 0x08, 0x01, 0x40,
0x00, 0x08, 0x01, 0x48, 0x00, 0x08, 0x01, 0x50, 0x00, 0x08, 0x01, 0x58, 0x00, 0x08, 0x01, 0x60,
0x00, 0x08, 0x01, 0x68, 0x00, 0x08, 0x01, 0x70, 0x00, 0x08, 0x01, 0x78, 0x00, 0x08, 0x01, 0x80,
0x00, 0x08, 0x01, 0x88, 0x00, 0x08, 0x01, 0x90, 0x00, 0x08, 0x01, 0x98, 0x00, 0x08, 0x01, 0xa0,
0x00, 0x08, 0x01, 0xa8, 0x00, 0x08, 0x01, 0xb0, 0x00, 0x08, 0x01, 0xb8, 0x00, 0x08, 0x01, 0xc0,
0x00, 0x08, 0x01, 0xc8, 0x00, 0x08, 0x01, 0xd0, 0x00, 0x08, 0x01, 0xd8, 0x00, 0x08, 0x01, 0xe0,
0x00, 0x08, 0x01, 0xe8, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xf8, 0x00, 0x08, 0x02, 0x00,
0x00, 0x08, 0x02, 0x08, 0x00, 0x08, 0x02, 0x10, 0x00, 0x08, 0x02, 0x18, 0x00, 0x08, 0x02, 0x20,
0x00, 0x08, 0x02, 0x28, 0x00, 0x08, 0x02, 0x30, 0x00, 0x08, 0x02, 0x38, 0x00, 0x08, 0x02, 0x40,
0x00, 0x08, 0x02, 0x48, 0x00, 0x08, 0x02, 0x50, 0x00, 0x08, 0x02, 0x58, 0x00, 0x08, 0x02, 0x60,
0x00, 0x08, 0x02, 0x68, 0x00, 0x08, 0x02, 0x70, 0x00, 0x08, 0x02, 0x78, 0x00, 0x08, 0x02, 0x80,
0x00, 0x08, 0x02, 0x88, 0x00, 0x08, 0x02, 0x90, 0x00, 0x08, 0x02, 0x98, 0x00, 0x08, 0x02, 0xa0,
0x00, 0x08, 0x02, 0xa8, 0x00, 0x08, 0x02, 0xb0, 0x00, 0x08, 0x02, 0xb8, 0x00, 0x08, 0x02, 0xc0,
0x00, 0x08, 0x02, 0xc8, 0x00, 0x08, 0x02, 0xd0, 0x00, 0x08, 0x02, 0xd8, 0x00, 0x08, 0x02, 0xe0,
0x00, 0x08, 0x02, 0xe8, 0x00, 0x08, 0x02, 0xf0, 0x00, 0x08, 0x02, 0xf8, 0x00, 0x08, 0x03, 0x00,
0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00,
0x00, 0x08, 0x03, 0x08, 0x00, 0x08, 0x03, 0x10, 0x00, 0x08, 0x03, 0x18, 0x00, 0x08, 0x03, 0x20,
0x00, 0x08, 0x03, 0x28, 0x00, 0x08, 0x03, 0x30, 0x00, 0x08, 0x03, 0x38, 0x00, 0x08, 0x03, 0x40,
0x00, 0x08, 0x03, 0x48, 0x00, 0x08, 0x03, 0x50, 0x00, 0x08, 0x03, 0x58, 0x00, 0x08, 0x03, 0x60,
0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x03, 0x68, 0x00, 0x08, 0x03, 0x70, 0x00, 0x08, 0x03, 0x78,
0x00, 0x08, 0x03, 0x80, 0x00, 0x08, 0x03, 0x88, 0x00, 0x08, 0x03, 0x90, 0x00, 0x08, 0x03, 0x98,
0x00, 0x08, 0x03, 0xa0, 0x00, 0x08, 0x03, 0xa8, 0x00, 0x08, 0x03, 0xb0, 0x00, 0x08, 0x03, 0xb8,
0x00, 0x08, 0x03, 0xc0, 0x00, 0x08, 0x03, 0xc8, 0x00, 0x08, 0x03, 0xd0, 0x00, 0x08, 0x03, 0xd8,
0x00, 0x08, 0x03, 0xe0, 0x00, 0x08, 0x03, 0xe8, 0x00, 0x08, 0x03, 0xf0, 0x00, 0x08, 0x03, 0xf8,
0x00, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x08, 0x00, 0x08, 0x04, 0x10, 0x00, 0x08, 0x04, 0x18,
0x00, 0x08, 0x04, 0x20, 0x00, 0x08, 0x04, 0x28, 0x00, 0x08, 0x04, 0x30, 0x00, 0x08, 0x04, 0x38,
0x00, 0x08, 0x04, 0x40, 0x00, 0x08, 0x04, 0x48, 0x00, 0x08, 0x04, 0x50, 0x00, 0x08, 0x04, 0x58,
0x00, 0x08, 0x04, 0x60, 0x00, 0x08, 0x04, 0x68, 0x00, 0x08, 0x04, 0x70, 0x00, 0x08, 0x04, 0x78,
0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04, 0x88, 0x00, 0x08, 0x04, 0x90, 0x00, 0x08, 0x04, 0x98,
0x00, 0x08, 0x04, 0xa0, 0x00, 0x08, 0x04, 0xa8, 0x00, 0x08, 0x04, 0xb0, 0x00, 0x08, 0x04, 0xb8,
0x00, 0x08, 0x04, 0xc0, 0x00, 0x08, 0x04, 0xc8, 0x00, 0x08, 0x04, 0xd0, 0x00, 0x08, 0x04, 0xd8,
0x00, 0x08, 0x04, 0xe0, 0x00, 0x08, 0x04, 0xe8, 0x00, 0x08, 0x04, 0xf0, 0x00, 0x08, 0x04, 0xf8,
0x00, 0x08, 0x05, 0x00, 0x00, 0x08, 0x05, 0x08, 0x00, 0x08, 0x05, 0x10, 0x00, 0x08, 0x05, 0x18,
0x00, 0x08, 0x05, 0x20, 0x00, 0x08, 0x05, 0x28, 0x00, 0x08, 0x05, 0x30, 0x00, 0x08, 0x05, 0x38,
0x00, 0x08, 0x05, 0x40, 0x00, 0x08, 0x05, 0x48, 0x00, 0x08, 0x05, 0x50, 0x00, 0x08, 0x05, 0x58,
0x00, 0x08, 0x05, 0x60, 0x00, 0x08, 0x05, 0x68, 0x00, 0x08, 0x05, 0x70, 0x00, 0x08, 0x05, 0x78,
0x00, 0x08, 0x05, 0x80, 0x00, 0x08, 0x05, 0x88, 0x00, 0x08, 0x05, 0x90, 0x00, 0x08, 0x05, 0x98,
0x00, 0x08, 0x05, 0xa0, 0x00, 0x08, 0x05, 0xa8, 0x00, 0x08, 0x05, 0xb0, 0x00, 0x08, 0x05, 0xb8,
0x00, 0x08, 0x05, 0xc0, 0x00, 0x08, 0x05, 0xc8, 0x00, 0x08, 0x05, 0xd0, 0x00, 0x08, 0x05, 0xd8,
0x00, 0x08, 0x05, 0xe0, 0x00, 0x08, 0x05, 0xe8, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x03, 0x00,
0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf2
};
AmigaFont::AmigaFont(Common::SeekableReadStream *stream) {
Common::SeekableReadStream *tmp;
if (!stream) {
tmp = new Common::MemoryReadStream(amigaTopazFont, sizeof(amigaTopazFont), DisposeAfterUse::NO);
} else {
tmp = stream;
}
tmp->seek(32); // skips dummy header
uint dataSize = tmp->size() - tmp->pos();
_data = (byte *)malloc(dataSize);
tmp->read(_data, dataSize);
if (tmp != stream) {
delete tmp;
tmp = nullptr;
}
_font = (AmigaDiskFont *)(_data + 78);
_font->_ySize = FROM_BE_16(_font->_ySize);
_font->_xSize = FROM_BE_16(_font->_xSize);
_font->_baseline = FROM_BE_16(_font->_baseline);
_font->_modulo = FROM_BE_16(_font->_modulo);
_charLoc = (CharLoc *)(_data + FROM_BE_32(_font->_charLoc));
_charData = _data + FROM_BE_32(_font->_charData);
_charSpace = 0;
_charKern = 0;
_cp = 0;
_pitch = 0;
if (_font->_charSpace != 0)
_charSpace = (uint16 *)(_data + FROM_BE_32(_font->_charSpace));
if (_font->_charKern != 0)
_charKern = (uint16 *)(_data + FROM_BE_32(_font->_charKern));
if (_charSpace) {
_maxCharWidth = _charSpace[0];
for (int i = _font->_hiChar - _font->_loChar; i > 0 ; i--)
if (_maxCharWidth < _charSpace[i])
_maxCharWidth = _charSpace[i];
} else {
_maxCharWidth = _font->_xSize;
}
}
AmigaFont::~AmigaFont() {
free(_data);
}
int AmigaFont::getFontHeight() const {
return _font->_ySize;
}
int AmigaFont::getCharWidth(uint32 chr) const {
return (_charSpace == 0) ? _font->_xSize : FROM_BE_16(_charSpace[mapChar(chr)]);
}
int AmigaFont::getMaxCharWidth() const {
return _maxCharWidth;
}
int AmigaFont::getKerningOffset(uint32 left, uint32 right) const {
return (_charKern == 0) ? 0 : FROM_BE_16(_charKern[mapChar(right)]);
}
uint16 AmigaFont::getPixels(byte c) const {
return FROM_BE_16(_charLoc[c]._length);
}
uint16 AmigaFont::getOffset(byte c) const {
return FROM_BE_16(_charLoc[c]._offset);
}
uint32 AmigaFont::mapChar(uint32 c) const {
if (c < _font->_loChar || c > _font->_hiChar)
error("character '%c (%x)' not supported by font", c, c);
return c - _font->_loChar;
}
template<typename PixelType>
void drawCharIntern(byte *ptr, uint32 pitch, int num, int bitOffset, byte *charData, int ySize, int modulo, uint32 color) {
PixelType *d = (PixelType *)ptr;
byte *s = charData;
for (int i = 0; i < ySize; i++) {
for (int j = bitOffset; j < bitOffset + num; j++) {
byte *b = s + (j >> 3);
byte bit = *b & (0x80 >> (j & 7));
if (bit)
*d = color;
d++;
}
s += modulo;
d = (PixelType *)((byte *)d + pitch) - num;
}
}
void AmigaFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
chr = mapChar(chr);
byte *ptr = (byte *)dst->getBasePtr(x, y);
if (dst->format.bytesPerPixel == 1)
drawCharIntern<byte>(ptr, dst->pitch, getPixels(chr), getOffset(chr), _charData, _font->_ySize, _font->_modulo, color);
else if (dst->format.bytesPerPixel == 2)
drawCharIntern<uint16>(ptr, dst->pitch, getPixels(chr), getOffset(chr), _charData, _font->_ySize, _font->_modulo, color);
else if (dst->format.bytesPerPixel == 4)
drawCharIntern<uint32>(ptr, dst->pitch, getPixels(chr), getOffset(chr), _charData, _font->_ySize, _font->_modulo, color);
}
} // End of namespace Graphics

View File

@@ -0,0 +1,98 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRAPHICS_FONTS_AMIGAFONT_H
#define GRAPHICS_FONTS_AMIGAFONT_H
#include "graphics/font.h"
namespace Common {
class SeekableReadStream;
}
namespace Graphics {
class AmigaFont : public Font {
#include "common/pack-start.h"
struct CharLoc {
uint16 _offset;
uint16 _length;
};
struct AmigaDiskFont {
uint16 _ySize;
byte _style;
byte _flags;
uint16 _xSize;
uint16 _baseline;
uint16 _boldSmear;
uint16 _accessors; // unused
byte _loChar;
byte _hiChar;
uint32 _charData;
uint16 _modulo;
uint32 _charLoc;
uint32 _charSpace;
uint32 _charKern;
};
#include "common/pack-end.h"
AmigaDiskFont *_font;
byte *_data;
byte *_charData;
CharLoc *_charLoc;
uint16 *_charSpace;
uint16 *_charKern;
byte *_cp;
uint32 _pitch;
int _maxCharWidth;
private:
uint16 getPixels(byte c) const;
uint16 getOffset(byte c) const;
uint32 mapChar(uint32 c) const;
public:
/**
* Create font in Amiga format.
*
* @param stream Stream with the font data. If NULL, then the built-in
* Topaz font is used.
*/
AmigaFont(Common::SeekableReadStream *stream = NULL);
virtual ~AmigaFont();
virtual int getFontHeight() const;
virtual int getCharWidth(uint32 chr) const;
virtual int getMaxCharWidth() const;
virtual int getKerningOffset(uint32 left, uint32 right) const;
virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
int getLoChar() { return _font->_loChar; }
int getHiChar() { return _font->_hiChar; }
};
} // End of namespace Graphics
#endif

957
graphics/fonts/bdf.cpp Normal file
View File

@@ -0,0 +1,957 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "graphics/fonts/bdf.h"
#include "common/file.h"
#include "common/endian.h"
#include "common/textconsole.h"
#include "graphics/surface.h"
#define DRAWDEBUG 0
namespace Graphics {
BdfFont::BdfFont(const BdfFontData &data, DisposeAfterUse::Flag dispose)
: _data(data), _dispose(dispose) {
}
BdfFont::~BdfFont() {
if (_dispose == DisposeAfterUse::YES) {
for (uint i = 0; i < _data.numCharacters; ++i)
delete[] _data.bitmaps[i];
delete[] _data.bitmaps;
delete[] _data.advances;
delete[] _data.boxes;
delete[] _data.familyName;
delete[] _data.slant;
}
}
const char *BdfFont::getFamilyName() const {
return _data.familyName;
}
const char *BdfFont::getFontSlant() const {
return _data.slant;
}
int BdfFont::getFontHeight() const {
return _data.height;
}
int BdfFont::getFontAscent() const {
return _data.ascent;
}
int BdfFont::getFontSize() const {
return _data.size;
}
int BdfFont::getMaxCharWidth() const {
return _data.maxAdvance;
}
int BdfFont::getCharWidth(uint32 chr) const {
// In case all font have the same advance value, we use the maximum.
if (!_data.advances)
return _data.maxAdvance;
const int ch = mapToIndex(chr);
// In case no mapping exists, we use the maximum advance.
if (ch < 0)
return _data.maxAdvance;
else
return _data.advances[ch];
}
template<typename PixelType>
void drawCharIntern(byte *ptr, uint pitch, const byte *src, int h, int width, int minX, int maxX, const PixelType color) {
byte data = 0;
while (h--) {
PixelType *dst = (PixelType *)ptr;
for (int x = 0; x < width; ++x) {
if (!(x % 8))
data = *src++;
if (x >= minX && x <= maxX && (data & 0x80))
dst[x] = color;
data <<= 1;
}
ptr += pitch;
}
}
int BdfFont::mapToIndex(uint32 ch) const {
// Check whether the character is included
if (_data.firstCharacter <= ch && ch <= _data.firstCharacter + _data.numCharacters) {
if (_data.bitmaps[ch - _data.firstCharacter])
return ch - _data.firstCharacter;
}
return _data.defaultCharacter - _data.firstCharacter;
}
void BdfFont::drawChar(Surface *dst, uint32 chr, const int tx, const int ty, const uint32 color) const {
assert(dst != 0);
// TODO: Where is the relation between the max advance being smaller or
// equal to 50 and the decision of the theme designer?
// asserting _data.maxAdvance <= 50: let the theme designer decide what looks best
//assert(_data.maxAdvance <= 50);
assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
const int idx = mapToIndex(chr);
if (idx < 0)
return;
int width, height, xOffset, yOffset;
// Get the bounding box of the character
if (!_data.boxes) {
width = _data.defaultBox.width;
height = _data.defaultBox.height;
xOffset = _data.defaultBox.xOffset;
yOffset = _data.defaultBox.yOffset;
} else {
width = _data.boxes[idx].width;
height = _data.boxes[idx].height;
xOffset = _data.boxes[idx].xOffset;
yOffset = _data.boxes[idx].yOffset;
}
int y = ty + _data.ascent - yOffset - height;
int x = tx + xOffset;
const byte *src = _data.bitmaps[idx];
const int bytesPerRow = (width + 7) / 8;
const int originalWidth = width;
// Make sure we do not draw outside the surface
if (y < 0) {
src -= y * bytesPerRow;
height += y;
y = 0;
}
if (y + height > dst->h)
height = dst->h - y;
if (height <= 0)
return;
int xStart = 0;
if (x < 0) {
xStart = -x;
width += x;
x = 0;
}
if (x + width > dst->w)
width = dst->w - x;
if (width <= 0)
return;
const int xEnd = xStart + width - 1;
byte *ptr = (byte *)dst->getBasePtr(x, y);
if (dst->format.bytesPerPixel == 1)
drawCharIntern<byte>(ptr, dst->pitch, src, height, originalWidth, xStart, xEnd, color);
else if (dst->format.bytesPerPixel == 2)
drawCharIntern<uint16>(ptr, dst->pitch, src, height, originalWidth, xStart, xEnd, color);
else if (dst->format.bytesPerPixel == 4)
drawCharIntern<uint32>(ptr, dst->pitch, src, height, originalWidth, xStart, xEnd, color);
}
namespace {
inline byte hexToInt(char c) {
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else
return 0;
}
byte *loadCharacter(Common::SeekableReadStream &stream, int &encoding, int &advance, BdfBoundingBox &box) {
Common::String line;
byte *bitmap = 0;
while (true) {
line = stream.readLine();
line.trim(); // BDF files created from unifont tools (make hex)
// have a rogue space character after the "BITMAP" label
if (stream.err() || stream.eos()) {
warning("BdfFont::loadCharacter: Premature end of file");
delete[] bitmap;
return 0;
}
if (line.hasPrefix("ENCODING ")) {
if (sscanf(line.c_str(), "ENCODING %d", &encoding) != 1) {
warning("BdfFont::loadCharacter: Invalid ENCODING");
delete[] bitmap;
return 0;
}
} else if (line.hasPrefix("DWIDTH ")) {
int yAdvance;
if (sscanf(line.c_str(), "DWIDTH %d %d", &advance, &yAdvance) != 2) {
warning("BdfFont::loadCharacter: Invalid DWIDTH");
delete[] bitmap;
return 0;
}
if (yAdvance != 0) {
warning("BdfFont::loadCharacter: Character %d has an y advance of %d", encoding, yAdvance);
delete[] bitmap;
return 0;
}
if (advance < 0) {
warning("BdfFont::loadCharacter: Character %d has an x advance of %d", encoding, advance);
delete[] bitmap;
return 0;
}
} else if (line.hasPrefix("BBX ")) {
int width, height, xOffset, yOffset;
if (sscanf(line.c_str(), "BBX %d %d %d %d",
&width, &height, &xOffset, &yOffset) != 4) {
warning("BdfFont::loadCharacter: Invalid BBX");
delete[] bitmap;
return 0;
}
box.width = width;
box.height = height;
box.xOffset = xOffset;
box.yOffset = yOffset;
} else if (line == "BITMAP") {
const uint bytesPerRow = (box.width + 7) / 8;
if (bitmap) {
warning("Bdf::loadCharacter(): Double BITMAP definitions");
delete[] bitmap;
}
byte *dst = bitmap = new byte[box.height * bytesPerRow];
for (int y = 0; y < box.height; ++y) {
line = stream.readLine();
if (stream.err() || stream.eos()) {
warning("BdfFont::loadCharacter: Premature end of file");
delete[] bitmap;
return 0;
}
if (line.size() != 2 * bytesPerRow) {
warning("BdfFont::loadCharacter: Pixel line has wrong size");
delete[] bitmap;
return 0;
}
for (uint x = 0; x < bytesPerRow; ++x) {
char nibble1 = line[x * 2 + 0];
char nibble2 = line[x * 2 + 1];
*dst++ = (hexToInt(nibble1) << 4) | hexToInt(nibble2);
}
}
} else if (line == "ENDCHAR") {
return bitmap;
}
}
}
void freeBitmaps(byte **bitmaps, int size) {
for (int i = 0; i < size; ++i)
delete[] bitmaps[i];
}
} // End of anonymous namespace
BdfFont *BdfFont::loadFont(Common::SeekableReadStream &stream) {
BdfFontData font;
memset(&font, 0, sizeof(font));
font.ascent = -1;
font.defaultCharacter = -1;
// We only load the first 256 characters
font.numCharacters = 256;
byte **bitmaps = new byte *[font.numCharacters];
memset(bitmaps, 0, sizeof(byte *) * font.numCharacters);
byte *advances = new byte[font.numCharacters];
BdfBoundingBox *boxes = new BdfBoundingBox[font.numCharacters];
char *familyName = nullptr;
char *slant = nullptr;
int descent = -1;
Common::String line;
while (true) {
line = stream.readLine();
if (stream.err() || stream.eos()) {
warning("BdfFont::loadFont: Premature end of file");
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
// Only parse and handle declarations we actually need
if (line.hasPrefix("FONTBOUNDINGBOX ")) {
int width, height, xOffset, yOffset;
if (sscanf(line.c_str(), "FONTBOUNDINGBOX %d %d %d %d",
&width, &height, &xOffset, &yOffset) != 4) {
warning("BdfFont::loadFont: Invalid FONTBOUNDINGBOX");
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
font.defaultBox.width = width;
font.defaultBox.height = height;
font.defaultBox.xOffset = xOffset;
font.defaultBox.yOffset = yOffset;
} else if (line.hasPrefix("PIXEL_SIZE ")) {
if (sscanf(line.c_str(), "PIXEL_SIZE %d", &font.size) != 1) {
warning("BdfFont::loadFont: Invalid PIXEL_SIZE");
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
} else if (line.hasPrefix("FONT_ASCENT ")) {
if (sscanf(line.c_str(), "FONT_ASCENT %d", &font.ascent) != 1) {
warning("BdfFont::loadFont: Invalid FONT_ASCENT");
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
} else if (line.hasPrefix("FONT_DESCENT ")) {
if (sscanf(line.c_str(), "FONT_DESCENT %d", &descent) != 1) {
warning("BdfFont::loadFont: Invalid FONT_DESCENT");
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
} else if (line.hasPrefix("DEFAULT_CHAR ")) {
if (sscanf(line.c_str(), "DEFAULT_CHAR %d", &font.defaultCharacter) != 1) {
warning("BdfFont::loadFont: Invalid DEFAULT_CHAR");
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
} else if (line.hasPrefix("STARTCHAR ")) {
BdfBoundingBox box = font.defaultBox;
int encoding = -1;
int advance = -1;
byte *bitmap = loadCharacter(stream, encoding, advance, box);
// Ignore all characters above 255.
if (encoding < 0 || encoding >= (int)font.numCharacters) {
delete[] bitmap;
continue;
}
// Calculate the max advance
if (advance > font.maxAdvance)
font.maxAdvance = advance;
if (!bitmap) {
warning("BdfFont::loadFont: Character %d invalid", encoding);
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
bitmaps[encoding] = bitmap;
advances[encoding] = advance;
boxes[encoding] = box;
} else if (line.hasPrefix("FAMILY_NAME \"")) {
if (familyName != nullptr) {
warning("BdfFont::loadFont: Duplicated FAMILY_NAME");
delete[] familyName;
}
familyName = new char[line.size()];
Common::strlcpy(familyName, line.c_str() + 13, line.size() - 12); // strlcpy() copies at most size-1 characters and then add a '\0'
char *p = &familyName[strlen(familyName)];
while (p != familyName && *p != '"')
p--;
if (p == familyName) {
warning("BdfFont::loadFont: Invalid FAMILY_NAME");
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
*p = '\0'; // Remove last quote
} else if (line.hasPrefix("SLANT \"")) {
if (slant != nullptr) {
warning("BdfFont::loadFont: Duplicated SLANT");
delete[] slant;
}
slant = new char[line.size()];
Common::strlcpy(slant, line.c_str() + 7, line.size() - 6); // strlcpy() copies at most size-1 characters and then add a '\0'
char *p = &slant[strlen(slant)];
while (p != slant && *p != '"')
p--;
if (p == slant) {
warning("BdfFont::loadFont: Invalid SLANT");
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
*p = '\0'; // Remove last quote
} else if (line == "ENDFONT") {
break;
}
}
if (font.ascent < 0 || descent < 0) {
warning("BdfFont::loadFont: Invalid ascent or descent");
freeBitmaps(bitmaps, font.numCharacters);
delete[] bitmaps;
delete[] advances;
delete[] boxes;
delete[] familyName;
delete[] slant;
return 0;
}
font.height = font.ascent + descent;
font.bitmaps = bitmaps;
font.advances = advances;
font.boxes = boxes;
font.familyName = familyName;
font.slant = slant;
uint firstCharacter = font.numCharacters;
int lastCharacter = -1;
bool hasFixedBBox = true;
bool hasFixedAdvance = true;
for (uint i = 0; i < font.numCharacters; ++i) {
if (!font.bitmaps[i])
continue;
if (i < firstCharacter)
firstCharacter = i;
if ((int)i > lastCharacter)
lastCharacter = i;
if (font.advances[i] != font.maxAdvance)
hasFixedAdvance = false;
const BdfBoundingBox &bbox = font.boxes[i];
if (bbox.width != font.defaultBox.width
|| bbox.height != font.defaultBox.height
|| bbox.xOffset != font.defaultBox.xOffset
|| bbox.yOffset != font.defaultBox.yOffset)
hasFixedBBox = false;
}
if (lastCharacter == -1) {
warning("BdfFont::loadFont: No glyphs found");
delete[] font.bitmaps;
delete[] font.advances;
delete[] font.boxes;
delete[] familyName;
delete[] slant;
return 0;
}
// Free the advance table, in case all glyphs use the same advance
if (hasFixedAdvance) {
delete[] font.advances;
font.advances = 0;
}
// Free the box table, in case all glyphs use the same box
if (hasFixedBBox) {
delete[] font.boxes;
font.boxes = 0;
}
// Adapt for the fact that we never use encoding 0.
if (font.defaultCharacter < (int)firstCharacter
|| font.defaultCharacter > lastCharacter)
font.defaultCharacter = -1;
font.firstCharacter = firstCharacter;
const int charsAvailable = lastCharacter - firstCharacter + 1;
// Try to compact the tables
if (charsAvailable < (int)font.numCharacters) {
byte **newBitmaps = new byte *[charsAvailable];
boxes = 0;
advances = 0;
if (!hasFixedBBox)
boxes = new BdfBoundingBox[charsAvailable];
if (!hasFixedAdvance)
advances = new byte[charsAvailable];
for (int i = 0; i < charsAvailable; ++i) {
const int encoding = i + firstCharacter;
if (font.bitmaps[encoding]) {
newBitmaps[i] = bitmaps[encoding];
if (!hasFixedBBox)
boxes[i] = font.boxes[encoding];
if (!hasFixedAdvance)
advances[i] = font.advances[encoding];
} else {
newBitmaps[i] = 0;
}
}
delete[] font.bitmaps;
font.bitmaps = newBitmaps;
delete[] font.advances;
font.advances = advances;
delete[] font.boxes;
font.boxes = boxes;
font.numCharacters = charsAvailable;
}
return new BdfFont(font, DisposeAfterUse::YES);
}
#define BDF_FONTCACHE_TAG MKTAG('S', 'V', 'F', 'C')
#define BDF_FONTCACHE_VERSION 1
bool BdfFont::cacheFontData(const BdfFont &font, const Common::Path &filename) {
Common::DumpFile cacheFile;
if (!cacheFile.open(filename)) {
warning("BdfFont::cacheFontData: Couldn't open file '%s' for writing", filename.toString(Common::Path::kNativeSeparator).c_str());
return false;
}
const BdfFontData &data = font._data;
cacheFile.writeUint32BE(BDF_FONTCACHE_TAG);
cacheFile.writeUint32BE(BDF_FONTCACHE_VERSION);
cacheFile.writeUint16BE(data.maxAdvance);
cacheFile.writeByte(data.height);
cacheFile.writeByte(data.defaultBox.width);
cacheFile.writeByte(data.defaultBox.height);
cacheFile.writeSByte(data.defaultBox.xOffset);
cacheFile.writeSByte(data.defaultBox.yOffset);
cacheFile.writeByte(data.ascent);
cacheFile.writeUint16BE(data.firstCharacter);
cacheFile.writeSint16BE(data.defaultCharacter);
cacheFile.writeUint16BE(data.numCharacters);
for (uint i = 0; i < data.numCharacters; ++i) {
const BdfBoundingBox &box = data.boxes ? data.boxes[i] : data.defaultBox;
if (data.bitmaps[i]) {
const int bytes = ((box.width + 7) / 8) * box.height;
cacheFile.writeUint32BE(bytes);
cacheFile.write(data.bitmaps[i], bytes);
} else {
cacheFile.writeUint32BE(0);
}
}
if (data.advances) {
cacheFile.writeByte(0xFF);
cacheFile.write(data.advances, data.numCharacters);
} else {
cacheFile.writeByte(0x00);
}
if (data.boxes) {
cacheFile.writeByte(0xFF);
for (uint i = 0; i < data.numCharacters; ++i) {
const BdfBoundingBox &box = data.boxes[i];
cacheFile.writeByte(box.width);
cacheFile.writeByte(box.height);
cacheFile.writeSByte(box.xOffset);
cacheFile.writeSByte(box.yOffset);
}
} else {
cacheFile.writeByte(0x00);
}
return !cacheFile.err();
}
BdfFont *BdfFont::loadFromCache(Common::SeekableReadStream &stream) {
const uint32 magic = stream.readUint32BE();
if (magic != BDF_FONTCACHE_TAG)
return nullptr;
const uint32 version = stream.readUint32BE();
if (version != BDF_FONTCACHE_VERSION)
return nullptr;
BdfFontData data;
data.maxAdvance = stream.readUint16BE();
data.height = stream.readByte();
data.defaultBox.width = stream.readByte();
data.defaultBox.height = stream.readByte();
data.defaultBox.xOffset = stream.readSByte();
data.defaultBox.yOffset = stream.readSByte();
data.ascent = stream.readByte();
data.firstCharacter = stream.readUint16BE();
data.defaultCharacter = stream.readSint16BE();
data.numCharacters = stream.readUint16BE();
if (stream.err() || stream.eos())
return nullptr;
if (data.numCharacters == 0) {
warning("BdfFont::loadFromCache(): Requested to load 0 characters font");
return nullptr;
}
byte **bitmaps = new byte *[data.numCharacters];
byte *advances = 0;
BdfBoundingBox *boxes = 0;
for (uint i = 0; i < data.numCharacters; ++i) {
uint32 size = stream.readUint32BE();
if (stream.err() || stream.eos()) {
for (uint j = 0; j < i; ++j)
delete[] bitmaps[j];
delete[] bitmaps;
return nullptr;
}
if (size) {
bitmaps[i] = new byte[size];
stream.read(bitmaps[i], size);
} else {
bitmaps[i] = 0;
}
}
if (stream.readByte() == 0xFF) {
advances = new byte[data.numCharacters];
stream.read(advances, data.numCharacters);
}
if (stream.readByte() == 0xFF) {
boxes = new BdfBoundingBox[data.numCharacters];
for (uint i = 0; i < data.numCharacters; ++i) {
boxes[i].width = stream.readByte();
boxes[i].height = stream.readByte();
boxes[i].xOffset = stream.readSByte();
boxes[i].yOffset = stream.readSByte();
}
}
if (stream.eos() || stream.err()) {
for (uint i = 0; i < data.numCharacters; ++i)
delete[] bitmaps[i];
delete[] bitmaps;
delete[] advances;
delete[] boxes;
return nullptr;
}
data.bitmaps = bitmaps;
data.advances = advances;
data.boxes = boxes;
data.familyName = nullptr;
data.slant = nullptr;
data.size = data.height;
return new BdfFont(data, DisposeAfterUse::YES);
}
static Common::Rect bdfBoxToRect(int ascent, const BdfBoundingBox &bbox) {
int top = ascent - bbox.yOffset - bbox.height;
int left = bbox.xOffset;
int bottom = top + bbox.height;
int right = left + bbox.width;
return Common::Rect(left, top, right, bottom);
}
static BdfBoundingBox rectToBdfBox(int ascent, const Common::Rect &rect) {
BdfBoundingBox bbox;
bbox.yOffset = ascent - rect.top - rect.height();
bbox.xOffset = rect.left;
bbox.height = rect.height();
bbox.width = rect.width();
return bbox;
}
static BdfBoundingBox scaleBdfBoundingBox(int srcAscent, float srcReferencePointX, float srcReferencePointY, int destAscent, float destReferencePointX, float destReferencePointY, const BdfBoundingBox &srcBBox, float scale) {
Common::Rect srcRect = bdfBoxToRect(srcAscent, srcBBox);
int destLeft = static_cast<int>(floorf((static_cast<float>(srcRect.left) - srcReferencePointX) * scale + destReferencePointX));
int destRight = static_cast<int>(ceilf((static_cast<float>(srcRect.right) - srcReferencePointX) * scale + destReferencePointX));
int destTop = static_cast<int>(floorf((static_cast<float>(srcRect.top) - srcReferencePointY) * scale + destReferencePointY));
int destBottom = static_cast<int>(ceilf((static_cast<float>(srcRect.bottom) - srcReferencePointY) * scale + destReferencePointY));
return rectToBdfBox(destAscent, Common::Rect(destLeft, destTop, destRight, destBottom));
}
BdfFont *BdfFont::scaleFont(const BdfFont *src, int newSize) {
if (!src) {
warning("BdfFont::scaleFont(): Empty font reference in scale font");
return nullptr;
}
if (src->getFontSize() == 0) {
warning("BdfFont::scaleFont(): Requested to scale 0 size font");
return nullptr;
}
if (src->_data.numCharacters == 0) {
warning("BdfFont::scaleFont(): Requested to scale 0 characters font");
return nullptr;
}
Graphics::Surface srcSurf;
srcSurf.create(MAX(src->getFontSize() * 2, newSize * 2), MAX(src->getFontSize() * 2, newSize * 2), PixelFormat::createFormatCLUT8());
int dstGraySize = newSize * 20 * newSize;
int *dstGray = (int *)malloc(dstGraySize * sizeof(int));
float scale = (float)newSize / (float)src->getFontSize();
int scaledAscent = (int)(roundf((float)src->_data.ascent * scale));
// The reference point is the center point of scaling in the old and new glyph.
// The coordinate values are relative to the top-left corner of the draw coordinate pixel.
// Since the baseline is located at the top edge of the pixel that is +ascent from the draw
// coordinate, we use the intersection of that edge and the left edge of the draw coordinate
// as the reference point. This seems to produce good results.
float srcReferencePointX = 0.0f;
float srcReferencePointY = static_cast<float>(src->_data.ascent);
float destReferencePointX = 0.0f;
float destReferencePointY = static_cast<float>(scaledAscent);
BdfFontData data;
data.maxAdvance = (int)(roundf((float)src->_data.maxAdvance * scale));
data.height = (int)(roundf((float)src->_data.height * scale));
data.size = (int)(roundf((float)src->_data.size * scale));
data.ascent = scaledAscent;
data.defaultBox = scaleBdfBoundingBox(src->_data.ascent, srcReferencePointX, srcReferencePointY, data.ascent, destReferencePointX, destReferencePointY, src->_data.defaultBox, scale);
data.defaultBox.width = (int)(roundf((float)src->_data.defaultBox.width * scale));
data.defaultBox.height = (int)(roundf((float)src->_data.defaultBox.height * scale));
data.defaultBox.xOffset = (int)(roundf((float)src->_data.defaultBox.xOffset * scale));
data.defaultBox.yOffset = (int)(roundf((float)src->_data.defaultBox.yOffset * scale));
data.firstCharacter = src->_data.firstCharacter;
data.defaultCharacter = src->_data.defaultCharacter;
data.numCharacters = src->_data.numCharacters;
uint sz = 1 + strlen(src->_data.familyName);
char *familyName = new char[sz];
Common::strcpy_s(familyName, sz, src->_data.familyName);
data.familyName = familyName;
sz = 1 + strlen(src->_data.slant);
char *slant = new char[sz];
Common::strcpy_s(slant, sz, src->_data.slant);
data.slant = slant;
Common::Array<Common::Rect> srcRects;
if (src->_data.boxes) {
srcRects.resize(data.numCharacters);
BdfBoundingBox *boxes = new BdfBoundingBox[data.numCharacters];
for (uint i = 0; i < data.numCharacters; ++i)
boxes[i] = scaleBdfBoundingBox(src->_data.ascent, srcReferencePointX, srcReferencePointY, data.ascent, destReferencePointX, destReferencePointY, src->_data.boxes[i], scale);
data.boxes = boxes;
} else {
// if the sources have null boxes
data.boxes = nullptr;
}
if (src->_data.advances) {
byte *advances = new byte[data.numCharacters];
for (uint i = 0; i < data.numCharacters; ++i) {
advances[i] = (int)(roundf((float)src->_data.advances[i] * scale));
}
data.advances = advances;
} else {
// if the sources have null advances
data.advances = nullptr;
}
byte **bitmaps = new byte *[data.numCharacters];
for (uint i = 0; i < data.numCharacters; i++) {
const BdfBoundingBox &box = data.boxes ? data.boxes[i] : data.defaultBox;
const BdfBoundingBox &srcBox = data.boxes ? src->_data.boxes[i] : src->_data.defaultBox;
#if DRAWDEBUG
int ccc = 'L';
#endif
if (src->_data.bitmaps[i]) {
int dstPitch = (box.width + 7) / 8 ;
const int bytes = dstPitch * box.height;
bitmaps[i] = new byte[bytes + 1];
#if DRAWDEBUG
if (i == ccc) {
Common::Rect srcRect = bdfBoxToRect(src->_data.ascent, srcBox);
debugN("Ascent: %i\n", static_cast<int>(src->_data.ascent));
debugN("Source box: (%i,%i) - (%i,%i)\n", static_cast<int>(srcRect.left), static_cast<int>(srcRect.top), static_cast<int>(srcRect.right), static_cast<int>(srcRect.bottom));
debugN("Source bitmap:\n");
int srcPitch = (srcBox.width + 7) / 8;
for (int y = 0; y < srcBox.height; y++) {
for (int x = 0; x < srcBox.width; x++) {
byte b = src->_data.bitmaps[i][y * srcPitch + x / 8];
b >>= 7 - (x % 8);
b &= 1;
debugN("%c", b ? '@' : '_');
}
debugN(" %i\n", static_cast<int>(y + srcRect.top));
}
}
#endif
Common::Rect rect = bdfBoxToRect(data.ascent, box);
Common::Rect srcRect = bdfBoxToRect(src->_data.ascent, srcBox);
byte *ptr = bitmaps[i];
const byte *srcPtr = src->_data.bitmaps[i];
int destPitch = (rect.width() + 7) / 8;
int srcPitch = (srcRect.width() + 7) / 8;
memset(ptr, 0, destPitch * rect.height());
float rcpScale = 1.0f / scale;
#if DRAWDEBUG
if (i == ccc) {
debugN("New ascent: %i\n", static_cast<int>(data.ascent));
debugN("Dest box: (%i,%i) - (%i,%i)\n", static_cast<int>(rect.left), static_cast<int>(rect.top), static_cast<int>(rect.right), static_cast<int>(rect.bottom));
}
#endif
for (int destRelY = 0; destRelY < rect.height(); destRelY++) {
int destY = destRelY + rect.top;
float destPixelCenterY = destY + 0.5f;
float srcPixelCenterY = (destPixelCenterY - destReferencePointY) * rcpScale + srcReferencePointY;
int srcY = static_cast<int>(floorf(srcPixelCenterY));
if (srcY < srcRect.top || srcY >= srcRect.bottom)
continue;
int srcRelY = srcY - srcRect.top;
byte *rowPtr = ptr + destPitch * destRelY;
const byte *srcRowPtr = srcPtr + srcPitch * srcRelY;
for (int destRelX = 0; destRelX < rect.width(); destRelX++) {
int destX = destRelX + rect.left;
float destPixelCenterX = destX + 0.5f;
float srcPixelCenterX = (destPixelCenterX - destReferencePointX) * rcpScale + srcReferencePointX;
int srcX = static_cast<int>(floorf(srcPixelCenterX));
if (srcX < srcRect.left || srcX >= srcRect.right)
continue;
int srcRelX = srcX - srcRect.left;
if ((srcRowPtr[srcRelX / 8] << (srcRelX % 8)) & 0x80)
rowPtr[destRelX / 8] |= (0x80 >> (destRelX % 8));
}
}
#if DRAWDEBUG
if (i == ccc) {
for (int y = 0; y < box.height; y++) {
const byte *srcRow = (const byte *)&bitmaps[i][y * dstPitch];
for (int x = 0; x < box.width; x++) {
int sx = x;
debugN("%c", (srcRow[sx / 8] & (0x80 >> (sx % 8))) ? '#' : '_');
}
debugN(" %i\n", static_cast<int>(y + rect.top));
}
}
#endif
} else {
bitmaps[i] = nullptr;
}
}
data.bitmaps = bitmaps;
free(dstGray);
srcSurf.free();
return new BdfFont(data, DisposeAfterUse::YES);
}
} // End of namespace Graphics

102
graphics/fonts/bdf.h Normal file
View File

@@ -0,0 +1,102 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRAPHICS_FONTS_BDF_H
#define GRAPHICS_FONTS_BDF_H
#include "common/system.h"
#include "common/types.h"
#include "graphics/font.h"
namespace Common {
class SeekableReadStream;
}
namespace Graphics {
struct BdfBoundingBox {
uint8 width, height;
int8 xOffset, yOffset;
};
struct BdfFontData {
const char *familyName;
const char *slant;
int maxAdvance;
int height;
int size;
BdfBoundingBox defaultBox;
int ascent;
uint firstCharacter;
int defaultCharacter;
uint numCharacters;
const byte *const *bitmaps;
const byte *advances;
const BdfBoundingBox *boxes;
};
class BdfFont : public Font {
public:
BdfFont(const BdfFontData &data, DisposeAfterUse::Flag dispose);
~BdfFont();
virtual int getFontHeight() const;
virtual int getFontAscent() const;
virtual int getMaxCharWidth() const;
virtual int getCharWidth(uint32 chr) const;
virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
const char *getFamilyName() const;
const char *getFontSlant() const;
int getFontSize() const;
static BdfFont *loadFont(Common::SeekableReadStream &stream);
static bool cacheFontData(const BdfFont &font, const Common::Path &filename);
static BdfFont *loadFromCache(Common::SeekableReadStream &stream);
static BdfFont *scaleFont(const BdfFont *src, int newSize);
private:
int mapToIndex(uint32 ch) const;
const BdfFontData _data;
const DisposeAfterUse::Flag _dispose;
};
#define DEFINE_FONT(n) \
const BdfFont *n = 0; \
void create_##n() { \
n = new BdfFont(desc, DisposeAfterUse::NO); \
}
#define FORWARD_DECLARE_FONT(n) \
extern const BdfFont *n; \
extern void create_##n()
#define INIT_FONT(n) \
create_##n()
} // End of namespace Graphics
#endif

213
graphics/fonts/bgifont.cpp Normal file
View File

@@ -0,0 +1,213 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "graphics/fonts/bgifont.h"
namespace Graphics {
BgiFont::BgiFont() {
}
BgiFont::~BgiFont() {
}
bool BgiFont::loadChr(const Common::Path &fileName) {
Common::File fontFile;
if (!fontFile.open(fileName)) {
error("unable to load font file %s", fileName.toString().c_str());
}
return loadChr(fontFile);
}
bool BgiFont::loadChr(Common::SeekableReadStream &stream) {
/* fileSignature = */ stream.readUint16LE();
/*
Description until finding value 0x1A
*/
Common::String description = stream.readString(0x1A);
uint16 headerSize = stream.readUint16LE();
Common::String name = stream.readString(0, 4);
/*uint16 fontSize = */ stream.readUint16LE();
/* byte majorVersion = */ stream.readByte();
/* byte minorVersion = */ stream.readByte();
/* byte majorRevision = */ stream.readByte();
/* byte minorRevision = */ stream.readByte();
int remainingBytes = headerSize - (description.size() + 1 + 14);
stream.seek(remainingBytes, SEEK_CUR);
/* char signature = */ stream.readByte();
_charCount = stream.readUint16LE();
// undefined byte
stream.skip(1);
_firstChar = stream.readByte();
/* uint16 strokeOffset = */ stream.readUint16LE();
/*byte scanFlag = */ stream.readByte();
// Distance from the origin to the font's highest point
_originToAscender = stream.readByte();
// Distance from the origin to the font's baseline (typically 0). Ignored.
/*signed char originToBaseline = */ stream.readByte();
// Distance from the origin to the font's lowest point.
_originToDescender = stream.readByte();
/**
* ----------- originToAscender
*
*
*
* ----------- 0
*
* ----------- originToDescender
* totalHeight is the distance between originToAscender and originToDescender plus 1 (the baseline or the zero)
*/
_totalHeight = (_originToAscender - _originToDescender) + 1;
// Unused bytes
stream.skip(5);
_glyphs = new GlyphEntry[_charCount];
// Glyph offsets
for (int i = 0; i < _charCount; i++) {
_glyphs[i].offset = stream.readUint16LE();
}
_maxWidth = 0;
// Glyph widths
for (int i = 0; i < _charCount; i++) {
_glyphs[i].charWidth = stream.readByte();
if (_maxWidth < _glyphs[i].charWidth)
_maxWidth = _glyphs[i].charWidth;
}
int64 pos = stream.pos();
// Read drawing instructions until next glyph definition
for (int i = 0; i < _charCount; i++) {
_totalWidth += _glyphs[i].charWidth;
stream.seek(pos + _glyphs[i].offset, SEEK_SET);
int m;
do {
DrawingInstruction *inst = new DrawingInstruction();
byte instructionX = stream.readByte();
byte instructionY = stream.readByte();
// Grabs the most significant bit which is the opcode
m = instructionX >> 7 & 0x1;
m += m + (instructionY >> 7 & 0x1);
instructionX = fixSign(instructionX);
instructionY = fixSign(instructionY);
inst->opCode = m;
inst->xCoord = instructionX;
inst->yCoord = instructionY;
_glyphs[i].insts.push_back(inst);
} while (m);
}
_fontCache.push_back(drawCachedFont(1));
return false;
}
byte Graphics::BgiFont::fixSign(byte original) {
// If negative shifts the sign bit to the right position
return (original & 0x7F) | ((original & 0x40) << 1);
}
BgiFont::CachedFont *BgiFont::drawCachedFont(int size) {
CachedFont *cachedFont = new CachedFont();
Graphics::Surface *surface = new Graphics::Surface();
surface->create(_totalWidth, _totalHeight, Graphics::PixelFormat::createFormatCLUT8());
uint32 offsetCount = 0;
for (int i = 0; i < _charCount; i++) {
int curPosX = offsetCount;
int curPosY = 0;
cachedFont->offsets[i] = offsetCount;
cachedFont->widths[i] = _glyphs[i].charWidth;
for (uint j = 0; j < _glyphs[i].insts.size(); j++) {
int opCode = _glyphs[i].insts[j]->opCode;
// Need to normalize Y coord because the stroke instructions start at origin and extend upwards up to originAscender, downwards to originToDescender
int adjustedY = _originToAscender - _glyphs[i].insts[j]->yCoord;
switch (opCode) {
case OPCODE_END:
break;
case OPCODE_MOVE:
break;
case OPCODE_DRAW:
surface->drawLine(
curPosX,
curPosY,
offsetCount + _glyphs[i].insts[j]->xCoord,
adjustedY,
255);
break;
default:
/* nothing to do */
break;
};
curPosX = offsetCount + _glyphs[i].insts[j]->xCoord;
curPosY = adjustedY;
}
offsetCount += _glyphs[i].charWidth;
}
cachedFont->surface = surface;
return cachedFont;
}
void Graphics::BgiFont::close() {
}
int BgiFont::getCharWidth(uint32 chr) const {
return _glyphs[characterToIndex(chr)].charWidth;
}
void BgiFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
CachedFont *font = _fontCache[0];
uint16 charIndex = characterToIndex(chr);
int charWidth = font->widths[charIndex];
for (uint16 i = 0; i < _totalHeight; i++) {
for (uint16 j = 0; j < charWidth; j++) {
if (font->surface->getPixel(font->offsets[charIndex] + j, i)) {
if (dst->format.bytesPerPixel == 1)
*((byte *)dst->getBasePtr(x + j, y + i)) = color;
else if (dst->format.bytesPerPixel == 2)
*((uint16 *)dst->getBasePtr(x + j, y + i)) = color;
else if (dst->format.bytesPerPixel == 4)
*((uint32 *)dst->getBasePtr(x + j, y + i)) = color;
}
}
}
}
uint16 BgiFont::characterToIndex(uint32 character) const {
uint16 index = _firstChar;
if (character >= _firstChar) {
if ((character - _firstChar) < _charCount) {
index = character - _firstChar;
}
}
return index;
}
} // End of namespace Graphics

96
graphics/fonts/bgifont.h Normal file
View File

@@ -0,0 +1,96 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRAPHICS_FONTS_BGIFONT_H
#define GRAPHICS_FONTS_BGIFONT_H
#include "common/file.h"
#include "common/array.h"
#include "graphics/font.h"
#include "graphics/surface.h"
namespace Graphics {
const int OPCODE_END = 0;
const int OPCODE_DOSCAN = 1;
const int OPCODE_MOVE = 2;
const int OPCODE_DRAW = 3;
class BgiFont : public Font {
public:
BgiFont();
~BgiFont();
bool loadChr(const Common::Path &fileName);
bool loadChr(Common::SeekableReadStream &stream);
void close();
int getFontHeight() const { return _totalHeight; }
int getCharWidth(uint32 chr) const;
int getMaxCharWidth() const { return _maxWidth; }
void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
private:
struct DrawingInstruction {
int opCode;
int8 xCoord;
int8 yCoord;
};
struct GlyphEntry {
GlyphEntry() {
charWidth = 0;
offset = 0;
}
~GlyphEntry() {}
uint16 charWidth;
uint32 offset;
Common::Array<DrawingInstruction *> insts;
} *_glyphs;
struct CachedFont {
int widths[256];
int offsets[256];
Graphics::Surface *surface;
~CachedFont() {
delete surface;
}
};
uint16 _charCount;
byte _firstChar;
// uint16 _pixHeight;
uint16 _maxWidth = 10;
uint32 _totalWidth = 0;
int16 _totalHeight = 0;
int8 _originToAscender = 0;
int8 _originToDescender = 0;
Common::Array<CachedFont *> _fontCache;
uint16 characterToIndex(uint32 character) const;
byte fixSign(byte original);
CachedFont *drawCachedFont(int size);
};
} // namespace Graphics
#endif

File diff suppressed because it is too large Load Diff

464
graphics/fonts/dosfont.cpp Normal file
View File

@@ -0,0 +1,464 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "graphics/fonts/dosfont.h"
#include "graphics/surface.h"
namespace Graphics {
DosFont::DosFont() {}
int DosFont::getFontHeight() const {
return 8;
}
int DosFont::getMaxCharWidth() const {
return 8;
}
int DosFont::getCharWidth(uint32 chr) const {
return 8;
}
void DosFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
int srcPixel = chr * 8;
for (int sy = 0; sy < 8; sy++) {
for (int sx = 0; sx < 8; sx++) {
if (Graphics::DosFont::fontData_PCBIOS[srcPixel] & 1 << (7 - sx)) {
if (dst->format.bytesPerPixel == 1)
*((byte *)dst->getBasePtr(x + sx, y + sy)) = color;
else if (dst->format.bytesPerPixel == 2)
*((uint16 *)dst->getBasePtr(x + sx, y + sy)) = color;
else if (dst->format.bytesPerPixel == 4)
*((uint32 *)dst->getBasePtr(x + sx, y + sy)) = color;
}
}
srcPixel++;
}
}
// 8x8 font patterns
// this is basically the standard PC BIOS font, taken from Dos-Box, with a few modifications
const uint8 DosFont::fontData_PCBIOS[256 * 8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00, // 0x0D changed
0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C, // 0x0E changed
0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, // 0x0F changed
//0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, // 0x0D original
//0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, // 0x0E original
//0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, // 0x0F original
0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x12 changed
//0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, // 0x12 original
0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00, // 0x14 changed
0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, // 0x14 changed
//0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, // 0x14 original
//0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78, // 0x15 original
0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E, // 0x17 changed
0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 changed
0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x19 changed
//0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, // 0x17 original
//0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 original
//0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, // 0x19 original
0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, // 0x1D changed
0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, // 0x1E changed
0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, // 0x1F changed
//0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, // 0x1D original
//0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, // 0x1E original
//0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, // 0x1F original
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30
0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40
0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50
0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70
0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78, // 0x80
0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00,
0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38,
0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00,
0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00,
0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00,
0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00,
0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18,
0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00,
0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30,
0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7,
0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70,
0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00,
0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00,
0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00,
0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00,
0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00,
0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00,
0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F,
0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03,
0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18,
0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36,
0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36,
0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36,
0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00,
0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18,
0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36,
0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36,
0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36,
0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00,
0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36,
0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00,
0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0,
0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00,
0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00,
0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00,
0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0,
0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00,
0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC,
0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00,
0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00,
0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00,
0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00,
0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0,
0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00,
0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00,
0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00,
0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00,
0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00,
0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C,
0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// Extended set (0x80-0xFF) for Russian versions of games
const uint8 DosFont::fontData_ExtendedRussian[128 * 8] = {
0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80
0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
};
} // end of namespace Graphics

47
graphics/fonts/dosfont.h Normal file
View File

@@ -0,0 +1,47 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRAPHICS_FONTS_DOSFONT_H
#define GRAPHICS_FONTS_DOSFONT_H
#include "graphics/font.h"
namespace Graphics {
class DosFont : public Graphics::Font {
public:
DosFont();
int getFontHeight() const override;
int getMaxCharWidth() const override;
int getCharWidth(uint32 chr) const override;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
public:
// 8x8 font patterns
// this is basically the standard PC BIOS font, taken from Dos-Box, with a few modifications
static const uint8 fontData_PCBIOS[256 * 8];
static const uint8 fontData_ExtendedRussian[128 * 8];
};
}
#endif

137
graphics/fonts/freetype.cpp Normal file
View File

@@ -0,0 +1,137 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
// Since FreeType2 includes files, which contain forbidden symbols, we need to
// allow all symbols here.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "common/scummsys.h"
#ifdef USE_FREETYPE2
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_MODULE_H
namespace Graphics {
namespace FreeType {
void *Alloc_Callback(FT_Memory memory, long size) {
return malloc(static_cast<size_t>(size));
}
void Free_Callback(FT_Memory memory, void *block) {
free(block);
block = nullptr;
}
void *Realloc_Callback(FT_Memory memory, long cur_size, long new_size, void *block) {
return realloc(block, static_cast<size_t>(new_size));
}
FT_Error Init_FreeType_With_Mem(FT_Library *alibrary, FT_Memory *amem) {
// It seems FT_New_Memory isn't part of the public API in 2.10.4
FT_Memory mem = static_cast<FT_Memory>(malloc(sizeof(FT_MemoryRec_)));
if (!mem)
return FT_Err_Out_Of_Memory;
mem->alloc = Alloc_Callback;
mem->free = Free_Callback;
mem->realloc = Realloc_Callback;
mem->user = nullptr;
FT_Error error = FT_New_Library(mem, alibrary);
if (!error) {
FT_Add_Default_Modules(*alibrary);
*amem = mem;
}
return error;
}
FT_Error Init_FreeType(FT_Library *alibrary) {
return FT_Init_FreeType(alibrary);
}
FT_Error Done_FreeType(FT_Library library) {
return FT_Done_FreeType(library);
}
FT_Error Done_FreeType_With_Mem(FT_Library library, FT_Memory mem) {
FT_Error error = FT_Done_Library(library);
free(mem);
return error;
}
FT_Error Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags) {
return FT_Load_Glyph(face, glyph_index, load_flags);
}
FT_Error Get_Glyph(FT_GlyphSlot slot, FT_Glyph *aglyph) {
return FT_Get_Glyph(slot, aglyph);
}
FT_Error Glyph_Copy(FT_Glyph source, FT_Glyph *target) {
return FT_Glyph_Copy(source, target);
}
FT_Error Glyph_To_Bitmap(FT_Glyph *the_glyph, FT_Render_Mode render_mode,
FT_Vector *origin, FT_Bool destroy) {
return FT_Glyph_To_Bitmap(the_glyph, render_mode, origin, destroy);
}
void Done_Glyph(FT_Glyph glyph) {
return FT_Done_Glyph(glyph);
}
FT_Error Set_Pixel_Sizes(FT_Face face, FT_UInt pixel_width,
FT_UInt pixel_height) {
return FT_Set_Pixel_Sizes(face, pixel_width, pixel_height);
}
FT_Error New_Face(FT_Library library, const char *pathname,
FT_Long face_index, FT_Face *aface) {
return FT_New_Face(library, pathname, face_index, aface);
}
FT_Error New_Memory_Face(FT_Library library, const FT_Byte *file_base,
FT_Long file_size, FT_Long face_index, FT_Face *aface) {
return FT_New_Memory_Face(library, file_base, file_size, face_index, aface);
}
FT_Error Done_Face(FT_Face face) {
return FT_Done_Face(face);
}
FT_UInt Get_Char_Index(FT_Face face, FT_ULong charcode) {
return FT_Get_Char_Index(face, charcode);
}
FT_Error Get_Kerning(FT_Face face, FT_UInt left_glyph,
FT_UInt right_glyph, FT_UInt kern_mode, FT_Vector *akerning) {
return FT_Get_Kerning(face, left_glyph, right_glyph, kern_mode, akerning);
}
} // End of namespace FreeType
} // End of namespace Graphics
#endif

62
graphics/fonts/freetype.h Normal file
View File

@@ -0,0 +1,62 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRAPHICS_FONTS_FREETYPE_H
#define GRAPHICS_FONTS_FREETYPE_H
#ifdef USE_FREETYPE2
#include "common/scummsys.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
namespace Graphics {
namespace FreeType {
extern FT_Error Init_FreeType(FT_Library *alibrary);
extern FT_Error Init_FreeType_With_Mem(FT_Library *alibrary, FT_Memory *amem);
extern FT_Error Done_FreeType(FT_Library library);
extern FT_Error Done_FreeType_With_Mem(FT_Library library, FT_Memory mem);
extern FT_Error Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags);
extern FT_Error Get_Glyph(FT_GlyphSlot slot, FT_Glyph *aglyph);
extern FT_Error Glyph_Copy(FT_Glyph source, FT_Glyph *target);
extern FT_Error Glyph_To_Bitmap(FT_Glyph *the_glyph, FT_Render_Mode render_mode,
FT_Vector *origin, FT_Bool destroy);
extern void Done_Glyph(FT_Glyph glyph);
extern FT_Error Set_Pixel_Sizes(FT_Face face, FT_UInt pixel_width,
FT_UInt pixel_height);
extern FT_Error New_Face(FT_Library library, const char *pathname,
FT_Long face_index, FT_Face *aface);
extern FT_Error New_Memory_Face(FT_Library library, const FT_Byte *file_base,
FT_Long file_size, FT_Long face_index, FT_Face *aface);
extern FT_Error Done_Face(FT_Face face);
extern FT_UInt Get_Char_Index(FT_Face face, FT_ULong charcode);
extern FT_Error Get_Kerning(FT_Face face, FT_UInt left_glyph,
FT_UInt right_glyph, FT_UInt kern_mode, FT_Vector *akerning);
} // End of namespace FreeType
} // End of namespace Graphics
#endif
#endif

856
graphics/fonts/macfont.cpp Normal file
View File

@@ -0,0 +1,856 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/stream.h"
#include "common/textconsole.h"
#include "graphics/managed_surface.h"
#include "graphics/macgui/macfontmanager.h"
#include "graphics/fonts/macfont.h"
#define DEBUGSCALING 0
namespace Graphics {
enum {
kFontTypeImageHeightTable = (1 << 0),
kFontTypeGlyphWidthTable = (1 << 1),
kFontTypeFontColorTable = (1 << 7),
kFontTypeSyntheticFont = (1 << 8),
kFontTypeFixedWidthFont = (1 << 13),
kFontTypeNotExpandable = (1 << 14)
};
enum {
kFamilyGlyphWidthTable = (1 << 1),
kFamilyFractEnable = (1 << 12),
kFamilyIntegerExtra = (1 << 13),
kFamilyNoFractionalTable = (1 << 14),
kFamilyFixedWidthFonts = (1 << 15)
};
enum {
kStylePropertyPlain = 0,
kStylePropertyBold = 1,
kStylePropertyItalic = 2,
kStylePropertyUnderline = 3,
kStylePropertyOutline = 4,
kStylePropertyShadow = 5,
kStylePropertyCondensed = 6,
kStylePropertyExtended = 7,
kStylePropertyUnused = 8
};
static int getDepth(uint16 _fontType) {
// Returns 1, 2, 4, 8
return 1 << ((_fontType >> 2) & 3);
}
MacFontFamily::MacFontFamily(const Common::String &name) {
_name = name;
_ffFlags = 0;
_ffFamID = 0;
_ffFirstChar = 0;
_ffLastChar = 0;
_ffAscent = 0;
_ffDescent = 0;
_ffLeading = 0;
_ffWidMax = 0;
_ffWTabOff = 0;
_ffKernOff = 0;
_ffStylOff = 0;
for (int i = 0; i < 9; i++)
_ffProperty[i] = 0;
_ffIntl[0] = 0;
_ffIntl[1] = 0;
_ffVersion = 0;
_ffNumAssoc = 0;
_ffNumOffsets = 0;
_ffOffsets = nullptr;
_ffNumBBoxes = 0;
_ffNumKerns = 0;
_ffNumStyleWidths = 0;
}
MacFontFamily::~MacFontFamily() {
free(_ffOffsets);
}
bool MacFontFamily::load(Common::SeekableReadStream &stream) {
_ffFlags = stream.readUint16BE(); // flags for family
_ffFamID = stream.readUint16BE(); // family ID number
_ffFirstChar = stream.readUint16BE(); // ASCII code of first character
_ffLastChar = stream.readUint16BE(); // ASCII code of last character
_ffAscent = stream.readSint16BE(); // maximum ascent for 1-pt font
_ffDescent = stream.readSint16BE(); // maximum descent for 1-pt font
_ffLeading = stream.readSint16BE(); // maximum leading for 1-pt font
_ffWidMax = stream.readSint16BE(); // maximum glyph width for 1-pt font
_ffWTabOff = stream.readUint32BE(); // offset to family glyph-width table
_ffKernOff = stream.readUint32BE(); // offset to kerning table
_ffStylOff = stream.readUint32BE(); // offset to style-mapping table
debug(10, "flags: %x famid: %d first: %d last: %d", _ffFlags, _ffFamID, _ffFirstChar, _ffLastChar);
debug(10, "ascent: %g descent: %g, leading: %g, widmax: %g", _ffAscent / (double)(1<<12),
_ffDescent / (double)(1<<12), _ffLeading / (double)(1<<12), _ffWidMax / (double)(1<<12));
debug(10, "wtaboff: %d kernoff: %d styloff: %d", _ffWTabOff, _ffKernOff, _ffStylOff);
debugN(10, "Extra width: ");
for (int i = 0; i < 9; i++) { // style properties info
_ffProperty[i] = stream.readUint16BE();
debugN(10, "%d ", _ffProperty[i]);
}
debug(10, "%s", "");
_ffIntl[0] = stream.readUint16BE(); // for international use
_ffIntl[1] = stream.readUint16BE(); // for international use
_ffVersion = stream.readUint16BE(); // version number
debug(10, "version: %d", _ffVersion);
_ffNumAssoc = stream.readUint16BE(); // number of entries - 1
_ffAssocEntries.resize(_ffNumAssoc + 1);
debug(10, "association cnt: %d", _ffNumAssoc + 1);
for (uint i = 0; i <= _ffNumAssoc; i++) {
_ffAssocEntries[i]._fontSize = stream.readUint16BE(); // point size of font
_ffAssocEntries[i]._fontStyle = stream.readUint16BE(); // style of font
_ffAssocEntries[i]._fontID = stream.readUint16BE(); // font resource ID
debug(10, " size: %d style: %d id: %d", _ffAssocEntries[i]._fontSize, _ffAssocEntries[i]._fontStyle,
_ffAssocEntries[i]._fontID);
}
if (_ffWTabOff || _ffStylOff || _ffKernOff) {
_ffNumOffsets = stream.readUint16BE(); // number of entries - 1
_ffOffsets = (uint32 *)calloc(_ffNumOffsets + 1, sizeof(uint32));
debugN(10, "offset cnt: %d, OFF: ", _ffNumOffsets + 1);
for (uint i = 0; i <= _ffNumOffsets; i++) {
_ffOffsets[i] = stream.readUint32BE();
debugN(10, "%d ", _ffOffsets[i]);
}
debug(10, "%s", "");
_ffNumBBoxes = stream.readUint16BE(); // number of entries - 1
_ffBBoxes.resize(_ffNumBBoxes + 1);
debug(10, "num BBoxes: %d", _ffNumBBoxes + 1);
for (uint i = 0; i <= _ffNumBBoxes; i++) {
_ffBBoxes[i]._style = stream.readUint16BE();
_ffBBoxes[i]._left = stream.readSint16BE();
_ffBBoxes[i]._bottom = stream.readSint16BE();
_ffBBoxes[i]._right = stream.readSint16BE();
_ffBBoxes[i]._top = stream.readSint16BE();
debug(10, "style: %d left: %g bottom: %g right: %g top: %g", _ffBBoxes[i]._style,
_ffBBoxes[i]._left / (double)(1<<12), _ffBBoxes[i]._bottom / (double)(1<<12),
_ffBBoxes[i]._right / (double)(1<<12), _ffBBoxes[i]._top / (double)(1<<12));
}
}
if (_ffWTabOff) {
stream.seek(_ffWTabOff);
_ffNumStyleWidths = stream.readUint16BE() + 1;
_ffStyleWidths.resize(_ffNumStyleWidths);
debug(10, "style widths entries: %d", _ffNumStyleWidths);
for (uint i = 0; i < _ffNumStyleWidths; i++) {
uint size = _ffLastChar - _ffFirstChar + 3;
_ffStyleWidths[i]._style = stream.readUint16BE();
_ffStyleWidths[i]._widths.resize(size);
for (uint j = 0; j < size; j++)
_ffStyleWidths[i]._widths[j] = stream.readUint16BE();
}
}
if (_ffStylOff) {
// looks like this part is not useful for now.
// stream.seek(_ffStylOff);
/*uint16 classFlag =*/ stream.readUint16BE();
/*uint8 plainIndex =*/ stream.readSByte();
/*uint8 boldIndex =*/ stream.readSByte();
/*uint8 italicIndex =*/ stream.readSByte();
}
if (_ffKernOff) {
stream.seek(_ffKernOff);
_ffNumKerns = stream.readUint16BE(); // number of entries - 1
_ffKernEntries.resize(_ffNumKerns + 1);
debug(10, "kern entries: %d", _ffNumKerns + 1);
for (uint i = 0; i <= _ffNumKerns; i++) {
_ffKernEntries[i]._style = stream.readUint16BE();
_ffKernEntries[i]._entryLength = stream.readUint16BE();
_ffKernEntries[i]._kernPairs.resize(_ffKernEntries[i]._entryLength);
debug(10, " style: %x kernpairs: %u", _ffKernEntries[i]._style, _ffKernEntries[i]._entryLength);
for (uint j = 0; j < _ffKernEntries[i]._entryLength; j++) {
byte f, s;
int16 d;
f = _ffKernEntries[i]._kernPairs[j]._firstChar = stream.readByte();
s = _ffKernEntries[i]._kernPairs[j]._secondChar = stream.readByte();
d = _ffKernEntries[i]._kernPairs[j]._distance = stream.readSint16BE();
_ffKernEntries[i]._kernTable[(f << 8) | s] = d;
}
}
}
return true;
}
int MacFontFamily::getGlyphWidth(uint style, uint c) {
for (uint i = 0; i < _ffStyleWidths.size(); i++) {
if (_ffKernEntries[i]._style == style) {
if (c < _ffFirstChar || c > _ffLastChar)
return -1;
return _ffStyleWidths[i]._widths[c - _ffFirstChar];
}
}
return -1;
}
int MacFontFamily::getKerningOffset(uint style, int32 left, uint32 right) const {
uint16 idx = ((left & 0xff) << 8) | (right & 0xff);
for (uint i = 0; i < _ffKernEntries.size(); i++) {
if (_ffKernEntries[i]._style == style)
if (_ffKernEntries[i]._kernTable.contains(idx))
return _ffKernEntries[i]._kernTable[idx];
}
return 0;
}
MacFONTFont::MacFONTFont() {
_data._fontType = 0;
_data._firstChar = 0;
_data._lastChar = 0;
_data._maxWidth = 0;
_data._kernMax = 0;
_data._nDescent = 0;
_data._fRectWidth = 0;
_data._fRectHeight = 0;
_data._owTLoc = 0;
_data._ascent = 0;
_data._descent = 0;
_data._leading = 0;
_data._rowWords = 0;
_data._bitImage = nullptr;
_data._surfHeight = 0;
_data._family = nullptr;
_data._size = 12;
_data._style = 0;
}
MacFONTFont::MacFONTFont(const MacFONTdata &data) {
_data = data;
}
MacFONTFont::~MacFONTFont() {
delete[] _data._bitImage;
}
bool MacFONTFont::loadFont(Common::SeekableReadStream &stream, MacFontFamily *family, int size, int style) {
_data._family = family;
_data._size = size;
_data._style = style;
_data._fontType = stream.readUint16BE(); // font type
_data._firstChar = stream.readUint16BE(); // character code of first glyph
_data._lastChar = stream.readUint16BE(); // character code of last glyph
_data._maxWidth = stream.readUint16BE(); // maximum glyph width
_data._kernMax = stream.readSint16BE(); // maximum glyph kern
_data._nDescent = stream.readSint16BE(); // negative of descent
_data._fRectWidth = stream.readUint16BE(); // width of font rectangle
_data._fRectHeight = stream.readUint16BE(); // height of font rectangle
_data._owTLoc = stream.readUint16BE(); // offset to width/offset table
_data._ascent = stream.readUint16BE(); // maximum ascent measurement
_data._descent = stream.readUint16BE(); // maximum descent measurement
_data._leading = stream.readUint16BE(); // leading measurement
_data._rowWords = stream.readUint16BE() * 2; // row width of bit image in 16-bit wds
_data._surfHeight = _data._fRectHeight;
// i use this as a flag to indicate whether the font is generated. see more detail on drawChar.
_data._slant = 0; // only used in generated font
if (getDepth(_data._fontType) != 1) {
warning("MacFONTFont: %dbpp fonts are not supported", getDepth(_data._fontType));
return false;
}
// If positive, _nDescent holds the high bits of the offset to the
// width/offset table.
// https://web.archive.org/web/20080724120946/developer.apple.com/documentation/mac/Text/Text-252.html
if (_data._nDescent > 0)
_data._owTLoc |= _data._nDescent << 16;
// Alignment is by word
_data._owTLoc *= 2;
_data._owTLoc += 16;
uint16 glyphCount = _data._lastChar - _data._firstChar + 1;
_data._glyphs.resize(glyphCount);
// Bit image table
uint bitImageSize = _data._rowWords * _data._surfHeight;
_data._bitImage = new byte[bitImageSize];
stream.read(_data._bitImage, bitImageSize);
// Bitmap location table
// Last glyph is the pic for the missing glyph
// One more word for determinig width
uint16 *bitmapOffsets = (uint16 *)calloc(glyphCount + 2, sizeof(uint16));
for (uint16 i = 0; i < glyphCount + 2; i++)
bitmapOffsets[i] = stream.readUint16BE();
for (uint16 i = 0; i < glyphCount + 1; i++) {
MacGlyph *glyph = (i == glyphCount) ? &_data._defaultChar : &_data._glyphs[i];
glyph->bitmapOffset = bitmapOffsets[i];
glyph->bitmapWidth = bitmapOffsets[i + 1] - bitmapOffsets[i];
}
// Width/offset table
stream.seek(_data._owTLoc);
for (uint16 i = 0; i < glyphCount; i++) {
byte kerningOffset = stream.readByte();
byte width = stream.readByte();
// 0xFF designates missing glyph
if (kerningOffset == 0xFF && width == 0xFF)
continue;
_data._glyphs[i].kerningOffset = _data._kernMax + kerningOffset;
_data._glyphs[i].width = width;
}
_data._defaultChar.kerningOffset = _data._kernMax + stream.readByte();
_data._defaultChar.width = _data._kernMax + stream.readByte();
if (_data._fontType & kFontTypeGlyphWidthTable) {
warning("Skipping glyph-width table");
for (uint16 i = 0; i < glyphCount; i++)
_data._glyphs[i].width1 = stream.readUint16BE();
}
if (_data._fontType & kFontTypeImageHeightTable) {
for (uint16 i = 0; i < glyphCount; i++)
_data._glyphs[i].height = stream.readUint16BE();
}
free(bitmapOffsets);
return true;
}
int MacFONTFont::getCharWidth(uint32 chr) const {
const MacGlyph *glyph = findGlyph(chr);
if (!glyph)
return _data._maxWidth;
// this part looks wrong
// if (_data._fontType & kFontTypeGlyphWidthTable) {
// return glyph->width1;
// } else {
// if (_data._family) {
// int width = _data._family->getGlyphWidth(_data._style, chr);
// if (width != -1)
// return (width * 1000L + (1 << 11)) >> 12;
// }
// }
return glyph->width;
}
void MacFONTFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
assert(dst != 0);
assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
if (x > dst->w || y > dst->h)
return;
const MacGlyph *glyph = findGlyph(chr);
if (!glyph || glyph->width == 0)
return;
if (x + glyph->bitmapWidth < 0 || y + _data._fRectHeight < 0)
return;
// Make sure we do not draw outside the surface
uint16 yStart = (y < 0) ? -y : 0;
uint16 yStop = _data._fRectHeight;
uint16 xStart = (x < 0) ? -x : 0;
uint16 xStop = glyph->bitmapWidth;
// due to the way we are handling the generated fonts. we only add the kerning offset for the original font
if (!_data._slant)
x += glyph->kerningOffset;
if (x >= dst->w)
return;
if (y + _data._fRectHeight >= dst->h)
yStop = dst->h - y;
if (x + glyph->bitmapWidth >= dst->w)
xStop = dst->w - x;
// for the underLine font, we need to draw the line at the whole area, which includes the kerning space.
if ((_data._slant & kMacFontUnderline) && glyph->kerningOffset) {
int underlineY = y + _data._ascent + 2;
if (underlineY >= 0 && underlineY < dst->h) {
int underlineXStart = x - glyph->kerningOffset;
int underlineXEnd = x - 1;
if (underlineXStart < 0)
underlineXStart = 0;
if (underlineXEnd >= dst->w)
underlineXEnd = dst->w - 1;
for (int ulx = underlineXStart; ulx <= underlineXEnd; ulx++) {
if (dst->format.bytesPerPixel == 1)
*((byte *)dst->getBasePtr(ulx, underlineY)) = color;
else if (dst->format.bytesPerPixel == 2)
*((uint16 *)dst->getBasePtr(ulx, underlineY)) = color;
else if (dst->format.bytesPerPixel == 4)
*((uint32 *)dst->getBasePtr(ulx, underlineY)) = color;
}
}
}
for (uint16 i = yStart; i < yStop; i++) {
byte *srcRow = _data._bitImage + i * _data._rowWords;
for (uint16 j = xStart; j < xStop; j++) {
uint16 bitmapOffset = glyph->bitmapOffset + j;
if (srcRow[bitmapOffset / 8] & (1 << (7 - (bitmapOffset % 8)))) {
if (dst->format.bytesPerPixel == 1)
*((byte *)dst->getBasePtr(x + j, y + i)) = color;
else if (dst->format.bytesPerPixel == 2)
*((uint16 *)dst->getBasePtr(x + j, y + i)) = color;
else if (dst->format.bytesPerPixel == 4)
*((uint32 *)dst->getBasePtr(x + j, y + i)) = color;
}
}
}
}
const MacGlyph *MacFONTFont::findGlyph(uint32 c) const {
if (_data._glyphs.empty())
return 0;
if (c < _data._firstChar || c > _data._lastChar)
return &_data._defaultChar;
return &_data._glyphs[c - _data._firstChar];
}
int MacFONTFont::getKerningOffset(uint32 left, uint32 right) const {
if (_data._family) {
int kerning = _data._family->getKerningOffset(_data._style, left, right);
kerning *= _data._size;
return (int)(kerning / (double)(1 << 12));
}
return 0;
}
static void makeBold(Surface *src, int *dstGray, MacGlyph *glyph, int height);
static void makeOutline(Surface *src, Surface *dst, MacGlyph *glyph, int height);
static void makeItalic(Surface *src, Surface *dst, MacGlyph *glyph, int height);
static void makeUnderLine(Surface *src, MacGlyph *glyph, int ascent);
static void makeShadow(Surface *src, Surface *dst, MacGlyph *glyph, int height);
MacFONTFont *MacFONTFont::scaleFont(const MacFONTFont *src, int newSize, int slant) {
if (!src) {
warning("Empty font reference in scale font");
return NULL;
}
if (src->getFontSize() == 0) {
warning("Requested to scale 0 size font");
return NULL;
}
Graphics::Surface srcSurf, tmpSurf;
srcSurf.create(MAX(src->getFontSize() * 2, newSize * 2), MAX(src->getFontSize() * 2, newSize * 2),
PixelFormat::createFormatCLUT8());
int dstGraySize = newSize * 20 * newSize;
int *dstGray = (int *)malloc(dstGraySize * sizeof(int));
tmpSurf.create(MAX(src->getFontSize() * 2, newSize * 2), MAX(src->getFontSize() * 2 + 2, newSize * 2 + 2),
PixelFormat::createFormatCLUT8());
float scale = (float)newSize / (float)src->getFontSize();
MacFONTdata data;
data._fontType = src->_data._fontType;
data._firstChar = src->_data._firstChar;
data._lastChar = src->_data._lastChar;
data._maxWidth = (int)((float)src->_data._maxWidth * scale);
data._kernMax = (int)((float)src->_data._kernMax * scale);
data._nDescent = (int)((float)src->_data._nDescent * scale);
data._fRectWidth = (int)((float)src->_data._fRectWidth * scale + data._lastChar * 2);
data._fRectHeight = (int)((float)src->_data._fRectHeight * scale);
data._owTLoc = src->_data._owTLoc;
data._ascent = (int)((float)src->_data._ascent * scale);
data._descent = (int)((float)src->_data._descent * scale);
data._leading = (int)((float)src->_data._leading * scale);
data._family = src->_data._family;
data._size = src->_data._size;
data._style = src->_data._style;
data._glyphs.resize(src->_data._glyphs.size());
// when we are generating the slant fonts. e.g. italic font, underLine font. we set this. more detail is in drawChar
data._slant = slant;
// update the height, for shadow and outline font, we are drawing the outline, thus we may have 2 more pixel height
// for the underLine, we are drawing the line at ascent + 2, so we shall extend the height when we need.
if ((slant & kMacFontShadow) || (slant & kMacFontOutline))
data._fRectHeight += 2;
else if (slant & kMacFontUnderline) {
data._fRectHeight = MAX((int)data._fRectHeight, data._ascent + 2);
}
data._surfHeight = data._fRectHeight;
// Determine width of the bit image table
int newBitmapWidth = 0;
// add the offset which we may use when we are making fonts
int bitmapOffset = 0;
if (slant & kMacFontBold)
bitmapOffset++;
if (slant & kMacFontOutline)
bitmapOffset += 2;
if (slant & kMacFontItalic)
bitmapOffset += (data._fRectHeight - 1) / SLANTDEEP;
if (slant & kMacFontShadow)
bitmapOffset++;
for (uint i = 0; i < src->_data._glyphs.size() + 1; i++) {
MacGlyph *glyph = (i == src->_data._glyphs.size()) ? &data._defaultChar : &data._glyphs[i];
const MacGlyph *srcglyph = (i == src->_data._glyphs.size()) ? &src->_data._defaultChar : &src->_data._glyphs[i];
glyph->width = (int)((float)srcglyph->width * scale);
glyph->kerningOffset = (int)((float)srcglyph->kerningOffset * scale);
glyph->bitmapWidth = glyph->width; //(int)((float)srcglyph->bitmapWidth * scale);
glyph->bitmapOffset = newBitmapWidth;
// Align width to a byte
newBitmapWidth += (glyph->bitmapWidth + 7 + bitmapOffset) & ~0x7;
}
data._rowWords = newBitmapWidth;
uint bitImageSize = data._rowWords * data._fRectHeight;
data._bitImage = new byte[bitImageSize]();
int dstPitch = data._rowWords;
for (uint i = 0; i < src->_data._glyphs.size() + 1; i++) {
const MacGlyph *srcglyph = (i == src->_data._glyphs.size()) ? &src->_data._defaultChar : &src->_data._glyphs[i];
int grayLevel = src->_data._fRectHeight * srcglyph->width / 4;
#if DEBUGSCALING
uint ccc = 'c';
#endif
MacGlyph *glyph = (i == src->_data._glyphs.size()) ? &data._defaultChar : &data._glyphs[i];
src->scaleSingleGlyph(&srcSurf, dstGray, dstGraySize, glyph->bitmapWidth, data._fRectHeight, 0, 0, grayLevel, i + src->_data._firstChar,
src->_data._fRectHeight, srcglyph->width, scale);
if (slant & kMacFontBold) {
memset(dstGray, 0, dstGraySize * sizeof(int));
makeBold(&srcSurf, dstGray, glyph, data._fRectHeight);
for (uint16 y = 0; y < data._fRectHeight; y++) {
int *srcPtr = &dstGray[y * glyph->bitmapWidth];
byte *dstPtr = (byte *)srcSurf.getBasePtr(0, y);
for (uint16 x = 0; x < glyph->bitmapWidth; x++, srcPtr++, dstPtr++) {
if (*srcPtr)
*dstPtr = 1;
#if DEBUGSCALING
if (i == ccc)
debugN("%c", *srcPtr ? '@' : '.');
#endif
}
#if DEBUGSCALING
if (i == ccc)
debugN("\n");
#endif
}
}
if (slant & kMacFontItalic) {
tmpSurf.fillRect(Common::Rect(tmpSurf.w, tmpSurf.h), 0);
makeItalic(&srcSurf, &tmpSurf, glyph, data._fRectHeight);
srcSurf.copyFrom(tmpSurf);
}
if (slant & kMacFontUnderline)
makeUnderLine(&srcSurf, glyph, data._ascent);
if (slant & kMacFontOutline) {
tmpSurf.fillRect(Common::Rect(tmpSurf.w, tmpSurf.h), 0);
makeOutline(&srcSurf, &tmpSurf, glyph, data._fRectHeight);
srcSurf.copyFrom(tmpSurf);
}
if (slant & kMacFontShadow) {
tmpSurf.fillRect(Common::Rect(tmpSurf.w, tmpSurf.h), 0);
makeShadow(&srcSurf, &tmpSurf, glyph, data._fRectHeight);
srcSurf.copyFrom(tmpSurf);
}
if (slant & kMacFontCondense)
glyph->width--;
if (slant & kMacFontExtend)
glyph->width++;
byte *ptr = &data._bitImage[glyph->bitmapOffset / 8];
for (int y = 0; y < data._fRectHeight; y++) {
byte *dst = ptr;
byte *srcPtr = (byte *)srcSurf.getBasePtr(0, y);
byte b = 0;
for (int x = 0; x < glyph->bitmapWidth; x++, srcPtr++) {
b <<= 1;
if (*srcPtr == 1)
b |= 1;
if (x % 8 == 7) {
*dst++ = b;
b = 0;
}
}
#if DEBUGSCALING
if (i == ccc) {
debugN(1, "--> %d ", grayLevel);
int *grayPtr = &dstGray[y * glyph->width];
for (int x = 0; x < glyph->width; x++, grayPtr++)
debugN("%c", *grayPtr > grayLevel ? '#' : '.');
}
#endif
if (((glyph->bitmapWidth - 1) % 8)) {
#if DEBUGSCALING
if (i == ccc)
debugN(" --- %02x (w: %d bw: %d << %d)", b, glyph->width, glyph->bitmapWidth, 7 - ((glyph->width - 1) % 8));
#endif
b <<= 7 - ((glyph->bitmapWidth - 1) % 8);
*dst = b;
#if DEBUGSCALING
if (i == ccc)
debugN(" --- %02x ", b);
#endif
}
#if DEBUGSCALING
if (i == ccc) {
byte *srcRow = data._bitImage + y * data._rowWords;
for (uint16 x = 0; x < glyph->bitmapWidth; x++) {
uint16 bitmapOffset = glyph->bitmapOffset + x;
debugN("%c", srcRow[bitmapOffset / 8] & (1 << (7 - (bitmapOffset % 8))) ? '*' : '.');
}
debugN("\n");
}
#endif
ptr += dstPitch;
}
}
srcSurf.free();
tmpSurf.free();
free(dstGray);
return new MacFONTFont(data);
}
static void makeBold(Surface *src, int *dstGray, MacGlyph *glyph, int height) {
glyph->width++;
glyph->bitmapWidth++;
for (uint16 y = 0; y < height; y++) {
byte *srcPtr = (byte *)src->getBasePtr(0, y);
int *dst = &dstGray[y * glyph->bitmapWidth];
for (uint16 x = 0; x < glyph->bitmapWidth; x++, srcPtr++, dst++) {
*dst |= *srcPtr;
*(dst + 1) |= *srcPtr;
}
}
}
static void makeOutline(Surface *src, Surface *dst, MacGlyph *glyph, int height) {
glyph->bitmapWidth += 2;
glyph->width++;
int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
for (uint16 y = 0; y < height + 2; y++) {
byte *srcPtr = (byte *)src->getBasePtr(0, y);
byte *dstPtr = (byte *)dst->getBasePtr(0, y);
for (uint16 x = 0; x < glyph->bitmapWidth; x++, dstPtr++, srcPtr++) {
if (x && *(srcPtr - 1))
continue;
// for every white pixel, if there is black pixel around it. It means that the white pixel is boundary, then we draw it as black pixel.
for (int i = 0; i < 8; i++) {
int nx = x + dx[i] - 1;
int ny = y + dy[i];
if (nx >= src->w || nx < 0 || ny >= src->h || ny < 0)
continue;
if (*((byte *)src->getBasePtr(nx, ny))) {
*dstPtr = 1;
break;
}
}
}
}
}
static void makeItalic(Surface *src, Surface *dst, MacGlyph *glyph, int height) {
int dw = (height - 1) / SLANTDEEP;
for (int16 y = height - 1; y >= 0; y--) {
int dx = (height - 1 - y) / SLANTDEEP;
byte *srcPtr = (byte *)src->getBasePtr(0, y);
byte *dstPtr = (byte *)dst->getBasePtr(dx, y);
for (uint16 x = 0; x < glyph->width; x++, srcPtr++, dstPtr++) {
*dstPtr = *srcPtr;
}
}
glyph->bitmapWidth += dw;
glyph->kerningOffset -= dw / 2;
}
static void makeUnderLine(Surface *src, MacGlyph *glyph, int ascent) {
// this case is for space, which has the same number of kerning offset and width.
// inorder to draw the underLine for space, we need to disable the kerning offset of it.
if (glyph->width == glyph->kerningOffset)
glyph->kerningOffset = 0;
for (int x = 0; x < glyph->width; x++)
*((byte *) src->getBasePtr(x, ascent + 2)) = 1;
}
static void makeShadow(Surface *src, Surface *dst, MacGlyph *glyph, int height) {
// makeShadow looks like just the outLine font with one more shadow at right-most edge and lowest edge
makeOutline(src, dst, glyph, height);
glyph->bitmapWidth++;
glyph->width++;
// right to left
for (uint16 y = 0; y < height + 2; y++) {
for (int x = dst->w - 1; x >= 0; x--) {
byte *dstPtr = (byte *)dst->getBasePtr(x, y);
if (*dstPtr)
continue;
// check the left pixel. if it's black, then we black the current one and break.
byte *left = (byte *)dst->getBasePtr(MAX(x - 1, 0), y);
if (*left) {
*dstPtr = 1;
break;
}
}
}
// down to up
for (uint16 x = 0; x < glyph->bitmapWidth; x++) {
for (int y = dst->h - 1; y >= 0; y--) {
byte *dstPtr = (byte *) dst->getBasePtr(x, y);
if (*dstPtr)
continue;
byte *up = (byte *)dst->getBasePtr(x, MAX(y - 1, 0));
if (*up) {
*dstPtr = 1;
break;
}
}
}
}
void MacFONTFont::testBlit(const MacFONTFont *src, ManagedSurface *dst, int color, int x0, int y0, int width) {
for (int y = 0; y < src->_data._fRectHeight; y++) {
byte *srcRow = src->_data._bitImage + y * src->_data._rowWords;
for (int x = 0; x < width; x++) {
uint16 bitmapOffset = x + 64;
if (srcRow[bitmapOffset / 8] & (1 << (7 - (bitmapOffset % 8)))) {
if (dst->format.bytesPerPixel == 1)
*((byte *)dst->getBasePtr(x0 + x, y0 + y)) = color;
else if (dst->format.bytesPerPixel == 2)
*((uint16 *)dst->getBasePtr(x0 + x, y0 + y)) = color;
else if (dst->format.bytesPerPixel == 4)
*((uint32 *)dst->getBasePtr(x0 + x, y0 + y)) = color;
}
}
}
}
} // End of namespace Graphics

196
graphics/fonts/macfont.h Normal file
View File

@@ -0,0 +1,196 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRAPHICS_FONTS_MACFONT_H
#define GRAPHICS_FONTS_MACFONT_H
#include "common/array.h"
#include "common/hashmap.h"
#include "common/stream.h"
#include "graphics/font.h"
namespace Graphics {
#define SLANTDEEP 2
class MacFontFamily {
public:
MacFontFamily(const Common::String &name);
~MacFontFamily();
bool load(Common::SeekableReadStream &stream);
int getKerningOffset(uint style, int32 left, uint32 right) const;
int getGlyphWidth(uint style, uint c);
struct AsscEntry {
uint16 _fontSize;
uint16 _fontStyle;
uint16 _fontID;
};
const Common::String &getName() { return _name; }
uint16 getFontFamilyId() { return _ffFamID; }
Common::Array<AsscEntry> *getAssocTable() { return &_ffAssocEntries; }
private:
Common::String _name;
// FOND
uint16 _ffFlags;
uint16 _ffFamID;
uint16 _ffFirstChar;
uint16 _ffLastChar;
int16 _ffAscent;
int16 _ffDescent;
int16 _ffLeading;
int16 _ffWidMax;
uint32 _ffWTabOff;
uint32 _ffKernOff;
uint32 _ffStylOff;
uint16 _ffProperty[9];
uint16 _ffIntl[2];
uint16 _ffVersion;
uint16 _ffNumAssoc;
Common::Array<AsscEntry> _ffAssocEntries;
uint16 _ffNumOffsets;
uint32 *_ffOffsets;
struct BBoxEntry {
uint16 _style;
int16 _left;
int16 _bottom;
int16 _right;
int16 _top;
};
uint16 _ffNumBBoxes;
Common::Array<BBoxEntry> _ffBBoxes;
struct KernPair {
byte _firstChar;
byte _secondChar;
uint16 _distance;
};
struct KernEntry {
uint16 _style;
uint16 _entryLength;
Common::Array<KernPair> _kernPairs;
Common::HashMap<uint16, int16> _kernTable;
};
uint16 _ffNumKerns;
Common::Array<KernEntry> _ffKernEntries;
struct StyleWidthEntry {
uint16 _style;
Common::Array<uint16> _widths;
};
uint16 _ffNumStyleWidths;
Common::Array<StyleWidthEntry> _ffStyleWidths;
};
struct MacGlyph {
void clear() {
bitmapOffset = 0;
width1 = 0;
height = 0;
bitmapWidth = 0;
kerningOffset = 0;
width = 0;
}
uint16 bitmapOffset;
uint16 height;
uint16 bitmapWidth;
uint16 width1; // this width is from glyph-table, which has the higher priority
byte width; // this width is from width/offset table
int kerningOffset;
};
struct MacFONTdata {
uint16 _fontType;
uint16 _firstChar;
uint16 _lastChar;
uint16 _maxWidth;
int16 _kernMax;
int16 _nDescent;
uint16 _fRectWidth;
uint16 _fRectHeight;
uint32 _owTLoc;
uint16 _ascent;
uint16 _descent;
uint16 _leading;
uint16 _rowWords;
uint16 _surfHeight;
byte *_bitImage;
Common::Array<MacGlyph> _glyphs;
MacGlyph _defaultChar;
MacFontFamily *_family;
int _size;
int _style;
// currently only available in generated fonts
int _slant;
};
/**
* Processing of Mac FONT/NFNT rResources
*/
class MacFONTFont : public Font {
public:
MacFONTFont();
MacFONTFont(const MacFONTdata &data);
virtual ~MacFONTFont();
virtual int getFontHeight() const { return _data._fRectHeight + getFontLeading(); }
virtual int getFontAscent() const { return _data._ascent; }
virtual int getFontDescent() const { return _data._descent; }
virtual int getFontLeading() const { return _data._leading; }
virtual int getMaxCharWidth() const { return _data._maxWidth; }
virtual int getCharWidth(uint32 chr) const;
virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
bool loadFont(Common::SeekableReadStream &stream, MacFontFamily *family = nullptr, int size = 12, int style = 0);
virtual int getKerningOffset(uint32 left, uint32 right) const;
int getFontSize() const { return _data._size; }
static MacFONTFont *scaleFont(const MacFONTFont *src, int newSize, int slant);
static void testBlit(const MacFONTFont *src, ManagedSurface *dst, int color, int x0, int y0, int width);
private:
MacFONTdata _data;
const MacGlyph *findGlyph(uint32 c) const;
};
} // End of namespace Graphics
#endif

10985
graphics/fonts/newfont.cpp Normal file

File diff suppressed because it is too large Load Diff

10137
graphics/fonts/newfont_big.cpp Normal file

File diff suppressed because it is too large Load Diff

1156
graphics/fonts/ttf.cpp Normal file

File diff suppressed because it is too large Load Diff

152
graphics/fonts/ttf.h Normal file
View File

@@ -0,0 +1,152 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRAPHICS_FONTS_TTF_H
#define GRAPHICS_FONTS_TTF_H
#include "common/scummsys.h"
#ifdef USE_FREETYPE2
#include "common/array.h"
#include "common/stream.h"
#include "common/ustr.h"
namespace Common {
class Path;
}
namespace Graphics {
class Font;
/**
* This specifies the mode in which TTF glyphs are rendered. This, for example,
* allows to render glyphs fully monochrome, i.e. without any anti-aliasing.
*/
enum TTFRenderMode {
/**
* Standard render mode. Equivalent of FreeType2's FT_RENDER_MODE_NORMAL.
*/
kTTFRenderModeNormal,
/**
* Use lighter hinting. Equivalent of FreeType2's FT_RENDER_MODE_LIGHT.
*/
kTTFRenderModeLight,
/**
* Render fully monochrome. This makes glyph pixels either be fully opaque
* or fully transparent.
*/
kTTFRenderModeMonochrome
};
/**
* This specifies how the font size is defined.
*/
enum TTFSizeMode {
/**
* Character height only.
*
* This matches rendering obtained when calling
* CreateFont in Windows with negative height values.
*/
kTTFSizeModeCharacter,
/**
* Full cell height.
*
* This matches rendering obtained when calling
* CreateFont in Windows with positive height values.
*/
kTTFSizeModeCell
};
/**
* Loads a TTF font file from a given data stream object.
*
* @param stream Stream object to load font data from.
* @param size The point size to load.
* @param sizeMode The point size definition used for the size parameter.
* @param dpi The dpi to use for size calculations, by default 72dpi
* are used.
* @param renderMode FreeType2 mode used to render glyphs. @see TTFRenderMode
* @param mapping A mapping from code points 0-255 into UTF-32 code points.
* This can be used to support various 8bit character sets.
* In case the msb of the UTF-32 code point is set the font
* loading fails in case no glyph for it is found. When this
* is non-null only characters given in the mapping are
* supported.
* @return 0 in case loading fails, otherwise a pointer to the Font object.
*/
Font *loadTTFFont(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, int size, TTFSizeMode sizeMode = kTTFSizeModeCharacter, uint xdpi = 0, uint ydpi = 0, TTFRenderMode renderMode = kTTFRenderModeLight, const uint32 *mapping = 0, bool stemDarkening = false);
/**
* Loads a TTF font file from the common fonts archive.
*
* @param filename The name of the font to load.
* @param size The point size to load.
* @param sizeMode The point size definition used for the size parameter.
* @param dpi The dpi to use for size calculations, by default 72dpi
* are used.
* @param renderMode FreeType2 mode used to render glyphs. @see TTFRenderMode
* @param mapping A mapping from code points 0-255 into UTF-32 code points.
* This can be used to support various 8bit character sets.
* In case the msb of the UTF-32 code point is set the font
* loading fails in case no glyph for it is found. When this
* is non-null only characters given in the mapping are
* supported.
* @return 0 in case loading fails, otherwise a pointer to the Font object.
*/
Font *loadTTFFontFromArchive(const Common::String &filename, int size, TTFSizeMode sizeMode = kTTFSizeModeCharacter, uint xdpi = 0, uint ydpi = 0, TTFRenderMode renderMode = kTTFRenderModeLight, const uint32 *mapping = 0);
/**
* Finds the specified face in a collection of TTF/TTC font files.
* This functions kinds of mimic CreateFont from Windows API.
*
* @param files List of files where to find specified face.
* @param faceName The face name to search for.
* @param bold The weight of the desired face.
* @param italic The slant of the desired face.
* @param size The point size to load.
* @param sizeMode The point size definition used for the size parameter.
* @param dpi The dpi to use for size calculations, by default 96dpi
* are used. Like in Windows.
* @param renderMode FreeType2 mode used to render glyphs. @see TTFRenderMode
* @param mapping A mapping from code points 0-255 into UTF-32 code points.
* This can be used to support various 8bit character sets.
* In case the msb of the UTF-32 code point is set the font
* loading fails in case no glyph for it is found. When this
* is non-null only characters given in the mapping are
* supported.
* @return 0 in case loading fails, otherwise a pointer to the Font object.
*/
Font *findTTFace(const Common::Array<Common::Path> &files, const Common::U32String &faceName, bool bold, bool italic, int size, uint xdpi = 0, uint ydpi = 0,TTFRenderMode renderMode = kTTFRenderModeLight, const uint32 *mapping = 0);
void shutdownTTF();
} // End of namespace Graphics
#endif
#endif

438
graphics/fonts/winfont.cpp Normal file
View File

@@ -0,0 +1,438 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/file.h"
#include "common/str.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "common/formats/winexe_ne.h"
#include "common/formats/winexe_pe.h"
#include "graphics/surface.h"
#include "graphics/fonts/winfont.h"
namespace Graphics {
WinFont::WinFont() {
_glyphs = nullptr;
close();
}
WinFont::~WinFont() {
close();
}
void WinFont::close() {
_pixHeight = 0;
_sizeInPoints = 0;
_dpi = 0;
_maxWidth = 0;
_firstChar = 0;
_lastChar = 0;
_defaultChar = 0;
_glyphCount = 0;
delete[] _glyphs;
_glyphs = nullptr;
}
// Reads a null-terminated string
static Common::String readString(Common::SeekableReadStream &stream) {
Common::String string;
char c = stream.readByte();
while (c && stream.pos() < stream.size()) {
string += c;
c = stream.readByte();
}
return string;
}
static WinFontDirEntry readDirEntry(Common::SeekableReadStream &stream) {
WinFontDirEntry entry;
stream.skip(68); // Useless
entry.points = stream.readUint16LE();
stream.skip(43); // Useless (for now, maybe not in the future)
readString(stream); // Skip Device Name
entry.faceName = readString(stream);
return entry;
}
bool WinFont::loadFromFON(const Common::Path &fileName, const WinFontDirEntry &dirEntry) {
Common::WinResources *exe = Common::WinResources::createFromEXE(fileName);
if (!exe)
return false;
bool ok = loadFromEXE(exe, fileName, dirEntry);
delete exe;
return ok;
}
bool WinFont::loadFromFON(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry) {
Common::WinResources *exe = Common::WinResources::createFromEXE(&stream);
if (!exe)
return false;
bool ok = loadFromEXE(exe, Common::Path("stream"), dirEntry);
delete exe;
return ok;
}
bool WinFont::loadFromEXE(Common::WinResources *exe, const Common::Path &fileName, const WinFontDirEntry &dirEntry) {
// Let's pull out the font directory
Common::SeekableReadStream *fontDirectory = exe->getResource(Common::kWinFontDir, Common::String("FONTDIR"));
if (!fontDirectory) {
warning("No font directory in '%s'", fileName.toString(Common::Path::kNativeSeparator).c_str());
return false;
}
uint32 fontId = getFontIndex(*fontDirectory, dirEntry);
delete fontDirectory;
// Couldn't match the face name
if (fontId == 0xffffffff) {
warning("Could not find face '%s' in '%s'", dirEntry.faceName.c_str(),
fileName.toString(Common::Path::kNativeSeparator).c_str());
return false;
}
// Actually go get our font now...
Common::SeekableReadStream *fontStream = exe->getResource(Common::kWinFont, fontId);
if (!fontStream) {
warning("Could not find font %d in %s", fontId,
fileName.toString(Common::Path::kNativeSeparator).c_str());
return false;
}
bool ok = loadFromFNT(*fontStream);
delete fontStream;
return ok;
}
/**
* Size in typographic "points"
*
* While early Macintosh mapped "points" and "pixels" very closely,
* that was not the case on Windows.
*
* Windows used 96 dpi for font rendering so a 10 point font would
*
* Macintosh used 72 dpi for fonts while Windows used 96 dpi
*/
int WinFont::getFontSizeInPointsAtDPI(const int dpi) const {
return _sizeInPoints * _dpi / dpi;
}
uint32 WinFont::getFontIndex(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry) {
uint16 numFonts = stream.readUint16LE();
// Probably not possible, so this is really a sanity check
if (numFonts == 0) {
warning("No fonts in exe");
return 0xffffffff;
}
// Scour the directory for our matching name
for (uint16 i = 0; i < numFonts; i++) {
uint16 id = stream.readUint16LE();
// Use the first name when empty
if (dirEntry.faceName.empty()) {
_name = getFONFontName(stream);
return id;
}
WinFontDirEntry entry = readDirEntry(stream);
if (dirEntry.faceName.equalsIgnoreCase(entry.faceName) && dirEntry.points == entry.points) // Match!
return id;
}
return 0xffffffff;
}
Common::String WinFont::getFONFontName(Common::SeekableReadStream& stream) {
// Currently only works when dirEntry.faceName in getFontIndex is empty
// But this can be used for each FONTDIR entry
stream.seek(117);
/* Device Name = */ stream.readString();
Common::String fontName = stream.readString();
return fontName;
}
bool WinFont::loadFromFNT(const Common::Path &fileName) {
Common::File file;
return file.open(fileName) && loadFromFNT(file);
}
char WinFont::indexToCharacter(uint16 index) const {
// Use a space for the sentinel value
if (index == _glyphCount - 1)
return ' ';
return index + _firstChar;
}
uint16 WinFont::characterToIndex(uint32 character) const {
// Go to the default character if we didn't find a mapping
if (character < _firstChar || character > _lastChar)
character = _defaultChar;
return character - _firstChar;
}
int WinFont::getCharWidth(uint32 chr) const {
return _glyphs[characterToIndex(chr)].charWidth;
}
bool WinFont::loadFromFNT(Common::SeekableReadStream &stream) {
uint16 version = stream.readUint16LE();
// We'll accept Win1, Win2, and Win3 fonts
if (version != 0x100 && version != 0x200 && version != 0x300) {
warning("Bad FNT version %04x", version);
return false;
}
/* uint32 sizeOfGlyphTableInBytes = */ stream.readUint32LE();
stream.skip(60); // Copyright info
uint16 fontType = stream.readUint16LE();
_sizeInPoints = stream.readUint16LE();
uint16 vertRes = stream.readUint16LE(); // usually 96 as in 96dpi
uint16 horizRes = stream.readUint16LE(); // usually 96 as in 96dpi
if (vertRes != horizRes)
warning("WinFont::loadFromFNT(): FNT horizontal resolution and vertical resolution differ (%d vs %d)", horizRes, vertRes);
_dpi = vertRes;
_ascent = stream.readUint16LE();
/* uint16 internalLeading = */ stream.readUint16LE();
/* uint16 externalLeading = */ stream.readUint16LE();
_italic = stream.readByte();
_underline = stream.readByte();
_strikethrough = stream.readByte();
_weight = stream.readUint16LE();
/* byte charSet = */ stream.readByte();
uint16 pixWidth = stream.readUint16LE();
_pixHeight = stream.readUint16LE();
/* byte pitchAndFamily = */ stream.readByte();
/* uint16 avgWidth = */ stream.readUint16LE();
_maxWidth = stream.readUint16LE();
_firstChar = stream.readByte();
_lastChar = stream.readByte();
_defaultChar = stream.readByte();
/* byte breakChar = */ stream.readByte();
/* uint16 widthBytes = */ stream.readUint16LE();
/* uint32 device = */ stream.readUint32LE();
/* uint32 face = */ stream.readUint32LE();
/* uint32 bitsPointer = */ stream.readUint32LE();
uint32 bitsOffset = stream.readUint32LE();
/* byte reserved = */ stream.readByte();
if (version == 0x100) {
// Seems Win1 has an extra byte?
stream.readByte();
} else if (version == 0x300) {
// For Windows 3.0, Microsoft added 6 new fields. All of which are
// guaranteed to be 0. Which leads to the question: Why add these at all?
/* uint32 flags = */ stream.readUint32LE();
/* uint16 aSpace = */ stream.readUint16LE();
/* uint16 bSpace = */ stream.readUint16LE();
/* uint16 cSpace = */ stream.readUint16LE();
/* uint32 colorPointer = */ stream.readUint32LE();
stream.skip(16); // Reserved
}
// Begin loading in the glyphs
_glyphCount = (_lastChar - _firstChar) + 2;
delete[] _glyphs;
_glyphs = new GlyphEntry[_glyphCount];
for (uint16 i = 0; i < _glyphCount; i++) {
_glyphs[i].charWidth = stream.readUint16LE();
// Use the default if present
if (pixWidth)
_glyphs[i].charWidth = pixWidth;
_glyphs[i].offset = (version == 0x300) ? stream.readUint32LE() : stream.readUint16LE();
// Seems the offsets in the Win1 font format are based on bitsOffset
if (version == 0x100)
_glyphs[i].offset += bitsOffset;
}
// TODO: Currently only raster fonts are supported!
if (fontType & 1) {
warning("Vector FNT files not supported yet");
return false;
}
// Read in the bitmaps for the raster images
for (uint16 i = 0; i < _glyphCount - 1; i++) {
stream.seek(_glyphs[i].offset);
_glyphs[i].bitmap = new byte[_pixHeight * _glyphs[i].charWidth];
// Calculate the amount of columns
byte colCount = (_glyphs[i].charWidth + 7) / 8;
for (uint16 j = 0; j < colCount; j++) {
for (uint16 k = 0; k < _pixHeight; k++) {
byte x = stream.readByte();
uint offset = j * 8 + k * _glyphs[i].charWidth;
for (byte l = 0; l < 8 && j * 8 + l < _glyphs[i].charWidth; l++)
_glyphs[i].bitmap[offset + l] = (x & (1 << (7 - l))) ? 1 : 0;
}
}
#if 0
// Debug print
debug("Character %02x '%c' at %08x", indexToCharacter(i), indexToCharacter(i), _glyphs[i].offset);
for (uint16 j = 0; j < _pixHeight; j++) {
for (uint16 k = 0; k < _glyphs[i].charWidth; k++)
debugN("%c", _glyphs[i].bitmap[k + j * _glyphs[i].charWidth] ? 'X' : ' ');
debugN("\n");
}
#endif
}
return true;
}
void WinFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
assert(dst);
assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
assert(_glyphs);
GlyphEntry &glyph = _glyphs[characterToIndex(chr)];
for (uint16 i = 0; i < _pixHeight; i++) {
for (uint16 j = 0; j < glyph.charWidth; j++) {
if (glyph.bitmap[j + i * glyph.charWidth]) {
if (dst->format.bytesPerPixel == 1)
*((byte *)dst->getBasePtr(x + j, y + i)) = color;
else if (dst->format.bytesPerPixel == 2)
*((uint16 *)dst->getBasePtr(x + j, y + i)) = color;
else if (dst->format.bytesPerPixel == 4)
*((uint32 *)dst->getBasePtr(x + j, y + i)) = color;
}
}
}
}
int WinFont::getStyle() const {
int style = kFontStyleRegular;
// This has been taken from Wine Source
// https://github.com/wine-mirror/wine/blob/b9a61cde89e5dc6264b4c152f4dc24ecf064f8f6/include/wingdi.h#L728
if (_weight >= 700)
style |= kFontStyleBold;
if (_italic)
style |= kFontStyleItalic;
if (_underline)
style |= kFontStyleUnderline;
return style;
}
WinFont *WinFont::scaleFont(const WinFont *src, int newSize) {
if (!src) {
warning("WinFont::scaleFont(): Empty font reference in scale font");
return nullptr;
}
if (src->getFontHeight() == 0) {
warning("WinFont::scaleFont(): Requested to scale 0 size font");
return nullptr;
}
WinFont *scaledFont = new WinFont();
Graphics::Surface srcSurf;
srcSurf.create(MAX(src->getFontHeight() * 2, newSize * 2), MAX(src->getFontHeight() * 2, newSize * 2), PixelFormat::createFormatCLUT8());
int dstGraySize = newSize * 20 * newSize;
int *dstGray = (int *)malloc(dstGraySize * sizeof(int));
float scale = (float)newSize / (float)src->getFontHeight();
scaledFont->_pixHeight = (int)(roundf((float)src->_pixHeight * scale));
scaledFont->_maxWidth = (int)(roundf((float)src->_maxWidth * scale));
scaledFont->_ascent = src->_ascent;
scaledFont->_firstChar = src->_firstChar;
scaledFont->_lastChar = src->_lastChar;
scaledFont->_defaultChar = src->_defaultChar;
scaledFont->_italic = src->_italic;
scaledFont->_strikethrough = src->_strikethrough;
scaledFont->_underline = src->_underline;
scaledFont->_weight = src->_weight;
scaledFont->_name = Common::String(src->_name);
scaledFont->_glyphCount = src->_glyphCount;
GlyphEntry *glyphs = new GlyphEntry[src->_glyphCount];
for (int i = 0; i < src->_glyphCount; i++) {
glyphs[i].charWidth = (int)(roundf((float)src->_glyphs[i].charWidth * scale));
glyphs[i].offset = src->_glyphs[i].offset;
int boxWidth = glyphs[i].charWidth;
int boxHeight = scaledFont->_pixHeight;
int grayLevel = (boxWidth * boxHeight) / 3;
byte *bitmap = new byte[boxWidth * boxHeight];
memset(bitmap, 0, boxWidth * boxHeight);
// Scale single character
src->scaleSingleGlyph(&srcSurf, dstGray, dstGraySize, boxWidth, boxHeight, 0, 0, grayLevel, i + src->_firstChar,
src->_pixHeight, src->_glyphs[i].charWidth, scale);
// Convert back to bytes representation
byte *ptr = bitmap;
for (int y = 0; y < boxHeight; y++) {
byte *srcd = (byte *)srcSurf.getBasePtr(0, y);
byte *dst = ptr;
for (int x = 0; x < boxWidth; x++, srcd++) {
*dst++ = *srcd;
}
ptr += boxWidth;
}
glyphs[i].bitmap = bitmap;
}
scaledFont->_glyphs = glyphs;
free(dstGray);
srcSurf.free();
return (WinFont *)scaledFont;
}
} // End of namespace Graphics

120
graphics/fonts/winfont.h Normal file
View File

@@ -0,0 +1,120 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRAPHICS_WINFONT_H
#define GRAPHICS_WINFONT_H
#include "common/str.h"
#include "common/path.h"
#include "graphics/font.h"
namespace Common {
class SeekableReadStream;
class WinResources;
}
namespace Graphics {
struct WinFontDirEntry {
WinFontDirEntry() : points(0) {}
WinFontDirEntry(const Common::String &name, uint16 p) : faceName(name), points(p) {}
// This is really just a simple identifier to match a directory entry with
// If need-be, we can add other things to check such as italics and strikethrough, etc.
Common::String faceName;
uint16 points;
};
class WinFont : public Font {
public:
WinFont();
~WinFont();
/**
* Open a font with a name in an FON file.
*
* If dirEntry is not given, the first font in the FONTDIR will be loaded
*/
bool loadFromFON(const Common::Path &fileName, const WinFontDirEntry &dirEntry = WinFontDirEntry());
bool loadFromFON(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry = WinFontDirEntry());
/** Open a font from an FNT file */
bool loadFromFNT(const Common::Path &fileName);
/** Close this font */
void close();
// Font API
int getFontHeight() const { return _pixHeight; } //< pixels, not points - for points, see getFontSizeInPointsAtDPI()
int getFontAscent() const { return _ascent; }
int getMaxCharWidth() const { return _maxWidth; }
Common::String getName() const { return _name; }
int getCharWidth(uint32 chr) const;
void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
int getStyle() const;
int getFontSizeInPointsAtDPI(const int dpi) const;
static WinFont *scaleFont(const WinFont *src, int newSize);
private:
bool loadFromEXE(Common::WinResources *exe, const Common::Path &fileName, const WinFontDirEntry &dirEntry);
uint32 getFontIndex(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry);
Common::String getFONFontName(Common::SeekableReadStream &stream);
bool loadFromFNT(Common::SeekableReadStream &stream);
char indexToCharacter(uint16 index) const;
uint16 characterToIndex(uint32 character) const;
uint16 _pixHeight;
uint16 _maxWidth;
uint16 _ascent;
uint16 _sizeInPoints;
uint16 _dpi;
byte _firstChar;
byte _lastChar;
byte _defaultChar;
bool _italic;
bool _strikethrough;
bool _underline;
uint16 _weight;
Common::String _name;
enum {
kFontStyleRegular,
kFontStyleBold = 1,
kFontStyleItalic = 2,
kFontStyleUnderline = 4,
};
uint16 _glyphCount;
struct GlyphEntry {
GlyphEntry() { bitmap = 0; charWidth = 0; offset = 0; }
~GlyphEntry() { delete[] bitmap; }
uint16 charWidth;
uint32 offset;
byte *bitmap;
} *_glyphs;
};
} // End of namespace Graphics
#endif