1
0
Fork 0
tetris-c/vendor/SDL3_ttf-3.2.2/examples/testapp.c
2026-05-10 00:20:28 +02:00

1387 lines
46 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
testapp: An example of using the SDL_ttf library with OpenGL.
Copyright (C) 2001-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* A simple program to test the text rendering feature of the TTF library,
* and find bugs
*
* <F1> for console help
*
* Use
* - fill/replace test_fonts[] with your fonts
* - replay a case, adding the log at line ~650 (search for 'replay')
* - add more string to test_strings[]
*
*/
static const int g_force_no_SDF = 0; /* make random fuzzer faster by disabling SDF rendering */
//#define HAVE_LCD
#define HAVE_SDF
#define HAVE_SET_FONT_SIZE_FUNCTION
// Need patch to set size dynamically
// https://bugzilla.libsdl.org/show_bug.cgi?id=2487
#define HAVE_WRAP_ALIGN
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
static char *testapp_basename(const char *path) {
static char buffer[1024];
const char *pos, *sep, *prev_sep;
int prev_was_sep = 0;
prev_sep = sep = NULL;
for (pos = path; *pos; pos++) {
if (*pos == '/' || *pos == '\\') {
if (!prev_was_sep) {
prev_sep = sep;
}
sep = pos;
prev_was_sep = 1;
} else {
prev_was_sep = 0;
}
}
if (!sep) {
if (path[0] == '\0') {
buffer[0] = '.';
buffer[1] = '\0';
} else {
SDL_strlcpy(buffer, path, sizeof(buffer));
}
} else {
if (sep[1] == '\0') {
if (prev_sep) {
char *s;
SDL_strlcpy(buffer, prev_sep + 1, sizeof(buffer));
SDL_strtok_r(buffer, "/\\", &s);
} else {
buffer[0] = *sep;
buffer[1] = '\0';
}
} else {
SDL_strlcpy(buffer, sep + 1, sizeof(buffer));
}
}
return buffer;
}
static void help(void)
{
SDL_Log("up/down : font size -/+");
SDL_Log("c/v : next/previous font");
SDL_Log("o/p : outline -/+");
SDL_Log("q/e : wrap size -/+");
SDL_Log("a : align wrap: left center right");
SDL_Log("w : wrap");
SDL_Log("u : underline");
SDL_Log("k : kerning");
SDL_Log("s : strike-through");
SDL_Log("b : bold");
SDL_Log("g/h : hinting -/+ (normal, light, light_subpix, mono, none)");
SDL_Log("i : italic");
SDL_Log("f : signed distance field");
SDL_Log("t : ticks elapsed for 50 rendering");
SDL_Log("d : display normal texture, no screen update, stream texture ");
SDL_Log("r : start/stop random test");
SDL_Log("m : render mode Solid/Blended/Shaded");
SDL_Log("x : text engine None/Surface/Renderer");
SDL_Log("n : change direction");
SDL_Log("9/0 : -/+ alpha color fg");
SDL_Log("7/8 : -/+ alpha color bg (Shaded only)");
SDL_Log("6 : invert bg/fg colors");
SDL_Log("345 : increase r/g/b fg color");
SDL_Log("2 : background color (Black->R->G->B->W)");
SDL_Log("<space> : next string/rendering function");
SDL_Log("<backspace> : previous string/rendering function");
SDL_Log("F1 : help");
SDL_Log("F2 : save current rendering to .bmp");
}
static int rand_n(int n);
static void init_rand(void);
static const char *test_fonts[] = {
"fonts/NotoColorEmoji.ttf", // Colored Emoji
"fonts/FletcherGothicFLF.ttf",
#if 1
/* CFF/OpenType font (.otf) */
"fonts/ITCAvantGardeStd-Demi.ttf", // BUG 4266
#endif
"fonts/DroidSansFallback.ttf", // xstart negative Jap
"fonts/Папка/Lazy.ttf",
"fonts/DroidSans.ttf", // no kerning here ?
"fonts/DejaVuSans.ttf",
"fonts/digital-7.ttf", // BUG 969
"fonts/HelveticaNeue-Regular.ttf",// BUG 2622
"fonts/ttf_amiga/amiga4ever pro2.ttf",
"fonts/ttf-bitstream-vera-1.10/VeraMoBI.ttf",
"fonts/ttf-bitstream-vera-1.10/VeraBd.ttf",
"fonts/ttf-bitstream-vera-1.10/Vera.ttf",
"fonts/nonscalable/sazanami-gothic.ttf", // BUG 190 crash?. Both Scalable and Fixed Sizes
"fonts/drakono.ttf", // BUG 2629 ........ ??????
"fonts/Lazy.ttf", // BUG 2468
"fonts/font_bug254.ttf", // BUG 254
"fonts/OpenSansEmoji.ttf", // BUG 3762
#if 1
"fonts/nonscalable/pvfixed_20b.pcf.gz",
"fonts/nonscalable/pvfixed_20r.pcf.gz",
"fonts/nonscalable/7x13B-ISO8859-15.pcf.gz",
"fonts/nonscalable/vgasys.fon", // BUG 2574
"fonts/nonscalable/fixed8.fon", // BUG 2127
#endif
#if 0
# include "fonts/fuzzing_corpora.h"
#endif
#if 0
# include "fonts/android_fonts_others.h"
# include "fonts/android_fonts.h"
#endif
"fonts/Kaumudi.ttf"
};
static const int test_fonts_count = SDL_arraysize(test_fonts);
static int wrap_size = 137;
static int w_align = 0;
static int outline = 0;
static int font_style = 0;
static int kerning = 1;
static int wrap = 0;
static int sdf = 0;
static int hinting = 0;
static int curr_str = 0;
static int curr_font = 1;
static int curr_size = 50;
static int fg_alpha = 0;
static int bg_alpha = 0;
static int background_color = 0;
static int seed = 0;
static int print_elapsed_ticks = 0;
static int update_screen_mode = 0;
static int save_to_bmp = 0;
/* RENDER_SOLID = 0, RENDER_BLENDED = 1, RENDER_SHADED = 2, RENDER_LCD = 3 } */
static int render_mode = -1;
static int render_mode_overwrite;
static const char *render_mode_desc[] = { "Solid", "Blended", "Shaded", "LCD" };
static const int render_mode_count = SDL_arraysize(render_mode_desc);
static int textengine_mode = 0;
static const char *textengine_desc[] = { "None", "Surface", "Renderer" };
static const int textengine_count = SDL_arraysize(textengine_desc);
static int direction = 0;
static const struct {
const char *description;
int value;
} directions[] = {
{ "LTR", TTF_DIRECTION_LTR },
{ "RTL", TTF_DIRECTION_RTL },
{ "TTB", TTF_DIRECTION_TTB },
{ "BTT", TTF_DIRECTION_BTT }
};
static const int direction_count = SDL_arraysize(directions);
//static const char *hinting_desc[] = { "normal", "light", "light_subpix", "lcd_subpix", "mono", "none" };
static const char *hinting_desc[] = { "normal", "light", "light_subpix", "mono", "none" };
static const int hinting_count = SDL_arraysize(hinting_desc);
static int mode_random_test = 0;
static int random_cnt = 0;
static int saved_curr_font = -1;
static int saved_curr_size = -1;
static SDL_Color boardcol = { 0, 0, 0, 0 };
static SDL_Color textcol = { 255, 255, 255, 0 };
static const char emoji[5] = { 0xF0, 0x9F, 0x98, 0x81, '\0'};
static const char *test_strings[] = {
// TMP BUG
#if 0
"وفي حالة كشف مربع يحتوي على لغم، يخسر اللاعب اللعبة.",
#endif
#if 1
"纸牌接龙",
//"空当接龙用一副没有大小王的52张扑克牌来玩这些扑克牌被摆在8列中。",
#endif
"ABC",
"The quick \n brown fox \n jumps over the lazy dog 0123456789",
"iiiiiiiiiiiiiiiiiiiiiiiiiiiiiii", // test supixel
emoji,
/* static const char emoji[5] = { 0xF0, 0x9F, 0x98, 0x81, '\0'}; */
#if 1
"abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz "
,
#endif
"aTa kerning iTo",
"AV VA Te eT Tr rT Td TA LV Vd pV Vq bV", // kerning
"if fi ifi aif fai aifia substitution",
"abc \xc4\x80", // String would be both outline and bitmap for Sazami-Gothic
#if 1
"abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz "
,
#endif
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"=",
"~",
"`~!@#$%^&*()_-+={}|[]\\;:'\",<.>/?",
#if 1
"Å", // ystart negative with DroidSans
"A\n\b\nB",
"Tap Å",
/* xstart negative */
"Jap",
"A\315\241B", /* 'A' + U+0361 + 'B' */
"\315\241BC", /* '.' + U+0361 + 'B' + 'C' */
".\315\241BC", /* '.' + U+0361 + 'B' + 'C' */
".\315\241BC\naaaaa", /* '.' + U+0361 + 'B' + 'C' */
".aaaaa\n.\315\241BC", /* '.' + U+0361 + 'B' + 'C' */
"aaa\n.\315\241BCaa\n.aaa\n.\315\241BCaaaaa", /* '.' + U+0361 + 'B' + 'C' */
"Tap Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å"
"Tap Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å"
"Tap Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å",
#endif
"+", "2", ")", "|",
"a\tsdfsad.f..| I V I A AV A V D \n F G H ",
"é ê è à â ô î ï fi if ñ ç Ã Â",
"Kl1AqvJAUOOKzdjpGTteM775hTYEuqvV b3EU0RZ88JIAMRVS7rMbyKsF1xMg9RTe",
"CGOXraiYCL44XSlvqx825GvZT3HQYXNQcVNjgzrccX1eUar8nG0FZ3MsYdB5caGqiG7l7RJCyNZFRUVQ8rEVnc0TJVrY3ef4v8miQpVvYswTjjZKTZLwwFxLbsHhaDQ3",
"7I8DRXPfbKUIl6SH5V6Twqw6mzEzTlDf",
"JJsSGv1EA MpN9FIctQxi9D iHgEQZe2Wg",
"xqKyuaT8H2xmySzWdbo wgMZ4Sp2BLUGj",
"hUEKUunoouIjw6Cu jdXnPkQzMNGG7U8u",
"4GDEgeCgEXwxoszBpriddAibgbhh36Vz",
"FdkAi hx8B3QvmjFXovy64TzYwaZ0uoW8",
"zAcp1V4PmI5dBv wtnbHqN1ISyrXB7P32",
"lJq5w9GNhpqveQ67kxyQlgAwgQz1AAj3",
"yi0jssXmCMjnFjl2rWs0rNIx51iVNLoI",
"HT1BYxlX3z39XBFEw8JMNwYdWeQrO8h2",
"aQmJI2hUruwhqvJeWL3 gZCGAZ09q67nR",
"rxGWF OPfQdxUR0cYRenCccz5XgSpTDqf",
"4NI1L2KbwybObecSDAAgb0K00oCEkf3E",
"heBlACb AfcK9G85Gl6mBpBUiblc81FSe",
"GwWx6pHvWyvxSu82PbJbZI UNwx9JSATu",
"AFCQd25jnbBJ7LBbaXI3I5IeSwDXqME6",
"lzSqw9t7hJ03AkTjWWUyd3KqrnGAvPJg",
"pxwCKuWxUOrIMvqXGL 5fbibttAPNIJFC",
"Fs6sFtGnRezLttwm8AbSKsuvLGbcqFbZ",
"hEdVvdwWDwsDA23dX0NjDqzYEaURRC7a",
"IBrdiqo3g0tj LkXz1a45DJD52tO8FJSw",
"h5QYsL9S1cfsWzTyyFJ6Npq7vLi1tjEX",
"zhUkVyCPdhWspT9kBQpOmmREmSU6GPW3",
"Ud1ih3stL5nq00PJMRoA1Zd1QJi0mOzj",
"iVppAFr5pGYa4oT8OozDi0oqGvqJg3Eg",
"YC9YUpKq95nIe7D3ckdc6Yy1cEmmuqf1",
"pzmZvs5j77aVaXXnPqzcuU9fW4Kfmiv5",
"04ifd9OyA5XGsLTovRo04MnIKToW9Qu3",
"iDJcbD5si6xPRcPRBEVeEhcJSs7n65SD",
"a4oZMmgJQAa72o6sllH4n0zfJE5H0HlA",
"5eSVmFkJMmPCRKdTZRJeuW71uhprmYHp",
"LcnSHbxguPfqPNhdDR4XDc2qv01Q4Y1Y",
"H3wT59MiQmEBZ7tYGMt1xMUu7wajECo6",
"JNGUtcQz660ApgN54rk2UzpqWimO25Cy",
"ss887dpFwjPaqAg53K6qZnc1NFiXc9WX",
"y9Th4vRk1jSpKlzB5soK66ckzl3USZq6",
"WGWY5YmWhaA5oKCoDmRA3n82XwclqvSP",
"hvlSZ6jE2BU9ImjUjQiY255GA5ASfUUx",
"e9o4tBCA9TCpilOI05UyHzes6s8lP9lQ",
"gJyC26gZsCKR8wSp9kNMYKJRRgA3u45U1DWdzPCWv1SUEKi3Wdo3zNFTWiMcCfcl5A0MzOhbqRee7OP13NruY WP0ufGiB4W9RBWqgSy7umnE6puTyCc9WhPOzdLz168BhQwYetZkADWibObi8jcYajuUv54zxXkXQwC1B8lAi8rIH9lmIy0G10fQ832HKiLx"
};
static const int test_strings_count = SDL_arraysize(test_strings);
static const char *font_path = NULL;
static TTF_Font *font = NULL;
static int iter = 0, sum = 0;
static void quit(const char *msg)
{
SDL_Log("ERROR: %s", msg);
SDL_Log("SDL_GetError: %s", SDL_GetError());
exit(1);
}
static void random_input(void);
static int wait_for_input(void)
{
int done = 0;
SDL_Event event;
while (!done) {
if (!SDL_WaitEvent(&event)) {
quit("Event handling");
}
switch (event.type) {
case SDL_EVENT_KEY_DOWN:
if (event.key.key == SDLK_F1) {
help();
done = 1;
}
if (event.key.key == SDLK_SPACE) {
iter++;
sum++;
done = 1;
}
if (event.key.key == SDLK_BACKSPACE) {
iter--;
sum++;
done = 1;
}
if (event.key.key == SDLK_DOWN) {
curr_size -= 1;
if (curr_size < -1) curr_size = -1;
done = 1;
SDL_Log("size: %d", curr_size);
}
if (event.key.key == SDLK_UP) {
curr_size += 1;
done = 1;
SDL_Log("size: %d", curr_size);
}
if (event.key.key == SDLK_C) {
curr_font -= 1;
if (curr_font < 0) curr_font = 0;
done = 1;
SDL_Log("Switch to font %s", test_fonts[curr_font]);
}
if (event.key.key == SDLK_V) {
curr_font += 1;
done = 1;
if (curr_font >= test_fonts_count) curr_font = test_fonts_count - 1;
SDL_Log("Switch to font %s", test_fonts[curr_font]);
}
if (event.key.key == SDLK_O) {
outline -= 1;
if (outline < -1) outline = -1;
done = 1;
SDL_Log("outline: %d", outline);
}
if (event.key.key == SDLK_P) {
outline += 1;
done = 1;
SDL_Log("outline: %d", outline);
}
if (event.key.key == SDLK_Q) {
wrap_size -= 1;
done = 1;
SDL_Log("wrap_size: %d", wrap_size);
}
if (event.key.key == SDLK_A) {
w_align += 1;
if (w_align == 3) w_align = 0;
done = 1;
SDL_Log("wrap_align: %d", w_align);
}
if (event.key.key == SDLK_E) {
wrap_size += 1;
done = 1;
SDL_Log("wrap_size: %d", wrap_size);
}
if (event.key.key == SDLK_I) {
int s = TTF_STYLE_ITALIC;
SDL_Log("italic %s", (font_style & s) ? "removed" : "added");
font_style ^= s;
done = 1;
}
if (event.key.key == SDLK_B) {
int s = TTF_STYLE_BOLD;
SDL_Log("bold %s", (font_style & s) ? "removed" : "added");
font_style ^= s;
done = 1;
}
if (event.key.key == SDLK_U) {
int s = TTF_STYLE_UNDERLINE;
SDL_Log("underline %s", (font_style & s) ? "removed" : "added");
font_style ^= s;
done = 1;
}
if (event.key.key == SDLK_S) {
int s = TTF_STYLE_STRIKETHROUGH;
SDL_Log("strike-through %s", (font_style & s) ? "removed" : "added");
font_style ^= s;
done = 1;
}
if (event.key.key == SDLK_K) {
done = 1;
kerning ^= 1;
if (kerning) {
SDL_Log("kerning allowed");
} else {
SDL_Log("kerning removed");
}
}
if (event.key.key == SDLK_W) {
done = 1;
wrap ^= 1;
if (wrap) {
SDL_Log("wrap allowed");
} else {
SDL_Log("wrap removed");
}
}
if (event.key.key == SDLK_F) {
done = 1;
sdf ^= 1;
if (sdf) {
SDL_Log("SDF allowed");
} else {
SDL_Log("SDF removed");
}
}
if (event.key.key == SDLK_T) {
done = 1;
print_elapsed_ticks ^= 1;
if (print_elapsed_ticks) {
SDL_Log("print_elapsed_ticks displayed");
} else {
SDL_Log("print_elapsed_ticks hidden");
}
}
if (event.key.key == SDLK_D) {
done = 1;
update_screen_mode += 1;
update_screen_mode %= 2;
if (update_screen_mode == 0) {
SDL_Log("texture displayed");
} else if (update_screen_mode == 1) {
SDL_Log("texture not displayed");
}
}
if (event.key.key == SDLK_G) {
done = 1;
hinting -= 1;
if (hinting < 0) hinting = 0;
SDL_Log("hinting: %s", hinting_desc[hinting]);
}
if (event.key.key == SDLK_H) {
done = 1;
hinting += 1;
hinting %= hinting_count;
SDL_Log("hinting: %s", hinting_desc[hinting]);
}
if (event.key.key == SDLK_R) {
done = 1;
mode_random_test = 1;
random_cnt = 0;
SDL_Log("start random test");
}
if (event.key.key == SDLK_M) {
done = 1;
render_mode += 1;
render_mode %= render_mode_count;
render_mode_overwrite = render_mode;
SDL_Log("render mode: %s", render_mode_desc[render_mode]);
}
if (event.key.key == SDLK_X) {
done = 1;
textengine_mode += 1;
textengine_mode %= textengine_count;
SDL_Log("Text Engine: %s", textengine_desc[textengine_mode]);
}
if (event.key.key == SDLK_N) {
done = 1;
direction += 1;
direction %= direction_count;
SDL_Log("direction: %s", directions[direction].description);
}
if (event.key.key == SDLK_F2) {
done = 1;
save_to_bmp = 1;
}
if (event.key.key == SDLK_9) {
done = 1;
fg_alpha -= 1;
if (fg_alpha < 0) fg_alpha = 0;
SDL_Log("color fg alpha = %d", fg_alpha);
}
if (event.key.key == SDLK_0) {
done = 1;
fg_alpha += 1;
if (fg_alpha > 255) fg_alpha = 255;
SDL_Log("color fg alpha = %d", fg_alpha);
}
if (event.key.key == SDLK_7) {
done = 1;
bg_alpha -= 1;
if (bg_alpha < 0) bg_alpha = 0;
SDL_Log("color bg alpha = %d", bg_alpha);
}
if (event.key.key == SDLK_8) {
done = 1;
bg_alpha += 1;
if (bg_alpha > 255) bg_alpha = 255;
SDL_Log("color bg alpha = %d", bg_alpha);
}
if (event.key.key == SDLK_6) {
SDL_Color tmp = textcol;
textcol = boardcol;
boardcol = tmp;
textcol.a = 0;
boardcol.a = 0;
SDL_Log("Invert BG / FG color");
done = 1;
}
if (event.key.key == SDLK_3) {
done = 1;
textcol.r += 1;
SDL_Log("color fg: r=%d g=%d b=%d alpha=%d", textcol.r, textcol.g, textcol.b, textcol.a);
}
if (event.key.key == SDLK_4) {
done = 1;
textcol.g += 1;
SDL_Log("color fg: r=%d g=%d b=%d alpha=%d", textcol.r, textcol.g, textcol.b, textcol.a);
}
if (event.key.key == SDLK_5) {
done = 1;
textcol.b += 1;
SDL_Log("color fg: r=%d g=%d b=%d alpha=%d", textcol.r, textcol.g, textcol.b, textcol.a);
}
if (event.key.key == SDLK_2) {
const char *str[6] = {"Black", "Red", "Green", "Blue", "White", "Gray" };
background_color += 1;
if (background_color == 6) background_color = 0;
SDL_Log("Background color '%s", str[background_color]);
done = 1;
}
if (event.key.key == SDLK_ESCAPE) {
SDL_Log("ESC");
return 1;
}
break;
case SDL_EVENT_QUIT:
return 1;
default:
break;
}
}
return 0;
}
int main(void)
{
SDL_Window *window = NULL;
SDL_Texture *text_texture = NULL;
SDL_Surface *text_surface = NULL;
SDL_Renderer *renderer = NULL;
TTF_Text *text_obj = NULL;
TTF_TextEngine *engine_surface = NULL;
TTF_TextEngine *engine_renderer = NULL;
const int windoww = 640;
const int windowh = 480;
const char *text;
char filename[256];
char infos[256];
int replay = 0;
int t1 = 0, t2 = 0, t_sum;
Uint64 T1 = 0, T2 = 0, T_sum, T_min;
int count, count_init;
#define INIT_VARS \
t_sum = 0; \
T_sum = 0; \
T_min = 999999999999ULL;\
count = count_init; \
#define START_MEASURE \
t1 = SDL_GetTicks(); \
T1 = SDL_GetPerformanceCounter(); \
#define END_MEASURE \
T2 = SDL_GetPerformanceCounter(); \
t2 = SDL_GetTicks(); \
\
t_sum += (t2 - t1); \
T_sum += (T2 - T1); \
T_min = SDL_min(T_min, T2 - T1); \
if (!SDL_Init(SDL_INIT_VIDEO)) {
quit("SDL init failed");
}
if (!TTF_Init()) {
SDL_Quit();
quit("SDL_ttf init failed");
}
window = SDL_CreateWindow("", windoww, windowh, 0);
if (window == NULL) {
quit("SDL windowdow setup failed");
}
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles2");
renderer = SDL_CreateRenderer(window, NULL);
if (renderer == NULL) {
quit("SDL renderer setup failed");
}
/* Display help */
help();
#if 0
/*****************************************/
/* Copy a log here to replay a rendering */
/*********************************** *****/
/* FreeType issue with FletcherGothicFLF, size=10 and outline at 9 -> error in FT_Glyph_To_Bitmap(). glyph '=' */
// replay=1; font_style=0; kerning=0; wrap=0; wrap_size=0; outline=8; curr_size=10; render_mode=0; curr_str=5; curr_font=0;
// do outline +1 (key p)
// --> SDL_GetError: Couldn't find glyph
//
/* FreeType issue with font/ITCAvantGardeStd-Demi.ttf glyph='Q' */
// replay=1; font_style=0; kerning=0; wrap=0; wrap_size=0; outline=0; curr_size=4; render_mode=0; curr_str=27; curr_font=1; hinting=3;
// do outline +1 (key p)
// --> SDL_GetError: Couldn't find glyph
#endif
// color
// replay=1; font_style=0; kerning=0; wrap=0; wrap_size=354; outline=0; curr_size=7; render_mode=1; curr_str=63; curr_font=1522; hinting=0; fg_alpha=255; // light Blended
//replay=1; font_style=15; kerning=0; wrap=1; wrap_size=56; outline=0; curr_size=5; render_mode=1; curr_str=68; curr_font=3007; hinting=0; fg_alpha=128; // mono Blended
#if 0
seed=1641805930; replay=1; font_style=9; kerning=1; sdf=1; wrap=0; wrap_size=661; w_align=2; outline=0; curr_size=20; render_mode=3; curr_str=14; curr_font=1777; hinting=1; fg_alpha=65; // light LCD
#endif
//seed=1673390190; replay=1; font_style=12; kerning=0; sdf=1; wrap=0; wrap_size=91; w_align=0; outline=0; curr_size=16; render_mode=0; curr_str=14; curr_font=1288; hinting=0; fg_alpha=77; // none Solid
//seed=1673390190; replay=1; font_style=12; kerning=0; sdf=0; wrap=0; wrap_size=91; w_align=0; outline=0; curr_size=30; render_mode=1; curr_str=14; curr_font=1288; hinting=0; fg_alpha=77; // none Solid
//seed=1673390190; replay=1; font_style=9; kerning=1; sdf=0; wrap=1; wrap_size=94; w_align=2; outline=7; curr_size=42; render_mode=1; curr_str=75; curr_font=1997; hinting=1; fg_alpha=90; // light Blended
if (replay) {
SDL_Log("Replay with string _%s_", test_strings[curr_str]);
}
while (1)
{
/* Normal mode <space>, try all combination {strings}x{render_mode} and exit
This updates "render_mode" and "curr_str" */
if (!mode_random_test && !replay) {
if (iter <= 0) {
iter = 0;
}
if (iter >= render_mode_count * test_strings_count) {
SDL_Log("End of rendering!");
break;
} else {
render_mode = iter / test_strings_count;
curr_str = iter - test_strings_count * render_mode;
}
}
if (render_mode_overwrite) {
render_mode = render_mode_overwrite;
}
textcol.a = fg_alpha;
boardcol.a = bg_alpha;
/* Set all parameters coming from random or user input */
#if 0
/* Force a parameter */
curr_font = 1250;
curr_size = 1;
curr_size &=0x3;
#endif
#if 0
/* From a specific seed, jump to a specific iteration */
{
static int skip = 1046;
if (skip) {
skip--;
goto next_loop;
}
}
#endif
if (saved_curr_font != curr_font) {
if (font) {
TTF_CloseFont(font);
}
saved_curr_font = curr_font;
saved_curr_size = curr_size;
font_path = test_fonts[curr_font];
SDL_Log("TTF_OpenFont: %s", font_path);
font = TTF_OpenFont(font_path, (float)curr_size);
if (!font) {
#if 1
quit("Font load failed");
#else
SDL_Log("Font load failed");
saved_curr_font = -1;
goto next_loop;
#endif
}
}
if (saved_curr_size != curr_size) {
#if defined(HAVE_SET_FONT_SIZE_FUNCTION)
TTF_SetFontSize(font, (float)curr_size);
#else
if (font) {
TTF_CloseFont(font);
}
font_path = test_fonts[curr_font];
SDL_Log("Re-TTF_OpenFont: %s to change size from %d to %d", font_path, saved_curr_size, curr_size);
font = TTF_OpenFont(font_path, curr_size);
if (!font) {
#if 1
quit("Font load failed (2)");
#else
SDL_Log("Font load failed (2)");
saved_curr_font = -1;
goto next_loop;
#endif
}
#endif
saved_curr_size = curr_size;
}
TTF_SetFontDirection(font, directions[direction].value);
{
int tmp;
tmp = TTF_GetFontOutline(font);
if (tmp != outline) {
TTF_SetFontOutline(font, outline);
}
tmp = TTF_GetFontStyle(font);
if (tmp != font_style) {
TTF_SetFontStyle(font, font_style);
}
tmp = TTF_GetFontKerning(font);
if (tmp != kerning) {
TTF_SetFontKerning(font, kerning);
}
#if defined(HAVE_SDF)
tmp = TTF_GetFontSDF(font);
if (tmp != sdf) {
TTF_SetFontSDF(font, sdf);
}
#endif
{
// static const char *hinting_desc[] = { "normal", "light", "light_subpix", "mono", "none" };
// static const char *hinting_desc[] = { "normal", "light", "light_subpix", "lcd_subpix", "mono", "none" };
int h = 0;
if (hinting == 0) h = TTF_HINTING_NORMAL;
if (hinting == 1) h = TTF_HINTING_LIGHT;
if (hinting == 2) h = 4; // TTF_HINTING_LIGHT_SUBPIXEL;
// if (hinting == 3) h = 5; // TTF_HINTING_LCD_SUBPIXEL;
if (hinting == 3) h = TTF_HINTING_MONO;
if (hinting == 4) h = TTF_HINTING_NONE;
tmp = TTF_GetFontHinting(font);
if (tmp != h) {
TTF_SetFontHinting(font, h);
}
}
}
/* Get some console output out in case we crash next... */
if (! mode_random_test) {
char title[1024];
SDL_snprintf(title, sizeof(title) - 1, "%s Sz=%d outline=%d Hinting=%s %s",
render_mode_desc[render_mode],
curr_size,
outline,
hinting_desc[hinting],
testapp_basename(font_path));
if (save_to_bmp) {
SDL_snprintf(filename, sizeof(filename) - 1 ,
"Render=%s_size=%d_outline=%d_wrap=%d_wrap_size=%d_kerning=%d_sdf=%d_italic=%d_bold=%d_underline=%d_strikethrough=%d_hinting=%s_%s__%" SDL_PRIs64 ".bmp",
render_mode_desc[render_mode],
curr_size,
outline,
wrap,
wrap_size,
kerning,
sdf,
!!(font_style & TTF_STYLE_ITALIC),
!!(font_style & TTF_STYLE_BOLD),
!!(font_style & TTF_STYLE_UNDERLINE),
!!(font_style & TTF_STYLE_STRIKETHROUGH),
hinting_desc[hinting],
testapp_basename(font_path),
(Sint64)time(NULL)
);
}
SDL_snprintf(infos, sizeof(infos) - 1 ,
"Render=%s size=%d outline=%d wrap=%d wrap_size=%d kerning=%d sdf=%d italic=%d bold=%d underline=%d strikethrough=%d hinting=%s %s",
render_mode_desc[render_mode],
curr_size,
outline,
wrap,
wrap_size,
kerning,
sdf,
!!(font_style & TTF_STYLE_ITALIC),
!!(font_style & TTF_STYLE_BOLD),
!!(font_style & TTF_STYLE_UNDERLINE),
!!(font_style & TTF_STYLE_STRIKETHROUGH),
hinting_desc[hinting],
font_path
);
SDL_SetWindowTitle(window, title);
SDL_Log("%s", infos);
#if 0
SDL_Log("font_style=%d; kerning=%d; wrap=%d; wrap_size=%d; outline=%d; curr_size=%d; render_mode=%d; curr_str=%d; curr_font=%d; hinting=%d;",
font_style, kerning, wrap, wrap_size, outline, curr_size, render_mode, curr_str, curr_font, hinting);
#endif
}
/* pick a string */
text = test_strings[curr_str];
/* Skip some string with no chars (all index == 0), zero advance and so zero width at low size
* That would fail to render because of size 0.
* */
{
int w = 0, h = 0;
#if defined(HAVE_SDF)
/* SDF change the str size. if we dont render with it (eg not blended mode).
* then set it to 0.
* otherwse it reports a valid size.
* but the texture isn't renderered.
*/
if (render_mode != 1) {
int tmp = TTF_GetFontSDF(font);
if (tmp != 0) {
TTF_SetFontSDF(font, 0);
}
}
#endif
if (!TTF_GetStringSize(font, text, 0, &w, &h)) {
SDL_Log("size failed");
}
if (w == 0) {
SDL_Log("skip size == 0");
goto next_loop;
}
}
if (textengine_mode != 0) {
if (!engine_surface) {
engine_surface = TTF_CreateSurfaceTextEngine();
if (!engine_surface) {
SDL_Log("Couldn't create surface text engine: %s", SDL_GetError());
}
}
if (!engine_renderer) {
engine_renderer = TTF_CreateRendererTextEngine(renderer);
if (!engine_renderer) {
SDL_Log("Couldn't create renderer text engine: %s", SDL_GetError());
}
}
}
count_init = print_elapsed_ticks ? 500 : 1;
INIT_VARS
/* render */
if (wrap == 0) {
while (count--) {
if (text_surface) {
SDL_DestroySurface(text_surface);
text_surface = NULL;
}
if (text_obj) {
TTF_DestroyText(text_obj);
text_obj = NULL;
}
if (textengine_mode == 0) {
switch (render_mode) {
case 0:
text_surface = TTF_RenderText_Solid(font, text, 0, textcol);
break;
case 1:
text_surface = TTF_RenderText_Blended(font, text, 0, textcol);
break;
case 2:
text_surface = TTF_RenderText_Shaded(font, text, 0, textcol, boardcol);
break;
case 3:
#if defined(HAVE_LCD)
text_surface = TTF_RenderText_LCD(font, text, 0, textcol, boardcol);
#else
text_surface = TTF_RenderText_Shaded(font, text, 0, textcol, boardcol);
#endif
break;
}
} else if (textengine_mode == 1) {
text_obj = TTF_CreateText(engine_surface, font, text, 0);
} else {
text_obj = TTF_CreateText(engine_renderer, font, text, 0);
}
if (text_surface) {
SDL_DestroySurface(text_surface);
text_surface = NULL;
}
if (text_obj) {
TTF_DestroyText(text_obj);
text_obj = NULL;
}
if (print_elapsed_ticks) {
START_MEASURE
}
if (textengine_mode == 0) {
switch (render_mode) {
case 0:
text_surface = TTF_RenderText_Solid(font, text, 0, textcol);
break;
case 1:
text_surface = TTF_RenderText_Blended(font, text, 0, textcol);
break;
case 2:
text_surface = TTF_RenderText_Shaded(font, text, 0, textcol, boardcol);
break;
case 3:
#if defined(HAVE_LCD)
text_surface = TTF_RenderText_LCD(font, text, 0, textcol, boardcol);
#else
text_surface = TTF_RenderText_Shaded(font, text, 0, textcol, boardcol);
#endif
break;
}
} else if (textengine_mode == 1) {
text_obj = TTF_CreateText(engine_surface, font, text, 0);
} else {
text_obj = TTF_CreateText(engine_renderer, font, text, 0);
}
if (print_elapsed_ticks) {
END_MEASURE
}
}
} else {
#if defined(HAVE_WRAP_ALIGN)
TTF_SetFontWrapAlignment(font, w_align);
#endif
while (count--) {
if (text_surface) {
SDL_DestroySurface(text_surface);
text_surface = NULL;
}
if (text_obj) {
TTF_DestroyText(text_obj);
text_obj = NULL;
}
if (print_elapsed_ticks) {
START_MEASURE
}
if (textengine_mode == 0) {
switch (render_mode) {
case 0:
text_surface = TTF_RenderText_Solid_Wrapped(font, text, 0, textcol, wrap_size);
break;
case 1:
text_surface = TTF_RenderText_Blended_Wrapped(font, text, 0, textcol, wrap_size);
break;
case 2:
text_surface = TTF_RenderText_Shaded_Wrapped(font, text, 0, textcol, boardcol, wrap_size);
break;
case 3:
#if defined(HAVE_LCD)
text_surface = TTF_RenderText_LCD_Wrapped(font, text, 0, textcol, boardcol, wrap_size);
#else
text_surface = TTF_RenderText_Shaded_Wrapped(font, text, 0, textcol, boardcol, wrap_size);
#endif
break;
}
} else if (textengine_mode == 1) {
text_obj = TTF_CreateText(engine_surface, font, text, 0);
TTF_SetTextWrapWidth(text_obj, wrap_size);
} else {
text_obj = TTF_CreateText(engine_renderer, font, text, 0);
TTF_SetTextWrapWidth(text_obj, wrap_size);
}
if (print_elapsed_ticks) {
END_MEASURE
}
}
}
if (print_elapsed_ticks) {
SDL_Log("Avg: %7lg ms Avg Perf: %7" SDL_PRIu64 " (min=%7" SDL_PRIu64 ")", (double)t_sum / (double)count_init, T_sum / count_init, T_min);
}
if (textengine_mode == 0) {
if (text_surface == NULL && render_mode == 1 && sdf == 1) {
// sometimes SDF has glyph not found ?? FT issue ?
SDL_Log("BLENDED/SDF not rendered--> %s", SDL_GetError());
goto next_loop;
} else if (text_surface == NULL && render_mode == 3) {
SDL_Log("LCD not rendered--> %s", SDL_GetError());
goto next_loop;
} else if (text_surface == NULL) {
goto finish;
}
} else {
if (text_obj == NULL) {
goto finish;
}
}
/* update_screen */
if (save_to_bmp) {
save_to_bmp = 0;
SDL_Log("Saving to %s", filename);
SDL_SaveBMP(text_surface, filename);
}
if (update_screen_mode == 1) {
/* No display */
} else if (update_screen_mode == 0) {
/* Normal texture */
if (background_color == 0) SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
if (background_color == 1) SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
if (background_color == 2) SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
if (background_color == 3) SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
if (background_color == 4) SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
if (background_color == 5) SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
SDL_RenderClear(renderer);
if (textengine_mode == 0) {
text_texture = SDL_CreateTextureFromSurface(renderer, text_surface);
if (text_texture == NULL) {
SDL_Log("Cannot create texture from surface(w=%d h=%d): %s", text_surface->w, text_surface->h, SDL_GetError());
} else {
SDL_Rect dstrect;
dstrect.x = windoww/2 - text_surface->w/2;
dstrect.y = windowh/2 - text_surface->h/2;
dstrect.w = text_surface->w;
dstrect.h = text_surface->h;
{
SDL_FRect d;
d.x = (float)dstrect.x;
d.y = (float)dstrect.y;
d.w = (float)dstrect.w;
d.h = (float)dstrect.h;
SDL_RenderTexture(renderer, text_texture, NULL, &d);
}
SDL_RenderPresent(renderer);
SDL_DestroyTexture(text_texture);
}
} else if (textengine_mode == 1) {
SDL_Surface *window_surface = SDL_GetWindowSurface(window);
int w, h;
int x, y;
TTF_GetTextSize(text_obj, &w, &h);
x = windoww/2 - w/2;
y = windowh/2 - h/2;
SDL_ClearSurface(window_surface, 0, 0, 0, 0);
TTF_DrawSurfaceText(text_obj, x, y, window_surface);
SDL_UpdateWindowSurface(window);
} else {
int w, h;
float x, y;
TTF_GetTextSize(text_obj, &w, &h);
x = windoww/2.0f - w/2.0f;
y = windowh/2.0f - h/2.0f;
TTF_DrawRendererText(text_obj, x, y);
SDL_RenderPresent(renderer);
}
}
if (text_surface) {
SDL_DestroySurface(text_surface);
text_surface = NULL;
}
if (text_obj) {
TTF_DestroyText(text_obj);
text_obj = NULL;
}
next_loop:
if (mode_random_test == 0) {
if (wait_for_input() > 0) {
break;
}
} else {
random_input();
}
}
finish:
SDL_Log("SDL_GetError: %s", SDL_GetError());
SDL_Log("cleanup");
if (font) {
TTF_CloseFont(font);
}
if (engine_surface) {
TTF_DestroySurfaceTextEngine(engine_surface);
}
if (engine_renderer) {
TTF_DestroyRendererTextEngine(engine_renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Log("SDL_GetError: %s", SDL_GetError());
TTF_Quit();
SDL_Quit();
SDL_Log("SDL_GetError: %s", SDL_GetError());
return 0;
}
/* random in [0; n - 1] */
static int rand_n(int n) {
return (rand() % n);
}
static void init_rand(void)
{
static int once = 0;
if (once == 0) {
once = 1;
/* Let's display the seed if we need to play the test again */
if (seed == 0) {
seed = time(NULL);
SDL_Log("seed %d", seed);
} else {
SDL_Log("re-use seed %d", seed);
}
srand(seed);
}
}
static void random_input(void)
{
SDL_Event event;
int r;
int r0, r1, r2, r3, r4, r5, r6, r7, r8, r9;
int r10, r11, r12, r13, r14, r15, r16, r17, r18, r19;
int r20;
init_rand();
while (SDL_PollEvent(&event) == 1) {
if (event.type == SDL_EVENT_KEY_DOWN) {
mode_random_test = 0;
SDL_Log("stop random test");
return;
}
}
random_cnt++;
font_style = 0;
r = rand();
r0 = !!(r & (1<<0));
r1 = !!(r & (1<<1));
r2 = !!(r & (1<<2));
r3 = !!(r & (1<<3));
r4 = !!(r & (1<<4));
r5 = !!(r & (1<<5));
r6 = !!(r & (1<<6));
r7 = !!(r & (1<<7));
r8 = !!(r & (1<<8));
r9 = !!(r & (1<<9));
r10 = !!(r & (1<<10));
r11 = !!(r & (1<<11));
r12 = !!(r & (1<<12));
r13 = !!(r & (1<<13));
r14 = !!(r & (1<<14));
r15 = !!(r & (1<<15));
r16 = !!(r & (1<<16));
r17 = !!(r & (1<<17));
r18 = !!(r & (1<<18));
r19 = !!(r & (1<<19));
r20 = !!(r & (1<<20));
if (r0) font_style |= TTF_STYLE_UNDERLINE;
if (r1) font_style |= TTF_STYLE_STRIKETHROUGH;
if (r2) font_style |= TTF_STYLE_BOLD;
if (r3) font_style |= TTF_STYLE_ITALIC;
kerning = r4;
wrap = r5;
/* wrap size: change less often, arbitrary distribution */
if (wrap) {
if (r6) {
wrap_size = rand_n(200);
} else if (r7) {
wrap_size = rand_n(400);
} else if (r8) {
wrap_size = rand_n(800);
} else {
wrap_size = rand_n(2000);
}
w_align = rand_n(3);
}
/* Current Outline: change less often, arbitrary distribution */
if (r9) {
outline = 0;
} else {
if (r10) {
outline = rand_n(10);
} else {
outline = rand_n(150);
}
}
/* Current Size: change less often, arbitrary distribution */
if (r11 && r12 && r13) {
if (r14) {
curr_size = rand_n(14);
} else {
if (r15) {
curr_size = rand_n(30);
} else if (r16) {
curr_size = rand_n(60);
} else {
curr_size = rand_n(200);
}
}
curr_size += 1; /* don't test size '0' */
}
/* Current Font: change less often */
if (r17 && r18 && r19) {
curr_font = rand_n(test_fonts_count);
}
sdf = r20;
/* using SDF is too slow */
if (g_force_no_SDF) {
sdf = 0;
} else if (sdf) {
/* also slow ? */
if (outline >= 4) {
outline = 4;
}
}
render_mode = rand_n(render_mode_count);
hinting = rand_n(hinting_count);
curr_str = rand_n(test_strings_count);
fg_alpha = rand_n(256);
SDL_Log("%6d] seed=%d; replay=1; font_style=%d; kerning=%d; sdf=%d; wrap=%d; wrap_size=%d; w_align=%d; outline=%d; curr_size=%d; render_mode=%d; curr_str=%d; curr_font=%d; hinting=%d; fg_alpha=%d; // %s %s",
random_cnt, seed,
font_style, kerning, sdf,
wrap, wrap_size, w_align,
outline, curr_size, render_mode, curr_str, curr_font, hinting,
fg_alpha,
hinting_desc[hinting],
render_mode_desc[render_mode]
);
return;
}