ZX-Next: problem using FZX library

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
Post Reply
jsj
New member
Posts: 2
Joined: Sun Jul 09, 2017 7:09 pm

ZX-Next: problem using FZX library

Post by jsj »

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:

Image

Image

This is when I try to use fzx_write and fzx_write_justified:

Image

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();
}
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

Looking at the screenshots it looks like only the standard ZX screen is being used.

I think what's happening is that the fzx_write() functions are hardwired into using asm_fzx_putc() and not asm_fzx_tshr_putc(). From the linker output it looks like adding this option: -pragma-redirect:asm_fzx_putc=asm_fzx_tshr_putc may well fix the issue.
jsj
New member
Posts: 2
Joined: Sun Jul 09, 2017 7:09 pm

Post by jsj »

I've compiled with the "pragma-redirect". Now it shows something diferent, some letters are readable.

Image

Perhaps some internal data structure not updating. I suspect that the call to:

Code: Select all

    struct fzx_state fs;
    struct r_Rect16 window = {0, 512, 0, 192};

    fzx_state_init(&fs, out_term_font, &window);
Is not working as intended. Any idea?
Post Reply