test/testime.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 27 Jan 2018 12:05:26 -0800
changeset 11836 a42b155124a3
parent 11811 5d94cb6b24d3
child 12503 806492103856
permissions -rw-r--r--
Fixed bug 4065 - SDL_wave.c fail to compile in armeabi with ndk r16b

Sylvain

armeabi is almost deprecated for android-ndk higher that r13b.
either it doesn't compile (ICE), or it executes wrongly (using long long for instance).

android people advices to use armeabi-v7a (or use r13b).
slouken@5535
     1
/*
slouken@11811
     2
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
slouken@5535
     3
slouken@5535
     4
  This software is provided 'as-is', without any express or implied
slouken@5535
     5
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     6
  arising from the use of this software.
slouken@5535
     7
slouken@5535
     8
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
     9
  including commercial applications, and to alter it and redistribute it
slouken@5535
    10
  freely.
slouken@5535
    11
*/
slouken@10416
    12
/* A simple program to test the Input Method support in the SDL library (2.0+)
slouken@10416
    13
   If you build without SDL_ttf, you can use the GNU Unifont hex file instead.
slouken@10416
    14
   Download at http://unifoundry.com/unifont.html */
slouken@3338
    15
slouken@3280
    16
#include <stdlib.h>
slouken@3280
    17
#include <stdio.h>
slouken@3280
    18
#include <string.h>
slouken@3280
    19
slouken@3280
    20
#include "SDL.h"
slouken@3280
    21
#ifdef HAVE_SDL_TTF
slouken@3280
    22
#include "SDL_ttf.h"
slouken@3280
    23
#endif
slouken@3338
    24
slouken@6785
    25
#include "SDL_test_common.h"
dimitris@6318
    26
slouken@10416
    27
#define DEFAULT_PTSIZE 30
slouken@10416
    28
#ifdef HAVE_SDL_TTF
slouken@10416
    29
#ifdef __MACOSX__
slouken@10416
    30
#define DEFAULT_FONT "/System/Library/Fonts/华文细黑.ttf"
slouken@10416
    31
#elif __WIN32__
slouken@10416
    32
/* Some japanese font present on at least Windows 8.1. */
slouken@10416
    33
#define DEFAULT_FONT "C:\\Windows\\Fonts\\yugothic.ttf"
slouken@10416
    34
#else
slouken@10416
    35
#define DEFAULT_FONT "NoDefaultFont.ttf"
slouken@10416
    36
#endif
slouken@10416
    37
#else
slouken@10416
    38
#define DEFAULT_FONT "unifont-9.0.02.hex"
slouken@10416
    39
#endif
slouken@3280
    40
#define MAX_TEXT_LENGTH 256
slouken@3280
    41
slouken@6785
    42
static SDLTest_CommonState *state;
dimitris@6318
    43
static SDL_Rect textRect, markedRect;
slouken@10416
    44
static SDL_Color lineColor = {0,0,0,255};
philipp@10100
    45
static SDL_Color backColor = {255,255,255,255};
slouken@10416
    46
static SDL_Color textColor = {0,0,0,255};
dimitris@6318
    47
