ZX-Next: problem using FZX library
Posted: Tue Aug 25, 2020 11:29 am
I'm trying to use FZX library using ZX Spectrum Next as target, and Timex hi-resmode.
I'm compiling using startup=24 (Timex hi-res with FZX support)
I want to change fonts at runtime, so I'm using calls to "ioctl" like this: ioctl(fileno(stdout), IOCTL_OTERM_FONT, font);
It works ok if I use stdio library functions: printf, puts, ...
Now I want to write the text word-wrapped. So I'm following the example "fzx_reader.c" in: libsrc/_DEVELOPMENT/EXAMPLES/zx/fzx_reader.
But I think I'm doing something wrong, because when the text is output via "fzx_write" or "fzx_write_justified" it shows only garbage.
This is my example code running with stdio functions printf and puts:
This is when I try to use fzx_write and fzx_write_justified:
I'm compiling using startup=24 (Timex hi-res with FZX support)
I want to change fonts at runtime, so I'm using calls to "ioctl" like this: ioctl(fileno(stdout), IOCTL_OTERM_FONT, font);
It works ok if I use stdio library functions: printf, puts, ...
Now I want to write the text word-wrapped. So I'm following the example "fzx_reader.c" in: libsrc/_DEVELOPMENT/EXAMPLES/zx/fzx_reader.
But I think I'm doing something wrong, because when the text is output via "fzx_write" or "fzx_write_justified" it shows only garbage.
This is my example code running with stdio functions printf and puts:
This is when I try to use fzx_write and fzx_write_justified:
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <input.h>
#include <string.h>
#include <sys/ioctl.h>
#include <input/input_zx.h>
#include <arch/zxn.h>
#include <arch/zxn/sysvar.h>
#include <font/fzx.h>
extern struct fzx_font ff_pd_QLStyle;
extern struct fzx_font ff_pd_Plotter;
extern struct fzx_font ff_ao_Lettera;
char *sample_txt =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse sed ex tincidunt, blandit nulla at, consequat libero. "
"Aenean elementum dui sit amet nulla lobortis feugiat. Maecenas id congue orci. "
"Nullam convallis eros quis hendrerit rutrum. Aenean quis massa quis sapien semper pellentesque sed sit amet felis. "
"Nulla id hendrerit ipsum. In mollis orci lorem, eget tincidunt erat eleifend a. Duis tristique pulvinar est quis pretium. "
"Duis nec malesuada felis, sit amet laoreet nisl."
"\n"
"Vivamus a sem volutpat, dapibus nunc sed, varius eros. Donec ac mollis risus. Ut interdum fermentum congue. "
"Vivamus nunc massa, pretium sed ultrices eu, varius eget augue. Sed viverra sapien lorem, at aliquet lorem sollicitudin id. "
"Suspendisse eget rhoncus sapien. Nunc rutrum vitae mauris eu commodo. Vivamus vel orci quis turpis fringilla ultrices. "
"Suspendisse consectetur ut mi sed gravida.";
// Terminal data structures.
static struct fzx_font *out_term_font;
static unsigned int out_term_line_width;
// FIXME: Remove when included in z88dk.
#define RTM_28MHZ 0x03
static void init_hardware(void)
{
// Make sure the Spectrum ROM is paged in initially.
GLOBAL_ZXN_PORT_7FFD = IO_7FFD_ROM0;
// Put Z80 in 28 MHz turbo mode.
ZXN_NEXTREG(REG_TURBO_MODE, RTM_28MHZ);
// Disable RAM memory contention.
ZXN_NEXTREGA(REG_PERIPHERAL_3, ZXN_READ_REG(REG_PERIPHERAL_3) | RP3_DISABLE_CONTENTION);
// Reset display palette and r/w palette selections to their defaults.
ZXN_NEXTREG(REG_PALETTE_CONTROL, 0);
// Reset clip windows to their defaults.
ZXN_NEXTREG(REG_CLIP_WINDOW_CONTROL, 0x07);
// TVM_SPECTRUM 256x192 pix, 32x24 attr
// TVM_DFILE1 synonym ^^
// TVM_DFILE2 256x192 pix, 32x24 attr second display file
// TVM_HICOLOR 256x192 pix, 32x192 attr
// TVM_HIRES 512x192 pix OR with paper colour
ts_vmod(TVM_HIRES);
// Set black border
zx_border(INK_BLACK);
// Set initial text font color.
///set_initial_text_color(TEXT_FONT_COLOR_INDEX);
// Default terminal font.
out_term_font = (struct fzx_font *)ioctl(fileno(stdout), IOCTL_OTERM_FONT, -1);
}
/*
* Returns information about the output terminal and stores it
* into predefined global data structures.
*/
static void get_out_terminal_info()
{
int fd;
struct r_Rect16 paper;
fd = fileno(stdout);
ioctl(fd, IOCTL_OTERM_FZX_GET_PAPER_RECT, &paper);
out_term_line_width = paper.width - ioctl(fd, IOCTL_OTERM_FZX_LEFT_MARGIN, -1) - 1;
}
/*
* Sets the current font for terminal output.
*/
void set_font(struct fzx_font *font)
{
ioctl(fileno(stdout), IOCTL_OTERM_FONT, font);
out_term_font = font;
}
void press_any_key()
{
puts("\nPulsa una tecla...\n");
in_wait_nokey();
in_pause(0);
}
void cls()
{
tshr_cls(PAPER_BLUE);
ioctl(fileno(stdout), IOCTL_OTERM_CLS);
}
/*
* Sample text using fzx functions.
*/
void sample_text0()
{
int res;
char *p_start, *p_end, *p_part;
struct fzx_state fs;
struct r_Rect16 window = {0, 512, 0, 192};
fzx_state_init(&fs, out_term_font, &window);
char *text = (char *)malloc(sizeof(text));
strcpy(text, sample_txt);
// Start of text.
p_start = strstrip(text);
while (*p_start)
{
// Delimit paragraph.
p_end = strchrnul(p_start, '\n');
// Print paragraph.
while (p_start < p_end)
{
// Find line that will fit into window.
//void *fzx_buffer_partition_ww(struct fzx_font *ff, char *buf, uint16_t buflen, uint16_t allowed_width)
// Find longest prefix of buffer without splitting words.
// that has pixel extent <= to the allowed pixel extent.
// The prefix will not end in a space.
p_part = fzx_buffer_partition_ww(fs.font, p_start, p_end - p_start, fs.paper.width - fs.left_margin);
if (p_part == p_start)
{
// Solid text without spaces exceeds allowed width.
// This text will not be justified -- should the justify function insert spaces between characters??
//void *fzx_buffer_partition(struct fzx_font *ff, char *buf, uint16_t buflen, uint16_t allowed_width)
// Find longest prefix of buffer that has pixel extent
// less than or equal to the allowed pixel extent.
p_part = fzx_buffer_partition(fs.font, p_start, p_end - p_start, fs.paper.width - fs.left_margin);
}
// Print line.
if (p_part == p_end)
{
// Last line of paragraph.
res = fzx_write(&fs, p_start, p_part - p_start);
}
else
{
res = fzx_write_justified(&fs, p_start, p_part - p_start, fs.paper.width - fs.left_margin);
}
if (res < 0)
{
// Bottom of window reached.
press_any_key();
cls();
}
else
{
// Move pointer to beginning of next line.
p_start = strstrip(p_part);
// Newline.
fs.x = fs.left_margin;
fs.y += fs.font->height * 3 / 2; // 1.5 line spacing
}
}
}
free(text);
}
/*
* Word wrap the given string (i.e. replace space characters with newline
* characters) so that it fits the width of the FZX output terminal on an
* even word boundary. Any existing newline characters are respected.
* The word wrapped string is returned.
*/
char *str_word_wrap(char *str, unsigned int str_len)
{
char *line;
char *line_end;
line = strtok(str, "\n");
while (line != NULL)
{
line_end = fzx_string_partition_ww(out_term_font, line, out_term_line_width);
if ((line_end - str) >= str_len)
{
break;
}
if ((*line_end == ' ') || (*line_end == '\0'))
{
*line_end = '\n';
}
line = strtok(line_end + 1, "\n");
}
return str;
}
/*
* Sample text using stdio funcions only.
*/
void sample_text()
{
char *text = (char *)malloc(sizeof(text));
strcpy(text, sample_txt);
str_word_wrap(text, strlen(text));
fputs(text, stdout);
free(text);
}
void main(void)
{
init_hardware();
cls();
get_out_terminal_info();
printf("(%u) [%u]\n", out_term_line_width, out_term_font);
puts("Esto es una prueba de fuente proporcional...\n");
press_any_key();
cls();
set_font(&ff_pd_QLStyle);
get_out_terminal_info();
printf("(%u) [%u]\n", out_term_line_width, out_term_font);
sample_text0(); // IF I USE sample_text() INSTEAD OF sample_text0() IT WORKS OK!!!
press_any_key();
cls();
set_font(&ff_pd_Plotter);
get_out_terminal_info();
printf("(%u) [%u]\n", out_term_line_width, out_term_font);
sample_text0();
press_any_key();
cls();
set_font(&ff_ao_Lettera);
get_out_terminal_info();
printf("(%u) [%u]\n", out_term_line_width, out_term_font);
sample_text0();
press_any_key();
cls();
}