From 409f3ade88fd8f48d39541995ea288477a611c92 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 29 Jan 2025 04:05:33 -0800 Subject: [PATCH] Removed SDF test program There's a much better example of SDF support in testgputext in SDL_ttf --- test/CMakeLists.txt | 1 - test/testgles2_sdf.c | 785 ------------------------------ test/testgles2_sdf_img_normal.bmp | Bin 68122 -> 0 bytes test/testgles2_sdf_img_sdf.bmp | Bin 72202 -> 0 bytes 4 files changed, 786 deletions(-) delete mode 100644 test/testgles2_sdf.c delete mode 100644 test/testgles2_sdf_img_normal.bmp delete mode 100644 test/testgles2_sdf_img_sdf.bmp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b5de853813..3be04e215e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -355,7 +355,6 @@ elseif(IOS OR TVOS) target_link_libraries(testgles PRIVATE "${GLES_LIB}") endif() add_sdl_test_executable(testgles2 SOURCES testgles2.c) -add_sdl_test_executable(testgles2_sdf NEEDS_RESOURCES TESTUTILS SOURCES testgles2_sdf.c) add_sdl_test_executable(testhaptic SOURCES testhaptic.c) add_sdl_test_executable(testhotplug SOURCES testhotplug.c) add_sdl_test_executable(testpen SOURCES testpen.c) diff --git a/test/testgles2_sdf.c b/test/testgles2_sdf.c deleted file mode 100644 index d9acc64a56..0000000000 --- a/test/testgles2_sdf.c +++ /dev/null @@ -1,785 +0,0 @@ -/* - Copyright (C) 1997-2025 Sam Lantinga - - 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. -*/ - -#include -#include -#include "testutils.h" - -#ifdef SDL_PLATFORM_EMSCRIPTEN -#include -#endif - -#include - -#if defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_EMSCRIPTEN) || defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_LINUX) -#define HAVE_OPENGLES2 -#endif - -#ifdef HAVE_OPENGLES2 - -#include - -typedef struct GLES2_Context -{ -#define SDL_PROC(ret, func, params) ret (APIENTRY *func) params; -#include "../src/render/opengles2/SDL_gles2funcs.h" -#undef SDL_PROC -} GLES2_Context; - -static SDL_Surface *g_surf_sdf = NULL; -static GLenum g_texture; -static GLenum g_texture_type = GL_TEXTURE_2D; -static GLfloat g_verts[24]; -typedef enum -{ - GLES2_ATTRIBUTE_POSITION = 0, - GLES2_ATTRIBUTE_TEXCOORD = 1, - GLES2_ATTRIBUTE_ANGLE = 2, - GLES2_ATTRIBUTE_CENTER = 3, -} GLES2_Attribute; - -typedef enum -{ - GLES2_UNIFORM_PROJECTION, - GLES2_UNIFORM_TEXTURE, - GLES2_UNIFORM_COLOR, -} GLES2_Uniform; - -static GLint g_uniform_locations[16]; - -static SDLTest_CommonState *state; -static SDL_GLContext *context = NULL; -static int depth = 16; -static GLES2_Context ctx; - -static bool LoadContext(GLES2_Context *data) -{ -#ifdef SDL_VIDEO_DRIVER_UIKIT -#define __SDL_NOGETPROCADDR__ -#elif defined(SDL_VIDEO_DRIVER_ANDROID) -#define __SDL_NOGETPROCADDR__ -#endif - -#if defined __SDL_NOGETPROCADDR__ -#define SDL_PROC(ret, func, params) data->func = func; -#else -#define SDL_PROC(ret, func, params) \ - do { \ - data->func = (ret (APIENTRY *) params)SDL_GL_GetProcAddress(#func); \ - if (!data->func) { \ - return SDL_SetError("Couldn't load GLES2 function %s: %s", #func, SDL_GetError()); \ - } \ - } while (0); -#endif /* __SDL_NOGETPROCADDR__ */ - -#include "../src/render/opengles2/SDL_gles2funcs.h" -#undef SDL_PROC - return true; -} - -/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ -static void -quit(int rc) -{ - int i; - - if (context) { - for (i = 0; i < state->num_windows; i++) { - if (context[i]) { - SDL_GL_DestroyContext(context[i]); - } - } - - SDL_free(context); - } - - SDLTest_CommonQuit(state); - /* Let 'main()' return normally */ - if (rc != 0) { - exit(rc); - } -} - -#define GL_CHECK(x) \ - x; \ - { \ - GLenum glError = ctx.glGetError(); \ - if (glError != GL_NO_ERROR) { \ - SDL_Log("glGetError() = %i (0x%.8x) at line %i", glError, glError, __LINE__); \ - quit(1); \ - } \ - } - -/** - * Create shader, load in source, compile, dump debug as necessary. - * - * shader: Pointer to return created shader ID. - * source: Passed-in shader source code. - * shader_type: Passed to GL, e.g. GL_VERTEX_SHADER. - */ -static void process_shader(GLenum *shader, const char *source, GLenum shader_type) -{ - GLint status = GL_FALSE; - const char *shaders[1] = { NULL }; - char buffer[1024]; - GLsizei length; - - /* Create shader and load into GL. */ - *shader = GL_CHECK(ctx.glCreateShader(shader_type)); - - shaders[0] = source; - - GL_CHECK(ctx.glShaderSource(*shader, 1, shaders, NULL)); - - /* Clean up shader source. */ - shaders[0] = NULL; - - /* Try compiling the shader. */ - GL_CHECK(ctx.glCompileShader(*shader)); - GL_CHECK(ctx.glGetShaderiv(*shader, GL_COMPILE_STATUS, &status)); - - /* Dump debug info (source and log) if compilation failed. */ - if (status != GL_TRUE) { - ctx.glGetShaderInfoLog(*shader, sizeof(buffer), &length, &buffer[0]); - buffer[length] = '\0'; - SDL_Log("Shader compilation failed: %s", buffer); - quit(-1); - } -} - -/* Notes on a_angle: - * It is a vector containing sine and cosine for rotation matrix - * To get correct rotation for most cases when a_angle is disabled cosine - * value is decremented by 1.0 to get proper output with 0.0 which is default value - */ -static const char GLES2_VertexSrc_Default_[] = " \ - uniform mat4 u_projection; \ - attribute vec2 a_position; \ - attribute vec2 a_texCoord; \ - attribute vec2 a_angle; \ - attribute vec2 a_center; \ - varying vec2 v_texCoord; \ - \ - void main() \ - { \ - float s = a_angle[0]; \ - float c = a_angle[1] + 1.0; \ - mat2 rotationMatrix = mat2(c, -s, s, c); \ - vec2 position = rotationMatrix * (a_position - a_center) + a_center; \ - v_texCoord = a_texCoord; \ - gl_Position = u_projection * vec4(position, 0.0, 1.0);\ - gl_PointSize = 1.0; \ - } \ -"; - -static const char GLES2_FragmentSrc_TextureABGRSrc_[] = " \ - precision mediump float; \ - uniform sampler2D u_texture; \ - uniform vec4 u_color; \ - varying vec2 v_texCoord; \ - \ - void main() \ - { \ - gl_FragColor = texture2D(u_texture, v_texCoord); \ - gl_FragColor *= u_color; \ - } \ -"; - -/* RGB to ABGR conversion */ -static const char GLES2_FragmentSrc_TextureABGRSrc_SDF[] = " \ - #extension GL_OES_standard_derivatives : enable\n\ - \ - precision mediump float; \ - uniform sampler2D u_texture; \ - uniform vec4 u_color; \ - varying vec2 v_texCoord; \ - \ - void main() \ - { \ - vec4 abgr = texture2D(u_texture, v_texCoord); \ -\ - float sigDist = abgr.a; \ - \ - float w = fwidth( sigDist );\ - float alpha = clamp(smoothstep(0.5 - w, 0.5 + w, sigDist), 0.0, 1.0); \ -\ - gl_FragColor = vec4(abgr.rgb, abgr.a * alpha); \ - gl_FragColor.rgb *= gl_FragColor.a; \ - gl_FragColor *= u_color; \ - } \ -"; - -/* RGB to ABGR conversion DEBUG */ -static const char *GLES2_FragmentSrc_TextureABGRSrc_SDF_dbg = " \ - #extension GL_OES_standard_derivatives : enable\n\ - \ - precision mediump float; \ - uniform sampler2D u_texture; \ - uniform vec4 u_color; \ - varying vec2 v_texCoord; \ - \ - void main() \ - { \ - vec4 abgr = texture2D(u_texture, v_texCoord); \ -\ - float a = abgr.a; \ - gl_FragColor = vec4(a, a, a, 1.0); \ - } \ -"; - -static float g_val = 1.0f; -static int g_use_SDF = 1; -static int g_use_SDF_debug = 0; -static float g_angle = 0.0f; -static float matrix_mvp[4][4]; - -typedef struct shader_data -{ - GLint shader_program; - GLenum shader_frag, shader_vert; - - GLint attr_position; - GLint attr_color, attr_mvp; - -} shader_data; - -static void -Render(int width, int height, shader_data *data) -{ - float *verts = g_verts; - ctx.glViewport(0, 0, 640, 480); - - GL_CHECK(ctx.glClear(GL_COLOR_BUFFER_BIT)); - - GL_CHECK(ctx.glUniformMatrix4fv(g_uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (const float *)matrix_mvp)); - GL_CHECK(ctx.glUniform4f(g_uniform_locations[GLES2_UNIFORM_COLOR], 1.0f, 1.0f, 1.0f, 1.0f)); - - GL_CHECK(ctx.glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(verts + 16))); - GL_CHECK(ctx.glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(verts + 8))); - GL_CHECK(ctx.glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)verts)); - - GL_CHECK(ctx.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); -} - -static void renderCopy_angle(float degree_angle) -{ - const float radian_angle = (float)(3.141592 * degree_angle) / 180.0f; - const GLfloat s = (GLfloat)SDL_sin(radian_angle); - const GLfloat c = (GLfloat)SDL_cos(radian_angle) - 1.0f; - GLfloat *verts = g_verts + 16; - *(verts++) = s; - *(verts++) = c; - *(verts++) = s; - *(verts++) = c; - *(verts++) = s; - *(verts++) = c; - *(verts++) = s; - *(verts++) = c; -} - -static void renderCopy_position(SDL_Rect *srcrect, SDL_Rect *dstrect) -{ - GLfloat minx, miny, maxx, maxy; - GLfloat minu, maxu, minv, maxv; - GLfloat *verts = g_verts; - - minx = (GLfloat)dstrect->x; - miny = (GLfloat)dstrect->y; - maxx = (GLfloat)(dstrect->x + dstrect->w); - maxy = (GLfloat)(dstrect->y + dstrect->h); - - minu = (GLfloat)srcrect->x / (GLfloat)g_surf_sdf->w; - maxu = (GLfloat)(srcrect->x + srcrect->w) / (GLfloat)g_surf_sdf->w; - minv = (GLfloat)srcrect->y / (GLfloat)g_surf_sdf->h; - maxv = (GLfloat)(srcrect->y + srcrect->h) / (GLfloat)g_surf_sdf->h; - - *(verts++) = minx; - *(verts++) = miny; - *(verts++) = maxx; - *(verts++) = miny; - *(verts++) = minx; - *(verts++) = maxy; - *(verts++) = maxx; - *(verts++) = maxy; - - *(verts++) = minu; - *(verts++) = minv; - *(verts++) = maxu; - *(verts++) = minv; - *(verts++) = minu; - *(verts++) = maxv; - *(verts++) = maxu; - *(verts++) = maxv; -} - -static int done; -static Uint32 frames; -static shader_data *datas; - -static void loop(void) -{ - SDL_Event event; - int i; - - /* Check for events */ - ++frames; - while (SDL_PollEvent(&event) && !done) { - switch (event.type) { - case SDL_EVENT_KEY_DOWN: - { - const int sym = event.key.key; - - if (sym == SDLK_TAB) { - SDL_Log("Tab"); - } - - if (sym == SDLK_LEFT) { - g_val -= 0.05f; - } - if (sym == SDLK_RIGHT) { - g_val += 0.05f; - } - if (sym == SDLK_UP) { - g_angle -= 1.0f; - } - if (sym == SDLK_DOWN) { - g_angle += 1.0f; - } - - break; - } - - case SDL_EVENT_WINDOW_RESIZED: - for (i = 0; i < state->num_windows; ++i) { - if (event.window.windowID == SDL_GetWindowID(state->windows[i])) { - int w, h; - if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); - break; - } - /* Change view port to the new window dimensions */ - SDL_GetWindowSizeInPixels(state->windows[i], &w, &h); - ctx.glViewport(0, 0, w, h); - state->window_w = event.window.data1; - state->window_h = event.window.data2; - /* Update window content */ - Render(event.window.data1, event.window.data2, &datas[i]); - SDL_GL_SwapWindow(state->windows[i]); - break; - } - } - break; - - default: - break; - } - SDLTest_CommonEvent(state, &event, &done); - } - - matrix_mvp[3][0] = -1.0f; - matrix_mvp[3][3] = 1.0f; - - matrix_mvp[0][0] = 2.0f / 640.0f; - matrix_mvp[1][1] = -2.0f / 480.0f; - matrix_mvp[3][1] = 1.0f; - - renderCopy_angle(g_angle); - - { - int w, h; - SDL_Rect rs, rd; - - SDL_GetWindowSizeInPixels(state->windows[0], &w, &h); - - rs.x = 0; - rs.y = 0; - rs.w = g_surf_sdf->w; - rs.h = g_surf_sdf->h; - rd.w = (int)((float)g_surf_sdf->w * g_val); - rd.h = (int)((float)g_surf_sdf->h * g_val); - rd.x = (w - rd.w) / 2; - rd.y = (h - rd.h) / 2; - renderCopy_position(&rs, &rd); - } - - if (!done) { - for (i = 0; i < state->num_windows; ++i) { - if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); - - /* Continue for next window */ - continue; - } - Render(state->window_w, state->window_h, &datas[i]); - SDL_GL_SwapWindow(state->windows[i]); - } - } -#ifdef SDL_PLATFORM_EMSCRIPTEN - else { - emscripten_cancel_main_loop(); - } -#endif -} - -int main(int argc, char *argv[]) -{ - int fsaa, accel; - int value; - int i; - const SDL_DisplayMode *mode; - Uint64 then, now; - shader_data *data; - char *path = NULL; - - /* Initialize parameters */ - fsaa = 0; - accel = 0; - - /* Initialize test framework */ - state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); - if (!state) { - return 1; - } - for (i = 1; i < argc;) { - int consumed; - - consumed = SDLTest_CommonArg(state, i); - if (consumed == 0) { - if (SDL_strcasecmp(argv[i], "--fsaa") == 0) { - ++fsaa; - consumed = 1; - } else if (SDL_strcasecmp(argv[i], "--accel") == 0) { - ++accel; - consumed = 1; - } else if (SDL_strcasecmp(argv[i], "--zdepth") == 0) { - i++; - if (!argv[i]) { - consumed = -1; - } else { - char *endptr = NULL; - depth = (int)SDL_strtol(argv[i], &endptr, 0); - if (endptr != argv[i] && *endptr == '\0') { - consumed = 1; - } else { - consumed = -1; - } - } - } else { - consumed = -1; - } - } - if (consumed < 0) { - static const char *options[] = { "[--fsaa]", "[--accel]", "[--zdepth %d]", NULL }; - SDLTest_CommonLogUsage(state, argv[0], options); - quit(1); - } - i += consumed; - } - - /* Set OpenGL parameters */ - state->window_flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - state->gl_red_size = 5; - state->gl_green_size = 5; - state->gl_blue_size = 5; - state->gl_depth_size = depth; - state->gl_major_version = 2; - state->gl_minor_version = 0; - state->gl_profile_mask = SDL_GL_CONTEXT_PROFILE_ES; - - if (fsaa) { - state->gl_multisamplebuffers = 1; - state->gl_multisamplesamples = fsaa; - } - if (accel) { - state->gl_accelerated = 1; - } - if (!SDLTest_CommonInit(state)) { - quit(2); - return 0; - } - - context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context)); - if (!context) { - SDL_Log("Out of memory!"); - quit(2); - } - - /* Create OpenGL ES contexts */ - for (i = 0; i < state->num_windows; i++) { - context[i] = SDL_GL_CreateContext(state->windows[i]); - if (!context[i]) { - SDL_Log("SDL_GL_CreateContext(): %s", SDL_GetError()); - quit(2); - } - } - - /* Important: call this *after* creating the context */ - if (!LoadContext(&ctx)) { - SDL_Log("Could not load GLES2 functions"); - quit(2); - return 0; - } - - SDL_memset(matrix_mvp, 0, sizeof(matrix_mvp)); - - { - SDL_Surface *tmp; - char *f; - g_use_SDF = 1; - g_use_SDF_debug = 0; - - if (g_use_SDF) { - f = "testgles2_sdf_img_sdf.bmp"; - } else { - f = "testgles2_sdf_img_normal.bmp"; - } - - SDL_Log("SDF is %s", g_use_SDF ? "enabled" : "disabled"); - - /* Load SDF BMP image */ -#if 1 - path = GetNearbyFilename(f); - - if (!path) { - path = SDL_strdup(f); - } - - if (!path) { - SDL_Log("out of memory"); - exit(-1); - } - - tmp = SDL_LoadBMP(path); - if (!tmp) { - SDL_Log("missing image file: %s", path); - exit(-1); - } else { - SDL_Log("Load image file: %s", path); - } - - SDL_free(path); -#else - /* Generate SDF image using SDL_ttf */ - -#include "SDL_ttf.h" - char *font_file = "./font/DroidSansFallback.ttf"; - char *str = "Abcde"; - SDL_Color color = { 0, 0, 0, 255 }; - - TTF_Init(); - TTF_Font *font = TTF_OpenFont(font_file, 72); - - if (font == NULL) { - SDL_Log("Cannot open font %s", font_file); - } - - TTF_SetFontSDF(font, g_use_SDF); - SDL_Surface *tmp = TTF_RenderUTF8_Blended(font, str, color); - - SDL_Log("err: %s", SDL_GetError()); - if (tmp == NULL) { - SDL_Log("can't render text"); - return -1; - } - - SDL_SaveBMP(tmp, f); - - TTF_CloseFont(font); - TTF_Quit(); -#endif - g_surf_sdf = SDL_ConvertSurface(tmp, SDL_PIXELFORMAT_ABGR8888); - - SDL_SetSurfaceBlendMode(g_surf_sdf, SDL_BLENDMODE_BLEND); - } - - SDL_GL_SetSwapInterval(state->render_vsync); - - mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); - if (mode) { - SDL_Log("Screen bpp: %d", SDL_BITSPERPIXEL(mode->format)); - SDL_Log("%s", ""); - } - SDL_Log("Vendor : %s", ctx.glGetString(GL_VENDOR)); - SDL_Log("Renderer : %s", ctx.glGetString(GL_RENDERER)); - SDL_Log("Version : %s", ctx.glGetString(GL_VERSION)); - SDL_Log("Extensions : %s", ctx.glGetString(GL_EXTENSIONS)); - SDL_Log("%s", ""); - - if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value)) { - SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d", 5, value); - } else { - SDL_Log("Failed to get SDL_GL_RED_SIZE: %s", - SDL_GetError()); - } - if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value)) { - SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d", 5, value); - } else { - SDL_Log("Failed to get SDL_GL_GREEN_SIZE: %s", - SDL_GetError()); - } - if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value)) { - SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d", 5, value); - } else { - SDL_Log("Failed to get SDL_GL_BLUE_SIZE: %s", - SDL_GetError()); - } - if (SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value)) { - SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d", depth, value); - } else { - SDL_Log("Failed to get SDL_GL_DEPTH_SIZE: %s", - SDL_GetError()); - } - if (fsaa) { - if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value)) { - SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d", value); - } else { - SDL_Log("Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s", - SDL_GetError()); - } - if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value)) { - SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d", fsaa, - value); - } else { - SDL_Log("Failed to get SDL_GL_MULTISAMPLESAMPLES: %s", - SDL_GetError()); - } - } - if (accel) { - if (SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value)) { - SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d", value); - } else { - SDL_Log("Failed to get SDL_GL_ACCELERATED_VISUAL: %s", - SDL_GetError()); - } - } - - datas = (shader_data *)SDL_calloc(state->num_windows, sizeof(shader_data)); - - /* Set rendering settings for each context */ - for (i = 0; i < state->num_windows; ++i) { - - int w, h; - if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); - - /* Continue for next window */ - continue; - } - - { - int format = GL_RGBA; - int type = GL_UNSIGNED_BYTE; - - GL_CHECK(ctx.glGenTextures(1, &g_texture)); - - ctx.glActiveTexture(GL_TEXTURE0); - ctx.glPixelStorei(GL_PACK_ALIGNMENT, 1); - ctx.glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - ctx.glBindTexture(g_texture_type, g_texture); - - ctx.glTexParameteri(g_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - ctx.glTexParameteri(g_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - ctx.glTexParameteri(g_texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - ctx.glTexParameteri(g_texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - GL_CHECK(ctx.glTexImage2D(g_texture_type, 0, format, g_surf_sdf->w, g_surf_sdf->h, 0, format, type, NULL)); - GL_CHECK(ctx.glTexSubImage2D(g_texture_type, 0, 0 /* xoffset */, 0 /* yoffset */, g_surf_sdf->w, g_surf_sdf->h, format, type, g_surf_sdf->pixels)); - } - - SDL_GetWindowSizeInPixels(state->windows[i], &w, &h); - ctx.glViewport(0, 0, w, h); - - data = &datas[i]; - - /* Shader Initialization */ - process_shader(&data->shader_vert, GLES2_VertexSrc_Default_, GL_VERTEX_SHADER); - - if (g_use_SDF) { - if (g_use_SDF_debug == 0) { - process_shader(&data->shader_frag, GLES2_FragmentSrc_TextureABGRSrc_SDF, GL_FRAGMENT_SHADER); - } else { - process_shader(&data->shader_frag, GLES2_FragmentSrc_TextureABGRSrc_SDF_dbg, GL_FRAGMENT_SHADER); - } - } else { - process_shader(&data->shader_frag, GLES2_FragmentSrc_TextureABGRSrc_, GL_FRAGMENT_SHADER); - } - - /* Create shader_program (ready to attach shaders) */ - data->shader_program = GL_CHECK(ctx.glCreateProgram()); - - /* Attach shaders and link shader_program */ - GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_vert)); - GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_frag)); - GL_CHECK(ctx.glLinkProgram(data->shader_program)); - - ctx.glBindAttribLocation(data->shader_program, GLES2_ATTRIBUTE_POSITION, "a_position"); - ctx.glBindAttribLocation(data->shader_program, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord"); - ctx.glBindAttribLocation(data->shader_program, GLES2_ATTRIBUTE_ANGLE, "a_angle"); - ctx.glBindAttribLocation(data->shader_program, GLES2_ATTRIBUTE_CENTER, "a_center"); - - /* Predetermine locations of uniform variables */ - g_uniform_locations[GLES2_UNIFORM_PROJECTION] = ctx.glGetUniformLocation(data->shader_program, "u_projection"); - g_uniform_locations[GLES2_UNIFORM_TEXTURE] = ctx.glGetUniformLocation(data->shader_program, "u_texture"); - g_uniform_locations[GLES2_UNIFORM_COLOR] = ctx.glGetUniformLocation(data->shader_program, "u_color"); - - GL_CHECK(ctx.glUseProgram(data->shader_program)); - - ctx.glEnableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_ANGLE); - ctx.glDisableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_CENTER); - ctx.glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); - ctx.glEnableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_TEXCOORD); - - ctx.glUniform1i(g_uniform_locations[GLES2_UNIFORM_TEXTURE], 0); /* always texture unit 0. */ - ctx.glActiveTexture(GL_TEXTURE0); - ctx.glBindTexture(g_texture_type, g_texture); - GL_CHECK(ctx.glClearColor(1, 1, 1, 1)); - - /* SDL_BLENDMODE_BLEND */ - GL_CHECK(ctx.glEnable(GL_BLEND)); - ctx.glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - ctx.glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - } - - /* Main render loop */ - frames = 0; - then = SDL_GetTicks(); - done = 0; - -#ifdef SDL_PLATFORM_EMSCRIPTEN - emscripten_set_main_loop(loop, 0, 1); -#else - while (!done) { - loop(); - } -#endif - - /* Print out some timing information */ - now = SDL_GetTicks(); - if (now > then) { - SDL_Log("%2.2f frames per second", - ((double)frames * 1000) / (now - then)); - } -#ifndef SDL_PLATFORM_ANDROID - quit(0); -#endif - return 0; -} - -#else /* HAVE_OPENGLES2 */ - -int main(int argc, char *argv[]) -{ - SDL_Log("No OpenGL ES support on this system"); - return 1; -} - -#endif /* HAVE_OPENGLES2 */ diff --git a/test/testgles2_sdf_img_normal.bmp b/test/testgles2_sdf_img_normal.bmp deleted file mode 100644 index 1209e1b1df7105dad9e3e401b9dd9a0d255e4162..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68122 zcmZ?rmEvM#0D&q728J9428I(13=E+R3=E763JlB)3=9i6A@U$K2>hRc0fIn6{}u8w z!$FKuJQ@O{Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*O zqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0;3@?8Umvs zFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiTtLqL#$fx(M`fuWFrfuWs&fng#8 z14AbR14A(b1A`|60|VaxhJXqK14A$a149YaZ4($67`hl37-|?87_t}`7~B{b802W= zJ}w3Z24@BahCBuah7P1~DPv$@@MmCP5T}v79oDK6@`RfOjE+b|RwS*9;5{Eci6iNRF3*f#Ew2H?6>9=LIx9=WwWH zVqjp1WME)8$iTqx7fsK9H2!Y}28Qj>yn@3xstTJiFfdGKU|@KG<_>gsA@iRxFfc4) zU|T(e1H)+s28L7y1_n^tM7LH6hkkT*l<+wi7#QLi z7#MaC;a=qM`ozG%u$h5@A(w%H0pw0XZUB`}$oi4lpt6;aern5u{EX}dWHvtcpyv;e zJ{dH}88a|2U{eQDO9<~}U|>){Gmlza0|o|${W#JTA$K9mKWAWIa3I4`k_-$C8_Bf) z4zw;qw$=}aS;%V0WrMbx=aX25Acqk$8xQxb@?lX}TN0C_0!0bh)KQJ&bxFDHHDHBxJgW3asaHJ<>yNP9|kmx8Y z1_lODTY*^fv8e;4Gmt-ER)g9!*wn$~$)!~p7#Kk90&HeeDh4W}aJg$2j`;b^z`y`% zi{jEpZE-OM1_n@@2Af}d30Q_Le{6&52_vE{h0RWEVn3 zGcYiGqoNx?eK=5%FU4UdNRC_#>JNRyVJ@*@gHIj4{1Jo4UQpdbuAfNN2Rgb1mml;A z7=|r>fZEZZV_?4G@ZW6)1_n?a3Ceq*@^2~w1H(={c@*ZhFANL}dIa1(>zOmD#DXc~wg#gUFdX`hgFAT`MD#>WQb2~9i(g2rb+<5-~Z#%0bG1_lOD9}$l+ zIHf9Z_!DLq$lm1)3=G~l`rM#)nIZ!NLl88*g8Jw%y~N}XP~CNwfE(s8Ffb_N^Z^5d z0Ce2%J(@Y7wmQiDF!vzSc#Oj-1&Sv^^#-W@6U)HBAd1rz1_n@H6f`DT&A`BL3`=_g zU;Y3Y3mOAK_6v*+YEOX1K|yM0i9vl|T;W{z;R9-C z!_*Q>YcMb{fWj1{9~%bM6{PmDLHPyLF9MZipfOHDZUK!CW3wA125R4e>Rdu*z~n(` z5>&5&^b*1_J;c(4^6_Kn_&l-ZA*%zqJDq`n0aVU`+)XHdfa)-iI&7GjG6~ska@e4> zhRtqJ-xXAz6Ec%f{s5J0p!8129CZ04wDJ+zji7Rk)H#w(c+3OU1M=t&AdwHsEBLgq zF)%QI>_PSiG8;7Kflog+InbE=89e@inU75`J~7a|6ihEV4Jt=KWhy@X#L9vCHlT4T zeCk2-0#9)G5j3`mPcJp(F5$3yE0Km1${$mRGzXh9P`QjAKQKNi=}CuyfdN+?2`UFb zR>pt=X$Ok_SO#)I1YuW+OZP@hbl6vL>b7BoML>>n5# zRQ5_y$qsDBXyXV6kp0At58%rmptL88&0-?OOz^l5)Q%_87zWTBILJ@fFsKhqtT~jZ z1C=+}><5W~+Gv!RJp)fTfy^hxY|z{zNDnp)8cQL?ENZC*m2cSG0}=z(b=0y4-5k(5 z0FWK%7&N{@Y#$h3{@8cgc~H9tSGxvO{($S#$j;c)|~Zllz0P#FN~GlRk$8z$C#5iH|N zF!SaUYY2_hfyRnpZb7F(Yv!nJttFl~vmwDUeE9=Zu909AR;8f!HF|i!_{8L6d}BtS z^%7VurLrLCdH|T4(P?tVF0eUoJ)Zc)rXHIZs7;OTJ{aEzn+7_HNiZ-lfZFRY_aM`> zX!lLV5uSHR^fSKv!B3)D*p!3HMqFdPpz(BUdXUBNwaw|#F9*2=H1C5PpU7-#weLXl zh{)z5vq5ek2IJ}ngUli{&P0s)l&ZnC2I@Mc2BYZ*t)~LbcY^$lj_c9X65`^@AMXfh zBtafFR*vr0w?vo$YD1yx1MxxQS@c@N1DXp5*@=!p^FpBfPlPuJDv8EX-hu2Ss2QpN zSNa2`6{wN{rSSRDkcut??O_0g8#)H18DiERBRd6G{s5(EWObCV@wFW|2^b7o=Zfx6 z5Fga{BA}IO(hqT@U229AsQm--7dA|+M?mE;HvOPA^~9P%OLd^~4A&YTP+0>SSE2^S z)m}MFhUakQ574+18OCANg0GE4Xs;4z+yz^lgVt4HwTuRWpt!^426Dn1m-9et9$(gUml|Mk^{kZ%{syJvJBQF1f#;5R^ z2dWdX>D`S_6BXq^?I&#ZgTz276a8O z%NhkK{OLr{s8S4CE5@I3PEc>(cKH zGM8H7q~;HN>!LvGH9=)FIT*B-0h^x)?V-gNzPR!SY!4wmy~N7(;VBzIYjg0KgKJGY zHT%Z+><7u=T0aQd`wo()1_rIo#}>CBF=EXJwXs3!>5W0-X2iM?rViJBU(o&;m>N=P zT;uRPq#A^z9#{SVt>ZybMiFx+p8O$Az~rYm^n%WhA)u9N(l2qiftqWF0&&;@O6$aW z1lKq;$P8Ly(7r=r-3U`xfWyC_c{g&-lL4(!!R1HL8V;Dfq|&(Z2RUT|F1xqj2n&#Z zK>I3i=>v&_>RXUHbPU@23mRJjsi8Fn#Xq|JAU-wc-O})c5wZRQjd_FIg^odC2s+1z zQVjAhy4fH;IpqXsZxXJ088jC}te;`(K=a}tx1eKC`i7|?hX(0KHxtAM%{!1|9yUFo z_9@6rbPQ@2VpESS1{!xj*9YShv;G&^EOObPeg@1=bee};L(%lLQXzjV#9;<#KRKFp zWN~rj574|lIR=8-@aW+Q;)B-nkZK<2d;ySNbWG{`d0hDeWDjUf8L93>R}bpn;_5>X zv#+QYN1TJ)2Rbhb-9B3I`|-GeTI(V}b&>TBxTpf>A6e-a8fY{6d)lZ;$3PmxA9DMl$w2p;D<1m!t8bPPHpmXLm!{3IOZ7pUHcsUerfmp?#jO35`Brmq2q+d<(0 zT8|A=hl>X7>G_4j3{ZU!8rQ_7ms;X#IP3@c0o1pm)E>~8K_IhmVPee(oy&kLy&<3Z zN340s>Ok`cxZDRig8^ABDQr;PgUwuG=eI!Z6I|mbp!3^EaSJxJ`0@v6Z#ygxW?!~ZD&v!MuJf&N*!^OJ)pK6F?~B+`4+Smjg&STildM?`0@uRZb0W~A}J?{ z2|9-gWCk`2I=_`z!|<((2CeTUXFQNtyJ6};Z9#1Q0EvOdPGIUtr9taLaE)Pu%m!gn z%*4083ABcV6tiGzLG==7ECu8ibWCpF9A-9X3=&t_13D7}rVbaq1V{cNX73#?Gm*s! zw6FuO=K7uVbyXik-!xCD&>!Q6sQN090`Eb4KcqX0V735#;L5UAb)oym#rCJ>(* zdtX5o5y~GRyFh1zfbuy=J+T-x4+_$Y4L`zhz9BxdvvHIYF!MoWIH_&~*#|ni7(^3; zLG$G>`_O67UPw?rCdM3?8qnThTx)KT&4;Ncmd00a!_N98)+|t+0~$|4b`OmGfJ%3H zfX;e^nTbq;+HRopCULnHSGxk#rog3#RB>YR2guE!wW@^Xx)(|fvke1^>3Q5GE zei&$;3*;7D7}Ullv|a^dEoh$(=)M||pFm@P<{&{LFi0IPyFuchJu}4Yw*`d}Xv~hp|xd9snolS~iF_{9m;uhZ-9=Q6Ypt6!oXJBZ< zl|Mk|6r+a;XwDE6wxBZ!K;z1wGz&5ibdIVi^bRRpXYs(y0_~X~r<@1b0~$vH^}AqZ z;i5rf0-$ya=nO}YTS4&*Dr-P-x(Zz5bRaWG#h|lH@U=-n@dO%M1nn;Xo#O~HALLF@{sx`9 z4jPw3_Zu>w(tZcXK4c6!FA&*$7#kE{$m(EhP`wW-+hFQoG^or0ov{p4M=6afe}LA< zfZA0sd$G}=^QTBz69;Nnfzk;jZU&vjMv9%-+>I^(I>w@j-3{ z#Tkf=3xm$q0*!;u5;IviasC45}@12k_9N;9B2ZdkZbLWAZiv?y^Xl3vhxRG>6XiF?rXl5(~* zsO-8%pbd#`J}y3}jSXt+fxHJQZ?LHY$&rge`3_$j37dWR#6WctzVqqHbtgz4t~v|b z+zqa^y5#Jk1=)=Y<+ps^TSdO-4&U{Jdhv<3^8`NWE!WME(*rVmQ4TS4>1*xUjd zcSAN4bQU=_b)Y(s)N{{~&BeyXl|Mk|Yr)im#sooQe4zdZHh19?1C@=SJ5fPx5|~-k zq(S`{Q2z}yUV+OE#E66P89DQepl|`**-K2H2-zK=b_{3@9&%d~#70(w%%(<|fyUNA zXZ@4vR**YDeJaoz5>Wqy8g9X5253GHoBKfF1XZJ@S1 zNG)i*jTAd5Q430UAp6lVD6U}Ug6b1=c@Q5omkv`yEgDz;0F`g}>;R3;fX*=m?I{4= zEd#0>L2U(4IfzdmJ>)?BIncUD(4HgESPW=9Ie>wI0n~2+l|!Id6lQP?|)JZ)7(4rVc%wpt1`zK8Ean7#r000hPxv zJ~BjZH}DwVQf%40N4Bzp>xy_rjy3Pl|Mk| zN04UHsA@_=U^IUqLJxGu6)aC6)1dv4*!sSpu{nfp>as@j2X(`fT+>GL2WrTH_Ov7C z4GhRc0fIn6{}u8w z!$FKuJQ@O{Aut*OgFFO41sW3r0|N*THm4%H4aBCW`#|=A!UTlrX)n2UA-fmkW)PoT zvxwCPsuH;w7#R2&7#IZbU_J&022NrPrBEHn-&{nv3FKywI*@u02C+e6*!%%-@(c_N(opw<)bcPeFo5);d6i@?D6T>N1^FA~e^5Ap>_ZM0PB+zT>Ol!1Xkih+Sa4lN!*?gqIZB#s+|#!#IC#UUt-XfiM`fb1mXCXhOidQdol*tqn7 z#MK!X7(i(Ql(#_P4oV{+J%$Vn3>FLw3^oi53=Rwo42}#83{FrC;)BG^pq%>Si%M5CQ!J6>;%ic!NLXP7LYj1UQikWvXJK0xjT#eE0^149%80|O{rKyHM&7es^j zAaPiDfx^~@fq}u5fq?;J2FUH8v<)g}LGb~~ujqE8^Fiqr{0Z`JDb##WIKaXMWOoD9 zO(1(gaRdrSP@V_nX)gu_22j}IOIM)u29gJbB`6(&(jzEcg3>3ha0J!0pfVR!cY^!` z@*5}~L1uv53yR|s1_p*o1_lODxPaUUaw`mj_#koQ@XCg!3y^z*85kHqZUNWf!sH zpmr~)TmY35pz@=bfq|ig2seS;3{nSDUj%g@$ek0g_@f7!KS1#aDr-Su4;o@^h1xTf zfq`K*0|Uc+1_p+O3=9m5pfrdN5(mkH%m#%)1p@;EC>}uJ080O$x&Rc%pfZhEKZD9* zP#FuVk3sPVO2;7cK=}cbhCy-P$-uxck%56>Is*g495lDV+&2&E?rBgzgYIRAz(17L-OnX%QbRlNlHoW->4^%w=F;SOASjkb6NG#77P0P5{LfsQn14OERJ5D#%<=ngE6M3aJ0L zF)%RfL310-efyy92B}%kz`y{~0}2z68$sa$s#ieu7N`sXrCCrt2pVGmxlR5pOp5UB49 zYX8IhPbv+nOF`{mP??hqtwTU*2^1!$@wf-%R**bM9Y{T>Jlf8{zyJ~h$)V#D3=9mQ zum+V~pz?k>0|NsnEr8O<8R#_NZ3YI0`wR>W4;dI39zkgk{}uxS!(|2r22dD)($OXc z1_n_20i}CTTLM()fzkuW51=v@lvY9M09#mq$~jOu3+l&%>LgG&g6daLJc8;#khvS7 z>ESp71H*X+28L@43=HUQgSqb>0|NudeOIAsL3%)G29yt0LhBY#ngi7rpt>Ja=7Pc- zv1E8`2WCqA@FBupZKH$NR85kIjLCZf-9R+Id zfYJlVJkXdN$p7SEQ2h=nGeK?w#VaVBKxGCf{XfOy9*|o>@*s7fFa^aUC@np~p$8O} zpg0G`Gbp_rW?*2r2+cpQ7#J8nGcYjxVgS#YgJ#ZA@J|K?hEEI(44^Oq#Rn)JKxG{$ z>_Fv92Ll5GC{KX;51{@ZDE>iZDtdT;(g~=X1C2L;+7qBQKd3AOwW~mN3Me0e%smIq zBOw31V_;zT%D}+z8;9HeLEZg@fq?;}_8BxSfzlNyzCh^&@kpKT-^_|Cw<@CS=~L4NoP4KGlbzK8k|ls2w2Fff411yK14%AcU}7F17z@-C>% z1NGHF(jTsHN7oPIgVGQvtUzTm$Zn8ZL3sg`UO{;Z6z`z26jaWF+WfF^0M+53aa~Zo z1PXspxmU};z%Yq{fdLeEpf(7|U7&OfGXDpT^Z;`QJ{pwwKsJt^m0cNAjkKxH?`eq4D7m%X5L3Q8lObPdW!Apd}t{($luHa#Hs zfzlJG%?0XTf$|Edi~)^{fWi$_9)ZdwP`(G1Qy{m3$}Lbk1f&O49)ipV`4MCm$bM}0 z5Gw}CUm$;j+z%>?K=}%kXF=sVs2l>t8OUwObqA!pn4Wmc7e)mP#y)9 zb-3&Yg)b-#f$DHj_=Eb(pnfMP--5B!=Um9R91ufz@TF z1NhQ9x_b!aCs4eC>UdBbg35i6eq4SfMjRCWpf&`kECRJNL3s)k-=K5>YL|f8`k;0l zEL=e2QlPP2P`@AKS5UbJDwjZQeo&nRN*kc^fs%ZL?ru={f$}G)T?MK~L3V=bBv3yU zRGxy|3vxFozk%{Hs67Yr7rHs5@ImFxb7=b*ls9pOGbj&$;sTU6u;nLEIt7(WpnMOi zLqX*g$gQCA3si1`(g!I2lHxXE)PlkcRL+9Rb5I!rYJ-Euhd_NyP@4~V%n8)b1NHYn z{s4fKMTaZ1V zJ}#*J02*%vtvvymPb>ztk3sDpP`H80Oi(`p)FuJ>0aR8K%G;p$KMHLtfyypW+63i8 zP(0!aPf#AER$hYH0m@S#w}9*hm9?O70o4Pbd;_YxLG>?aEDzMC1*H#ASqo}IEQ5~M zf!gh$vH@luHEC@53FIzNISO(o$i1NcIH;Zl`GcBvgUkZ;XFxPI3`$F&@(|<(^!f>u zK0)OXs9XZ&dr&zAN*AEK1S-Ek?OAMQQcH}K`~+(Af#!`sE1k#HQgX%(%ouK#vlLomPls-V_ zBb$Mb4T@t>JqB_osGbF35F6A^1dTmnOJ~^f6KH(^Xs!j+b^^HtswJ3 z=>+6v7zVXnK;Z?7Q;=D>;uRFuq~s^$F=|jB2vlBy`b40<5vZ?@&&{B41;qoX-3=P2 z2lWL&eMV4w29!^U$xEPl1#JB|P+A1}12lGk%MG9~0Ht+M*$Ns<0gb5;TR)+j397F^ z{sq|y%EzFwUeH(w2!qB5K;vDYwkJppD2~weqw_)e5fp}?umq(AP+b7(8-mu~fa)gD z922Mx2AK~U+X2NXx*6zv(D(qzeo%c38pj6ZLy)^b7{msZE1>uQ_5DHigVGDgUm$Zp zX&hAlAdg4D;u_Re2DS4*;R#ZU3xoU(vLDpH29=|r_5;ZMAPkBFkUK!-Fepwy=@gea z=;EOCjx9fd${$cU1S*d}rFboSXkb6Pl z2`Upn>Ot-Xg%!*^Qu7mN%n39m2dY;=ZU>Fkf#yU(;SP!yP#D6@MyEmcg8KEK^ae^B zp!N%>-3V$wg4&Uwb{wHR1zMv7>Yw8pXGFIXnGdQ3P<(>MzCdXY)ZRsQ3pyJVFQEJfYA3+l1{(JP^<_cp z%0Ocfpt=c^2S9ZTx_)#%sO$pe2T(c&twjL!H9&3xwJAXu#0JfGfZ7%yc~E%(%5$JN z1l4^Y_uPc8p8%yzP*{P=Ku}o-N~54OjczA0ALL(99tHUy6h@#n2`J7%;RC`THmK|X znFq?BAiIc3_aHk!c4Ny=pz;S)4uQ%eklCR5C6F6HdhlUTSb^#=P<(>=BcQo^P@ICo z35G%81!@C<0}z5yDm1C7~%)>z`hpm{pbSP7_J2ldZE{ZUvt1J%*^!VOfO zpxaGOegc)bps)vpEvPI3wKqZa2dHcTm5rdjAt+8k=?0WuKyxY}yYaaVRMvy?D5%^9 zvpPFM;w1C~QD(gtcu!<6R&O@;4~_L1Vh0 zek5p&0~Cj#ISo)4fy!u5ItS%BP+kU=eV{x5N=Kmd11cNwxdD{EK=~8oe^5Ap>;jnq z@(T!q*r56jRCa*!8pz+Eyo|4X0kaQRegc(0pnQ)!HU%mdVEVApAp1ad5-6-dWe%uJ z1kFW&;tv!~FboSXP+AAIc|lYBF9Y?HLE|VOJ3(z#Q1}xn576rf(AXSkj1JUK0GUY)2CZcVt&alDX@bg5PjI@CY+(ix1C^JcG6>Yx0M#F$_yoBf6i%SB2b6|DX#k`aABMRfWG5({fZB|pFawQ? zfcn88cY*3{P`?foE+D%=X%v(XKUQ0b$VkFi`&)WH%`Ng8U3B??G+{ z`2iosm7hT652zdhl}Dib2};}e#x+24ptb|3oee5CKw$+M+X96Ns4oKwCm05W7s$P! zwgM>6g3=EtOh9@->x@A82UNF#+O(iN1`0=zTR{3jduKpvmqBeSP<@1sLF@KGFd{WSf%?#(cn75|P?-x#C!leEP@5H$&q4EZpmsc{UkIwZ zL1h#uu0Zt}sBQ+i1s4XDm7w-0sLcn8Cy*OK=7Y=t#TTf&CshA~+Abh7K=~b1r-9-f zl1H~n%Ed&Y^Q2PW_?tt2Q zAR6R$P~HUD4=SHP>TzLE`x4|IPdt3mAyQ27H2J5ur! zs5}F;bwKqyDBM8d4+>XMUIO*$KyyW)c`;BO3mQiNr4>+l2P&gMdO&?xkQun#2x>!t z>QGR*4r-%;+C`xH8x%jFz8Il87-TM}?*r;XgYr9Q3>6f%pgaSLQ&1TRn$rSdkb6O6 z@t`p=P`LzcdJCiv6h@%B7BnXYN^hX{CaB)Q*GC4q0W@|8svkh*B`B?d z!T}T>p!I5?@Bv{^9~`vy8nku*IsJg*lF&Q=w)_NgJE;5tl|!KX0V-2KZ3&QjaA8ne z3e=_o)%~C}0rEG7KLeEwps{IC-U8J@pfUs0-UpQpp!y3Gb|5)W z*$N7GMl^6fWir69w^+9>se4egv%eGb`L0RfYJ!4Eea}A$ibj84HUXY6pSJCQz7x!WT3r4Vq^LjX#3Y3n)%N zav(JzwV*K&&{!bI@3_JRBo2yWP<;yuOHkbnax17!4{E1^@-n{s2y4@V+8rQ0ptuF) zcTn7e=IcQ1bkKMb2!qCcKyeHz7eQ?eP#FN4TL+a5pn3~b-h;|$P&k3i0hJ%1HU+2+ z1#%}Y3<_&de1PglP~3v@BB);jYR`kp8(0|)>LY{F87%$4+8Utr4J!L^nGX`jmY+a% zET}F8#V@El0`(t3;Q>;Q4a3|CNMl@Q3DhS5)oGx*4OC{6nx8=J98fImlc0JORCj{%)KUfp22dU&)VBcTRZ!T2%4bkH4Jxle@eHa5 zK>NgC?n9?Rdjvsw4K!x~8fOKS%b+QREbg$;*zyyo+yJ!&Ky@N0T@h;kBgZAE ztp;)@sJ%!n3~FnE!VXk#g32>cn1aeKnE$cS$n&ZocYx{`P+yjqJ}anB2i5JAVo*Dp zP#T5hT~N9Nm4l$Z7pOf;R1c zfZ7tEzC9>hK=}n*8i9#{>;Q!csEh&G0UC<{G>JNbOET|0(%EO?%3@Rr< zc>^?W2y-7k8nn(Bl(#_j8K~|+4kM5oh;ctCj9~5ug%PN}1GV))<|5k-s?$N`H>f-Z z)nl+WC1{)sU)_Q&KY`*D)Mo*WZ-d(PpnfhaOtI0RJ_)E#3req`u%b2w#T_VrgUVdc z-Z43hlzpYLFzzx15|f_(i+GdP}&291t?5F7_=W9w1x^4 zE}$|BR=$JA=LnVWuyPYrmxB7FpfLeZoP+wCpfU*N7Hl-geV{Y~>N|n*FeopB`bD6; z4Qii*+(rxrsRix71?^D-^#eftFi;sntQ&|4Bak~lZ6MIR3#bkSwTnUR8&Euf#HPWiDAo6pyOSU!wQsNKx%PeP}v0PXM)NeT3}Fkf!f@lcmRzlf!afa+6kaA0ksi8 zWejLd45)np8asoH1A+XF%RlrI2bHIwGzRh?Xbc)uW`pJfK=}ZaA3*s6ls`ae0F)l_ zxeHY0fyzEm{}oivf%@5?JOj!*pgsvGJU|%KmI3uiKzjy2SJGy##VItgQ&De~57(sEh`c)u4VYs0|Mqe?Z>L267`l3@SrG^$Dn60rkP$>)hnR35vlG3m1`g~ zXoW#(4pcUP`g5TECnz0&#xzwK7#KkN*+BlshC%HJ*dAF>Sq93Fp!NwU-GSVUD@^Di z4jL~5_2EHna?ltXsQv}j7oapoPJRN7oq_5YP+tO6=YY%twT(ezRmfok8kYc#kAlX{ zKz##Hc!KI}V*2y2J`iXQ12oqPN-v;v1B!Q0I>HxjpzsFuaR|8&TRb9*f!bxD_CBaz z4oa)!xB=9*2KD_w?G{j52R)2H_JR5fpt*Ta*$o;Wqa;6(>P}Et(h`H>0#yHj@&c&M z4l27rX%5tu0kx??{>O$vWezB;KzR=|76j^7g7PG2EDbcKhOgenmo}&&2WmTk%6d@R z1oh8BZ3@ts8))ne#=SxFd!TkO zXv`d+-$3OusC)*M)1dSPYV(2GexPv>kbm&$CB=QnZbfH<#{EELB&hENs?TZV25ROf zQr(F!9H}7(YHxz-DCD*`s6P$rLm~GK(8C_Y$F=?l)Heq8uc_faa?AkLC!jI{)Sd&i ztwDWbP?-zrpATey!Z()y8pfhGb@d6sl0?m7a`tan8?~ytlfiDiIAxBAmf`tvJ zZwZ>;1dR`Z%2m)D1ZXY-WHvrGg32^fF`=SzQuLBxq0`&($W5=NJU(mP}x%mk; zzK3o64AhSVg#!qK=0`zi3!;zjf#w-O?!p%q$m4sUc}CDY254*&6pn=2&Y-bO&^RTi zeGBRrg4zn8dKlziLTz@CyI~l#b^+Ah0L`s|+Q_830W?nq>xYBpg+S}zK=Uf-V~n7F z0;qfgjSYj=Re{!1fY$JV`rX*}IKsjWG>!l&D?#HlpmYYRn?Pe>uyK7*SP`0AfSE-r z8k9b9#Rb0c2v{6|<}5&cEl}8j#*sl|JFqcg&>9tdeFo4tFsQ!`O8>-QP=6g%j^hdo zP<;q0<3MqPyp{ws7Y|D3p!5YwXQ1>3N_U|22l6{83~-qV5(mkH)PdB4^nvmywmv2( zZ-K^#L1XElumFv%gYq?~ZUdFyAhU2`%_g5@XVxCG^AP}u?s6I>XSUn#}7 z%m#^r=C?rZAf{YF4igv~w*CkdKA`z-PLgH}0OdtcUzC` za-jMhl%DbV1ym1$>O;`nDQHb8D2zdA0#qM?)(L>pI=T4?J-vd~e1Y;QXl)v(Zw*T; zAT~%0*7gOZE6|uXsEq=ui?R71CI(8cpfO2Mn-bJc1*J3C+!dj81}c|8Yf(Yc@i0e$YM=P})VFBLle=)TaWS)dpJk18R?f#yvr04hVzB%RzG>pmlMu`DjpCMreEq z)NTN^A3)>%pz%pizX-Jc0o1MoweLXof-q=J7N`ycwP!$WLgYLPN(->?z(!-sPq2AD z(3%9$d?TTG30T<(3M*1EXxy4mJc8Qwpzs2vLD0M>C>%lINy^v|s9gvu*FbZepm{t{ zJb=;yXx;@>hvQp+1PUYAI!e$yCTPAKWCjR>+5(_<8)z*sD7}Ejl(B^~NDNdDg6cz1 zy$GrwLF;ru>vchML7+KSkQ>R(PoTLpko}->7EoIsW;Uo!2AK_NQ-Sg;Xq_j>K9Id2 zH6XRHem1Br3UVhd3`(z{cmTDPLGb`u9|iL}s4NBL8C-fn;xPT7avGFILG2(=KL}LL zf!bG~dJ0rWgVwcx<_$sfwy<^OpmGqjRsn=TV|$>nP|)}iDEvWlim27=YHEgU0JX=>#<24=PiL!Jx8^ob^Ybwk&9kJuDtzOoL_2&xxB^&=>(LG2CD8gNj(K}miB*$1opKfXZD^T@NawK=ma^FDR@*=3v91FaVA5gXY3PeF;$g0veYDl`o(* zT!i8gWF{yrg33?OxF$#+sND^UOHlm`n#Tr>r-3l23;^X9P+kMoAE0sz6jq>e3}h#$ zEek61L2{rv1~m2tDx*Mk52y|T*@X*(+FHnM4NyN06bGQSdZ6$Dg%c=@KlqcgZkt6>JU(w0Lu5EG!H8CL1jNEtZ-qF8$oqGs4fGQ zsrd3LNDib1l&?Yl0_Ag1eh1|XeCzzNs0{}SUr;#XiUW{1 zsGbM4bwK@ZP+u0L9~8Hs@orEUfyyM%I5;f#MV7XHfbCmARlY85B35G!1I&f!e8{ejPSz#4 zlomnbR-o|!P&olAFJS7i(V+SZlukhX5KzAhq!*M&K>Z6)zZNt$4Z@(h6VwI)g)vAT z)UE`TKcF@mXk7*<{6Xme6n?P!1LS9rKR|gFo82%mPfzmFh9}Ds?s0;y>>DclO zE-}#97N{Kos^39r3RKsD+6tgD7t~$>pmYHWcToBV%@=^mGtk@- zC=NjFc~ISp&+i~Vf#MgGXFzo;D2;*40;OkA*$L{agUkV~M+B9vAoaK~D7}NyGpH;D z)s3M38?5aJ3R4gUxesJ6sJsK^T~NCOWG^TWfZ9Ny^bJa5pz;D#&w|>HAisdx2!!@w zfyU-Q`2y4*2bBY$atD;BK;Z)N6DXWO;RSL7$e$p;fy#1FSptefT>gTIgVbQlPoVS$ zYS$2(UO;VcP(1=_6M@>tpz;LNzJ|FIR$qhq;Gi})C~QFK3tyQIaw8}nL1TL$zk|vp zP?-fPM?m#5sI3c1hooRozY|oqgWBPsya@_VP#Fzshk)W5WG6O^T)%+g7gT0~;+xp= z22}rn>OqitkUr4Z8pt1@J_4xU4e|q}`3dB1(0B+ay@K*Ms4fMCHOP;k`~!*;Q2GVc z^B{MC)PT|nK7WJEg!vtmXJG9QP+kJH6F_MiRBwRNIVe6s=?SC<7Y3D`pm7aQn+KFu zKx2iVGz)64fZA;!401C_4CH=Lp8%u|l$Sw$Pmp^-Jw021nI|zLH@^ z+W}N|fcgR;|ANvdNG&dR!^A;l9w_~T{0j0js15<;B~UvCRK9`A2T**2>IYDqg4_Vp zi;V`!gX{&Bzo0e^sQm{@Gaz??Fo+Ej1BEpxY(e!WDC|M~bWj=uwd+9bDNr2+s!Ko^ z#0H6h+PfgLvDu3(1}Z~9c?uLpp!x?CE}-xMg%c>eK;Z`R4=DeF>?Tz2!psJx18n&T z)MtgIH&9ss>a&9Cb5Oq&rWc(C`qX8fXW(>pF#a!P@RTu1~MO8 zJi^*YpfMm&8YC4HT7QJEKMN|?KxIFuEC!Xypga!B>!3aXDDNY?9hr?S4S?oeKz(n} zSQ5++)W}aTdqM3}(D(=_&4SV-s5}IvLr}f|t+N8Pc|dUwQ;&-V`3n?Rpm9A=n+i1k z0;*d<{R~jM8B{KS>IYESNo<<~W)~=|L35iR^Fi%YQ2GX85F6w^P&x*=5jo9)+O!}) zf$|)zYyyqDfZ9EvaTrj1fbt)x41?K&iw4CfDF1`P0~9Wx@BxJrD7-*+faE~-Odt7#d(iJG(fZ_yHK7rz!P&tNd z7O2euN*|!I5Y!d}wc$bI)S&eopfCiDZ-Dw7pgIav&x7g}P#lwD2gv=Pd<)7eAoqgU z$ZkMqgZfCIdIeM`!qNq(&IGlkK;<_m9zl5#T^}w!$gQAo0fi4JoIv3PatAK;_{2fx zfWiw@SAx$3gRFpfU(FE&)mdpu7*NTR{01RPW+56DEi5PLMw2vIeFO8x2a= zAa`MlN8~mVEG?2kgVvV7=IcOn!=SNckpDnw0W>xbs%Npe2_y!}JD@xS%1fZ~7*s}p z`~{N3hH>p_2bEW#xggM7Jk0In<|lma#pWhr#X$Z7#W$$@0JTv-ZDUaT4m1}88si7G zxj}7KQ2qjyyP)?>?X`r&5*tjOvJur2kG!LpzKxI70PS6-2s2>H2M^N7uRCj^e zyC8KiJ=CP}*40121eF{oLpmG6}=0If$HQk787N~px)%&3Qi!B~O z^$RQwl0#!#e*`LfVfh1OKeBs}*&sPk9s;Q)CjWujGoU^KsNW6h>w?C2L1j8X8ECx#Xe)t0gZ(r$0ND<2w5L!9u>4c476?qR0o2}HITnR<2#^m!Q~H79s-TEfWjB#c3kQ} za~7cV1j-YjG87c&u)ZniTuEfNfY_AeC(u|PsEq@1JBUqcnGEXZf#%3SW9XoR^0Oy1`XHf$|e*t`XFC2lYEa&tUzH8b1SGk z2DOJ^W)q@8YC(EH{sg51P#X$VPlMVQpfV9uhlAn~w4MvpUPq5dP#UBJgZu`n^FZx? zQ27fQqXMLJj6b8KM_>Pvy<*g<3HpmYMtgCPB&F*ne-Ca6yZ%I~1G1_~EY z_=4&zklR3M7BqGNau*1L*dX_U(k-aI1cfswFM`rEs9gX`C!lf*GLU44||LiUUwP6kDAN3wu!8 z6*RsAs;5AC52O!NXMozcp!OfAt^ma^C_F&n3u=df+G`*;fbt0_yg}{)xevq!xet^! zKyx&pd=4tNL3tfi-+}5RP<{ushe76p+Uv0X0H_TQ%2S}WDQN5#H0}s$8-T`1Kz%Jx zIs^F^lt(~iILvO4y&(HR_JZ65avR8vpm|+T84v0UP%A%y!VI)l4wR=rVFju)Kw%9E zbC6p>brmQMLH2>l4p4g^R3C%#GAL|dZUwPHVjww?8c;n9(gUg!KxTmI2ax|k@c^o~ zLFEl7FHthr1adn*44O{`^$9?Emz4EKpt2KGKH$nvpt21VAE5FEl%7E4C1{QuREFa! z<0;8cpzt(yV0)j)X*)ZPJ&D}(Y2XdD@omO(U#4=Uq9@*q7R^`NmaP+10Q zuYu-iLH!ZXSOX}H5*r7gJO@$_YDa_o3)eqwP7AOya+z9I9gW8~=bOI`KLFR+jx`5`wK>dACn+nt>1(jPM z`$1#*pneLdtOS)4ptcVvTtH<9%x;*yAR3fsLE!?*Lm)ST#tT4oASnNW(kdwZg6afZ z@eZmhK;;|>*LG2)r+mO>DD6Bx~8x+Q%um-KQ2dM{*8G!N?s0;#)V}Z&6 zP&ov$9~3sAFao(1#0G^ONDib1q!y$Hq!(lc$SjcmLG3S4e1O_Tpf(w@8>r0&&8L#H z{s`1o#TBNY@CKE0Ape5OMbP>IP*{Qb?4UjE=zHg2exg=>0;M-l`USPiL3s<5hC$&B zDziZD0ns2nNF0=hKCyacW30*&c|#_vF31al)XG)O&YFAZo86Xa*m zd=)5OL1hZ4o(83DQ2z?#Hqcr*&{`8vUIDoa*?pk43Mfs2%2`nRA5?yW@;a!z1-0)$ zX%J*S$R1GN8rFse%`bxPg8+@?gW8{h~h572xCESz9r1PU{d7)TBjMxZt$ zNDoLa$PAFbL1u!&0Tdsg{aqkCX^AOWe}pSPf!czg_5!GF0xH|k_q5~k4>j`>C|`iu zJD{)y&C7t=MWFNuN>3mf#0QCkDQt&KgOO|3GC1s7(W^ zD?n)l)UE;57oc_ksO|&h36R|&H-P#-pmYFo8wi8k2b${wwHH8n9Fz}1{sHA7kQ+hc zpP)7!C?A2^>!5Zf$Ucz0Fbv{@`gEZ3A2gN)Djz`OTA=we(6~RS&jPX=WDm$bn7yEI z0oe<38_12Ia)6fk3FKZ-7=!jvg4_z)s|M<0gUTR~e?k5R)$gD*gd9#FH-o|qBnFZL z)zzSOFKGN2q!(lc$ShD>0Td3Pz75DOdSH-!p!NbNKZD9YP?-p-??HVFP`?#dzQHCA z8ao2@ok8t=P`d(D_JiUDlmweu5bo(oilgZeU{elIAjL2(44L41%ns4W5- z7X$T?K=l!*p9C8B1eKfA2zyYS0ZQ+ndKuK#1+}d~c?)DG$Zeo72lXpKV;CT}fiTE@ zATdxq2}&EF_8cfbfbtN?ji9^^s((QJdP3<0R9Aua6oAqdC|`s65TG&x*=~@1FniI% z1>^===O)3}S=CKysk63ZxdK2c#F| zUr>1nG81M#y=YLFgW?Dj$Dpzr)E)q}*Fk+j(3lCnwjFw&0*wuU#@0aXT2R{oRE~hk zL{L0}>Rixy{J8u@?fe8Pqd@I;P#OfKV^A9!)K&-4AU;SOBoE3%Ah&_a6yOa$6KLELG}Z#@?}GXVpf)?GodF6DP+Gv}H&7UW(ix~O zBXvF(c{~DC9)Q{jp!@`C4}roL)Sdv9eW0;L5Dnsk#6f*zP+9|p0Y0};Qx23DKz;?; z4eFDF@-Zl%f!qedF!zDN3)FuGRJ5z6>-^56d^WXi%FAv^D{>z5q1W2pV$%^(8_51W>z$ zkPAoi6QK~IpZsWkqCBiYX&#jJL3sd_7eILels7=@H$Zs>S3UxXgVwEp)}w;v*+6rE zp!qb=xG-q#1*i{0O#6Q{KT#fs)G}c-KT#f%pfnFk`=C4k$_t=80m>Vo`DoDE4t(p6 zK%24TIX7pfygQbseB} zk)Sbu&{{~)Iv-FOL981_)j>i4G#?2n4?*jpK<$3e8d=y_FK9m!wm1NZf%cGs_JV-c z&V%OjLF)uT<6EHg1Zw+0OdnY!XsrNf&K$Jf5;PwL>Pvyv>w?laE(}^@32Nhk>LpNK z0_6+Pcp)hv2TJ##yIVkOra|K&pta4Qwa=jWEKpk$6i>J?Xs-sSy$M=x3|c1%T8{== z?*>}4LW&zk)j~o5w0;7V2S9lNG}a5+YXWM6fX1dk>tAri18DvqwATbQcL{2%fYJr1 zd<3NjQ2PU7`p6?eX&bZ_1+=aYwAKwY<_8KFTo|+l0@Pmum1&@QiPXFV3t^C*pfy>b zHIAUN4b*=FpNF ztwRUxZ2_%&0qw`a6%QaeP~QNwe*(1b8#I>*S{n!|*FbBXh!K zBo2xv(7JxmUJ6iO0hE_O>*)CU5!#c{;}NE{STpuJk4JP7J5(84{VW>OXcpmql+kAU_m;ldz!P@9x8 zn?`jL3IR~N9#