static char text[MAX_TEXT_LENGTH], markedText[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
dimitris@6318
    48
static int cursor = 0;
slouken@3280
    49
#ifdef HAVE_SDL_TTF
dimitris@6318
    50
static TTF_Font *font;
slouken@10416
    51
#else
slouken@10416
    52
#define UNIFONT_MAX_CODEPOINT 0x1ffff
slouken@10416
    53
#define UNIFONT_NUM_GLYPHS 0x20000
slouken@10416
    54
/* Using 512x512 textures that are supported everywhere. */
slouken@10416
    55
#define UNIFONT_TEXTURE_WIDTH 512
slouken@10416
    56
#define UNIFONT_GLYPHS_IN_ROW (UNIFONT_TEXTURE_WIDTH / 16)
slouken@10416
    57
#define UNIFONT_GLYPHS_IN_TEXTURE (UNIFONT_GLYPHS_IN_ROW * UNIFONT_GLYPHS_IN_ROW)
slouken@10416
    58
#define UNIFONT_NUM_TEXTURES ((UNIFONT_NUM_GLYPHS + UNIFONT_GLYPHS_IN_TEXTURE - 1) / UNIFONT_GLYPHS_IN_TEXTURE)
slouken@10416
    59
#define UNIFONT_TEXTURE_SIZE (UNIFONT_TEXTURE_WIDTH * UNIFONT_TEXTURE_WIDTH * 4)
slouken@10416
    60
#define UNIFONT_TEXTURE_PITCH (UNIFONT_TEXTURE_WIDTH * 4)
slouken@10416
    61
#define UNIFONT_DRAW_SCALE 2
slouken@10416
    62
struct UnifontGlyph {
slouken@10416
    63
    Uint8 width;
slouken@10416
    64
    Uint8 data[32];
slouken@10416
    65
} *unifontGlyph;
slouken@10416
    66
static SDL_Texture **unifontTexture;
slouken@10416
    67
static Uint8 unifontTextureLoaded[UNIFONT_NUM_TEXTURES] = {0};
slouken@10416
    68
slouken@10416
    69
/* Unifont loading code start */
slouken@10416
    70
slouken@10416
    71
static Uint8 dehex(char c)
slouken@10416
    72
{
slouken@10416
    73
    if (c >= '0' && c <= '9')
slouken@10416
    74
        return c - '0';
slouken@10416
    75
    else if (c >= 'a' && c <= 'f')
slouken@10416
    76
        return c - 'a' + 10;
slouken@10416
    77
    else if (c >= 'A' && c <= 'F')
slouken@10416
    78
        return c - 'A' + 10;
slouken@10416
    79
    return 255;
slouken@10416
    80
}
slouken@10416
    81
slouken@10416
    82
static Uint8 dehex2(char c1, char c2)
slouken@10416
    83
{
slouken@10416
    84
    return (dehex(c1) << 4) | dehex(c2);
slouken@10416
    85
}
slouken@10416
    86
slouken@10416
    87
static Uint8 validate_hex(const char *cp, size_t len, Uint32 *np)
slouken@10416
    88
{
slouken@10416
    89
    Uint32 n = 0;
slouken@10416
    90
    for (; len > 0; cp++, len--)
slouken@10416
    91
    {
slouken@10416
    92
        Uint8 c = dehex(*cp);
slouken@10416
    93
        if (c == 255)
slouken@10416
    94
            return 0;
slouken@10416
    95
        n = (n << 4) | c;
slouken@10416
    96
    }
slouken@10416
    97
    if (np != NULL)
slouken@10416
    98
        *np = n;
slouken@10416
    99
    return 1;
slouken@10416
   100
}
slouken@10416
   101
slouken@11361
   102
static int unifont_init(const char *fontname)
slouken@10416
   103
{
slouken@10416
   104
    Uint8 hexBuffer[65];
slouken@10416
   105
    Uint32 numGlyphs = 0;
slouken@10416
   106
    int lineNumber = 1;
slouken@10416
   107
    size_t bytesRead;
slouken@10416
   108
    SDL_RWops *hexFile;
slouken@10416
   109
    const size_t unifontGlyphSize = UNIFONT_NUM_GLYPHS * sizeof(struct UnifontGlyph);
slouken@10416
   110
    const size_t unifontTextureSize = UNIFONT_NUM_TEXTURES * state->num_windows * sizeof(void *);
slouken@10416
   111
slouken@10416
   112
    /* Allocate memory for the glyph data so the file can be closed after initialization. */
philipp@10503
   113
    unifontGlyph = (struct UnifontGlyph *)SDL_malloc(unifontGlyphSize);
slouken@10416
   114
    if (unifontGlyph == NULL)
slouken@10416
   115
    {
slouken@10416
   116
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for glyph data.\n", (int)(unifontGlyphSize + 1023) / 1024);
slouken@11361
   117
        return -1;
slouken@10416
   118
    }
slouken@10416
   119
    SDL_memset(unifontGlyph, 0, unifontGlyphSize);
slouken@10416
   120
slouken@10416
   121
    /* Allocate memory for texture pointers for all renderers. */
philipp@10503
   122
    unifontTexture = (SDL_Texture **)SDL_malloc(unifontTextureSize);
slouken@10416
   123
    if (unifontTexture == NULL)
slouken@10416
   124
    {
slouken@10416
   125
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for texture pointer data.\n", (int)(unifontTextureSize + 1023) / 1024);
slouken@11361
   126
        return -1;
slouken@10416
   127
    }
slouken@10416
   128
    SDL_memset(unifontTexture, 0, unifontTextureSize);
slouken@10416
   129
slouken@10416
   130
    hexFile = SDL_RWFromFile(fontname, "rb");
slouken@10416
   131
    if (hexFile == NULL)
slouken@10416
   132
    {
slouken@10416
   133
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to open font file: %s\n", fontname);
slouken@11361
   134
        return -1;
slouken@10416
   135
    }
slouken@10416
   136
slouken@10416
   137
    /* Read all the glyph data into memory to make it accessible later when textures are created. */
slouken@10416
   138
    do {
slouken@10416
   139
        int i, codepointHexSize;
slouken@10416
   140
        size_t bytesOverread;
slouken@10416
   141
        Uint8 glyphWidth;
slouken@10416
   142
        Uint32 codepoint;
slouken@10416
   143
slouken@10416
   144
        bytesRead = SDL_RWread(hexFile, hexBuffer, 1, 9);
slouken@10416
   145
        if (numGlyphs > 0 && bytesRead == 0)
slouken@10416
   146
            break; /* EOF */
slouken@10416
   147
        if ((numGlyphs == 0 && bytesRead == 0) || (numGlyphs > 0 && bytesRead < 9))
slouken@10416
   148
        {
philipp@11133
   149
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
slouken@11361
   150
            return -1;
slouken@10416
   151
        }
slouken@10416
   152
slouken@10416
   153
        /* Looking for the colon that separates the codepoint and glyph data at position 2, 4, 6 and 8. */
slouken@10416
   154
        if (hexBuffer[2] == ':')
slouken@10416
   155
            codepointHexSize = 2;
slouken@10416
   156
        else if (hexBuffer[4] == ':')
slouken@10416
   157
            codepointHexSize = 4;
slouken@10416
   158
        else if (hexBuffer[6] == ':')
slouken@10416
   159
            codepointHexSize = 6;
slouken@10416
   160
        else if (hexBuffer[8] == ':')
slouken@10416
   161
            codepointHexSize = 8;
slouken@10416
   162
        else
slouken@10416
   163
        {
slouken@10416
   164
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Could not find codepoint and glyph data separator symbol in hex file on line %d.\n", lineNumber);
slouken@11361
   165
            return -1;
slouken@10416
   166
        }
slouken@10416
   167
slouken@10416
   168
        if (!validate_hex((const char *)hexBuffer, codepointHexSize, &codepoint))
slouken@10416
   169
        {
slouken@10416
   170
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal number in hex file on line %d.\n", lineNumber);
slouken@11361
   171
            return -1;
slouken@10416
   172
        }
slouken@10416
   173
        if (codepoint > UNIFONT_MAX_CODEPOINT)
slouken@10416
   174
            SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Codepoint on line %d exceeded limit of 0x%x.\n", lineNumber, UNIFONT_MAX_CODEPOINT);
slouken@10416
   175
slouken@10416
   176
        /* If there was glyph data read in the last file read, move it to the front of the buffer. */
slouken@10416
   177
        bytesOverread = 8 - codepointHexSize;
slouken@10416
   178
        if (codepointHexSize < 8)
slouken@10416
   179
            SDL_memmove(hexBuffer, hexBuffer + codepointHexSize + 1, bytesOverread);
slouken@10416
   180
        bytesRead = SDL_RWread(hexFile, hexBuffer + bytesOverread, 1, 33 - bytesOverread);
slouken@10416
   181
        if (bytesRead < (33 - bytesOverread))
slouken@10416
   182
        {
slouken@10416
   183
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
slouken@11361
   184
            return -1;
slouken@10416
   185
        }
slouken@10416
   186
        if (hexBuffer[32] == '\n')
slouken@10416
   187
            glyphWidth = 8;
slouken@10416
   188
        else
slouken@10416
   189
        {
slouken@10416
   190
            glyphWidth = 16;
slouken@10416
   191
            bytesRead = SDL_RWread(hexFile, hexBuffer + 33, 1, 32);
slouken@10416
   192
            if (bytesRead < 32)
slouken@10416
   193
            {
slouken@10416
   194
                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
slouken@11361
   195
                return -1;
slouken@10416
   196
            }
slouken@10416
   197
        }
slouken@10416
   198
slouken@10416
   199
        if (!validate_hex((const char *)hexBuffer, glyphWidth * 4, NULL))
slouken@10416
   200
        {
slouken@10416
   201
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal glyph data in hex file on line %d.\n", lineNumber);
slouken@11361
   202
            return -1;
slouken@10416
   203
        }
slouken@10416
   204
slouken@10416
   205
        if (codepoint <= UNIFONT_MAX_CODEPOINT)
slouken@10416
   206
        {
slouken@10416
   207
            if (unifontGlyph[codepoint].width > 0)
slouken@10416
   208
                SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Ignoring duplicate codepoint 0x%08x in hex file on line %d.\n", codepoint, lineNumber);
slouken@10416
   209
            else
slouken@10416
   210
            {
slouken@10416
   211
                unifontGlyph[codepoint].width = glyphWidth;
slouken@10416
   212
                /* Pack the hex data into a more compact form. */
slouken@10416
   213
                for (i = 0; i < glyphWidth * 2; i++)
slouken@10416
   214
                    unifontGlyph[codepoint].data[i] = dehex2(hexBuffer[i * 2], hexBuffer[i * 2 + 1]);
slouken@10416
   215
                numGlyphs++;
slouken@10416
   216
            }
slouken@10416
   217
        }
slouken@10416
   218
slouken@10416
   219
        lineNumber++;
slouken@10416
   220
    } while (bytesRead > 0);
slouken@10416
   221
slouken@10416
   222
    SDL_RWclose(hexFile);
slouken@10416
   223
    SDL_Log("unifont: Loaded %u glyphs.\n", numGlyphs);
slouken@11361
   224
    return 0;
slouken@10416
   225
}
slouken@10416
   226
slouken@10416
   227
static void unifont_make_rgba(Uint8 *src, Uint8 *dst, Uint8 width)
slouken@10416
   228
{
slouken@10416
   229
    int i, j;
slouken@10416
   230
    Uint8 *row = dst;
slouken@10416
   231
slouken@10416
   232
    for (i = 0; i < width * 2; i++)
slouken@10416
   233
    {
slouken@10416
   234
        Uint8 data = src[i];
slouken@10416
   235
        for (j = 0; j < 8; j++)
slouken@10416
   236
        {
slouken@10416
   237
            if (data & 0x80)
slouken@10416
   238
            {
slouken@10416
   239
                row[0] = textColor.r;
slouken@10416
   240
                row[1] = textColor.g;
slouken@10416
   241
                row[2] = textColor.b;
slouken@10416
   242
                row[3] = textColor.a;
slouken@10416
   243
            }
slouken@10416
   244
            else
slouken@10416
   245
            {
slouken@10416
   246
                row[0] = 0;
slouken@10416
   247
                row[1] = 0;
slouken@10416
   248
                row[2] = 0;
slouken@10416
   249
                row[3] = 0;
slouken@10416
   250
            }
slouken@10416
   251
            data <<= 1;
slouken@10416
   252
            row += 4;
slouken@10416
   253
        }
slouken@10416
   254
slouken@10416
   255
        if (width == 8 || (width == 16 && i % 2 == 1))
slouken@10416
   256
        {
slouken@10416
   257
            dst += UNIFONT_TEXTURE_PITCH;
slouken@10416
   258
            row = dst;
slouken@10416
   259
        }
slouken@10416
   260
    }
slouken@10416
   261
}
slouken@10416
   262
slouken@11361
   263
static int unifont_load_texture(Uint32 textureID)
slouken@10416
   264
{
slouken@10416
   265
    int i;
slouken@10416
   266
    Uint8 * textureRGBA;
slouken@10416
   267
slouken@10416
   268
    if (textureID >= UNIFONT_NUM_TEXTURES)
slouken@10416
   269
    {
slouken@10416
   270
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Tried to load out of range texture %u.\n", textureID);
slouken@11361
   271
        return -1;
slouken@10416
   272
    }
slouken@10416
   273
philipp@10503
   274
    textureRGBA = (Uint8 *)SDL_malloc(UNIFONT_TEXTURE_SIZE);
slouken@10416
   275
    if (textureRGBA == NULL)
slouken@10416
   276
    {
slouken@10416
   277
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d MiB for a texture.\n", UNIFONT_TEXTURE_SIZE / 1024 / 1024);
slouken@11361
   278
        return -1;
slouken@10416
   279
    }
slouken@10416
   280
    SDL_memset(textureRGBA, 0, UNIFONT_TEXTURE_SIZE);
slouken@10416
   281
slouken@10416
   282
    /* Copy the glyphs into memory in RGBA format. */
slouken@10416
   283
    for (i = 0; i < UNIFONT_GLYPHS_IN_TEXTURE; i++)
slouken@10416
   284
    {
slouken@10416
   285
        Uint32 codepoint = UNIFONT_GLYPHS_IN_TEXTURE * textureID + i;
slouken@10416
   286
        if (unifontGlyph[codepoint].width > 0)
slouken@10416
   287
        {
slouken@10416
   288
            const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
slouken@10416
   289
            const size_t offset = (cInTex / UNIFONT_GLYPHS_IN_ROW) * UNIFONT_TEXTURE_PITCH * 16 + (cInTex % UNIFONT_GLYPHS_IN_ROW) * 16 * 4;
slouken@10416
   290
            unifont_make_rgba(unifontGlyph[codepoint].data, textureRGBA + offset, unifontGlyph[codepoint].width);
slouken@10416
   291
        }
slouken@10416
   292
    }
slouken@10416
   293
slouken@10416
   294
    /* Create textures and upload the RGBA data from above. */
slouken@10416
   295
    for (i = 0; i < state->num_windows; ++i)
slouken@10416
   296
    {
slouken@10416
   297
        SDL_Renderer *renderer = state->renderers[i];
slouken@10416
   298
        SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID];
slouken@10416
   299
        if (state->windows[i] == NULL || renderer == NULL || tex != NULL)
slouken@10416
   300
            continue;
slouken@10416
   301
        tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, UNIFONT_TEXTURE_WIDTH, UNIFONT_TEXTURE_WIDTH);
slouken@10416
   302
        if (tex == NULL)
slouken@10416
   303
        {
slouken@10416
   304
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to create texture %u for renderer %d.\n", textureID, i);
slouken@11361
   305
            return -1;
slouken@10416
   306
        }
slouken@10416
   307
        unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID] = tex;
slouken@10416
   308
        SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
slouken@10416
   309
        if (SDL_UpdateTexture(tex, NULL, textureRGBA, UNIFONT_TEXTURE_PITCH) != 0)
slouken@10416
   310
        {
slouken@10416
   311
            SDL_Log("unifont error: Failed to update texture %u data for renderer %d.\n", textureID, i);
slouken@10416
   312
        }
slouken@10416
   313
    }
slouken@10416
   314
slouken@10416
   315
    SDL_free(textureRGBA);
slouken@10416
   316
    unifontTextureLoaded[textureID] = 1;
slouken@11361
   317
    return 0;
slouken@10416
   318
}
slouken@10416
   319
slouken@10416
   320
static Sint32 unifont_draw_glyph(Uint32 codepoint, int rendererID, SDL_Rect *dstrect)
slouken@10416
   321
{
slouken@10416
   322
    SDL_Texture *texture;
slouken@10416
   323
    const Uint32 textureID = codepoint / UNIFONT_GLYPHS_IN_TEXTURE;
slouken@10416
   324
    SDL_Rect srcrect;
slouken@10416
   325
    srcrect.w = srcrect.h = 16;
slouken@11361
   326
    if (codepoint > UNIFONT_MAX_CODEPOINT) {
slouken@10416
   327
        return 0;
slouken@11361
   328
    }
slouken@11361
   329
    if (!unifontTextureLoaded[textureID]) {
slouken@11361
   330
        if (unifont_load_texture(textureID) < 0) {
slouken@11361
   331
            return 0;
slouken@11361
   332
        }
slouken@11361
   333
    }
slouken@10416
   334
    texture = unifontTexture[UNIFONT_NUM_TEXTURES * rendererID + textureID];
slouken@10416
   335
    if (texture != NULL)
slouken@10416
   336
    {
slouken@10416
   337
        const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
slouken@10416
   338
        srcrect.x = cInTex % UNIFONT_GLYPHS_IN_ROW * 16;
slouken@10416
   339
        srcrect.y = cInTex / UNIFONT_GLYPHS_IN_ROW * 16;
slouken@10416
   340
        SDL_RenderCopy(state->renderers[rendererID], texture, &srcrect, dstrect);
slouken@10416
   341
    }
slouken@10416
   342
    return unifontGlyph[codepoint].width;
slouken@10416
   343
}
slouken@10416
   344
