naomi: printer support for f355 and tduno[2]. Fix some bios font glyphs
Thermal printer support for f355 (G2 ext bus) and tduno[2] (maple JVS) Change game id for sgdrvsim and dragntr3 to distinguish them. Fix cyrillic page in BIOS font.
This commit is contained in:
parent
fa525b4488
commit
78f80eb7dc
|
@ -842,6 +842,8 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
core/hw/naomi/card_reader.cpp
|
||||
core/hw/naomi/touchscreen.h
|
||||
core/hw/naomi/touchscreen.cpp
|
||||
core/hw/naomi/printer.h
|
||||
core/hw/naomi/printer.cpp
|
||||
core/hw/pvr/elan.cpp
|
||||
core/hw/pvr/elan.h
|
||||
core/hw/pvr/elan_struct.h
|
||||
|
@ -920,6 +922,12 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
core/hw/sh4/sh4_sched.h
|
||||
core/hw/sh4/storeq.cpp)
|
||||
|
||||
cmrc_add_resources(flycast-resources
|
||||
fonts/printer_ascii8x16.bin
|
||||
fonts/printer_ascii12x24.bin
|
||||
fonts/printer_kanji16x16.bin
|
||||
fonts/printer_kanji24x24.bin)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/imgread/cdi.cpp
|
||||
core/imgread/chd.cpp
|
||||
|
|
|
@ -741,10 +741,6 @@ void loadGameSpecificSettings()
|
|||
if (settings.content.gameId.empty())
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.content.gameId = naomi_game_id;
|
||||
}
|
||||
|
||||
// Default per-game settings
|
||||
loadSpecialSettings();
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "stdclass.h"
|
||||
#include "cfg/option.h"
|
||||
#include "network/output.h"
|
||||
#include "hw/naomi/printer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
@ -1510,6 +1511,7 @@ void maple_naomi_jamma::serialize(Serializer& ser) const
|
|||
{
|
||||
maple_base::serialize(ser);
|
||||
ser << crazy_mode;
|
||||
ser << hotd2p;
|
||||
ser << jvs_repeat_request;
|
||||
ser << jvs_receive_length;
|
||||
ser << jvs_receive_buffer;
|
||||
|
@ -1523,6 +1525,10 @@ void maple_naomi_jamma::deserialize(Deserializer& deser)
|
|||
{
|
||||
maple_base::deserialize(deser);
|
||||
deser >> crazy_mode;
|
||||
if (deser.version() >= Deserializer::V35)
|
||||
deser >> hotd2p;
|
||||
else
|
||||
hotd2p = settings.content.gameId == "hotd2p";
|
||||
deser >> jvs_repeat_request;
|
||||
deser >> jvs_receive_length;
|
||||
deser >> jvs_receive_buffer;
|
||||
|
@ -1674,7 +1680,7 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
|||
break;
|
||||
|
||||
default:
|
||||
if (jvs_cmd >= 0x20 && jvs_cmd <= 0x38) // Read inputs and more
|
||||
if ((jvs_cmd >= 0x20 && jvs_cmd <= 0x38) || jvs_cmd == 0x74) // Read inputs and more
|
||||
{
|
||||
LOGJVS("JVS Node %d: ", node_id);
|
||||
u32 buttons[4] {};
|
||||
|
@ -1910,6 +1916,25 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
|||
cmdi += 4;
|
||||
break;
|
||||
|
||||
case 0x74: // Custom: used to read and write the board serial port (touch de uno)
|
||||
{
|
||||
u32 len = buffer_in[cmdi + 1];
|
||||
for (u32 i = 0; i < len; i++)
|
||||
printer::print(buffer_in[cmdi + 2 + i]);
|
||||
|
||||
cmdi += len + 2;
|
||||
JVS_STATUS1(); // report
|
||||
// data
|
||||
// 00 hardware error
|
||||
// 01 head up error
|
||||
// 02 Vp Volt error
|
||||
// 03 auto cutter error
|
||||
// 04 head temp error
|
||||
// 3* paper end error
|
||||
JVS_OUT(0xf); // printer ok
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
INFO_LOG(MAPLE, "JVS: Unknown input type %x", buffer_in[cmdi]);
|
||||
JVS_OUT(2); // report byte: command error
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "network/output.h"
|
||||
#include "hw/sh4/modules/modules.h"
|
||||
#include "rend/gui.h"
|
||||
#include "printer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -846,3 +847,42 @@ void initDriveSimSerialPipe()
|
|||
pipe.reset();
|
||||
serial_setPipe(&pipe);
|
||||
}
|
||||
|
||||
G2PrinterConnection g2PrinterConnection;
|
||||
|
||||
u32 G2PrinterConnection::read(u32 addr, u32 size)
|
||||
{
|
||||
if (addr == STATUS_REG_ADDR)
|
||||
{
|
||||
u32 ret = printerStat;
|
||||
printerStat |= 1;
|
||||
DEBUG_LOG(NAOMI, "Printer status == %x", ret);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(NAOMI, "Unhandled G2 Ext read<%d> at %x", size, addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void G2PrinterConnection::write(u32 addr, u32 size, u32 data)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case DATA_REG_ADDR:
|
||||
for (u32 i = 0; i < size; i++)
|
||||
printer::print((char)(data >> (i * 8)));
|
||||
break;
|
||||
|
||||
case STATUS_REG_ADDR:
|
||||
DEBUG_LOG(NAOMI, "Printer status = %x", data);
|
||||
printerStat &= ~1;
|
||||
break;
|
||||
|
||||
default:
|
||||
INFO_LOG(NAOMI, "Unhandled G2 Ext write<%d> at %x: %x", size, addr, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,19 +33,39 @@ void initDriveSimSerialPipe();
|
|||
u32 libExtDevice_ReadMem_A0_006(u32 addr, u32 size);
|
||||
void libExtDevice_WriteMem_A0_006(u32 addr, u32 data, u32 size);
|
||||
|
||||
class G2PrinterConnection
|
||||
{
|
||||
public:
|
||||
u32 read(u32 addr, u32 size);
|
||||
void write(u32 addr, u32 size, u32 data);
|
||||
|
||||
static constexpr u32 STATUS_REG_ADDR = 0x1018000;
|
||||
static constexpr u32 DATA_REG_ADDR = 0x1010000;
|
||||
|
||||
private:
|
||||
u32 printerStat = 0xf;
|
||||
};
|
||||
extern G2PrinterConnection g2PrinterConnection;
|
||||
|
||||
extern Multiboard *multiboard;
|
||||
|
||||
//Area 0 , 0x01000000- 0x01FFFFFF [G2 Ext. Device]
|
||||
static inline u32 g2ext_readMem(u32 addr, u32 size)
|
||||
{
|
||||
if (addr == G2PrinterConnection::STATUS_REG_ADDR || addr == G2PrinterConnection::DATA_REG_ADDR)
|
||||
return g2PrinterConnection.read(addr, size);
|
||||
if (multiboard != nullptr)
|
||||
return multiboard->readG2Ext(addr, size);
|
||||
|
||||
INFO_LOG(NAOMI, "Unhandled G2 Ext read<%d> at %x", size, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void g2ext_writeMem(u32 addr, u32 data, u32 size)
|
||||
{
|
||||
if (multiboard != nullptr)
|
||||
if (addr == G2PrinterConnection::STATUS_REG_ADDR || addr == G2PrinterConnection::DATA_REG_ADDR)
|
||||
g2PrinterConnection.write(addr, size, data);
|
||||
else if (multiboard != nullptr)
|
||||
multiboard->writeG2Ext(addr, size, data);
|
||||
else
|
||||
INFO_LOG(NAOMI, "Unhandled G2 Ext write<%d> at %x: %x", size, addr, data);
|
||||
|
|
|
@ -40,11 +40,11 @@
|
|||
#include "card_reader.h"
|
||||
#include "naomi_flashrom.h"
|
||||
#include "touchscreen.h"
|
||||
#include "printer.h"
|
||||
|
||||
Cartridge *CurrentCartridge;
|
||||
bool bios_loaded = false;
|
||||
|
||||
char naomi_game_id[33];
|
||||
InputDescriptors *NaomiGameInputs;
|
||||
u8 *naomi_default_eeprom;
|
||||
|
||||
|
@ -413,7 +413,7 @@ static void loadMameRom(const char *filename, LoadProgress *progress)
|
|||
md5.getDigest(settings.network.md5.game);
|
||||
}
|
||||
// Default game name if ROM boot id isn't found
|
||||
strcpy(naomi_game_id, game->name);
|
||||
settings.content.gameId = game->name;
|
||||
|
||||
} catch (...) {
|
||||
delete CurrentCartridge;
|
||||
|
@ -595,12 +595,21 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
|||
|
||||
atomiswaveForceFeedback = false;
|
||||
RomBootID bootId;
|
||||
if (CurrentCartridge->GetBootId(&bootId))
|
||||
if (CurrentCartridge->GetBootId(&bootId)
|
||||
&& (!memcmp(bootId.boardName, "NAOMI", 5) || !memcmp(bootId.boardName, "Naomi2", 6)))
|
||||
{
|
||||
std::string gameId = trim_trailing_ws(std::string(bootId.gameTitle[0], &bootId.gameTitle[0][32]));
|
||||
if (strlen(gameId.c_str()) > 0)
|
||||
strcpy(naomi_game_id, gameId.c_str());
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s] region %x players %x vertical %x", naomi_game_id, (u8)bootId.country, bootId.cabinet, bootId.vertical);
|
||||
if (gameId == "SAMPLE GAME MAX LONG NAME-")
|
||||
{
|
||||
// Use better game names
|
||||
if (!strcmp(CurrentCartridge->game->name, "sgdrvsim"))
|
||||
gameId = "SEGA DRIVING SIMULATOR";
|
||||
else if (!strcmp(CurrentCartridge->game->name, "dragntr3"))
|
||||
gameId = "DRAGON TREASURE 3";
|
||||
}
|
||||
if (!gameId.empty())
|
||||
settings.content.gameId = gameId;
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s] region %x players %x vertical %x", settings.content.gameId.c_str(), (u8)bootId.country, bootId.cabinet, bootId.vertical);
|
||||
|
||||
if (gameId == "INITIAL D"
|
||||
|| gameId == "INITIAL D Ver.2"
|
||||
|
@ -616,7 +625,7 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
|||
}
|
||||
else if (gameId == "THE KING OF ROUTE66"
|
||||
|| gameId == "CLUB KART IN JAPAN"
|
||||
|| gameId == "SAMPLE GAME MAX LONG NAME-") // Driving Simulator
|
||||
|| gameId == "SEGA DRIVING SIMULATOR")
|
||||
{
|
||||
if (settings.naomi.drivingSimSlave == 0)
|
||||
initMidiForceFeedback();
|
||||
|
@ -626,10 +635,17 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
|||
{
|
||||
touchscreen::init();
|
||||
}
|
||||
if (gameId == " TOUCH DE UNOH -------------"
|
||||
|| gameId == " TOUCH DE UNOH 2 -----------"
|
||||
// only for F355 Deluxe
|
||||
|| (gameId == "F355 CHALLENGE JAPAN" && !strcmp(CurrentCartridge->game->name, "f355")))
|
||||
{
|
||||
printer::init();
|
||||
}
|
||||
|
||||
#ifdef NAOMI_MULTIBOARD
|
||||
// Not a multiboard game but needs the same desktop environment
|
||||
if (gameId == "SAMPLE GAME MAX LONG NAME-") // Driving Simulator
|
||||
if (gameId == "SEGA DRIVING SIMULATOR")
|
||||
{
|
||||
initDriveSimSerialPipe();
|
||||
|
||||
|
@ -659,7 +675,7 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
|||
#endif
|
||||
}
|
||||
else
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", settings.content.gameId.c_str());
|
||||
}
|
||||
|
||||
void naomi_cart_ConfigureEEPROM()
|
||||
|
@ -678,6 +694,7 @@ void naomi_cart_ConfigureEEPROM()
|
|||
void naomi_cart_Close()
|
||||
{
|
||||
touchscreen::term();
|
||||
printer::term();
|
||||
delete CurrentCartridge;
|
||||
CurrentCartridge = nullptr;
|
||||
NaomiGameInputs = nullptr;
|
||||
|
@ -689,6 +706,7 @@ void naomi_cart_serialize(Serializer& ser)
|
|||
if (CurrentCartridge != nullptr)
|
||||
CurrentCartridge->Serialize(ser);
|
||||
touchscreen::serialize(ser);
|
||||
printer::serialize(ser);
|
||||
}
|
||||
|
||||
void naomi_cart_deserialize(Deserializer& deser)
|
||||
|
@ -696,6 +714,7 @@ void naomi_cart_deserialize(Deserializer& deser)
|
|||
if (CurrentCartridge != nullptr && (!settings.platform.isAtomiswave() || deser.version() >= Deserializer::V10_LIBRETRO))
|
||||
CurrentCartridge->Deserialize(deser);
|
||||
touchscreen::deserialize(deser);
|
||||
printer::deserialize(deser);
|
||||
}
|
||||
|
||||
int naomi_cart_GetPlatform(const char *path)
|
||||
|
|
|
@ -140,7 +140,6 @@ void naomi_cart_ConfigureEEPROM();
|
|||
void naomi_cart_serialize(Serializer& ser);
|
||||
void naomi_cart_deserialize(Deserializer& deser);
|
||||
|
||||
extern char naomi_game_id[];
|
||||
extern u8 *naomi_default_eeprom;
|
||||
|
||||
extern Cartridge *CurrentCartridge;
|
||||
|
|
|
@ -561,25 +561,25 @@ static u8 vtennisg_eeprom_dump[] {
|
|||
0x00, 0x00,
|
||||
};
|
||||
|
||||
// printer disabled, touchscreen calibrated
|
||||
// touchscreen calibrated
|
||||
static u8 tduno_eeprom_dump[] {
|
||||
0x5f, 0xdc, 0x10, 0x42, 0x41, 0x50, 0x31, 0x09, 0x00, 0x1a, 0x01, 0x01, 0x01, 0x00, 0x11, 0x11, 0x11, 0x11,
|
||||
0x5f, 0xdc, 0x10, 0x42, 0x41, 0x50, 0x31, 0x09, 0x00, 0x1a, 0x01, 0x01, 0x01, 0x00, 0x11, 0x11, 0x11, 0x11,
|
||||
0xc4, 0x10, 0x18, 0x18, 0xc4, 0x10, 0x18, 0x18, 0x14, 0x00, 0x14, 0x00, 0x16, 0x00, 0x16, 0x00, 0x97, 0x6d,
|
||||
0x80, 0x3f, 0xa4, 0x4a, 0x80, 0x3f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00,
|
||||
0x16, 0x00, 0x16, 0x00, 0x97, 0x6d, 0x80, 0x3f, 0xa4, 0x4a, 0x80, 0x3f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
|
||||
0xe4, 0x28, 0x18, 0x18, 0xe4, 0x28, 0x18, 0x18, 0x14, 0x00, 0x14, 0x00, 0x16, 0x00, 0x16, 0x00, 0x97, 0x6d,
|
||||
0x80, 0x3f, 0xa4, 0x4a, 0x80, 0x3f, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00,
|
||||
0x16, 0x00, 0x16, 0x00, 0x97, 0x6d, 0x80, 0x3f, 0xa4, 0x4a, 0x80, 0x3f, 0x01, 0x00, 0x01, 0x00, 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, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
};
|
||||
|
||||
// printer disabled, touchscreen calibrated
|
||||
// touchscreen calibrated
|
||||
static u8 tduno2_eeprom_dump[] {
|
||||
0x8a, 0xd3, 0x10, 0x42, 0x42, 0x48, 0x32, 0x09, 0x00, 0x1a, 0x01, 0x01, 0x01, 0x00, 0x11, 0x11, 0x11, 0x11,
|
||||
0x8a, 0xd3, 0x10, 0x42, 0x42, 0x48, 0x32, 0x09, 0x00, 0x1a, 0x01, 0x01, 0x01, 0x00, 0x11, 0x11, 0x11, 0x11,
|
||||
0xd1, 0xbd, 0x18, 0x18, 0xd1, 0xbd, 0x18, 0x18, 0x28, 0x00, 0x28, 0x00, 0x2a, 0x00, 0x29, 0x00, 0xbe, 0xeb,
|
||||
0x80, 0x3f, 0xaa, 0xa4, 0x80, 0x3f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00,
|
||||
0x2a, 0x00, 0x29, 0x00, 0xbe, 0xeb, 0x80, 0x3f, 0xaa, 0xa4, 0x80, 0x3f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
|
||||
0xb2, 0x67, 0x18, 0x18, 0xb2, 0x67, 0x18, 0x18, 0x28, 0x00, 0x28, 0x00, 0x2a, 0x00, 0x29, 0x00, 0xbe, 0xeb,
|
||||
0x80, 0x3f, 0xaa, 0xa4, 0x80, 0x3f, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00,
|
||||
0x2a, 0x00, 0x29, 0x00, 0xbe, 0xeb, 0x80, 0x3f, 0xaa, 0xa4, 0x80, 0x3f, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x4c, 0x27, 0xab, 0x37, 0x7e, 0x03, 0x49, 0x54, 0x78, 0x45, 0x61, 0x7a, 0xa3, 0x52, 0xfc, 0xca,
|
||||
0xcb, 0x64, 0xbc, 0xe5, 0xa5, 0x68, 0x16, 0x42, 0x69, 0x4e, 0x4c, 0xe8, 0xfc, 0x82, 0x81, 0x78, 0xa6, 0x25,
|
||||
0x63, 0x46,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright 2023 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
namespace printer
|
||||
{
|
||||
|
||||
void init();
|
||||
void term();
|
||||
void print(char c);
|
||||
void serialize(Serializer& ser);
|
||||
void deserialize(Deserializer& deser);
|
||||
|
||||
}
|
|
@ -371,7 +371,7 @@ void SetNaomiNetworkConfig(int node)
|
|||
{
|
||||
configure_maxspeed_flash(node != -1, node == 0);
|
||||
}
|
||||
else if (!strcmp("F355 CHALLENGE JAPAN", naomi_game_id))
|
||||
else if (gameId == "F355 CHALLENGE JAPAN")
|
||||
{
|
||||
// FIXME need default flash
|
||||
write_naomi_flash(0x230, node == -1 ? 0 : node == 0 ? 1 : 2);
|
||||
|
@ -392,7 +392,7 @@ bool NaomiNetworkSupported()
|
|||
"F355 CHALLENGE JAPAN",
|
||||
// Naomi 2
|
||||
"CLUB KART IN JAPAN", "INITIAL D", "INITIAL D Ver.2", "INITIAL D Ver.3", "THE KING OF ROUTE66",
|
||||
"SAMPLE GAME MAX LONG NAME-" // Driving Simulator
|
||||
"SEGA DRIVING SIMULATOR"
|
||||
};
|
||||
if (!config::NetworkEnable)
|
||||
return false;
|
||||
|
|
|
@ -59,7 +59,8 @@ public:
|
|||
V32,
|
||||
V33,
|
||||
V34,
|
||||
Current = V34,
|
||||
V35,
|
||||
Current = V35,
|
||||
|
||||
Next = Current + 1,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(FlycastFonts)
|
||||
add_executable(biosfont biosfont.cpp fontutil.cpp)
|
||||
add_executable(printerfont printerfont.cpp fontutil.cpp)
|
||||
|
||||
target_compile_features(biosfont PRIVATE cxx_std_17)
|
||||
target_compile_features(printerfont PRIVATE cxx_std_17)
|
||||
set_target_properties(biosfont PROPERTIES CXX_EXTENSIONS OFF LINK_FLAGS_RELEASE -s)
|
||||
set_target_properties(printerfont PROPERTIES CXX_EXTENSIONS OFF LINK_FLAGS_RELEASE -s)
|
||||
target_compile_options(biosfont PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wall>)
|
||||
target_compile_options(printerfont PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wall>)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(freetype2 IMPORTED_TARGET freetype2)
|
||||
target_link_libraries(biosfont PRIVATE PkgConfig::freetype2)
|
||||
target_link_libraries(printerfont PRIVATE PkgConfig::freetype2)
|
Binary file not shown.
|
@ -0,0 +1,455 @@
|
|||
//
|
||||
// Build the dreamcast BIOS font table using the specified fonts with the help of FreeType2.
|
||||
// Fonts should be listed in increasing priority order since glyphs are replaced by later fonts if found.
|
||||
//
|
||||
// biosfont 12x24rk.pcf jiskan24.pcf neep-iso8859-1-12x24.pcf
|
||||
//
|
||||
// 12x24rk.pcf: Copyright 1989 by Sony Corp.
|
||||
// Attrib license
|
||||
// jiskan24.pcf: Licensed under Public Domain
|
||||
// neep-iso8859-1-12x24.pcf: Copyright Jim Knoble <jmknoble@pobox.com>
|
||||
// GPL v2+
|
||||
//
|
||||
#include "fontutil.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include <freetype/ftbdf.h>
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <wchar.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
// BIOS table
|
||||
// 288 12x24 characters (unicode encoding)
|
||||
const unsigned charcodes12[] = {
|
||||
// from, to
|
||||
// overbar
|
||||
0xaf, 0xaf,
|
||||
// ASCII 33-126
|
||||
'!', '~',
|
||||
// Yen
|
||||
0xa5, 0xa5,
|
||||
// ISO-8859-1 (chars 160-255)
|
||||
0xa0, 0xff,
|
||||
// JIS X0201 (chars 160-255)
|
||||
' ', ' ',
|
||||
0xff61, 0xff9f,
|
||||
// FIXME chars E0-FF are unknown???
|
||||
0xff61, 0xff7f, // wrong
|
||||
' ', ' ',
|
||||
};
|
||||
|
||||
// 7078 24x24 characters (JIS X0208 encoding)
|
||||
const unsigned charcodes24[] = {
|
||||
// prefix, from, to
|
||||
// JIS X0208 row 33, Symbols
|
||||
0x21, 0x21, 0x7e,
|
||||
// JIS X0208 row 34, Symbols
|
||||
0x22, 0x21, 0x7e,
|
||||
// JIS X0208 row 35, Roman alphabet
|
||||
0x23, 0x21, 0x7e,
|
||||
// JIS X0208 row 36, Hiragana
|
||||
0x24, 0x21, 0x7e,
|
||||
// JIS X0208 row 37, Katakana
|
||||
0x25, 0x21, 0x7e,
|
||||
// JIS X0208 row 38, Greek
|
||||
0x26, 0x21, 0x7e,
|
||||
// JIS X0208 row 39, Cyrillic
|
||||
0x27, 0x21, 0x7e,
|
||||
// JIS X0208 row 48
|
||||
0x30, 0x21, 0x7e,
|
||||
// JIS X0208 row 49
|
||||
0x31, 0x21, 0x7e,
|
||||
// JIS X0208 row 50
|
||||
0x32, 0x21, 0x7e,
|
||||
// JIS X0208 row 51
|
||||
0x33, 0x21, 0x7e,
|
||||
// JIS X0208 row 52
|
||||
0x34, 0x21, 0x7e,
|
||||
// JIS X0208 row 53
|
||||
0x35, 0x21, 0x7e,
|
||||
// JIS X0208 row 54
|
||||
0x36, 0x21, 0x7e,
|
||||
// JIS X0208 row 55
|
||||
0x37, 0x21, 0x7e,
|
||||
// JIS X0208 row 56
|
||||
0x38, 0x21, 0x7e,
|
||||
// JIS X0208 row 57
|
||||
0x39, 0x21, 0x7e,
|
||||
// JIS X0208 row 58
|
||||
0x3a, 0x21, 0x7e,
|
||||
// JIS X0208 row 59
|
||||
0x3b, 0x21, 0x7e,
|
||||
// JIS X0208 row 60
|
||||
0x3c, 0x21, 0x7e,
|
||||
// JIS X0208 row 61
|
||||
0x3d, 0x21, 0x7e,
|
||||
// JIS X0208 row 62
|
||||
0x3e, 0x21, 0x7e,
|
||||
// JIS X0208 row 63
|
||||
0x3f, 0x21, 0x7e,
|
||||
// JIS X0208 row 64
|
||||
0x40, 0x21, 0x7e,
|
||||
// JIS X0208 row 65
|
||||
0x41, 0x21, 0x7e,
|
||||
// JIS X0208 row 66
|
||||
0x41, 0x21, 0x7e,
|
||||
// JIS X0208 row 67
|
||||
0x43, 0x21, 0x7e,
|
||||
// JIS X0208 row 68
|
||||
0x44, 0x21, 0x7e,
|
||||
// JIS X0208 row 69
|
||||
0x45, 0x21, 0x7e,
|
||||
// JIS X0208 row 70
|
||||
0x46, 0x21, 0x7e,
|
||||
// JIS X0208 row 71
|
||||
0x47, 0x21, 0x7e,
|
||||
// JIS X0208 row 72
|
||||
0x48, 0x21, 0x7e,
|
||||
// JIS X0208 row 73
|
||||
0x49, 0x21, 0x7e,
|
||||
// JIS X0208 row 74
|
||||
0x4a, 0x21, 0x7e,
|
||||
// JIS X0208 row 75
|
||||
0x4b, 0x21, 0x7e,
|
||||
// JIS X0208 row 76
|
||||
0x4c, 0x21, 0x7e,
|
||||
// JIS X0208 row 77
|
||||
0x4d, 0x21, 0x7e,
|
||||
// JIS X0208 row 78
|
||||
0x4e, 0x21, 0x7e,
|
||||
// JIS X0208 row 79
|
||||
0x4f, 0x21, 0x7e,
|
||||
|
||||
// JIS X0208 row 80
|
||||
0x50, 0x21, 0x7e,
|
||||
// JIS X0208 row 81
|
||||
0x51, 0x21, 0x7e,
|
||||
// JIS X0208 row 82
|
||||
0x52, 0x21, 0x7e,
|
||||
// JIS X0208 row 83
|
||||
0x53, 0x21, 0x7e,
|
||||
// JIS X0208 row 84
|
||||
0x54, 0x21, 0x7e,
|
||||
// JIS X0208 row 85
|
||||
0x55, 0x21, 0x7e,
|
||||
// JIS X0208 row 86
|
||||
0x56, 0x21, 0x7e,
|
||||
// JIS X0208 row 87
|
||||
0x57, 0x21, 0x7e,
|
||||
// JIS X0208 row 88
|
||||
0x58, 0x21, 0x7e,
|
||||
// JIS X0208 row 89
|
||||
0x59, 0x21, 0x7e,
|
||||
// JIS X0208 row 90
|
||||
0x5a, 0x21, 0x7e,
|
||||
// JIS X0208 row 91
|
||||
0x5b, 0x21, 0x7e,
|
||||
// JIS X0208 row 92
|
||||
0x5c, 0x21, 0x7e,
|
||||
// JIS X0208 row 93
|
||||
0x5d, 0x21, 0x7e,
|
||||
// JIS X0208 row 94
|
||||
0x5e, 0x21, 0x7e,
|
||||
// JIS X0208 row 95
|
||||
0x5f, 0x21, 0x7e,
|
||||
// JIS X0208 row 96
|
||||
0x60, 0x21, 0x7e,
|
||||
// JIS X0208 row 97
|
||||
0x61, 0x21, 0x7e,
|
||||
// JIS X0208 row 98
|
||||
0x62, 0x21, 0x7e,
|
||||
// JIS X0208 row 99
|
||||
0x63, 0x21, 0x7e,
|
||||
// JIS X0208 row 100
|
||||
0x64, 0x21, 0x7e,
|
||||
// JIS X0208 row 101
|
||||
0x65, 0x21, 0x7e,
|
||||
// JIS X0208 row 102
|
||||
0x66, 0x21, 0x7e,
|
||||
// JIS X0208 row 103
|
||||
0x67, 0x21, 0x7e,
|
||||
// JIS X0208 row 104
|
||||
0x68, 0x21, 0x7e,
|
||||
// JIS X0208 row 105
|
||||
0x69, 0x21, 0x7e,
|
||||
// JIS X0208 row 106
|
||||
0x6a, 0x21, 0x7e,
|
||||
// JIS X0208 row 107
|
||||
0x6b, 0x21, 0x7e,
|
||||
// JIS X0208 row 108
|
||||
0x6c, 0x21, 0x7e,
|
||||
// JIS X0208 row 109
|
||||
0x6d, 0x21, 0x7e,
|
||||
// JIS X0208 row 110
|
||||
0x6e, 0x21, 0x7e,
|
||||
// JIS X0208 row 111
|
||||
0x6f, 0x21, 0x7e,
|
||||
// JIS X0208 row 112
|
||||
0x70, 0x21, 0x7e,
|
||||
// JIS X0208 row 113
|
||||
0x71, 0x21, 0x7e,
|
||||
// JIS X0208 row 114
|
||||
0x72, 0x21, 0x7e,
|
||||
// JIS X0208 row 115
|
||||
0x73, 0x21, 0x7e,
|
||||
// JIS X0208 row 116
|
||||
0x74, 0x21, 0x26,
|
||||
// TODO Dreamcast symbols (22 chars)
|
||||
// copyright U+24B8
|
||||
// register U+24C7
|
||||
// trademark U+2122
|
||||
// up arrow U+2B06
|
||||
// down U+2B07
|
||||
// left U+2B05
|
||||
// right U+27A1 ???
|
||||
// up+right U+2B08
|
||||
// down+right U+2B0A
|
||||
// down+left U+2B0B
|
||||
// up+left U+2B09
|
||||
// circled A U+24B6
|
||||
// circled B U+24B7
|
||||
// circled C U+24B8
|
||||
// circled D U+24B8
|
||||
// circled X U+24CD
|
||||
// circled Y U+24CE
|
||||
// circled Z U+24CF
|
||||
// squared L U+1F13B (Supplementary Multilingual Plane)
|
||||
// squared R U+1F141 (Supplementary Multilingual Plane)
|
||||
// start button U+1F142 (Squared S, SMP)
|
||||
// VMU U+1F4DF (pager) U+1F4F1 (mobile phone)
|
||||
};
|
||||
|
||||
static uint8_t biosfont[288 * 36 + 7078 * 72];
|
||||
|
||||
static FT_Library library;
|
||||
static FT_Face face;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
loadjisx208Table();
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <font>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
int error = FT_Init_FreeType(&library);
|
||||
if (error)
|
||||
{
|
||||
fprintf(stderr, "FreeType init failed\n");
|
||||
return 1;
|
||||
}
|
||||
for (int font = 1; font < argc; font++)
|
||||
{
|
||||
const char *fontname = argv[font];
|
||||
long index = 0;
|
||||
if (strlen(fontname) >= 4 && !strcmp(fontname + strlen(fontname) - 4, ".ttc"))
|
||||
// 5: NotoSans Mono CJK.ttc
|
||||
index = strtoul(argv[++font], nullptr, 10);
|
||||
error = FT_New_Face(library, fontname, index, &face);
|
||||
if (error)
|
||||
{
|
||||
fprintf(stderr, "Can't load %s\n", fontname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *registry;
|
||||
const char *encoding;
|
||||
FT_Get_BDF_Charset_ID(face, &encoding, ®istry);
|
||||
printf("%s: %s %s\n%ld glyphs\n%d fixed sizes\n%d charmaps\n", fontname, encoding, registry, face->num_glyphs, face->num_fixed_sizes, face->num_charmaps);
|
||||
FT_Bitmap_Size *size = face->available_sizes;
|
||||
for (int i = 0; i < face->num_fixed_sizes; i++, size++)
|
||||
printf("%d: %d x %d\n", i + 1, size->width, size->height);
|
||||
if (face->num_fixed_sizes == 0)
|
||||
FT_Set_Pixel_Sizes(face, 0, 24);
|
||||
|
||||
bool jisx0201Encoding = false;
|
||||
bool jisx0208Encoding = false;
|
||||
if (registry != nullptr)
|
||||
{
|
||||
if (!strcmp(registry, "JISX0208.1983"))
|
||||
{
|
||||
jisx0208Encoding = true;
|
||||
FT_Set_Charmap(face, face->charmaps[0]);
|
||||
}
|
||||
else if (!strcmp(registry, "JISX0201.1976"))
|
||||
{
|
||||
jisx0201Encoding = true;
|
||||
FT_Set_Charmap(face, face->charmaps[0]);
|
||||
}
|
||||
}
|
||||
/* list chars
|
||||
unsigned gindex;
|
||||
long charcode = FT_Get_First_Char(face, &gindex);
|
||||
while (gindex != 0)
|
||||
{
|
||||
printf("code %lx index %d\n", charcode, gindex);
|
||||
charcode = FT_Get_Next_Char(face, charcode, &gindex);
|
||||
}
|
||||
*/
|
||||
|
||||
unsigned offset = 0;
|
||||
if (jisx0208Encoding)
|
||||
{
|
||||
offset = 288 * 36;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < std::size(charcodes12); i += 2)
|
||||
{
|
||||
int from = charcodes12[i];
|
||||
int to = charcodes12[i + 1];
|
||||
for (int j = from; j <= to; j++)
|
||||
{
|
||||
int code = j;
|
||||
if (jisx0201Encoding)
|
||||
{
|
||||
if (code >= 0xff61 && code <= 0xff9f)
|
||||
code = code - 0xff61 + 0xa1;
|
||||
else if (code >= 0x80) {
|
||||
offset += 36;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!loadGlyph(face, code, 12, 24)) {
|
||||
offset += 36;
|
||||
continue;
|
||||
}
|
||||
uint8_t *p = face->glyph->bitmap.buffer;
|
||||
for (int r = 0; r < 24; r++)
|
||||
{
|
||||
if (r & 1)
|
||||
{
|
||||
biosfont[offset + 1] |= p[0] >> 4;
|
||||
biosfont[offset + 2] = ((p[0] & 0xf) << 4) | (p[1] >> 4);
|
||||
offset += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
biosfont[offset] = p[0];
|
||||
biosfont[offset + 1] = p[1];
|
||||
}
|
||||
p += face->glyph->bitmap.pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Final offset(12) %d 288 * 36 = %d\n", offset, 288 * 36);
|
||||
}
|
||||
|
||||
if (jisx0201Encoding)
|
||||
{
|
||||
offset += 7078 * 72;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t range = 0; range < std::size(charcodes24); range += 3)
|
||||
{
|
||||
int prefix = charcodes24[range];
|
||||
int from = charcodes24[range + 1];
|
||||
int to = charcodes24[range + 2];
|
||||
for (int j = from; j <= to; j++)
|
||||
{
|
||||
uint16_t jis = (prefix << 8) | j;
|
||||
wchar_t u;
|
||||
if (jisx0208Encoding) {
|
||||
u = jis;
|
||||
}
|
||||
else
|
||||
{
|
||||
u = jisx208[jis];
|
||||
if (u == 0) {
|
||||
printf("JISX208 conversion failed: [%02x %02x]\n", prefix, j);
|
||||
offset += 72;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!loadGlyph(face, u, 24, 24)) {
|
||||
offset += 72;
|
||||
continue;
|
||||
}
|
||||
const FT_GlyphSlot glyph = face->glyph;
|
||||
uint8_t *p = glyph->bitmap.buffer;
|
||||
// left=0 top=22 is ok
|
||||
// other values need to shift the bitmap
|
||||
if (glyph->bitmap.pitch == 3 && glyph->bitmap_left == 0 && glyph->bitmap_top == 22) {
|
||||
memcpy(&biosfont[offset], p, 72);
|
||||
offset += 72;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int topFill = std::max(0, 21 - glyph->bitmap_top);
|
||||
memset(&biosfont[offset], 0, topFill * 3);
|
||||
offset += topFill * 3;
|
||||
const int rows = std::min((int)glyph->bitmap.rows, 24 - topFill);
|
||||
const int width = glyph->bitmap.width;
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
if (width == 24)
|
||||
{
|
||||
memcpy(&biosfont[offset], p, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
int left = glyph->bitmap_left;
|
||||
unsigned o = offset;
|
||||
while (left >= 8 && o - offset < 3)
|
||||
{
|
||||
left -= 8;
|
||||
biosfont[o++] = 0;
|
||||
}
|
||||
if (o - offset < 3)
|
||||
{
|
||||
biosfont[o++] = p[0] >> left;
|
||||
if (left > 0 && o - offset < 3)
|
||||
biosfont[o] = p[0] << (8 - left);
|
||||
if (width > 8 && o - offset < 3)
|
||||
{
|
||||
biosfont[o++] |= p[1] >> left;
|
||||
if (o - offset < 3)
|
||||
{
|
||||
if (left > 0)
|
||||
biosfont[o] = p[1] << (8 - left);
|
||||
if (width > 16)
|
||||
biosfont[o++] |= p[2] >> left;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
o++;
|
||||
if (o - offset < 3)
|
||||
biosfont[o] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
offset += 3;
|
||||
p += glyph->bitmap.pitch;
|
||||
}
|
||||
const int bottomFill = 24 - (topFill + rows);
|
||||
assert(bottomFill >= 0);
|
||||
memset(&biosfont[offset], 0, bottomFill * 3);
|
||||
offset += bottomFill * 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Final offset(24) %d 288 * 36 + 7078 * 72 = %d\n", offset, 288 * 36 + 7078 * 72);
|
||||
FT_Done_Face(face);
|
||||
}
|
||||
FT_Done_FreeType(library);
|
||||
|
||||
FILE *f = fopen("biosfont.bin", "wb");
|
||||
if (f == nullptr) {
|
||||
perror("biosfont.bin");
|
||||
return 1;
|
||||
}
|
||||
fwrite(biosfont, 1, sizeof(biosfont), f);
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
//
|
||||
// Make PNGs of the BIOS font for half- and full-width glyphs.
|
||||
// Compare with http://submarine.org.uk/info/biosfont/
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb/stb_image_write.h>
|
||||
#include <vector>
|
||||
|
||||
// BIOS table
|
||||
// 288 12x24 characters (unicode encoding)
|
||||
const unsigned charcodes12[] = {
|
||||
// from, to
|
||||
// overbar
|
||||
1,
|
||||
// ASCII 33-126
|
||||
94,
|
||||
// Yen
|
||||
1,
|
||||
// ISO-8859-1 (chars 160-255)
|
||||
96,
|
||||
// JIS X0201 (chars 160-255)
|
||||
96,
|
||||
};
|
||||
|
||||
// 7078 24x24 characters (JIS X0208 encoding)
|
||||
const unsigned charcodes24[] = {
|
||||
// JIS X0208 row 33, Symbols
|
||||
94,
|
||||
// JIS X0208 row 34, Symbols
|
||||
94,
|
||||
// JIS X0208 row 35, Roman alphabet
|
||||
94,
|
||||
// JIS X0208 row 36, Hiragana
|
||||
94,
|
||||
// JIS X0208 row 37, Katakana
|
||||
94,
|
||||
// JIS X0208 row 38, Greek
|
||||
94,
|
||||
// JIS X0208 row 39, Cyrillic
|
||||
94,
|
||||
// JIS X0208 row 48
|
||||
94,
|
||||
// JIS X0208 row 49
|
||||
94,
|
||||
// JIS X0208 row 50
|
||||
94,
|
||||
// JIS X0208 row 51
|
||||
94,
|
||||
// JIS X0208 row 52
|
||||
94,
|
||||
// JIS X0208 row 53
|
||||
94,
|
||||
// JIS X0208 row 54
|
||||
94,
|
||||
// JIS X0208 row 55
|
||||
94,
|
||||
// JIS X0208 row 56
|
||||
94,
|
||||
// JIS X0208 row 57
|
||||
94,
|
||||
// JIS X0208 row 58
|
||||
94,
|
||||
// JIS X0208 row 59
|
||||
94,
|
||||
// JIS X0208 row 60
|
||||
94,
|
||||
// JIS X0208 row 61
|
||||
94,
|
||||
// JIS X0208 row 62
|
||||
94,
|
||||
// JIS X0208 row 63
|
||||
94,
|
||||
// JIS X0208 row 64
|
||||
94,
|
||||
// JIS X0208 row 65
|
||||
94,
|
||||
// JIS X0208 row 66
|
||||
94,
|
||||
// JIS X0208 row 67
|
||||
94,
|
||||
// JIS X0208 row 68
|
||||
94,
|
||||
// JIS X0208 row 69
|
||||
94,
|
||||
// JIS X0208 row 70
|
||||
94,
|
||||
// JIS X0208 row 71
|
||||
94,
|
||||
// JIS X0208 row 72
|
||||
94,
|
||||
// JIS X0208 row 73
|
||||
94,
|
||||
// JIS X0208 row 74
|
||||
94,
|
||||
// JIS X0208 row 75
|
||||
94,
|
||||
// JIS X0208 row 76
|
||||
94,
|
||||
// JIS X0208 row 77
|
||||
94,
|
||||
// JIS X0208 row 78
|
||||
94,
|
||||
// JIS X0208 row 79
|
||||
94,
|
||||
|
||||
// JIS X0208 row 80
|
||||
94,
|
||||
// JIS X0208 row 81
|
||||
94,
|
||||
// JIS X0208 row 82
|
||||
94,
|
||||
// JIS X0208 row 83
|
||||
94,
|
||||
// JIS X0208 row 84
|
||||
94,
|
||||
// JIS X0208 row 85
|
||||
94,
|
||||
// JIS X0208 row 86
|
||||
94,
|
||||
// JIS X0208 row 87
|
||||
94,
|
||||
// JIS X0208 row 88
|
||||
94,
|
||||
// JIS X0208 row 89
|
||||
94,
|
||||
// JIS X0208 row 90
|
||||
94,
|
||||
// JIS X0208 row 91
|
||||
94,
|
||||
// JIS X0208 row 92
|
||||
94,
|
||||
// JIS X0208 row 93
|
||||
94,
|
||||
// JIS X0208 row 94
|
||||
94,
|
||||
// JIS X0208 row 95
|
||||
94,
|
||||
// JIS X0208 row 96
|
||||
94,
|
||||
// JIS X0208 row 97
|
||||
94,
|
||||
// JIS X0208 row 98
|
||||
94,
|
||||
// JIS X0208 row 99
|
||||
94,
|
||||
// JIS X0208 row 100
|
||||
94,
|
||||
// JIS X0208 row 101
|
||||
94,
|
||||
// JIS X0208 row 102
|
||||
94,
|
||||
// JIS X0208 row 103
|
||||
94,
|
||||
// JIS X0208 row 104
|
||||
94,
|
||||
// JIS X0208 row 105
|
||||
94,
|
||||
// JIS X0208 row 106
|
||||
94,
|
||||
// JIS X0208 row 107
|
||||
94,
|
||||
// JIS X0208 row 108
|
||||
94,
|
||||
// JIS X0208 row 109
|
||||
94,
|
||||
// JIS X0208 row 110
|
||||
94,
|
||||
// JIS X0208 row 111
|
||||
94,
|
||||
// JIS X0208 row 112
|
||||
94,
|
||||
// JIS X0208 row 113
|
||||
94,
|
||||
// JIS X0208 row 114
|
||||
94,
|
||||
// JIS X0208 row 115
|
||||
94,
|
||||
// JIS X0208 row 116
|
||||
6,
|
||||
// Dreamcast symbols
|
||||
22
|
||||
};
|
||||
|
||||
static uint8_t biosfont[288 * 36 + 7078 * 72];
|
||||
|
||||
void make12x24()
|
||||
{
|
||||
std::vector<uint8_t> bitmap;
|
||||
constexpr int WIDTH = 16 * 32;
|
||||
bitmap.resize(WIDTH * 20 * 32); // 16 cols and 20 rows of 32x32 pix
|
||||
int c = 0;
|
||||
int y = 0;
|
||||
for (int pg : charcodes12)
|
||||
{
|
||||
while (pg > 0)
|
||||
{
|
||||
for (int x = 0; x < 16 && pg > 0; x++, pg--, c++)
|
||||
{
|
||||
uint8_t *src = &biosfont[c * 3 * 12];
|
||||
for (int row = 0; row < 24; row += 2)
|
||||
{
|
||||
uint8_t *dst = &bitmap[y * 32 * WIDTH + x * 32 + WIDTH * row];
|
||||
for (int i = 0; i < 8; i++, dst++)
|
||||
if (src[0] & (0x80 >> i))
|
||||
*dst = 0xff;
|
||||
for (int i = 0; i < 4; i++, dst++)
|
||||
if (src[1] & (0x80 >> i))
|
||||
*dst = 0xff;
|
||||
|
||||
dst += WIDTH - 12;
|
||||
for (int i = 0; i < 4; i++, dst++)
|
||||
if (src[1] & (0x8 >> i))
|
||||
*dst = 0xff;
|
||||
for (int i = 0; i < 8; i++, dst++)
|
||||
if (src[2] & (0x80 >> i))
|
||||
*dst = 0xff;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
y++;
|
||||
}
|
||||
}
|
||||
stbi_write_png("bios12x24.png", WIDTH, 20 * 32, 1, &bitmap[0], WIDTH);
|
||||
}
|
||||
|
||||
void make24x24()
|
||||
{
|
||||
int lines = 0;
|
||||
for (int pg : charcodes24)
|
||||
lines += (pg + 15) / 16;
|
||||
|
||||
std::vector<uint8_t> bitmap;
|
||||
constexpr int WIDTH = 16 * 32;
|
||||
bitmap.resize(WIDTH * lines * 32); // 16 cols and n rows of 32x32 pix
|
||||
uint8_t *fontbase = &biosfont[288 * 3 * 12];
|
||||
int c = 0;
|
||||
int y = 0;
|
||||
for (int pg : charcodes24)
|
||||
{
|
||||
while (pg > 0)
|
||||
{
|
||||
for (int x = 0; x < 16 && pg > 0; x++, pg--, c++)
|
||||
{
|
||||
uint8_t *src = &fontbase[c * 3 * 24];
|
||||
for (int row = 0; row < 24; row++)
|
||||
{
|
||||
uint8_t *dst = &bitmap[y * 32 * WIDTH + x * 32 + WIDTH * row];
|
||||
for (int i = 0; i < 8; i++, dst++)
|
||||
if (src[0] & (0x80 >> i))
|
||||
*dst = 0xff;
|
||||
for (int i = 0; i < 8; i++, dst++)
|
||||
if (src[1] & (0x80 >> i))
|
||||
*dst = 0xff;
|
||||
for (int i = 0; i < 8; i++, dst++)
|
||||
if (src[2] & (0x80 >> i))
|
||||
*dst = 0xff;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
y++;
|
||||
}
|
||||
}
|
||||
stbi_write_png("bios24x24.png", WIDTH, lines * 32, 1, &bitmap[0], WIDTH);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *f = fopen("biosfont.bin", "rb");
|
||||
if (f == nullptr) {
|
||||
perror("biosfont.bin");
|
||||
return 1;
|
||||
}
|
||||
if (fread(biosfont, 1, sizeof(biosfont), f) != sizeof(biosfont))
|
||||
{
|
||||
fprintf(stderr, "Invalid bios font file: truncated read");
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
make12x24();
|
||||
make24x24();
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#include "fontutil.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
|
||||
wchar_t jisx208[65536];
|
||||
|
||||
void loadjisx208Table()
|
||||
{
|
||||
FILE *f = fopen("jisx0213-2004-8bit-std.txt" ,"rb");
|
||||
if (f == nullptr) {
|
||||
perror("jisx0213-2004-8bit-std.txt");
|
||||
return;
|
||||
}
|
||||
char buf[512];
|
||||
while (fgets(buf, sizeof(buf), f) != nullptr)
|
||||
{
|
||||
if (buf[0] == '#')
|
||||
continue;
|
||||
char *p;
|
||||
uint16_t jis = strtoul(buf, &p, 16);
|
||||
p += 3; // "\tU+"
|
||||
wchar_t utf = strtoul(p, &p, 16);
|
||||
if (!isspace((int8_t)*p))
|
||||
continue;
|
||||
jisx208[jis] = utf;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
bool loadGlyph(FT_Face face, unsigned glyph, unsigned w, unsigned h)
|
||||
{
|
||||
unsigned glyph_index = FT_Get_Char_Index(face, glyph);
|
||||
if (glyph_index == 0) {
|
||||
//fprintf(stderr, "Missing glyph(%d) code %x char %lc\n", w, glyph, glyph);
|
||||
return false;
|
||||
}
|
||||
int error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
|
||||
if (error) {
|
||||
fprintf(stderr, "Can't load glyph(%d) code %x char %lc\n", w, glyph, glyph);
|
||||
return false;
|
||||
}
|
||||
if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
|
||||
{
|
||||
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
|
||||
if (error) {
|
||||
fprintf(stderr, "Render glyph failed: glyph(%d) code %x char %lc\n", w, glyph, glyph);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (face->glyph->bitmap.width != w || face->glyph->bitmap.rows != h) {
|
||||
//fprintf(stderr, "glyph(%d) code %x char %lc wrong size %d x %d\n", w, glyph, glyph, face->glyph->bitmap.width, face->glyph->bitmap.rows);
|
||||
return false;
|
||||
}
|
||||
// printf("%lc bitmap %d x %d pitch %d px mode %d left %d top %d\n", glyph < 0x80 || glyph >= 0xA0 ? glyph : '?',
|
||||
// face->glyph->bitmap.width, face->glyph->bitmap.rows, face->glyph->bitmap.pitch, face->glyph->bitmap.pixel_mode,
|
||||
// face->glyph->bitmap_left, face->glyph->bitmap_top);
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
extern wchar_t jisx208[65536];
|
||||
void loadjisx208Table();
|
||||
|
||||
bool loadGlyph(FT_Face face, unsigned glyph, unsigned w, unsigned h);
|
|
@ -0,0 +1,75 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void printAsciiTestPage(bool largeFont)
|
||||
{
|
||||
const char *fname = largeFont ? "test12x24.dump" : "test8x16.dump";
|
||||
FILE *f = fopen(fname, "wb");
|
||||
if (!f) {
|
||||
perror(fname);
|
||||
return;
|
||||
}
|
||||
fprintf(f, "\33H\22F%c\n", largeFont); // disable Kanji, select font
|
||||
fprintf(f, " \33-\2TEST PAGE %s\33-%c\n\n", largeFont ? "12x24" : "8x16", 0);
|
||||
for (int i = 0x20; i < 0x100; i += 0x10)
|
||||
{
|
||||
fprintf(f, "%02X", i);
|
||||
for (int j = 0; j < 0x10; j++)
|
||||
{
|
||||
if (i + j == 0xa0 || i + j == 0xff)
|
||||
fprintf(f, " ");
|
||||
else
|
||||
fprintf(f, " %c", i + j);
|
||||
}
|
||||
fputc('\n', f);
|
||||
}
|
||||
fputc('\n', f);
|
||||
fputc('\n', f);
|
||||
fprintf(f, "\33i"); // full cut
|
||||
fclose(f);
|
||||
|
||||
printf("%s created\n", fname);
|
||||
}
|
||||
|
||||
void printKanjiTestPage(bool largeFont)
|
||||
{
|
||||
const char *fname = largeFont ? "test24x24.dump" : "test16x16.dump";
|
||||
FILE *f = fopen(fname, "wb");
|
||||
if (!f) {
|
||||
perror(fname);
|
||||
return;
|
||||
}
|
||||
fprintf(f, "\33H\22F%c\n", largeFont); // disable Kanji, select font
|
||||
fprintf(f, " \33-\2KANJI TEST PAGE %s\33-%c\n\n", largeFont ? "24x24" : "16x16", 0);
|
||||
for (int plane = 0x21; plane <= 0x7e; plane++)
|
||||
{
|
||||
fprintf(f, " Plane %02X\n\n", plane);
|
||||
for (int c = 0x21; c <= 0x7e; c++)
|
||||
{
|
||||
if (c == 0x21 || (c & 0xf) == 0)
|
||||
fprintf(f, " %02X ", (c & 0xf0));
|
||||
if (c == 0x21)
|
||||
fprintf(f, " ");
|
||||
fprintf(f, "\33K%c%c\33H ", plane, c);
|
||||
if ((c & 0xf) == 0xf)
|
||||
fputc('\n', f);
|
||||
}
|
||||
fputc('\n', f);
|
||||
fputc('\n', f);
|
||||
}
|
||||
fputc('\n', f);
|
||||
fputc('\n', f);
|
||||
fprintf(f, "\33i"); // full cut
|
||||
fclose(f);
|
||||
|
||||
printf("%s created\n", fname);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printAsciiTestPage(false);
|
||||
printAsciiTestPage(true);
|
||||
printKanjiTestPage(false);
|
||||
printKanjiTestPage(true);
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,255 @@
|
|||
//
|
||||
// printerfont 12x24rk.pcf jiskan24.pcf jiskan16.pcf ter-u24b.bdf unifont-15.0.01.bdf
|
||||
//
|
||||
// TODO:
|
||||
// 8x16 ascii: missing F1-FD
|
||||
// 12x24 ascii: missing 80-9F, E0-FF
|
||||
// 16x16 kanji:
|
||||
// plane 22 additional chars line 30
|
||||
// plane 23-28 some additional chars
|
||||
// plane 2D missing some line 30, line 70 missing all
|
||||
// kanji planes ok, some additional chars
|
||||
// 24x24 kanji: ok
|
||||
//
|
||||
// 12x24rk.pcf uses JISX0201.1976
|
||||
// jiskan24 and jiskan16 kanji only
|
||||
//
|
||||
// Copyright
|
||||
// 12x24rk.pcf: Copyright 1989 by Sony Corp.
|
||||
// Attrib license
|
||||
// jiskan16.pcf, jiskan24.pcf: Licensed under Public Domain
|
||||
// GNU unifont: GPL
|
||||
// Terminus: SIL Open Font License, Version 1.1
|
||||
//
|
||||
#include "fontutil.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include <freetype/ftbdf.h>
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <wchar.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
static FT_Library library;
|
||||
static FT_Face face;
|
||||
|
||||
// L"▁▂▃▄▅▆▇█▏▎▍▌▋▊▉┼┴┬┤├▔─│▕┌┐└┘╭╮╰╯"
|
||||
const wchar_t katakana80[33] = L"\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588\u258F\u258E\u258D\u258C\u258B\u258A\u2589\u253C"
|
||||
"\u2534\u252C\u2524\u251C\u2594\u2500\u2502\u2595\u250C\u2510\u2514\u2518\u256D\u256E\u2570\u256F";
|
||||
// L" 。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソ"
|
||||
const wchar_t katakanaA0[33] = L" \uFF61\uFF62\uFF63\uFF64\uFF65\uFF66\uFF67\uFF68\uFF69\uFF6A\uFF6B\uFF6C\uFF6D\uFF6E\uFF6F"
|
||||
"\uFF70\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F";
|
||||
// L"タチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚"
|
||||
const wchar_t katakanaC0[33] = L"\uFF80\uFF81\uFF82\uFF83\uFF84\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E\uFF8F"
|
||||
"\uFF90\uFF91\uFF92\uFF93\uFF94\uFF95\uFF96\uFF97\uFF98\uFF99\uFF9A\uFF9B\uFF9C\uFF9D\uFF9E\uFF9F";
|
||||
// L"゠ᅣ‡ᅧ◢◣◤◥♠♥♦♣●○╱╲╳円年月日時分秒〒市区町村人▒ "
|
||||
const wchar_t katakanaE0[33] = L"\u30A0\uFFC4\u2021\uFFCA\u25E2\u25E3\u25E4\u25E5\u2660\u2665\u2666\u2663\u25CF\u25CB\u2571\u2572"
|
||||
"\u2573\u5186\u5E74\u6708\u65E5\u6642\u5206\u79D2\u3012\u5E02\u533A\u753A\u6751\u4EBA\u2592 ";
|
||||
|
||||
constexpr int ASCII_CHARS = 256 - 32;
|
||||
constexpr int KANJI_CHARS = 1 + 94 * 94;
|
||||
|
||||
static uint8_t ascii8x16[ASCII_CHARS * 16];
|
||||
static uint8_t kanji16x16[KANJI_CHARS * 2 * 16];
|
||||
static uint8_t ascii12x24[ASCII_CHARS * 2 * 24];
|
||||
static uint8_t kanji24x24[KANJI_CHARS * 3 * 24];
|
||||
|
||||
bool save(const char *name, void *data, size_t size)
|
||||
{
|
||||
FILE *f = fopen(name, "wb");
|
||||
if (f == nullptr) {
|
||||
perror(name);
|
||||
return false;
|
||||
}
|
||||
bool status = fwrite(data, size, 1, f) == 1;
|
||||
fclose(f);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
wchar_t convertKatakana(wchar_t c)
|
||||
{
|
||||
if (c >= 0xe0)
|
||||
return katakanaE0[c - 0xe0];
|
||||
if (c >= 0xc0)
|
||||
return katakanaC0[c - 0xc0];
|
||||
if (c >= 0xa0)
|
||||
return katakanaA0[c - 0xa0];
|
||||
if (c >= 0x80)
|
||||
return katakana80[c - 0x80];
|
||||
return c;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
loadjisx208Table();
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <font>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
int error = FT_Init_FreeType(&library);
|
||||
if (error)
|
||||
{
|
||||
fprintf(stderr, "FreeType init failed\n");
|
||||
return 1;
|
||||
}
|
||||
for (int font = 1; font < argc; font++)
|
||||
{
|
||||
const char *fontname = argv[font];
|
||||
long index = 0;
|
||||
if (strlen(fontname) >= 4 && !strcmp(fontname + strlen(fontname) - 4, ".ttc"))
|
||||
// 5: NotoSans Mono CJK.ttc
|
||||
index = strtoul(argv[++font], nullptr, 10);
|
||||
error = FT_New_Face(library, fontname, index, &face);
|
||||
if (error)
|
||||
{
|
||||
fprintf(stderr, "Can't load %s\n", fontname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *registry;
|
||||
const char *encoding;
|
||||
int fontHeight = 0;
|
||||
FT_Get_BDF_Charset_ID(face, &encoding, ®istry);
|
||||
printf("%s: %s %s\n%ld glyphs\n%d fixed sizes\n%d charmaps\n", fontname, encoding, registry, face->num_glyphs, face->num_fixed_sizes, face->num_charmaps);
|
||||
FT_Bitmap_Size *size = face->available_sizes;
|
||||
for (int i = 0; i < face->num_fixed_sizes; i++, size++)
|
||||
{
|
||||
printf("%d: %d x %d\n", i + 1, size->width, size->height);
|
||||
fontHeight = size->height;
|
||||
}
|
||||
if (face->num_fixed_sizes == 0)
|
||||
FT_Set_Pixel_Sizes(face, 0, 24);
|
||||
|
||||
bool jisx0201Encoding = false;
|
||||
bool jisx0208Encoding = false;
|
||||
if (registry != nullptr)
|
||||
{
|
||||
if (!strcmp(registry, "JISX0208.1983"))
|
||||
{
|
||||
jisx0208Encoding = true;
|
||||
FT_Set_Charmap(face, face->charmaps[0]);
|
||||
}
|
||||
else if (!strcmp(registry, "JISX0201.1976"))
|
||||
{
|
||||
jisx0201Encoding = true;
|
||||
FT_Set_Charmap(face, face->charmaps[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (fontHeight == 16)
|
||||
{
|
||||
for (wchar_t c = 32; c < 256; c++)
|
||||
{
|
||||
wchar_t uni = convertKatakana(c);
|
||||
if (!loadGlyph(face, uni, 8, 16))
|
||||
continue;
|
||||
uint8_t *src = face->glyph->bitmap.buffer;
|
||||
uint8_t *dst = &ascii8x16[(c - 32) * 16];
|
||||
memcpy(dst, src, 16);
|
||||
}
|
||||
for (int plane = 0x21; plane <= 0x7e; plane++)
|
||||
{
|
||||
for (int c = 0x21; c <= 0x7e; c++)
|
||||
{
|
||||
wchar_t code = (plane << 8) | c;
|
||||
if (!jisx0208Encoding)
|
||||
code = jisx208[code];
|
||||
if (!loadGlyph(face, code, 16, 16))
|
||||
continue;
|
||||
uint8_t *src = face->glyph->bitmap.buffer;
|
||||
uint8_t *dst = &kanji16x16[(1 + (plane - 0x21) * 94 + (c - 0x21)) * 2 * 16];
|
||||
if (face->glyph->bitmap.pitch == 2)
|
||||
{
|
||||
memcpy(dst, src, 2 * 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
*dst++ = src[0];
|
||||
*dst++ = src[1];
|
||||
src += face->glyph->bitmap.pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fontHeight == 24)
|
||||
{
|
||||
for (wchar_t c = 32; c < 256; c++)
|
||||
{
|
||||
wchar_t uni;
|
||||
if (jisx0201Encoding)
|
||||
{
|
||||
if ((c >= 0x80 && c <= 0x9F) || (c >= 0xE0 && c <= 0xFF))
|
||||
continue;
|
||||
uni = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == 0x7f)
|
||||
continue;
|
||||
uni = convertKatakana(c);
|
||||
}
|
||||
if (!loadGlyph(face, uni, 12, 24))
|
||||
continue;
|
||||
uint8_t *src = face->glyph->bitmap.buffer;
|
||||
uint8_t *dst = &ascii12x24[(c - 32) * 2 * 24];
|
||||
if (face->glyph->bitmap.pitch == 2)
|
||||
memcpy(dst, src, 2 * 24);
|
||||
else
|
||||
{
|
||||
for (int y= 0; y < 24; y++)
|
||||
{
|
||||
*dst++ = src[0];
|
||||
*dst++ = src[1];
|
||||
src += face->glyph->bitmap.pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int plane = 0x21; plane <= 0x7e; plane++)
|
||||
{
|
||||
for (int c = 0x21; c <= 0x7e; c++)
|
||||
{
|
||||
wchar_t code = (plane << 8) | c;
|
||||
if (!jisx0208Encoding)
|
||||
code = jisx208[code];
|
||||
if (!loadGlyph(face, code, 24, 24))
|
||||
continue;
|
||||
uint8_t *src = face->glyph->bitmap.buffer;
|
||||
uint8_t *dst = &kanji24x24[(1 + (plane - 0x21) * 94 + (c - 0x21)) * 3 * 24];
|
||||
if (face->glyph->bitmap.pitch == 3)
|
||||
{
|
||||
memcpy(dst, src, 3 * 24);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < 24; y++)
|
||||
{
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
src += face->glyph->bitmap.pitch - 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FT_Done_Face(face);
|
||||
}
|
||||
FT_Done_FreeType(library);
|
||||
save("printer_ascii8x16.bin", ascii8x16, sizeof(ascii8x16));
|
||||
save("printer_ascii12x24.bin", ascii12x24, sizeof(ascii12x24));
|
||||
save("printer_kanji16x16.bin", kanji16x16, sizeof(kanji16x16));
|
||||
save("printer_kanji24x24.bin", kanji24x24, sizeof(kanji24x24));
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue