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