slouken@10416
   345
static void unifont_cleanup()
slouken@10416
   346
{
slouken@10416
   347
    int i, j;
slouken@10416
   348
    for (i = 0; i < state->num_windows; ++i)
slouken@10416
   349
    {
slouken@10416
   350
        SDL_Renderer *renderer = state->renderers[i];
slouken@10416
   351
        if (state->windows[i] == NULL || renderer == NULL)
slouken@10416
   352
            continue;
slouken@10416
   353
        for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
slouken@10416
   354
        {
slouken@10416
   355
            SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + j];
slouken@10416
   356
            if (tex != NULL)
slouken@10416
   357
                SDL_DestroyTexture(tex);
slouken@10416
   358
        }
slouken@10416
   359
    }
slouken@10416
   360
slouken@10416
   361
    for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
slouken@10416
   362
          unifontTextureLoaded[j] = 0;
slouken@10416
   363
slouken@10416
   364
    SDL_free(unifontTexture);
slouken@10416
   365
    SDL_free(unifontGlyph);
slouken@10416
   366
}
slouken@10416
   367
slouken@10416
   368
/* Unifont code end */
slouken@3280
   369
#endif
dewyatt@4757
   370
slouken@5150
   371
size_t utf8_length(unsigned char c)
slouken@5150
   372
{
slouken@5150
   373
    c = (unsigned char)(0xff & c);
slouken@5150
   374
    if (c < 0x80)
slouken@5150
   375
        return 1;
slouken@5150
   376
    else if ((c >> 5) ==0x6)
slouken@5150
   377
        return 2;
slouken@5150
   378
    else if ((c >> 4) == 0xe)
slouken@5150
   379
        return 3;
slouken@5150
   380
    else if ((c >> 3) == 0x1e)
slouken@5150
   381
        return 4;
slouken@5150
   382
    else
slouken@5150
   383
        return 0;
slouken@5150
   384
}
slouken@5150
   385
