Bladeren bron

First tentative support.
Need first to make it to build!

Godzil 4 jaren geleden
bovenliggende
commit
844a209027

+ 19 - 15
CMakeLists.txt

@@ -4,27 +4,31 @@
 # Created by Manoel TRAPIER.
 # Copyright (c) 2002-2019 986-Studio.
 #
-cmake_minimum_required (VERSION 2.8)
+cmake_minimum_required (VERSION 3.1)
 
 project (peTI-NESulator)
 
 # External cmake modules
 set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external/cmake ${CMAKE_MODULE_PATH})
 
-# Include GLFW
-set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
-set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
-set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
-add_subdirectory("external/glfw")
-find_package(OpenGL REQUIRED)
-
-include_directories(${OPENGL_INCLUDE_DIR})
-
-# Include PortAudio
-set(PA_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
-set(PA_BUILD_TESTS OFF CACHE BOOL "" FORCE)
-set(PA_ENABLE_DEBUG_OUTPUT OFF CACHE BOOL "" FORCE)
-add_subdirectory("external/portaudio")
+if (USE_GLFW)
+    message("Coucou ${USE_GLFW}")
+    # Include GLFW
+    set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
+    set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
+    set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
+    add_subdirectory("external/glfw")
+    find_package(OpenGL REQUIRED)
+    include_directories(${OPENGL_INCLUDE_DIR})
+endif (USE_GLFW)
+
+if (USE_PORTAUDIO)
+    # Include PortAudio
+    set(PA_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
+    set(PA_BUILD_TESTS OFF CACHE BOOL "" FORCE)
+    set(PA_ENABLE_DEBUG_OUTPUT OFF CACHE BOOL "" FORCE)
+    add_subdirectory("external/portaudio")
+endif (USE_PORTAUDIO)
 
 if (COVERALLS)
     enable_testing()

+ 21 - 13
src/CMakeLists.txt

@@ -15,18 +15,17 @@ set(DETECT_BUS_CONFLICT OFF CACHE BOOL "Activate the bus conflit detector? (Coul
 set(USE_EFENCE OFF CACHE BOOL "Use electricfence memory debugger?")
 set(USE_PROFILING OFF CACHE BOOL "Use profiling tools? (Will slow down a lot.)")
 
-set(USE_ALLEGRO ON CACHE BOOL "Use Allegro backend")
-
 option(COVERALLS "Generate coveralls data" OFF)
 
 ##########################
 # Link & Compile flags
 ##########################
 
-set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-unused-result -Werror ${PLATFORM_FLAGS}")
-set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-unused-result -Werror ${PLATFORM_FLAGS}")
+#set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-unused-result -Werror ${PLATFORM_FLAGS}")
+#set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-unused-result -Werror ${PLATFORM_FLAGS}")
+set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-unused-result  ${PLATFORM_FLAGS}")
+set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-unused-result ${PLATFORM_FLAGS}")
 
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/external/coveralls-cmake/cmake)
 
 add_executable(petines main.c paddle.c NESCarts.c)
 
@@ -68,6 +67,20 @@ endif ()
 
 include_directories(include)
 
+set(OS_TARGET "UNIX" CACHE STRING "Select target to build against")
+set_property(CACHE OS_TARGET PROPERTY STRINGS TI68K WIN32 UNIX 32BLIT)
+
+
+if ("${OS_TARGET}" STREQUAL "TI68K")
+    add_subdirectory(os/ti68k)
+elseif ("${OS_TARGET}" STREQUAL "WIN32")
+    add_subdirectory(os/win32)
+elseif ("${OS_TARGET}" STREQUAL "UNIX")
+    add_subdirectory(os/unix)
+elseif ("${OS_TARGET}" STREQUAL "32BLIT")
+    add_subdirectory(os/32blit)
+endif ()
+
 add_subdirectory(apu)
 add_subdirectory(corecpu)
 add_subdirectory(mappersmanager)
@@ -76,14 +89,9 @@ add_subdirectory(pluginsmanager)
 add_subdirectory(ppu)
 
 
-if (TARGET_TI68k)
-    add_subdirectory(os/ti68k)
-elseif (WIN32)
-    add_subdirectory(os/win32)
-else (TARGET_TI68k)
-    add_subdirectory(os/unix)
-endif (TARGET_TI68k)
-
+if ( (NOT ${OS_TARGET} STREQUAL "TI68K") AND (NOT ${OS_TARGET} STREQUAL "32BLIT") )
+    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/external/coveralls-cmake/cmake)
+endif ()
 #find_library(PTHREADLIB pthread)
 
 if (COVERALLS)

+ 5 - 1
src/apu/CMakeLists.txt

@@ -5,4 +5,8 @@
 # Copyright (c) 2002-2019 986-Studio.
 #
 add_library(apu apu.c apu.c)
-target_link_libraries(apu portaudio_static)
+if (USE_PORTAUDIO)
+    target_link_libraries(apu portaudio_static)
+else()
+    target_link_libraries(apu)
+endif()

+ 17 - 0
src/os/32blit/CMakeLists.txt

@@ -0,0 +1,17 @@
+#
+# peTI-NESulator CMake
+#
+# Created by Manoël Trapier.
+# Copyright (c) 2002-2019 986-Studio.
+#
+set(USE_GLFW OFF BOOL CACHE INTERNAL "USE_GLFW")
+set(USE_PORTAUDIO OFF BOOL CACHE INTERNAL "USE_PORTAUDIO")
+
+set(PATH_32BLIT "../32blit" CACHE PATH "Path to 32Blit SDK")
+set(CMAKE_TOOLCHAIN_FILE "../../"${PATH_32BLIT}/32blit.toolchain)
+
+
+include("../../"${PATH_32BLIT}/32blit.cmake)
+
+add_library(oslib loadfile.c graphics.c sound.c io.c text.c)
+target_link_libraries(oslib)

+ 86 - 0
src/os/32blit/graphics.c

@@ -0,0 +1,86 @@
+/*
+ *  Graphic Manager - The peTI-NESulator Project
+ *  os/macos/graphics.c
+ *
+ *  Created by Manoël Trapier on 08/05/08.
+ *  Copyright (c) 2002-2019 986-Studio.
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <os_dependent.h>
+
+#include <palette.h>
+
+
+int graphics_init()
+{
+
+    return 0;
+}
+
+static uint32_t getColour(long color)
+{
+    Palette *pal = &basicPalette[color];
+    uint8_t r, g, b, a;
+    r = pal->r << 2;
+    b = pal->b << 2;
+    g = pal->g << 2;
+    a = 255;//pal->a;
+    return (b << 24) | (g << 16) | (r << 8) | a;
+}
+
+int graphics_getScreenSize(int *w, int *h)
+{
+
+    return 0;
+}
+
+int graphics_drawRect(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint32_t colour)
+{
+
+    return getColour(colour);
+}
+
+int graphics_drawFillrect(int x0, int y0, int w, int h, uint32_t colour)
+{
+    return 0;
+}
+
+int graphics_drawpixel(long x, long y, long color)
+{
+
+    return 0;
+}
+
+int graphics_drawCircle(int xc, int yc, int radius, uint32_t colour)
+{
+
+    return 0;
+}
+
+int graphics_drawline(uint32_t x, uint32_t y, uint32_t x1, uint32_t y1, uint32_t colour)
+{
+
+    return 0;
+}
+
+int graphics_blit(long x, long y, long w, long h)
+{
+
+    return 0;
+}
+
+int getKeyStatus(int key)
+{
+    return 0;
+}
+
+/* Sync with 60Hz (or try to) */
+void vsync(void)
+{
+
+}

+ 59 - 0
src/os/32blit/io.c

@@ -0,0 +1,59 @@
+/*
+ *  IO Manager - The peTI-NESulator Project
+ *  os/macos/graphics.c
+ *
+ *  Created by Manoël Trapier on 04/01/09.
+ *  Copyright (c) 2002-2019 986-Studio.
+ *
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <os_dependent.h>
+
+char LevelChar[] = { 'E', 'W', 'A', 'N', 'V', 'D' };
+
+ConsoleLevel console_ActualLevel = Console_Default;
+
+/* Actually nothing to do */
+int console_init(ConsoleLevel DefaultLevel)
+{
+    console_ActualLevel = DefaultLevel;
+    return 0;
+}
+
+/* Actually a simple printf with levels */
+int console_vprintf(const ConsoleLevel level, const char *format, va_list ap)
+{
+    if (console_ActualLevel >= level)
+    {
+        vprintf(format, ap);
+    }
+
+    return 0;
+}
+
+
+int console_printf(const ConsoleLevel level, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+
+    console_vprintf(level, format, ap);
+
+    va_end(ap);
+    return 0;
+}
+
+int console_printf_d(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+
+    console_vprintf(Console_Debug, format, ap);
+
+    va_end(ap);
+
+    return 0;
+}

+ 39 - 0
src/os/32blit/loadfile.c

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2002-2019 986-Studio.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include <sys/mman.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+
+
+/* Map a file in memory */
+void *LoadFilePtr(char *filename)
+{
+    int fd;
+    void *RetPtr;
+    struct stat FileStat;
+
+    fd = open(filename, O_RDONLY);
+
+    fstat(fd, &FileStat);
+
+    RetPtr = mmap(NULL, FileStat.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+    close(fd);
+
+    if (RetPtr == MAP_FAILED)
+    {
+        RetPtr = NULL;
+    }
+
+    return RetPtr;
+}

+ 0 - 0
src/os/32blit/sound.c


+ 512 - 0
src/os/32blit/text.c

@@ -0,0 +1,512 @@
+/*
+ *  FbLib graphic library
+ *
+ *  Created by Manoël TRAPIER.
+ *  Copyright (c) 2003-2019 986-Studio. All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include <os_dependent.h>
+
+#define DEFAULT_FONT "default_font.psf"
+FBLibFont *defaultFont = NULL;
+
+/* Function will fail, if no string terminator */
+static int getNextWordLen(char *str)
+{
+    int ret = 0, i;
+    /* Word delimiters */
+    char word_lim[] = { ' ', '\t', '\n', 0 };
+
+    while (1)
+    {
+        for (i = 0 ; word_lim[i] != 0 ; i++)
+        {
+            if (*str == word_lim[i])
+            {
+                return ret;
+            }
+        }
+        str++;
+        ret++;
+    }
+}
+
+void graphics_text_line(int x, int y, int w, int charw, uint32_t color, int valign, void *font, char *text)
+{
+    uint32_t len = strlen(text);
+
+    switch (valign)
+    {
+    default:
+    case TEXT_VALIGN_LEFT:
+        graphics_draw_text(x, y, color, (const FBLibFont *)font, text);
+        break;
+    case TEXT_VALIGN_CENTER:
+        graphics_draw_text(x + ((w - len * charw) / 2), y, color, (const FBLibFont *)font, text);
+        break;
+    case TEXT_VALIGN_RIGHT:
+        graphics_draw_text(x + (w - (len * charw)), y, color, (const FBLibFont *)font, text);
+        break;
+    }
+}
+
+/* Currently halign is not honored, but valign is */
+int graphics_text_ex(int x, int y, int w, int h,
+                     void *font,
+                     uint32_t bgcolor, uint32_t fgcolor,
+                     char valign, char halign,
+                     uint16_t options,
+                     void *format, ...)
+{
+    char string[1024];
+    char line[300];
+    int charWidth, charHeight;
+    int textPos = 0;
+    int wordLen = 0;
+    int nextWordLen = 0;
+
+    va_list va;
+    uint16_t curColPos = 0, curLinePos = 0;
+    uint16_t maxCharPerLine, maxTextLine;
+
+    FBLibFont *userFont = font;
+    if (defaultFont == NULL)
+    {
+        defaultFont = load_psf(DEFAULT_FONT);
+    }
+
+    if (font == NULL)
+    {
+        userFont = defaultFont;
+    }
+
+    /* Do some usefull calculation */
+    /* We use fixed size font */
+    graphics_get_text_size(&charWidth, &charHeight, userFont, "A");
+    maxCharPerLine = w / charWidth;
+    maxTextLine = h / charHeight;
+
+    /* Now convert to a useable string */
+    va_start(va, format);
+    vsnprintf(string, 1024, format, va);
+    va_end(va);
+
+    /* Fill rect with bg color */
+    graphics_drawFillrect(x, y, w, h, bgcolor);
+
+    /* Now fill as much as possible */
+    memset(line, 0, 300);
+    while (curLinePos < maxTextLine)
+    {
+        if (options & TEXT_OPT_WORDWRAP)
+        {
+            /* Do thoses check only one time per word, not per characters */
+            if (wordLen <= 0)
+            {
+                /* check if next word is too large for width */
+                nextWordLen = getNextWordLen(&string[textPos]);
+                //printf("\nNextword len = %d", nextWordLen);
+                if (nextWordLen <= maxCharPerLine)
+                {
+                    if ((curColPos + nextWordLen) > maxCharPerLine)
+                    {
+                        /* Go next line... */
+                        line[curColPos] = 0;
+                        graphics_text_line(x, y + curLinePos * charHeight, w, charWidth, fgcolor, valign, userFont,
+                                           line);
+                        curColPos = 0;
+                        curLinePos++;
+                        memset(line, 0, 300);
+                    }
+                }
+                wordLen = nextWordLen;
+            }
+            /* Now when the word is too long for a line, it will be automatically wrapped to the next line */
+        }
+
+        if ((string[textPos] == '\n') || (string[textPos] == '\r'))
+        {
+            textPos++;
+            line[curColPos] = 0;
+            graphics_text_line(x, y + curLinePos * charHeight, w, charWidth, fgcolor, valign, userFont, line);
+            curColPos = 0;
+            curLinePos++;
+            memset(line, 0, 300);
+        }
+        else if (string[textPos] == 0)
+        {
+            line[curColPos] = 0;
+            graphics_text_line(x, y + curLinePos * charHeight, w, charWidth, fgcolor, valign, userFont, line);
+            goto exit;
+        }
+        else if (curColPos >= maxCharPerLine)
+        {
+            /* display the line */
+            line[curColPos] = 0;
+            graphics_text_line(x, y + curLinePos * charHeight, w, charWidth, fgcolor, valign, userFont, line);
+            /* skip until a "\n" (and exit is "\0" found)) */
+            if (options & TEXT_OPT_WORDWRAP)
+            {
+                curColPos = 0;
+                curLinePos++;
+                memset(line, 0, 300);
+            }
+            else
+            {
+                while (1)
+                {
+                    if ((string[textPos] == '\r') || (string[textPos] == '\n'))
+                    {
+                        curColPos = 0;
+                        curLinePos++;
+                        memset(line, 0, 300);
+                        break;
+                    }
+                    else if (string[textPos] == 0)
+                    {
+                        goto exit;
+                    }
+
+                    textPos++;
+                }
+            }
+        }
+        else
+        {
+            line[curColPos++] = string[textPos++];
+        }
+
+        if (options & TEXT_OPT_WORDWRAP)
+        {
+            wordLen--;
+        }
+    }
+
+exit:
+    return 0;
+}
+
+void *fblib_loadfont(char *filename)
+{
+    return (void *)load_psf(filename);
+}
+
+
+/* PSF management */
+#define PSF1_MAGIC0     0x36
+#define PSF1_MAGIC1     0x04
+
+#define PSF1_MODE512    0x01
+#define PSF1_MODEHASTAB 0x02
+#define PSF1_MODEHASSEQ 0x04
+#define PSF1_MAXMODE    0x05
+
+#define PSF1_SEPARATOR  0xFFFF
+#define PSF1_STARTSEQ   0xFFFE
+
+struct psf1_header
+{
+    unsigned char magic[2];     /* Magic number */
+    unsigned char mode;         /* PSF font mode */
+    unsigned char charsize;     /* Character size */
+};
+
+#define PSF2_MAGIC0     0x72
+#define PSF2_MAGIC1     0xb5
+#define PSF2_MAGIC2     0x4a
+#define PSF2_MAGIC3     0x86
+
+/* bits used in flags */
+#define PSF2_HAS_UNICODE_TABLE 0x01
+
+/* max version recognized so far */
+#define PSF2_MAXVERSION 0
+
+/* UTF8 separators */
+#define PSF2_SEPARATOR  0xFF
+#define PSF2_STARTSEQ   0xFE
+
+struct psf2_header
+{
+    unsigned char magic[4];
+    unsigned int version;
+    unsigned int headersize;    /* offset of bitmaps in file */
+    unsigned int flags;
+    unsigned int length;        /* number of glyphs */
+    unsigned int charsize;      /* number of bytes for each character */
+    unsigned int height, width; /* max dimensions of glyphs */
+    /* charsize = height * ((width + 7) / 8) */
+};
+
+static FBLibFont *load_psf1(char *filename, FILE *fp)
+{
+    struct psf1_header head;
+    struct FBLibFont *font;
+    fread(&head, sizeof(head), 1, fp);
+
+    if ((head.magic[0] != PSF1_MAGIC0) || (head.magic[1] != PSF1_MAGIC1))
+    {
+        return NULL;
+    }
+
+    font = (FBLibFont *)malloc(sizeof(FBLibFont));
+
+    if (font != NULL)
+    {
+        font->height = head.charsize;
+        font->index_mask = 0xFF;
+
+
+    }
+
+    return NULL;
+}
+
+void printbin(uint32_t val, uint8_t bitlen)
+{
+    int i;
+    for (i = 0 ; i < bitlen ; i++)
+    {
+        if (val & (1 << (bitlen - 1)))
+        {
+            printf("*");
+        }
+        else
+        {
+            printf("_");
+        }
+        val <<= 1;
+    }
+}
+
+static FBLibFont *load_psf2(char *filename, FILE *fp)
+{
+    struct psf2_header head;
+    struct FBLibFont *font, *ret = NULL;
+    uint32_t charWidth;
+    uint32_t i, j, k;
+    uint8_t *bitmap;
+
+    fread(&head, sizeof(head), 1, fp);
+
+    if ((head.magic[0] != PSF2_MAGIC0) || (head.magic[1] != PSF2_MAGIC1) ||
+        (head.magic[2] != PSF2_MAGIC2) || (head.magic[3] != PSF2_MAGIC3)
+            )
+    {
+        goto exit;
+    }
+
+    font = (FBLibFont *)malloc(sizeof(FBLibFont));
+
+    assert(head.width <= 32); /* For now, do not support font with width larger than 32 pixels */
+
+    if (font != NULL)
+    {
+        font->height = head.height;
+
+        bitmap = (uint8_t *)malloc(sizeof(uint8_t) * head.charsize * head.length);
+        font->index_mask = 0xFF;
+        font->offset = (int *)malloc(sizeof(int) * head.length);
+        font->index = (int *)malloc(sizeof(int) * head.length * 3);
+        font->content = (uint32_t *)malloc(sizeof(uint32_t) * head.length * head.height);
+
+        charWidth = ((head.width + 7) / 8);
+
+        assert(bitmap != NULL);
+        assert(font->offset != NULL);
+        assert(font->index != NULL);
+        assert(font->content != NULL);
+
+        fread(bitmap, sizeof(uint8_t), head.charsize * head.length, fp);
+
+        for (i = 0 ; i < head.length ; i++)
+        {
+            font->offset[i] = i * 3;
+            font->index[(i * 3) + 0] = head.width;
+            font->index[(i * 3) + 1] = i * head.height;
+            font->index[(i * 3) + 2] = 0;
+
+            for (j = 0 ; j < head.height ; j++)
+            {
+                font->content[(i * head.height) + j] = 0;
+                for (k = 0 ; k < charWidth ; k++)
+                {
+                    font->content[(i * head.height) + j] |=
+                            (bitmap[(i * head.charsize) + (j * charWidth) + k]) << 8 * (3 - k);
+                }
+            }
+        }
+        ret = font;
+        free(bitmap);
+    }
+
+exit:
+    fclose(fp);
+    return ret;
+}
+
+FBLibFont *load_psf(char *filename)
+{
+    FILE *fp;
+    uint8_t byte;
+    console_printf(Console_Default, "Loading font '%s'\n", filename);
+    fp = fopen(filename, "rb");
+    if (fp != NULL)
+    {
+        byte = fgetc(fp);
+        rewind(fp);
+        switch (byte)
+        {
+        default:
+            fclose(fp);
+            return NULL; // Unsuported format
+        case PSF1_MAGIC0:
+            return load_psf1(filename, fp);
+        case PSF2_MAGIC0:
+            return load_psf2(filename, fp);
+        }
+    }
+
+    return NULL;
+}
+
+/* Font rendering code based on BOGL by Ben Pfaff */
+
+static int fblib_draw_glyph(const FBLibFont *font, uint8_t wc, uint32_t **bitmap)
+{
+    int mask = font->index_mask;
+    int i;
+
+    for (;;)
+    {
+        for (i = font->offset[wc & mask] ; font->index[i] ; i += 3)
+        {
+            if ((font->index[i] & ~mask) == (wc & ~mask))
+            {
+                if (bitmap != NULL)
+                {
+                    *bitmap = &font->content[font->index[i + 1]];
+                }
+                return font->index[i] & mask;
+            }
+        }
+    }
+    return 0;
+}
+
+void graphics_get_text_size(int *width, int *height,
+                            const FBLibFont *font,
+                            const char *text)
+{
+    uint8_t *c = (uint8_t *)text;
+    uint8_t wc;
+    int k, n, w, h, mw;
+
+    if (defaultFont == NULL)
+    {
+        defaultFont = load_psf(DEFAULT_FONT);
+    }
+
+    if (font == NULL)
+    {
+        font = defaultFont;
+    }
+
+    n = strlen(text);
+    mw = h = w = 0;
+
+    for (k = 0 ; k < n ; k++)
+    {
+        wc = *(c++);
+        if (wc == '\n')
+        {
+            if (w > mw)
+            {
+                mw = 0;
+            }
+
+            h += font->height;
+            continue;
+        }
+
+        w += fblib_draw_glyph(font, wc, NULL);
+    }
+
+    if (width != NULL)
+    {
+        *width = (w > mw) ? w : mw;
+    }
+    if (height != NULL)
+    {
+        *height = (h == 0) ? font->height : h;
+    }
+}
+
+void graphics_draw_text(int x, int y,
+                        uint32_t colour,
+                        const FBLibFont *font,
+                        const char *text)
+{
+    int32_t h, w, k, n, cx, cy, dx, dy;
+    uint8_t *c = (uint8_t *)text;
+    uint8_t wc;
+
+    if (defaultFont == NULL)
+    {
+        defaultFont = load_psf(DEFAULT_FONT);
+    }
+
+    if (font == NULL)
+    {
+        font = defaultFont;
+    }
+
+    n = strlen(text);
+    h = font->height;
+    dx = dy = 0;
+
+    for (k = 0 ; k < n ; k++)
+    {
+        uint32_t *glyph = NULL;
+        wc = *(c++);
+
+        if (wc == '\n')
+        {
+            dy += h;
+            dx = 0;
+            continue;
+        }
+
+        w = fblib_draw_glyph(font, wc, &glyph);
+
+        if (glyph == NULL)
+        {
+            continue;
+        }
+
+        for (cy = 0 ; cy < h ; cy++)
+        {
+            uint32_t g = *glyph++;
+
+            for (cx = 0 ; cx < w ; cx++)
+            {
+                if (g & 0x80000000)
+                {
+                    graphics_drawpixel(x + dx + cx, y + dy + cy, colour);
+                }
+                g <<= 1;
+            }
+        }
+
+        dx += w;
+    }
+}
+
+/* End of PSF */

+ 5 - 2
src/os/unix/CMakeLists.txt

@@ -4,11 +4,14 @@
 # Created by Manoël Trapier.
 # Copyright (c) 2002-2019 986-Studio.
 #
+set(USE_GLFW ON BOOL CACHE INTERNAL "USE_GLFW")
+set(USE_PORTAUDIO ON BOOL CACHE INTERNAL "USE_PORTAUDIO")
+
 if (COVERALLS)
     set(COVERAGE_SRCS src/os/unix/loadfile.c src/os/unix/graphics_dummy.c src/os/unix/sound.c src/os/unix/io.c ${COVERAGE_SRCS} PARENT_SCOPE)
-    add_library(oslib loadfile.c graphics_dummy.c sound.c io.c)
+    add_library(oslib loadfile.c graphics_dummy.c sound.c io.c text.c)
 else()
-    add_library(oslib loadfile.c graphics.c sound.c io.c)
+    add_library(oslib loadfile.c graphics.c sound.c io.c text.c)
 endif()
 
 target_link_libraries(oslib glfw ${OPENGL_glu_LIBRARY} ${OPENGL_gl_LIBRARY})