mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-13 14:36:06 +09:00
revived unicode print function
This commit is contained in:
@@ -1366,12 +1366,12 @@ unicode.getUniprint = (c) => {
|
|||||||
return unicode.uniprint[k]
|
return unicode.uniprint[k]
|
||||||
}}
|
}}
|
||||||
|
|
||||||
print = function(str) {
|
unicode.print = (str) => {
|
||||||
if ((typeof str === 'string' || str instanceof String) && str.length > 0) {
|
if ((typeof str === 'string' || str instanceof String) && str.length > 0) {
|
||||||
|
|
||||||
let cp = unicode.utf8toCodepoints(str)
|
let cp = unicode.utf8toCodepoints(str)
|
||||||
cp.forEach(c => {
|
cp.forEach(c => {
|
||||||
let q = unicode.getUniprint(c)
|
let q = unicode.getUniprint(c)
|
||||||
|
|
||||||
if (q == undefined || !q[0](c)) {
|
if (q == undefined || !q[0](c)) {
|
||||||
con.addch(4)
|
con.addch(4)
|
||||||
con.curs_right()
|
con.curs_right()
|
||||||
@@ -1381,6 +1381,13 @@ print = function(str) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
sys.print(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unicode.println = (str) => {
|
||||||
|
unicode.print(str+'\n\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.freeze(unicode);
|
Object.freeze(unicode);
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ graphics.setPalette(0, 0, 0, 0, 9)
|
|||||||
|
|
||||||
|
|
||||||
function processSubtitlePacket(packetSize) {
|
function processSubtitlePacket(packetSize) {
|
||||||
|
|
||||||
// Read subtitle packet data according to SSF format
|
// Read subtitle packet data according to SSF format
|
||||||
// uint24 index + uint8 opcode + variable arguments
|
// uint24 index + uint8 opcode + variable arguments
|
||||||
|
|
||||||
@@ -168,11 +169,14 @@ function processSubtitlePacket(packetSize) {
|
|||||||
// Font upload - read payload length and font data
|
// Font upload - read payload length and font data
|
||||||
if (remainingBytes >= 3) { // uint16 length + at least 1 byte data
|
if (remainingBytes >= 3) { // uint16 length + at least 1 byte data
|
||||||
let payloadLen = seqread.readShort()
|
let payloadLen = seqread.readShort()
|
||||||
|
|
||||||
|
serial.println(`Uploading ${(opcode == SSF_OP_UPLOAD_LOW_FONT) ? 'low' : 'high'} font rom (${payloadLen} bytes)`)
|
||||||
|
|
||||||
if (remainingBytes >= payloadLen + 2) {
|
if (remainingBytes >= payloadLen + 2) {
|
||||||
let fontData = seqread.readBytes(payloadLen)
|
let fontData = seqread.readBytes(payloadLen)
|
||||||
|
|
||||||
// upload font data
|
// upload font data
|
||||||
for (let i = 0; i < Math.min(payloadLen, 1920); i++) sys.poke(-1300607 - i, sys.peek(fontData + i))
|
for (let i = 0; i < Math.min(payloadLen, 1920); i++) sys.poke(-133121 - i, sys.peek(fontData + i))
|
||||||
sys.poke(-1299460, (opcode == SSF_OP_UPLOAD_LOW_FONT) ? 18 : 19)
|
sys.poke(-1299460, (opcode == SSF_OP_UPLOAD_LOW_FONT) ? 18 : 19)
|
||||||
|
|
||||||
sys.free(fontData)
|
sys.free(fontData)
|
||||||
@@ -571,6 +575,8 @@ try {
|
|||||||
// Read packet header
|
// Read packet header
|
||||||
var packetType = seqread.readOneByte()
|
var packetType = seqread.readOneByte()
|
||||||
|
|
||||||
|
// serial.println(`Packet ${packetType} at offset ${seqread.getReadCount() - 1}`)
|
||||||
|
|
||||||
// Try to read next TAV file header
|
// Try to read next TAV file header
|
||||||
if (packetType == TAV_FILE_HEADER_FIRST) {
|
if (packetType == TAV_FILE_HEADER_FIRST) {
|
||||||
let nextHeader = tryReadNextTAVHeader()
|
let nextHeader = tryReadNextTAVHeader()
|
||||||
@@ -766,6 +772,9 @@ finally {
|
|||||||
} else {
|
} else {
|
||||||
console.log(`Playback failed with error ${errorlevel}`)
|
console.log(`Playback failed with error ${errorlevel}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sys.poke(-1299460, 20)
|
||||||
|
sys.poke(-1299460, 21)
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics.setPalette(0, 0, 0, 0, 0)
|
graphics.setPalette(0, 0, 0, 0, 0)
|
||||||
|
|||||||
@@ -1,37 +1,3 @@
|
|||||||
let status = 0
|
|
||||||
let workarea = sys.malloc(1920)
|
|
||||||
|
|
||||||
// install LOCHRROM
|
|
||||||
let hangulRomL = files.open("A:/tvdos/i18n/hang_lo.chr")
|
|
||||||
if (!hangulRomL.exists) {
|
|
||||||
printerrln("hang_lo.chr not found")
|
|
||||||
sys.free(workarea)
|
|
||||||
return status
|
|
||||||
}
|
|
||||||
//dma.comToRam(filesystem._toPorts("A")[0], 0, workarea, 1920)
|
|
||||||
hangulRomL.pread(workarea, 1920, 0)
|
|
||||||
for (let i = 0; i < 1920; i++) sys.poke(-1300607 - i, sys.peek(workarea + i))
|
|
||||||
sys.poke(-1299460, 18)
|
|
||||||
|
|
||||||
|
|
||||||
// install HICHRROM
|
|
||||||
let hangulRomH = files.open("A:/tvdos/i18n/hang_hi.chr")
|
|
||||||
if (!hangulRomH.exists) {
|
|
||||||
printerrln("hang_hi.chr not found")
|
|
||||||
sys.free(workarea)
|
|
||||||
sys.poke(-1299460, 20) // clean up the crap
|
|
||||||
return status
|
|
||||||
}
|
|
||||||
//dma.comToRam(filesystem._toPorts("A")[0], 0, workarea, 1920)
|
|
||||||
hangulRomH.pread(workarea, 1920, 0)
|
|
||||||
for (let i = 0; i < 1920; i++) sys.poke(-1300607 - i, sys.peek(workarea + i))
|
|
||||||
sys.poke(-1299460, 19)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sys.free(workarea)
|
|
||||||
|
|
||||||
graphics.setHalfrowMode(true)
|
|
||||||
/*
|
/*
|
||||||
* A character is defined as one of:
|
* A character is defined as one of:
|
||||||
* 1. [I,x] (Initial only)
|
* 1. [I,x] (Initial only)
|
||||||
@@ -222,12 +188,5 @@ if (unicode.uniprint) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
println("조합한글 커널모듈이 로드되었습니다.")
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
println("Failed to load Assembly Hangul kernel module: incompatible DOS version")
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,15 @@ function displayFormattedLine(line) {
|
|||||||
|
|
||||||
let i = 0
|
let i = 0
|
||||||
let inBoldOrItalic = false
|
let inBoldOrItalic = false
|
||||||
|
let buffer = "" // Accumulate characters for batch printing
|
||||||
|
|
||||||
|
// Helper function to flush the buffer
|
||||||
|
function flushBuffer() {
|
||||||
|
if (buffer.length > 0) {
|
||||||
|
unicode.print(buffer)
|
||||||
|
buffer = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// insert initial padding block
|
// insert initial padding block
|
||||||
con.color_pair(0, 255)
|
con.color_pair(0, 255)
|
||||||
@@ -68,27 +77,32 @@ function displayFormattedLine(line) {
|
|||||||
// Check for opening tags
|
// Check for opening tags
|
||||||
if (line.substring(i, i + 3).toLowerCase() === '<b>' ||
|
if (line.substring(i, i + 3).toLowerCase() === '<b>' ||
|
||||||
line.substring(i, i + 3).toLowerCase() === '<i>') {
|
line.substring(i, i + 3).toLowerCase() === '<i>') {
|
||||||
|
flushBuffer() // Flush before color change
|
||||||
con.color_pair(254, 0) // Switch to white for formatted text
|
con.color_pair(254, 0) // Switch to white for formatted text
|
||||||
inBoldOrItalic = true
|
inBoldOrItalic = true
|
||||||
i += 3
|
i += 3
|
||||||
} else if (i < line.length - 3 &&
|
} else if (i < line.length - 3 &&
|
||||||
(line.substring(i, i + 4).toLowerCase() === '</b>' ||
|
(line.substring(i, i + 4).toLowerCase() === '</b>' ||
|
||||||
line.substring(i, i + 4).toLowerCase() === '</i>')) {
|
line.substring(i, i + 4).toLowerCase() === '</i>')) {
|
||||||
|
flushBuffer() // Flush before color change
|
||||||
con.color_pair(231, 0) // Switch back to yellow for normal text
|
con.color_pair(231, 0) // Switch back to yellow for normal text
|
||||||
inBoldOrItalic = false
|
inBoldOrItalic = false
|
||||||
i += 4
|
i += 4
|
||||||
} else {
|
} else {
|
||||||
// Not a formatting tag, print the character
|
// Not a formatting tag, add to buffer
|
||||||
print(line[i])
|
buffer += line[i]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Regular character, print it
|
// Regular character, add to buffer
|
||||||
print(line[i])
|
buffer += line[i]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flush any remaining buffered text
|
||||||
|
flushBuffer()
|
||||||
|
|
||||||
// insert final padding block
|
// insert final padding block
|
||||||
con.color_pair(0, 255)
|
con.color_pair(0, 255)
|
||||||
con.prnch(0xDD)
|
con.prnch(0xDD)
|
||||||
|
|||||||
@@ -810,6 +810,7 @@ When SSF is interleaved with MP2 audio, the payload must be inserted in-between
|
|||||||
|
|
||||||
## Packet Structure
|
## Packet Structure
|
||||||
uint8 0x30 (packet type)
|
uint8 0x30 (packet type)
|
||||||
|
uint32 Packet Size
|
||||||
* SSF Payload (see below)
|
* SSF Payload (see below)
|
||||||
|
|
||||||
## SSF Packet Structure
|
## SSF Packet Structure
|
||||||
|
|||||||
@@ -222,6 +222,8 @@ typedef struct tav_encoder_s {
|
|||||||
char *input_file;
|
char *input_file;
|
||||||
char *output_file;
|
char *output_file;
|
||||||
char *subtitle_file;
|
char *subtitle_file;
|
||||||
|
char *fontrom_lo_file;
|
||||||
|
char *fontrom_hi_file;
|
||||||
FILE *output_fp;
|
FILE *output_fp;
|
||||||
FILE *mp2_file;
|
FILE *mp2_file;
|
||||||
FILE *ffmpeg_video_pipe;
|
FILE *ffmpeg_video_pipe;
|
||||||
@@ -602,6 +604,8 @@ static void show_usage(const char *program_name) {
|
|||||||
printf(" -a, --arate N MP2 audio bitrate in kbps (overrides quality-based audio rate)\n");
|
printf(" -a, --arate N MP2 audio bitrate in kbps (overrides quality-based audio rate)\n");
|
||||||
printf(" Valid values: 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384\n");
|
printf(" Valid values: 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384\n");
|
||||||
printf(" -S, --subtitles FILE SubRip (.srt) or SAMI (.smi) subtitle file\n");
|
printf(" -S, --subtitles FILE SubRip (.srt) or SAMI (.smi) subtitle file\n");
|
||||||
|
printf(" --fontrom-lo FILE Low font ROM file (max 1920 bytes) for internationalized subtitles\n");
|
||||||
|
printf(" --fontrom-hi FILE High font ROM file (max 1920 bytes) for internationalized subtitles\n");
|
||||||
printf(" -v, --verbose Verbose output\n");
|
printf(" -v, --verbose Verbose output\n");
|
||||||
printf(" -t, --test Test mode: generate solid colour frames\n");
|
printf(" -t, --test Test mode: generate solid colour frames\n");
|
||||||
printf(" --lossless Lossless mode: use 5/3 reversible wavelet\n");
|
printf(" --lossless Lossless mode: use 5/3 reversible wavelet\n");
|
||||||
@@ -2165,6 +2169,82 @@ static void rgba_to_colour_space_frame(tav_encoder_t *enc, const uint8_t *rgba,
|
|||||||
free(temp_rgb);
|
free(temp_rgb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Write font ROM upload packet (SSF format)
|
||||||
|
static int write_fontrom_packet(FILE *fp, const char *filename, uint8_t opcode) {
|
||||||
|
if (!filename || !fp) return 0;
|
||||||
|
|
||||||
|
FILE *rom_file = fopen(filename, "rb");
|
||||||
|
if (!rom_file) {
|
||||||
|
fprintf(stderr, "Warning: Could not open font ROM file: %s\n", filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get file size
|
||||||
|
fseek(rom_file, 0, SEEK_END);
|
||||||
|
long file_size = ftell(rom_file);
|
||||||
|
fseek(rom_file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if (file_size > 1920) {
|
||||||
|
fprintf(stderr, "Warning: Font ROM file too large (max 1920 bytes): %s\n", filename);
|
||||||
|
fclose(rom_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read font data
|
||||||
|
uint8_t *font_data = malloc(file_size);
|
||||||
|
if (!font_data) {
|
||||||
|
fprintf(stderr, "Error: Could not allocate memory for font ROM\n");
|
||||||
|
fclose(rom_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes_read = fread(font_data, 1, file_size, rom_file);
|
||||||
|
fclose(rom_file);
|
||||||
|
|
||||||
|
if (bytes_read != file_size) {
|
||||||
|
fprintf(stderr, "Warning: Could not read entire font ROM file: %s\n", filename);
|
||||||
|
free(font_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write SSF packet
|
||||||
|
// Packet type: 0x30 (subtitle/SSF)
|
||||||
|
fputc(0x30, fp);
|
||||||
|
|
||||||
|
// Calculate packet size: 3 (index) + 1 (opcode) + 2 (length) + file_size + 1 (terminator)
|
||||||
|
uint32_t packet_size = 3 + 1 + 2 + file_size + 1;
|
||||||
|
|
||||||
|
// Write packet size (uint32, little-endian)
|
||||||
|
fputc(packet_size & 0xFF, fp);
|
||||||
|
fputc((packet_size >> 8) & 0xFF, fp);
|
||||||
|
fputc((packet_size >> 16) & 0xFF, fp);
|
||||||
|
fputc((packet_size >> 24) & 0xFF, fp);
|
||||||
|
|
||||||
|
// SSF payload:
|
||||||
|
// uint24 index (3 bytes) - use 0 for font ROM uploads
|
||||||
|
fputc(0, fp);
|
||||||
|
fputc(0, fp);
|
||||||
|
fputc(0, fp);
|
||||||
|
|
||||||
|
// uint8 opcode (0x80 = low font ROM, 0x81 = high font ROM)
|
||||||
|
fputc(opcode, fp);
|
||||||
|
|
||||||
|
// uint16 payload length (little-endian)
|
||||||
|
uint16_t payload_len = (uint16_t)file_size;
|
||||||
|
fputc(payload_len & 0xFF, fp);
|
||||||
|
fputc((payload_len >> 8) & 0xFF, fp);
|
||||||
|
|
||||||
|
// Font data
|
||||||
|
fwrite(font_data, 1, file_size, fp);
|
||||||
|
|
||||||
|
// Terminator
|
||||||
|
fputc(0x00, fp);
|
||||||
|
|
||||||
|
free(font_data);
|
||||||
|
|
||||||
|
printf("Font ROM uploaded: %s (%ld bytes, opcode 0x%02X)\n", filename, file_size, opcode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Write TAV file header
|
// Write TAV file header
|
||||||
static int write_tav_header(tav_encoder_t *enc) {
|
static int write_tav_header(tav_encoder_t *enc) {
|
||||||
@@ -3175,6 +3255,8 @@ int main(int argc, char *argv[]) {
|
|||||||
{"no-perceptual-tuning", no_argument, 0, 1007},
|
{"no-perceptual-tuning", no_argument, 0, 1007},
|
||||||
{"encode-limit", required_argument, 0, 1008},
|
{"encode-limit", required_argument, 0, 1008},
|
||||||
{"dump-frame", required_argument, 0, 1009},
|
{"dump-frame", required_argument, 0, 1009},
|
||||||
|
{"fontrom-lo", required_argument, 0, 1011},
|
||||||
|
{"fontrom-hi", required_argument, 0, 1012},
|
||||||
{"help", no_argument, 0, '?'},
|
{"help", no_argument, 0, '?'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
@@ -3300,6 +3382,12 @@ int main(int argc, char *argv[]) {
|
|||||||
case 1009: // --dump-frame
|
case 1009: // --dump-frame
|
||||||
debugDumpFrameTarget = atoi(optarg);
|
debugDumpFrameTarget = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 1011: // --fontrom-lo
|
||||||
|
enc->fontrom_lo_file = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 1012: // --fontrom-hi
|
||||||
|
enc->fontrom_hi_file = strdup(optarg);
|
||||||
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
{
|
{
|
||||||
int bitrate = atoi(optarg);
|
int bitrate = atoi(optarg);
|
||||||
@@ -3444,6 +3532,18 @@ int main(int argc, char *argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write font ROM packets if provided
|
||||||
|
if (enc->fontrom_lo_file) {
|
||||||
|
if (write_fontrom_packet(enc->output_fp, enc->fontrom_lo_file, 0x80) != 0) {
|
||||||
|
fprintf(stderr, "Warning: Failed to write low font ROM, continuing without it\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (enc->fontrom_hi_file) {
|
||||||
|
if (write_fontrom_packet(enc->output_fp, enc->fontrom_hi_file, 0x81) != 0) {
|
||||||
|
fprintf(stderr, "Warning: Failed to write high font ROM, continuing without it\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gettimeofday(&enc->start_time, NULL);
|
gettimeofday(&enc->start_time, NULL);
|
||||||
|
|
||||||
if (enc->output_fps != enc->fps) {
|
if (enc->output_fps != enc->fps) {
|
||||||
@@ -3688,6 +3788,8 @@ static void cleanup_encoder(tav_encoder_t *enc) {
|
|||||||
free(enc->input_file);
|
free(enc->input_file);
|
||||||
free(enc->output_file);
|
free(enc->output_file);
|
||||||
free(enc->subtitle_file);
|
free(enc->subtitle_file);
|
||||||
|
free(enc->fontrom_lo_file);
|
||||||
|
free(enc->fontrom_hi_file);
|
||||||
free(enc->frame_rgb[0]);
|
free(enc->frame_rgb[0]);
|
||||||
free(enc->frame_rgb[1]);
|
free(enc->frame_rgb[1]);
|
||||||
free(enc->current_frame_y);
|
free(enc->current_frame_y);
|
||||||
|
|||||||
Reference in New Issue
Block a user