slouken@5150
   386
char *utf8_next(char *p)
slouken@5150
   387
{
slouken@5150
   388
    size_t len = utf8_length(*p);
slouken@5150
   389
    size_t i = 0;
slouken@5150
   390
    if (!len)
slouken@5150
   391
        return 0;
slouken@5150
   392
slouken@5150
   393
    for (; i < len; ++i)
slouken@5150
   394
    {
slouken@5150
   395
        ++p;
slouken@5150
   396
        if (!*p)
slouken@5150
   397
            return 0;
slouken@5150
   398
    }
slouken@5150
   399
    return p;
slouken@5150
   400
}
dewyatt@4757
   401
dewyatt@4757
   402
char *utf8_advance(char *p, size_t distance)
dewyatt@4757
   403
{
dewyatt@4757
   404
    size_t i = 0;
dewyatt@4757
   405
    for (; i < distance && p; ++i)
dewyatt@4757
   406
    {
dewyatt@4757
   407
        p = utf8_next(p);
dewyatt@4757
   408
    }
dewyatt@4757
   409
    return p;
dewyatt@4757
   410
}
slouken@3280
   411
slouken@10416
   412
Uint32 utf8_decode(char *p, size_t len)
slouken@10416
   413
{
slouken@10416
   414
    Uint32 codepoint = 0;
slouken@10416
   415
    size_t i = 0;
slouken@10416
   416
    if (!len)
slouken@10416
   417
        return 0;
slouken@10416
   418
slouken@10416
   419
    for (; i < len; ++i)
slouken@10416
   420
    {
slouken@10416
   421
        if (i == 0)
slouken@10416
   422
            codepoint = (0xff >> len) & *p;
slouken@10416
   423
        else
slouken@10416
   424
        {
slouken@10416
   425
            codepoint <<= 6;
slouken@10416
   426
            codepoint |= 0x3f & *p;
slouken@10416
   427
        }
slouken@10416
   428
        if (!*p)
slouken@10416
   429
            return 0;
slouken@10416
   430
        p++;
slouken@10416
   431
    }
slouken@10416
   432
slouken@10416
   433
    return codepoint;
slouken@10416
   434
}
slouken@10416
   435
slouken@3280
   436
void usage()
slouken@3280
   437
{
aschiffler@7639
   438
    SDL_Log("usage: testime [--font fontfile]\n");
slouken@3280
   439
}
slouken@3280
   440
dimitris@6318
   441
void InitInput()
slouken@3280
   442
{
dimitris@6318
   443
    /* Prepare a rect for text input */
dimitris@6318
   444
    textRect.x = textRect.y = 100;
dimitris@6318
   445
    textRect.w = DEFAULT_WINDOW_WIDTH - 2 * textRect.x;
dimitris@6318
   446
    textRect.h = 50;
dimitris@6318
   447
dimitris@6318
   448
    text[0] = 0;
dimitris@6318
   449
    markedRect = textRect;
dimitris@6318
   450
    markedText[0] = 0;
dimitris@6318
   451
dimitris@6318
   452
    SDL_StartTextInput();
dimitris@6318
   453
}
dimitris@6318
   454
dimitris@6318
   455
void CleanupVideo()
dimitris@6318
   456
{
dimitris@6318
   457
    SDL_StopTextInput();
dimitris@6318
   458
#ifdef HAVE_SDL_TTF
dimitris@6318
   459
    TTF_CloseFont(font);
dimitris@6318
   460
    TTF_Quit();
slouken@10416
   461
#else
slouken@10416
   462
    unifont_cleanup();
dimitris@6318
   463
#endif
dimitris@6318
   464
}
dimitris@6318
   465
slouken@11361
   466
