diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd657ca..832a923 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(src_lib STATIC cali.c dri.c filecheck.c + font.c gameresource.c hankaku.c mmap.c @@ -72,7 +73,6 @@ target_sources(xsystem35 PRIVATE ecopy.c effect.c event.c - font.c hacks.c gfx_draw.c gfx_image.c @@ -137,16 +137,17 @@ if (ENABLE_DEBUGGER) endif() if (WIN32) + target_sources(src_lib PRIVATE win/resources.c) target_sources(xsystem35 PRIVATE - win/dialog.c win/resources.rc win/resources.c win/menubar.c win/console.c) + win/dialog.c win/resources.rc win/menubar.c win/console.c) endif() if (NOT HAVE_LIBINTL) target_sources(xsystem35 PRIVATE nls.c) endif() -target_link_libraries(src_lib PRIVATE sdl2 zlib) -target_link_libraries(xsystem35 PRIVATE m zlib sdl2 freetype2) +target_link_libraries(src_lib PRIVATE sdl2 freetype2 zlib) +target_link_libraries(xsystem35 PRIVATE m zlib sdl2) if (TARGET sdl2_mixer) target_link_libraries(xsystem35 PRIVATE sdl2_mixer) endif() @@ -201,12 +202,15 @@ else() # non-emscripten, non-android add_executable(src_tests src_tests.c + font_test.c gameresource_test.c hankaku_test.c qnt_test.c variable_test.c ) target_compile_options(src_tests PRIVATE -Wno-pointer-sign -Wall) + target_compile_definitions(src_tests PRIVATE + TEST_FONT_DIR="${PROJECT_SOURCE_DIR}/fonts") target_link_libraries(src_tests PRIVATE src_lib sdl2) add_test(NAME src_tests COMMAND src_tests) file(COPY testdata DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/src/font_test.c b/src/font_test.c new file mode 100644 index 0000000..59c2343 --- /dev/null +++ b/src/font_test.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2026 + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "font.h" +#include "unittest.h" + +#include + +static const FontType font_types[] = {FONT_GOTHIC, FONT_MINCHO}; +#define NTYPES ((int)(sizeof(font_types) / sizeof(font_types[0]))) + +static const int sizes[] = {8, 16, 24, 32}; +#define NSIZES ((int)(sizeof(sizes) / sizeof(sizes[0]))) + +static const char *texts[] = { + "Hello, world!", + " ", + "iWiW", + "\xe9\xad\x94\xe7\x89\xa9\xe3\x81\xae\xe6\xa3\xae", // 魔物の森 + "\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86" // あいう + "\xe3\x82\xa2\xe3\x82\xa4\xe3\x82\xa6", // アイウ +}; +#define NTEXTS ((int)(sizeof(texts) / sizeof(texts[0]))) + +static const SDL_Color white = {255, 255, 255, 255}; + +static int measure_w(FontSpec f, const char *s) { + int w; + font_measure_text(f, s, -1, &w, NULL); + return w; +} + +static int measure_h(FontSpec f) { + int h; + font_measure_text(f, "", -1, NULL, &h); + return h; +} + +static void invariants_test(void) { + for (int ti = 0; ti < NTYPES; ti++) { + for (int si = 0; si < NSIZES; si++) { + FontSpec f = {font_types[ti], FONT_WEIGHT_NORMAL, sizes[si]}; + for (int i = 0; i < NTEXTS; i++) { + const char *text = texts[i]; + for (int aa = 0; aa < 2; aa++) { + SDL_Surface *s = font_render_text(f, text, white, aa); + ASSERT_TRUE(s); + // gfx_drawString() blits the surface using the measured + // width, so the two must agree. + ASSERT_EQUAL(s->w, measure_w(f, text)); + // microui lays out text rows by the measured height, + // so the surface must be exactly that tall. + ASSERT_EQUAL(s->h, measure_h(f)); + // The antialiased surface goes to gfx_drawAntiAlias_8bpp(), + // which reads a 32-bit alpha channel. The other one is + // blitted onto the indexed screen surface as is. + ASSERT_EQUAL(s->format->BitsPerPixel, aa ? 32 : 8); + SDL_FreeSurface(s); + } + } + // gfx_drawString() draws text by the top of the character cell, + // shifting the surface up by the overhang. The result must cover + // the whole cell. + ASSERT_TRUE(font_cell_overhang(f) >= 0); + ASSERT_TRUE(measure_h(f) - font_cell_overhang(f) >= f.size); + + // microui positions the text cursor by measuring a prefix of the + // string, so that must equal measuring a truncated copy. + const char *text = texts[0]; + for (int len = 0; text[len]; len++) { + char buf[64]; + int w; + font_measure_text(f, text, len, &w, NULL); + memcpy(buf, text, len); + buf[len] = '\0'; + ASSERT_EQUAL(w, measure_w(f, buf)); + } + } + } +} + +void font_test(void) { + font_init(); + font_set_name_and_index(FONT_GOTHIC, TEST_FONT_DIR "/MTLc3m.ttf", 0); + font_set_name_and_index(FONT_MINCHO, TEST_FONT_DIR "/mincho.ttf", 0); + + invariants_test(); +} diff --git a/src/src_tests.c b/src/src_tests.c index ace33a8..ce02860 100644 --- a/src/src_tests.c +++ b/src/src_tests.c @@ -20,6 +20,7 @@ #include #include +void font_test(void); void gameresource_test(void); void hankaku_test(void); void qnt_test(void); @@ -41,6 +42,7 @@ void sys_message(int level, char *format, ...) { } int main() { + font_test(); gameresource_test(); variable_test(); hankaku_test();