void _Redraw(int rendererID)
slouken@11361
   467
{
slouken@10416
   468
    SDL_Renderer * renderer = state->renderers[rendererID];
slouken@10416
   469
    SDL_Rect drawnTextRect, cursorRect, underlineRect;
slouken@10416
   470
    drawnTextRect = textRect;
slouken@10416
   471
    drawnTextRect.w = 0;
dimitris@6318
   472
philipp@10100
   473
    SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
dimitris@6318
   474
    SDL_RenderFillRect(renderer,&textRect);
dimitris@6318
   475
dimitris@6318
   476
    if (*text)
dimitris@6318
   477
    {
slouken@10416
   478
#ifdef HAVE_SDL_TTF
dimitris@6318
   479
        SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, textColor);
philipp@10111
   480
        SDL_Texture *texture;
slouken@10416
   481
slouken@10416
   482
        /* Vertically center text */
slouken@10416
   483
        drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
slouken@10416
   484
        drawnTextRect.w = textSur->w;
slouken@10416
   485
        drawnTextRect.h = textSur->h;
dimitris@6318
   486
philipp@10111
   487
        texture = SDL_CreateTextureFromSurface(renderer,textSur);
dimitris@6318
   488
        SDL_FreeSurface(textSur);
dimitris@6318
   489
slouken@10416
   490
        SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
dimitris@6318
   491
        SDL_DestroyTexture(texture);
slouken@10416
   492
#else
slouken@10416
   493
        char *utext = text;
slouken@10416
   494
        Uint32 codepoint;
slouken@10416
   495
        size_t len;
slouken@10416
   496
        SDL_Rect dstrect;
slouken@10416
   497
slouken@10416
   498
        dstrect.x = textRect.x;
slouken@10416
   499
        dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
slouken@10416
   500
        dstrect.w = 16 * UNIFONT_DRAW_SCALE;
slouken@10416
   501
        dstrect.h = 16 * UNIFONT_DRAW_SCALE;
slouken@10416
   502
        drawnTextRect.y = dstrect.y;
slouken@10416
   503
        drawnTextRect.h = dstrect.h;
slouken@10416
   504
slouken@10416
   505
        while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
slouken@10416
   506
        {
slouken@10416
   507
            Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
slouken@10416
   508
            dstrect.x += advance;
slouken@10416
   509
            drawnTextRect.w += advance;
slouken@10416
   510
            utext += len;
slouken@10416
   511
        }
slouken@10416
   512
#endif
dimitris@6318
   513
    }
dimitris@6318
   514
slouken@10416
   515
    markedRect.x = textRect.x + drawnTextRect.w;
slouken@10416
   516
    markedRect.w = textRect.w - drawnTextRect.w;
dimitris@6318
   517
    if (markedRect.w < 0)
dimitris@6318
   518
    {
gabomdq@7663
   519
        /* Stop text input because we cannot hold any more characters */
dimitris@6318
   520
        SDL_StopTextInput();
dimitris@6318
   521
        return;
dimitris@6318
   522
    }
dimitris@6318
   523
    else
dimitris@6318
   524
    {
dimitris@6318
   525
        SDL_StartTextInput();
dimitris@6318
   526
    }
dimitris@6318
   527
slouken@10416
   528
    cursorRect = drawnTextRect;
slouken@10416
   529
    cursorRect.x += cursorRect.w;
dimitris@6318
   530
    cursorRect.w = 2;
slouken@10416
   531
    cursorRect.h = drawnTextRect.h;
slouken@10416
   532
slouken@10416
   533
    drawnTextRect.x += drawnTextRect.w;
slouken@10416
   534
    drawnTextRect.w = 0;
dimitris@6318
   535
philipp@10100
   536
    SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
dimitris@6318
   537
    SDL_RenderFillRect(renderer,&markedRect);
dimitris@6318
   538
dimitris@6318
   539
    if (markedText[0])
dimitris@6318
   540
    {
dimitris@6318
   541
#ifdef HAVE_SDL_TTF
philipp@10111
   542
        SDL_Surface *textSur;
philipp@10111
   543
        SDL_Texture *texture;
dimitris@6318
   544
        if (cursor)
dimitris@6318
   545
        {
dimitris@6318
   546
            char *p = utf8_advance(markedText, cursor);
dimitris@6318
   547
            char c = 0;
dimitris@6318
   548
            if (!p)
philipp@10097
   549
                p = &markedText[SDL_strlen(markedText)];
dimitris@6318
   550
dimitris@6318
   551
            c = *p;
dimitris@6318
   552
            *p = 0;
slouken@10416
   553
            TTF_SizeUTF8(font, markedText, &drawnTextRect.w, NULL);
slouken@10416
   554
            cursorRect.x += drawnTextRect.w;
dimitris@6318
   555
            *p = c;
dimitris@6318
   556
        }
philipp@10111
   557
        textSur = TTF_RenderUTF8_Blended(font, markedText, textColor);
slouken@10416
   558
        /* Vertically center text */
slouken@10416
   559
        drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
slouken@10416
   560
        drawnTextRect.w = textSur->w;
slouken@10416
   561
        drawnTextRect.h = textSur->h;
slouken@10416
   562
philipp@10111
   563
        texture = SDL_CreateTextureFromSurface(renderer,textSur);
dimitris@6318
   564
        SDL_FreeSurface(textSur);
dimitris@6318
   565
slouken@10416
   566
        SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
dimitris@6318
   567
        SDL_DestroyTexture(texture);
slouken@10416
   568
#else
slouken@10416
   569
        int i = 0;
slouken@10416
   570
        char *utext = markedText;
slouken@10416
   571
        Uint32 codepoint;
slouken@10416
   572
        size_t len;
slouken@10416
   573
        SDL_Rect dstrect;
slouken@10416
   574
slouken@10416
   575
        dstrect.x = drawnTextRect.x;
slouken@10416
   576
        dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
slouken@10416
   577
        dstrect.w = 16 * UNIFONT_DRAW_SCALE;
slouken@10416
   578
        dstrect.h = 16 * UNIFONT_DRAW_SCALE;
slouken@10416
   579
        drawnTextRect.y = dstrect.y;
slouken@10416
   580
        drawnTextRect.h = dstrect.h;
slouken@10416
   581
slouken@10416
   582
        while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
slouken@10416
   583
        {
slouken@10416
   584
            Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
slouken@10416
   585
            dstrect.x += advance;
slouken@10416
   586
            drawnTextRect.w += advance;
slouken@10416
   587
            if (i < cursor)
slouken@10416
   588
                cursorRect.x += advance;
slouken@10416
   589
            i++;
slouken@10416
   590
            utext += len;
slouken@10416
   591
        }
dimitris@6318
   592
#endif
dimitris@6318
   593
slouken@10416
   594
        if (cursor > 0)
slouken@10416
   595
        {
slouken@10416
   596
            cursorRect.y = drawnTextRect.y;
slouken@10416
   597
            cursorRect.h = drawnTextRect.h;
slouken@10416
   598
        }
slouken@10416
   599
dimitris@6318
   600
        underlineRect = markedRect;
slouken@10416
   601
        underlineRect.y = drawnTextRect.y + drawnTextRect.h - 2;
dimitris@6318
   602
        underlineRect.h = 2;
slouken@10416
   603
        underlineRect.w = drawnTextRect.w;
dimitris@6318
   604
philipp@10100
   605
        SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
slouken@10416
   606
        SDL_RenderFillRect(renderer, &underlineRect);
dimitris@6318
   607
    }
dimitris@6318
   608
philipp@10100
   609
    SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
dimitris@6318
   610
    SDL_RenderFillRect(renderer,&cursorRect);
dimitris@6318
   611
dimitris@6318
   612
    SDL_SetTextInputRect(&markedRect);
dimitris@6318
   613
}
dimitris@6318
   614
slouken@11361
   615
void Redraw()
slouken@11361
   616
{
dimitris@6318
   617
    int i;
dimitris@6318
   618
    for (i = 0; i < state->num_windows; ++i) {
dimitris@6318
   619
        SDL_Renderer *renderer = state->renderers[i];
slouken@7787
   620
        if (state->windows[i] == NULL)
slouken@7787
   621
            continue;
dimitris@6318
   622
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
dimitris@6318
   623
        SDL_RenderClear(renderer);
dimitris@6318
   624
slouken@10416
   625
        /* Sending in the window id to let the font renderers know which one we're working with. */
slouken@10416
   626
        _Redraw(i);
dimitris@6318
   627
dimitris@6318
   628
        SDL_RenderPresent(renderer);
dimitris@6318
   629
    }
dimitris@6318
   630
}
dimitris@6318
   631
slouken@11361
   632
int main(int argc, char *argv[])
slouken@11361
   633
{
dimitris@6318
   634
    int i, done;
dimitris@6318
   635
    SDL_Event event;
slouken@3280
   636
    const char *fontname = DEFAULT_FONT;
slouken@3280
   637
aschiffler@7639
   638
    /* Enable standard application logging */
aschiffler@7639
   639
    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
aschiffler@7639
   640
dimitris@6318
   641
    /* Initialize test framework */
slouken@6785
   642
    state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
dimitris@6318
   643
    if (!state) {
dimitris@6318
   644
        return 1;
dimitris@6318
   645
    }
dimitris@6318
   646
    for (i = 1; i < argc;i++) {
slouken@6785
   647
        SDLTest_CommonArg(state, i);
dimitris@6318
   648
    }
slouken@3280
   649
    for (argc--, argv++; argc > 0; argc--, argv++)
slouken@3280
   650
    {
dimitris@6318
   651
        if (strcmp(argv[0], "--help") == 0) {
slouken@3280
   652
            usage();
dimitris@6318
   653
            return 0;
dimitris@6318
   654
        }
slouken@3280
   655
slouken@3280
   656
        else if (strcmp(argv[0], "--font") == 0)
slouken@3280
   657
        {
slouken@3280
   658
            argc--;
slouken@3280
   659
            argv++;
slouken@3280
   660
slouken@3280
   661
            if (argc > 0)
slouken@3280
   662
                fontname = argv[0];
dimitris@6318
   663
            else {
slouken@3280
   664
                usage();
dimitris@6318
   665
                return 0;
dimitris@6318
   666
            }
slouken@3280
   667
        }
slouken@3280
   668
    }
slouken@7191
   669
slouken@6785
   670
    if (!SDLTest_CommonInit(state)) {
dimitris@6318
   671
        return 2;
dimitris@6318
   672
    }
slouken@3280
   673
slouken@3280
   674
slouken@3280
   675
#ifdef HAVE_SDL_TTF
slouken@3280
   676
    /* Initialize fonts */
slouken@3280
   677
    TTF_Init();
slouken@3280
   678
slouken@3280
   679
    font = TTF_OpenFont(fontname, DEFAULT_PTSIZE);
slouken@3280
   680
    if (! font)
slouken@3280
   681
    {
aschiffler@7639
   682
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to find font: %s\n", TTF_GetError());
slouken@11361
   683
        return -1;
slouken@3280
   684
    }
slouken@10416
   685
#else
slouken@11361
   686
    if (unifont_init(fontname) < 0) {
slouken@11361
   687
        return -1;
slouken@11361
   688
    }
slouken@3280
   689
#endif
slouken@3280
   690
aschiffler@7639
   691
    SDL_Log("Using font: %s\n", fontname);
slouken@3280
   692
dimitris@6318
   693
    InitInput();
dimitris@6318
   694
    /* Create the windows and initialize the renderers */
dimitris@6318
   695
    for (i = 0; i < state->num_windows; ++i) {
dimitris@6318
   696
        SDL_Renderer *renderer = state->renderers[i];
dimitris@6318
   697
        SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
dimitris@6318
   698
        SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
dimitris@6318
   699
        SDL_RenderClear(renderer);
slouken@3280
   700
    }
slouken@7191
   701
    Redraw();
dimitris@6318
   702
    /* Main render loop */
dimitris@6318
   703
    done = 0;
dimitris@6318
   704
    while (!done) {
dimitris@6318
   705
        /* Check for events */
dimitris@6318
   706
        while (SDL_PollEvent(&event)) {
slouken@6785
   707
            SDLTest_CommonEvent(state, &event, &done);
dimitris@6318
   708
            switch(event.type) {
dimitris@6318
   709
                case SDL_KEYDOWN: {
dimitris@6318
   710
                    switch (event.key.keysym.sym)
dimitris@6318
   711
                    {
dimitris@6318
   712
                        case SDLK_RETURN:
dimitris@6318
   713
                             text[0]=0x00;
dimitris@6318
   714
                             Redraw();
dimitris@6318
   715
                             break;
dimitris@6318
   716
                        case SDLK_BACKSPACE:
slouken@10416
   717
                            /* Only delete text if not in editing mode. */
slouken@10416
   718
                             if (!markedText[0])
dimitris@6318
   719
                             {
philipp@9938
   720
                                 size_t textlen = SDL_strlen(text);
slouken@3280
   721
dimitris@6318
   722
                                 do {
dimitris@6318
   723
                                     if (textlen==0)
dimitris@6318
   724
                                     {
dimitris@6318
   725
                                         break;
dimitris@6318
   726
                                     }
dimitris@6318
   727
                                     if ((text[textlen-1] & 0x80) == 0x00)
dimitris@6318
   728
                                     {
dimitris@6318
   729
                                         /* One byte */
dimitris@6318
   730
                                         text[textlen-1]=0x00;
dimitris@6318
   731
                                         break;
dimitris@6318
   732
                                     }
dimitris@6318
   733
                                     if ((text[textlen-1] & 0xC0) == 0x80)
dimitris@6318
   734
                                     {
dimitris@6318
   735
                                         /* Byte from the multibyte sequence */
dimitris@6318
   736
                                         text[textlen-1]=0x00;
dimitris@6318
   737
                                         textlen--;
dimitris@6318
   738
                                     }
dimitris@6318
   739
                                     if ((text[textlen-1] & 0xC0) == 0xC0)
dimitris@6318
   740
                                     {
dimitris@6318
   741
                                         /* First byte of multibyte sequence */
dimitris@6318
   742
                                         text[textlen-1]=0x00;
dimitris@6318
   743
                                         break;
dimitris@6318
   744
                                     }
dimitris@6318
   745
                                 } while(1);
dimitris@6318
   746
dimitris@6318
   747
                                 Redraw();
dimitris@6318
   748
                             }
dimitris@6318
   749
                             break;
dimitris@6318
   750
                    }
dimitris@6318
   751
dimitris@6318
   752
                    if (done)
dimitris@6318
   753
                    {
dimitris@6318
   754
                        break;
dimitris@6318
   755
                    }
dimitris@6318
   756
aschiffler@7639
   757
                    SDL_Log("Keyboard: scancode 0x%08X = %s, keycode 0x%08X = %s\n",
dimitris@6318
   758
                            event.key.keysym.scancode,
dimitris@6318
   759
                            SDL_GetScancodeName(event.key.keysym.scancode),
dimitris@6318
   760
                            event.key.keysym.sym, SDL_GetKeyName(event.key.keysym.sym));
dimitris@6318
   761
                    break;
dimitris@6318
   762
dimitris@6318
   763
                case SDL_TEXTINPUT:
slouken@7721
   764
                    if (event.text.text[0] == '\0' || event.text.text[0] == '\n' ||
dimitris@6318
   765
                        markedRect.w < 0)
dimitris@6318
   766
                        break;
dimitris@6318
   767
aschiffler@7639
   768
                    SDL_Log("Keyboard: text input \"%s\"\n", event.text.text);
dimitris@6318
   769
dimitris@6318
   770
                    if (SDL_strlen(text) + SDL_strlen(event.text.text) < sizeof(text))
dimitris@6318
   771
                        SDL_strlcat(text, event.text.text, sizeof(text));
dimitris@6318
   772
aschiffler@7639
   773
                    SDL_Log("text inputed: %s\n", text);
dimitris@6318
   774
gabomdq@7663
   775
                    /* After text inputed, we can clear up markedText because it */
gabomdq@7677
   776
                    /* is committed */
dimitris@6318
   777
                    markedText[0] = 0;
dimitris@6318
   778
                    Redraw();
dimitris@6318
   779
                    break;
dimitris@6318
   780
dimitris@6318
   781
                case SDL_TEXTEDITING:
aschiffler@7639
   782
                    SDL_Log("text editing \"%s\", selected range (%d, %d)\n",
dimitris@6318
   783
                            event.edit.text, event.edit.start, event.edit.length);
dimitris@6318
   784
slouken@10416
   785
                    SDL_strlcpy(markedText, event.edit.text, SDL_TEXTEDITINGEVENT_TEXT_SIZE);
dimitris@6318
   786
                    cursor = event.edit.start;
dimitris@6318
   787
                    Redraw();
dimitris@6318
   788
                    break;
dimitris@6318
   789
                }
dimitris@6318
   790
                break;
slouken@7191
   791
dimitris@6318
   792
            }
dimitris@6318
   793
        }
slouken@3280
   794
    }
dimitris@6318
   795
    CleanupVideo();
slouken@6785
   796
    SDLTest_CommonQuit(state);
dimitris@6318
   797
    return 0;
slouken@3280
   798
}
slouken@3280
   799
slouken@5244
   800
slouken@5244
   801
/* vi: set ts=4 sw=4 expandtab: */