SDL_Surface *generateTextSurface(char *text, TTF_Font *font, int fr, int fg, int fb, int br, int bg, int bb) { SDL_Surface *surface; SDL_Color foregroundcolour, backgroundcolour; foregroundcolour.r = fr; foregroundcolour.g = fg; foregroundcolour.b = fb; backgroundcolour.r = br; backgroundcolour.g = bg; backgroundcolour.b = bb; /* Use SDL_TTF to generate a string image, this returns an SDL_Surface */ surface = TTF_RenderUTF8_Shaded(font, text, foregroundcolour, backgroundcolour); if (surface == NULL) { printf("Couldn't create String %s: %s\n", text, SDL_GetError()); return NULL; } /* Return the generated string image */ return surface; }
void TFont_ttf::surf_string(SDL_Surface *surf,int x, int y, const char *s, int color, int bgcolor, int w) { if (!s[0]) return; if (!ttf) return TFont::surf_string(surf,x,y,s,color,bgcolor,w); if (!bgcolor) // 0 is totally transparent in sdl_gfx -> no bg return surf_string_tr(surf,x,y,s,color,w); SDL_Rect dest; SDL_Color sc,bg; sc.b = (color >> 8) & 0xff; sc.g = (color >> 16) & 0xff; sc.r = (color >> 24) & 0xff; bg.b = (bgcolor >> 8) & 0xff; bg.g = (bgcolor >> 16) & 0xff; bg.r = (bgcolor >> 24) & 0xff; SDL_Surface *sf; if (is_utf) sf = TTF_RenderUTF8_Shaded(ttf,s,sc,bg); else sf = TTF_RenderText_Shaded(ttf,s,sc,bg); // SDL_SetColorKey(sf,SDL_SRCCOLORKEY | SDL_RLEACCEL,0); dest.x = x; dest.y = y; if (w && w < sf->w) { SDL_Rect src; src.w = w; src.h = sf->h; src.x = src.y = 0; SDL_BlitSurface(sf,&src,surf,&dest); } else SDL_BlitSurface(sf,NULL,surf,&dest); SDL_FreeSurface(sf); }
extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderUTF8_Shaded_p( TTF_Font *font, const char *text, SDL_Color *fg, SDL_Color *bg) { return TTF_RenderUTF8_Shaded(font, text, *fg, *bg); }
void Screen::print_line_at(const std::string& line, unsigned int y, unsigned int x) { auto surf = TTF_RenderUTF8_Shaded(font_.get(), line.c_str(), text_color_, empty_); SDL_Rect position{(int) x, (int) y, surf->w, surf->h}; auto texture = SDL_CreateTextureFromSurface(renderer_.get(), surf); SDL_RenderCopy(renderer_.get(), texture, nullptr /* whole text texture */, &position); SDL_DestroyTexture(texture); SDL_FreeSurface(surf); }
/** * Constructs a broadcast message. It may consist of up to three "parts". * When numbers 1 to MAX_PLAYERS are used, the number is exchanged for a * "PlayerN" string, and colored according the current player color. * * @param msg Message string to be displayed. * @param pcolors An array of the current player colors. * @return The constructed broadcast message. */ SDL_Surface *makeBroadcast(char *msg, SDL_Color pcolors[MAX_PLAYERS]) { extern struct player players[MAX_PLAYERS]; SDL_Surface *broadcast; unsigned int i; char *strings[BROADC_PARTS]; SDL_Surface *parts[BROADC_PARTS]; unsigned int width = 0; /* Split message string */ strings[0] = strtok(msg, ";"); for (i = 1; (strings[i] = strtok(NULL, ";")) != NULL; ++i) {} for (i = 0; i < BROADC_PARTS && strings[i] != NULL; ++i) { char pstring[PLAYER_NAME_LEN]; if (strlen(strings[i]) == 1) { int pnum = atoi(strings[i]); snprintf(pstring, PLAYER_NAME_LEN, "%s", (&players[pnum - 1])->name); parts[i] = TTF_RenderUTF8_Shaded(font_broadc, pstring, pcolors[pnum - 1], cMenuBG); } else parts[i] = TTF_RenderUTF8_Shaded(font_broadc, strings[i], cBroadcast, cMenuBG); width += parts[i]->w; } broadcast = SDL_CreateRGBSurface(SDL_HWSURFACE, width, parts[0]->h, SCREEN_BPP, 0, 0, 0, 0); unsigned int nparts = i; int hoffset = 0; for (i = 0; i < nparts; ++i) { SDL_Rect offset = {hoffset, 0, 0, 0}; SDL_BlitSurface(parts[i], NULL, broadcast, &offset); hoffset += parts[i]->w; SDL_FreeSurface(parts[i]); } return broadcast; }
void Font::DrawText(SDL_Surface* surface, const SDL_Color& color, const SDL_Color& back_color, const std::string& font_text, const Sint16 x, const Sint16 y) const // TODO { BOOST_ASSERT(surface); BOOST_ASSERT(Point(x, y) == Point(x, y)); SDL_Surface *sText = TTF_RenderUTF8_Shaded( font, font_text.c_str(), color, back_color); BOOST_ASSERT(sText); SDL_Rect rcDest = {x, static_cast<Sint16>(y-4), 0, 0}; SDL_BlitSurface( sText, NULL, surface, &rcDest ); SDL_FreeSurface( sText ); }
SDL_Surface * TTF_RenderText_Shaded_FAST(TTF_Font *font, const char *text, Uint8 fr, Uint8 fg, Uint8 fb, Uint8 br, Uint8 bg, Uint8 bb) { color.r = fr; color.g = fg; color.b = fb; back.r = br; back.g = bg; back.b = bb; return TTF_RenderUTF8_Shaded(font, text, color, back); }
void text::quick_draw(render& render_obj, GLfloat x, GLfloat y, const std::string& str, const std::string& font, int size, const color& c) { SDL_Color bg = {0, 0, 0, 255}; surface_ptr surf = surface_ptr(TTF_RenderUTF8_Shaded(font::get_font(font, size).get(), str.c_str(), c.as_sdl_color(), bg), SDL_FreeSurface); ASSERT_LOG(surf != NULL, "Couldn't render text into texture"); render_obj.blit_2d_texture(texture::get(surf), x, y); }
rect quick_draw(int x, int y, const std::string& str, const std::string& font, int size, const color& c) { SDL_Color bg = {0, 0, 0, 255}; surface_ptr surf = surface_ptr(new surface(TTF_RenderUTF8_Shaded(font::get_font(font, size).get(), str.c_str(), c.as_sdl_color(), bg))); ASSERT_LOG(surf != NULL, "Couldn't render text into texture"); blit_2d_texture(texture::get(surf), static_cast<float>(x), static_cast<float>(y), static_cast<float>(surf->width()), static_cast<float>(surf->height())); return rect(x, y, surf->width(), surf->height()); }
/** * Method used to display on a screen only one string. * @param font is the pointer to TTF_Font which will be used to type a text on the screen. * @param screen is the pointer to the screen on which we will type. * @param text is the text to type. * @param foregroundColor is the color which will be used to type not active options. * @param x is the x axis location. * @param y is the y axis location. */ void IMenuState::displayOneText(TTF_Font* font, SDL_Surface* screen, const char* text, SDL_Color foregroundColor, int x, int y) throw(TextCreationException) { SDL_Surface *sText; SDL_Rect dest = {x, y, 0, 0}; if (!(sText= TTF_RenderUTF8_Shaded(font, text, foregroundColor, backgroundColor))) { if(sText != NULL) SDL_FreeSurface(sText); throw new TextCreationException(); } SDL_BlitSurface( sText, NULL, screen, &dest ); SDL_FreeSurface( sText ); }
int render_glyph(Glyph *g, SDL_Surface **ret) { SDL_Color color = {0,0,0}, bgcolor={0xff,0xff,0xff}; int bold, italic, underline, strikethrough, sup, sub, supsub; int font; int baseline; char *byte; TTF_Font **fs; byte = g->bytes; if (format_byte(*byte, &bold, &italic, &underline, &strikethrough, &sup, &sub, &supsub)) byte++; if (sup || sub || supsub) fs = su_fonts; else fs = fonts; baseline = 0; if (sub) baseline = 9; else if(supsub) baseline = 3; if (bold && italic) font = FONT_BOLD_ITALIC; else if (bold) font = FONT_BOLD; else if (italic) font = FONT_ITALIC; else font = FONT_NORMAL; if (underline && strikethrough) TTF_SetFontStyle(fs[font], TTF_STYLE_UNDERLINE | TTF_STYLE_STRIKETHROUGH); else if (underline) TTF_SetFontStyle(fs[font], TTF_STYLE_UNDERLINE); else if (strikethrough) TTF_SetFontStyle(fs[font], TTF_STYLE_STRIKETHROUGH); *ret = TTF_RenderUTF8_Shaded(fs[font], byte, color, bgcolor); TTF_SetFontStyle(fs[font], TTF_STYLE_NORMAL); return baseline; }
SDL_Surface * Font::renderShadedText(const char * text, int style, SDL_Color * c, SDL_Color * s) { SDL_Surface * surf; int old = this->setStyle(style); SDL_Color color = {0,0,0}; SDL_Color bg = {0,0,0}; if (c == NULL) c = &color; if (s == NULL) s = &bg; surf = TTF_RenderUTF8_Shaded(this->font, text, *c, *s); if (surf == NULL) throw SDLException("Nie mogę utworzyć powieszchni tekstowej"); this->setStyle(old); return surf; }
SDL_Surface *TText::render() { if (strlen(str) == 0) { setAspect(0, 0); return NULL; } SDL_Surface *t = TTF_RenderUTF8_Shaded(font, str, forecolor, backcolor); if ( t == NULL ) { fprintf(stderr, "Couldn't render text: %s\n", SDL_GetError()); TTF_CloseFont(font); } setAspect(t->w, t->h); return t; }
JNIEXPORT jlong JNICALL Java_sdljava_x_swig_SWIG_1SDLTTFJNI_TTF_1RenderUTF8_1Shaded(JNIEnv *jenv, jclass jcls, jlong jarg1, jstring jarg2, jlong jarg3, jlong jarg4) { jlong jresult = 0 ; TTF_Font *arg1 = (TTF_Font *) 0 ; char *arg2 ; SDL_Color arg3 ; SDL_Color arg4 ; SDL_Surface *result; SDL_Color *argp3 ; SDL_Color *argp4 ; (void)jenv; (void)jcls; arg1 = *(TTF_Font **)&jarg1; { arg2 = 0; if (jarg2) { arg2 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg2, 0); if (!arg2) return 0; } } argp3 = *(SDL_Color **)&jarg3; if (!argp3) { SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "Attempt to dereference null SDL_Color"); return 0; } arg3 = *argp3; argp4 = *(SDL_Color **)&jarg4; if (!argp4) { SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "Attempt to dereference null SDL_Color"); return 0; } arg4 = *argp4; result = (SDL_Surface *)TTF_RenderUTF8_Shaded(arg1,(char const *)arg2,arg3,arg4); *(SDL_Surface **)&jresult = result; { if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, arg2); } return jresult; }
static mrb_value mrb_sdl2_ttf_font_render_UTF8_shaded(mrb_state *mrb, mrb_value self) { mrb_value text; mrb_int fgr, fgg, fgb, fga, bgr, bgg, bgb, bga; SDL_Surface * c; SDL_Color fgcolor; SDL_Color bgcolor; mrb_get_args(mrb, "Siiiiiiii", &text, &fgr, &fgg, &fgb, &fga, &bgr, &bgg, &bgb, &bga); fgcolor.r = fgr; fgcolor.g = fgg; fgcolor.b = fgb; fgcolor.a = fga; bgcolor.r = bgr; bgcolor.g = bgg; bgcolor.b = bgb; bgcolor.a = bga; c = TTF_RenderUTF8_Shaded(mrb_sdl2_font_get_ptr(mrb, self), RSTRING_PTR(text), fgcolor, bgcolor); if (c == NULL) { mruby_sdl2_raise_error(mrb); return mrb_false_value(); } return mrb_sdl2_video_surface(mrb, c, 0); }
int main(int argc, char *argv[]) { char *argv0 = argv[0]; SDL_Surface *screen; TTF_Font *font; SDL_Surface *text, *temp; int ptsize; int i, done; int rdiff, gdiff, bdiff; SDL_Color colors[NUM_COLORS]; SDL_Color white = { 0xFF, 0xFF, 0xFF, 0 }; SDL_Color black = { 0x00, 0x00, 0x00, 0 }; SDL_Color *forecol; SDL_Color *backcol; SDL_Rect dstrect; SDL_Event event; int rendersolid; int renderstyle; int outline; int hinting; int kerning; int dump; enum { RENDER_LATIN1, RENDER_UTF8, RENDER_UNICODE } rendertype; char *message, string[128]; /* Look for special execution mode */ dump = 0; /* Look for special rendering types */ rendersolid = 0; renderstyle = TTF_STYLE_NORMAL; rendertype = RENDER_LATIN1; outline = 0; hinting = TTF_HINTING_NORMAL; kerning = 1; /* Default is black and white */ forecol = &black; backcol = &white; for ( i=1; argv[i] && argv[i][0] == '-'; ++i ) { if ( strcmp(argv[i], "-solid") == 0 ) { rendersolid = 1; } else if ( strcmp(argv[i], "-utf8") == 0 ) { rendertype = RENDER_UTF8; } else if ( strcmp(argv[i], "-unicode") == 0 ) { rendertype = RENDER_UNICODE; } else if ( strcmp(argv[i], "-b") == 0 ) { renderstyle |= TTF_STYLE_BOLD; } else if ( strcmp(argv[i], "-i") == 0 ) { renderstyle |= TTF_STYLE_ITALIC; } else if ( strcmp(argv[i], "-u") == 0 ) { renderstyle |= TTF_STYLE_UNDERLINE; } else if ( strcmp(argv[i], "-s") == 0 ) { renderstyle |= TTF_STYLE_STRIKETHROUGH; } else if ( strcmp(argv[i], "-outline") == 0 ) { if ( sscanf (argv[++i], "%d", &outline) != 1 ) { fprintf(stderr, Usage, argv0); return(1); } } else if ( strcmp(argv[i], "-hintlight") == 0 ) { hinting = TTF_HINTING_LIGHT; } else if ( strcmp(argv[i], "-hintmono") == 0 ) { hinting = TTF_HINTING_MONO; } else if ( strcmp(argv[i], "-hintnone") == 0 ) { hinting = TTF_HINTING_NONE; } else if ( strcmp(argv[i], "-nokerning") == 0 ) { kerning = 0; } else if ( strcmp(argv[i], "-dump") == 0 ) { dump = 1; } else if ( strcmp(argv[i], "-fgcol") == 0 ) { int r, g, b; if ( sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3 ) { fprintf(stderr, Usage, argv0); return(1); } forecol->r = (Uint8)r; forecol->g = (Uint8)g; forecol->b = (Uint8)b; } else if ( strcmp(argv[i], "-bgcol") == 0 ) { int r, g, b; if ( sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3 ) { fprintf(stderr, Usage, argv0); return(1); } backcol->r = (Uint8)r; backcol->g = (Uint8)g; backcol->b = (Uint8)b; } else { fprintf(stderr, Usage, argv0); return(1); } } argv += i; argc -= i; /* Check usage */ if ( ! argv[0] ) { fprintf(stderr, Usage, argv0); return(1); } /* Initialize SDL */ if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError()); return(2); } /* Initialize the TTF library */ if ( TTF_Init() < 0 ) { fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError()); SDL_Quit(); return(2); } /* Open the font file with the requested point size */ ptsize = 0; if ( argc > 1 ) { ptsize = atoi(argv[1]); } if ( ptsize == 0 ) { i = 2; ptsize = DEFAULT_PTSIZE; } else { i = 3; } font = TTF_OpenFont(argv[0], ptsize); if ( font == NULL ) { fprintf(stderr, "Couldn't load %d pt font from %s: %s\n", ptsize, argv[0], SDL_GetError()); cleanup(2); } TTF_SetFontStyle(font, renderstyle); TTF_SetFontOutline(font, outline); TTF_SetFontKerning(font, kerning); TTF_SetFontHinting(font, hinting); if( dump ) { for( i = 48; i < 123; i++ ) { SDL_Surface* glyph = NULL; glyph = TTF_RenderGlyph_Shaded( font, i, *forecol, *backcol ); if( glyph ) { char outname[64]; sprintf( outname, "glyph-%d.bmp", i ); SDL_SaveBMP( glyph, outname ); } } cleanup(0); } /* Set a 640x480x8 video mode */ screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE); if ( screen == NULL ) { fprintf(stderr, "Couldn't set 640x480x8 video mode: %s\n", SDL_GetError()); cleanup(2); } /* Set a palette that is good for the foreground colored text */ rdiff = backcol->r - forecol->r; gdiff = backcol->g - forecol->g; bdiff = backcol->b - forecol->b; for ( i=0; i<NUM_COLORS; ++i ) { colors[i].r = forecol->r + (i*rdiff)/4; colors[i].g = forecol->g + (i*gdiff)/4; colors[i].b = forecol->b + (i*bdiff)/4; } SDL_SetColors(screen, colors, 0, NUM_COLORS); /* Clear the background to background color */ SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, backcol->r, backcol->g, backcol->b)); SDL_UpdateRect(screen, 0, 0, 0, 0); /* Show which font file we're looking at */ sprintf(string, "Font file: %s", argv[0]); /* possible overflow */ if ( rendersolid ) { text = TTF_RenderText_Solid(font, string, *forecol); } else { text = TTF_RenderText_Shaded(font, string, *forecol, *backcol); } if ( text != NULL ) { dstrect.x = 4; dstrect.y = 4; dstrect.w = text->w; dstrect.h = text->h; SDL_BlitSurface(text, NULL, screen, &dstrect); SDL_FreeSurface(text); } /* Render and center the message */ if ( argc > 2 ) { message = argv[2]; } else { message = DEFAULT_TEXT; } switch (rendertype) { case RENDER_LATIN1: if ( rendersolid ) { text = TTF_RenderText_Solid(font,message,*forecol); } else { text = TTF_RenderText_Shaded(font,message,*forecol,*backcol); } break; case RENDER_UTF8: if ( rendersolid ) { text = TTF_RenderUTF8_Solid(font,message,*forecol); } else { text = TTF_RenderUTF8_Shaded(font,message,*forecol,*backcol); } break; case RENDER_UNICODE: { Uint16 unicode_text[BUFSIZ]; int index; #ifdef HAVE_ICONV /* Use iconv to convert the message into utf-16. * "char" and "" are aliases for the local 8-bit encoding */ iconv_t cd; /*ICONV_CONST*/ char *from_str = message; char *to_str = (char*)unicode_text; size_t from_sz = strlen(message) + 1; size_t to_sz = sizeof(unicode_text); size_t res; int i; if ((cd = iconv_open("UTF-16", "char")) == (iconv_t)-1 && (cd = iconv_open("UTF-16", "")) == (iconv_t)-1) { perror("Couldn't open iconv"); exit(1); } res = iconv(cd, &from_str, &from_sz, &to_str, &to_sz); if (res == -1) { perror("Couldn't use iconv"); exit(1); } iconv_close(cd); #else /* Convert the message from ascii into utf-16. * This is unreliable as a test because it always * gives the local ordering. */ for (index = 0; message[index]; index++) { unicode_text[index] = message[index]; } unicode_text[index] = 0; #endif if ( rendersolid ) { text = TTF_RenderUNICODE_Solid(font, unicode_text, *forecol); } else { text = TTF_RenderUNICODE_Shaded(font, unicode_text, *forecol, *backcol); } } break; default: text = NULL; /* This shouldn't happen */ break; } if ( text == NULL ) { fprintf(stderr, "Couldn't render text: %s\n", SDL_GetError()); TTF_CloseFont(font); cleanup(2); } dstrect.x = (screen->w - text->w)/2; dstrect.y = (screen->h - text->h)/2; dstrect.w = text->w; dstrect.h = text->h; printf("Font is generally %d big, and string is %hd big\n", TTF_FontHeight(font), text->h); /* Blit the text surface */ if ( SDL_BlitSurface(text, NULL, screen, &dstrect) < 0 ) { fprintf(stderr, "Couldn't blit text to display: %s\n", SDL_GetError()); TTF_CloseFont(font); cleanup(2); } SDL_UpdateRect(screen, 0, 0, 0, 0); /* Set the text colorkey and convert to display format */ if ( SDL_SetColorKey(text, SDL_SRCCOLORKEY|SDL_RLEACCEL, 0) < 0 ) { fprintf(stderr, "Warning: Couldn't set text colorkey: %s\n", SDL_GetError()); } temp = SDL_DisplayFormat(text); if ( temp != NULL ) { SDL_FreeSurface(text); text = temp; } /* Wait for a keystroke, and blit text on mouse press */ done = 0; while ( ! done ) { if ( SDL_WaitEvent(&event) < 0 ) { fprintf(stderr, "SDL_PullEvent() error: %s\n", SDL_GetError()); done = 1; continue; } switch (event.type) { case SDL_MOUSEBUTTONDOWN: dstrect.x = event.button.x - text->w/2; dstrect.y = event.button.y - text->h/2; dstrect.w = text->w; dstrect.h = text->h; if ( SDL_BlitSurface(text, NULL, screen, &dstrect) == 0 ) { SDL_UpdateRects(screen, 1, &dstrect); } else { fprintf(stderr, "Couldn't blit text to display: %s\n", SDL_GetError()); } break; case SDL_KEYDOWN: case SDL_QUIT: done = 1; break; default: break; } } SDL_FreeSurface(text); TTF_CloseFont(font); cleanup(0); /* Not reached, but fixes compiler warnings */ return 0; }
/** * @brief Creates the text surface. * * This function is called when there is a change. */ void TextSurface::rebuild() { if (surface != NULL) { // another text was previously set: delete it SDL_FreeSurface(surface->get_internal_surface()); delete surface; surface = NULL; } if (is_empty()) { // empty string: no surface to create return; } // create the text surface SDL_Surface *internal_surface = NULL; switch (rendering_mode) { case TEXT_SOLID: internal_surface = TTF_RenderUTF8_Solid(fonts[font_id].internal_font, text.c_str(), *text_color.get_internal_color()); break; case TEXT_SHADED: internal_surface = TTF_RenderUTF8_Shaded(fonts[font_id].internal_font, text.c_str(), *text_color.get_internal_color(), *background_color.get_internal_color()); break; case TEXT_BLENDED: internal_surface = TTF_RenderUTF8_Blended(fonts[font_id].internal_font, text.c_str(), *text_color.get_internal_color()); break; } Debug::check_assertion(internal_surface != NULL, StringConcat() << "Cannot create the text surface for string '" << text << "': " << SDL_GetError()); surface = new Surface(internal_surface); // calculate the coordinates of the top-left corner int x_left = 0, y_top = 0; switch (horizontal_alignment) { case ALIGN_LEFT: x_left = x; break; case ALIGN_CENTER: x_left = x - surface->get_width() / 2; break; case ALIGN_RIGHT: x_left = x - surface->get_width(); break; } switch (vertical_alignment) { case ALIGN_TOP: y_top = y; break; case ALIGN_MIDDLE: y_top = y - surface->get_height() / 2; break; case ALIGN_BOTTOM: y_top = y - surface->get_height(); break; } text_position.set_xy(x_left, y_top); }
static PyObject* font_render(PyObject* self, PyObject* args) { TTF_Font* font = PyFont_AsFont (self); int aa; PyObject* text, *final; PyObject* fg_rgba_obj, *bg_rgba_obj = NULL; Uint8 rgba[] = {0, 0, 0, 0}; SDL_Surface* surf; SDL_Color foreg, backg; int just_return; if (!PyArg_ParseTuple(args, "OiO|O", &text, &aa, &fg_rgba_obj, &bg_rgba_obj)) { return NULL; } if (!RGBAFromColorObj(fg_rgba_obj, rgba)) { return RAISE(PyExc_TypeError, "Invalid foreground RGBA argument"); } foreg.r = rgba[0]; foreg.g = rgba[1]; foreg.b = rgba[2]; foreg.unused = 0; if (bg_rgba_obj != NULL) { if (!RGBAFromColorObj(bg_rgba_obj, rgba)) { bg_rgba_obj = NULL; backg.r = 0; backg.g = 0; backg.b = 0; backg.unused = 0; } else { backg.r = rgba[0]; backg.g = rgba[1]; backg.b = rgba[2]; backg.unused = 0; } } else { backg.r = 0; backg.g = 0; backg.b = 0; backg.unused = 0; } just_return = PyObject_Not(text); if (just_return) { int height = TTF_FontHeight(font); if (just_return == -1 || !(PyUnicode_Check(text) || Bytes_Check(text) || text == Py_None)) { PyErr_Clear(); return RAISE_TEXT_TYPE_ERROR(); } surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, height, 32, 0xff<<16, 0xff<<8, 0xff, 0); if (surf == NULL) { return RAISE(PyExc_SDLError, SDL_GetError()); } if (bg_rgba_obj != NULL) { Uint32 c = SDL_MapRGB(surf->format, backg.r, backg.g, backg.b); SDL_FillRect(surf, NULL, c); } else { SDL_SetColorKey(surf, SDL_SRCCOLORKEY, 0); } } else if (PyUnicode_Check(text)) { PyObject *bytes = PyUnicode_AsEncodedString(text, "utf-8", "replace"); const char *astring = NULL; if (!bytes) { return NULL; } astring = Bytes_AsString(bytes); if (strlen(astring) != Bytes_GET_SIZE(bytes)) { Py_DECREF(bytes); return RAISE(PyExc_ValueError, "A null character was found in the text"); } if (utf_8_needs_UCS_4(astring)) { Py_DECREF(bytes); return RAISE(PyExc_UnicodeError, "A Unicode character above '\\uFFFF' was found;" " not supported"); } if (aa) { if (bg_rgba_obj == NULL) { surf = TTF_RenderUTF8_Blended(font, astring, foreg); } else { surf = TTF_RenderUTF8_Shaded(font, astring, foreg, backg); } } else { surf = TTF_RenderUTF8_Solid(font, astring, foreg); } Py_DECREF(bytes); } else if (Bytes_Check(text)) { const char *astring = Bytes_AsString(text); if (strlen(astring) != Bytes_GET_SIZE(text)) { return RAISE(PyExc_ValueError, "A null character was found in the text"); } if (aa) { if (bg_rgba_obj == NULL) { surf = TTF_RenderText_Blended(font, astring, foreg); } else { surf = TTF_RenderText_Shaded(font, astring, foreg, backg); } } else { surf = TTF_RenderText_Solid(font, astring, foreg); } } else { return RAISE_TEXT_TYPE_ERROR(); } if (surf == NULL) { return RAISE(PyExc_SDLError, TTF_GetError()); } if (!aa && (bg_rgba_obj != NULL) && !just_return) { /* turn off transparancy */ SDL_SetColorKey(surf, 0, 0); surf->format->palette->colors[0].r = backg.r; surf->format->palette->colors[0].g = backg.g; surf->format->palette->colors[0].b = backg.b; } final = PySurface_New(surf);
int main(int argc, char *argv[]) { char *argv0 = argv[0]; SDL_Window *window; SDL_Renderer *renderer; TTF_Font *font; SDL_Surface *text; Scene scene; int ptsize; int i, done; SDL_Color white = { 0xFF, 0xFF, 0xFF, 0 }; SDL_Color black = { 0x00, 0x00, 0x00, 0 }; SDL_Color *forecol; SDL_Color *backcol; SDL_Event event; int rendersolid; int renderstyle; int outline; int hinting; int kerning; int dump; enum { RENDER_LATIN1, RENDER_UTF8, RENDER_UNICODE } rendertype; char *message, string[128]; /* Look for special execution mode */ dump = 0; /* Look for special rendering types */ rendersolid = 0; renderstyle = TTF_STYLE_NORMAL; rendertype = RENDER_LATIN1; outline = 0; hinting = TTF_HINTING_NORMAL; kerning = 1; /* Default is black and white */ forecol = &black; backcol = &white; for ( i=1; argv[i] && argv[i][0] == '-'; ++i ) { if ( strcmp(argv[i], "-solid") == 0 ) { rendersolid = 1; } else if ( strcmp(argv[i], "-utf8") == 0 ) { rendertype = RENDER_UTF8; } else if ( strcmp(argv[i], "-unicode") == 0 ) { rendertype = RENDER_UNICODE; } else if ( strcmp(argv[i], "-b") == 0 ) { renderstyle |= TTF_STYLE_BOLD; } else if ( strcmp(argv[i], "-i") == 0 ) { renderstyle |= TTF_STYLE_ITALIC; } else if ( strcmp(argv[i], "-u") == 0 ) { renderstyle |= TTF_STYLE_UNDERLINE; } else if ( strcmp(argv[i], "-s") == 0 ) { renderstyle |= TTF_STYLE_STRIKETHROUGH; } else if ( strcmp(argv[i], "-outline") == 0 ) { if ( sscanf (argv[++i], "%d", &outline) != 1 ) { fprintf(stderr, Usage, argv0); return(1); } } else if ( strcmp(argv[i], "-hintlight") == 0 ) { hinting = TTF_HINTING_LIGHT; } else if ( strcmp(argv[i], "-hintmono") == 0 ) { hinting = TTF_HINTING_MONO; } else if ( strcmp(argv[i], "-hintnone") == 0 ) { hinting = TTF_HINTING_NONE; } else if ( strcmp(argv[i], "-nokerning") == 0 ) { kerning = 0; } else if ( strcmp(argv[i], "-dump") == 0 ) { dump = 1; } else if ( strcmp(argv[i], "-fgcol") == 0 ) { int r, g, b; if ( sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3 ) { fprintf(stderr, Usage, argv0); return(1); } forecol->r = (Uint8)r; forecol->g = (Uint8)g; forecol->b = (Uint8)b; } else if ( strcmp(argv[i], "-bgcol") == 0 ) { int r, g, b; if ( sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3 ) { fprintf(stderr, Usage, argv0); return(1); } backcol->r = (Uint8)r; backcol->g = (Uint8)g; backcol->b = (Uint8)b; } else { fprintf(stderr, Usage, argv0); return(1); } } argv += i; argc -= i; /* Check usage */ if ( ! argv[0] ) { fprintf(stderr, Usage, argv0); return(1); } /* Initialize the TTF library */ if ( TTF_Init() < 0 ) { fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError()); SDL_Quit(); return(2); } /* Open the font file with the requested point size */ ptsize = 0; if ( argc > 1 ) { ptsize = atoi(argv[1]); } if ( ptsize == 0 ) { i = 2; ptsize = DEFAULT_PTSIZE; } else { i = 3; } font = TTF_OpenFont(argv[0], ptsize); if ( font == NULL ) { fprintf(stderr, "Couldn't load %d pt font from %s: %s\n", ptsize, argv[0], SDL_GetError()); cleanup(2); } TTF_SetFontStyle(font, renderstyle); TTF_SetFontOutline(font, outline); TTF_SetFontKerning(font, kerning); TTF_SetFontHinting(font, hinting); if( dump ) { for( i = 48; i < 123; i++ ) { SDL_Surface* glyph = NULL; glyph = TTF_RenderGlyph_Shaded( font, i, *forecol, *backcol ); if( glyph ) { char outname[64]; sprintf( outname, "glyph-%d.bmp", i ); SDL_SaveBMP( glyph, outname ); } } cleanup(0); } /* Create a window */ if (SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, 0, &window, &renderer) < 0) { fprintf(stderr, "SDL_CreateWindowAndRenderer() failed: %s\n", SDL_GetError()); cleanup(2); } /* Show which font file we're looking at */ sprintf(string, "Font file: %s", argv[0]); /* possible overflow */ if ( rendersolid ) { text = TTF_RenderText_Solid(font, string, *forecol); } else { text = TTF_RenderText_Shaded(font, string, *forecol, *backcol); } if ( text != NULL ) { scene.captionRect.x = 4; scene.captionRect.y = 4; scene.captionRect.w = text->w; scene.captionRect.h = text->h; scene.caption = SDL_CreateTextureFromSurface(renderer, text); SDL_FreeSurface(text); } /* Render and center the message */ if ( argc > 2 ) { message = argv[2]; } else { message = DEFAULT_TEXT; } switch (rendertype) { case RENDER_LATIN1: if ( rendersolid ) { text = TTF_RenderText_Solid(font,message,*forecol); } else { text = TTF_RenderText_Shaded(font,message,*forecol,*backcol); } break; case RENDER_UTF8: if ( rendersolid ) { text = TTF_RenderUTF8_Solid(font,message,*forecol); } else { text = TTF_RenderUTF8_Shaded(font,message,*forecol,*backcol); } break; case RENDER_UNICODE: { Uint16 *unicode_text = SDL_iconv_utf8_ucs2(message); if ( rendersolid ) { text = TTF_RenderUNICODE_Solid(font, unicode_text, *forecol); } else { text = TTF_RenderUNICODE_Shaded(font, unicode_text, *forecol, *backcol); } SDL_free(unicode_text); } break; default: text = NULL; /* This shouldn't happen */ break; } if ( text == NULL ) { fprintf(stderr, "Couldn't render text: %s\n", SDL_GetError()); TTF_CloseFont(font); cleanup(2); } scene.messageRect.x = (WIDTH - text->w)/2; scene.messageRect.y = (HEIGHT - text->h)/2; scene.messageRect.w = text->w; scene.messageRect.h = text->h; scene.message = SDL_CreateTextureFromSurface(renderer, text); printf("Font is generally %d big, and string is %d big\n", TTF_FontHeight(font), text->h); draw_scene(renderer, &scene); /* Wait for a keystroke, and blit text on mouse press */ done = 0; while ( ! done ) { if ( SDL_WaitEvent(&event) < 0 ) { fprintf(stderr, "SDL_PullEvent() error: %s\n", SDL_GetError()); done = 1; continue; } switch (event.type) { case SDL_MOUSEBUTTONDOWN: scene.messageRect.x = event.button.x - text->w/2; scene.messageRect.y = event.button.y - text->h/2; scene.messageRect.w = text->w; scene.messageRect.h = text->h; draw_scene(renderer, &scene); break; case SDL_KEYDOWN: case SDL_QUIT: done = 1; break; default: break; } } SDL_FreeSurface(text); TTF_CloseFont(font); SDL_DestroyTexture(scene.caption); SDL_DestroyTexture(scene.message); cleanup(0); /* Not reached, but fixes compiler warnings */ return 0; }
// WARNING: // This function contains an unusual amount of raw pointers, and is // the most C-like function you can get without being C++. // Sorry Joshua. void Text::render() { int width = this->width; int height = this->height; std::pair<int,int> window_size = window->get_window_size(); // Automatic sizing if dimension is 0. if (width == 0) { switch (alignment_h) { default: case Alignment::LEFT: width = window_size.first - this->x; break; case Alignment::CENTRE: width = ((window_size.first / 2) < this->x) ? this->x : window_size.first - this->x; break; case Alignment::RIGHT: width = this->x; break; } } if (height == 0) { switch (alignment_v) { default: case Alignment::TOP: height = this->y; break; case Alignment::CENTRE: height = ((window_size.second / 2) < this->y) ? window_size.second - this->y : this->y; break; case Alignment::BOTTOM: height = window_size.second - this->y; break; } } // If they are still zero, don't continue. if (width == 0 || height == 0) { throw Text::RenderException("Invalid dimensions after auto-sizing."); } int available_width = width; // It took a whole day to discover that there was a bug in // SDL_ttf. Starting with certain characters on certain // fonts seems to break it. :( // As a hack, prepend and (for balance) append a space. int border; TTF_SizeUTF8(font.font, " ", &border, NULL); border *= 2; // If they are still zero, don't continue. if (available_width <= 0) { throw Text::RenderException("No available width for rendering text."); } int line_height = TTF_FontHeight(font.font); int line_number = 0; int lost_lines = 0; int used_width = 0; int length = (int)text.length(); // Entire text. const char* ctext = text.c_str(); // Line of text. char* line = new char[length+1]; // Null-terminator separated lines of text. // The worst case is a character per line, so we need to do // 2 * length (character, null, character, null, ...). char* lines = new char[2*length+1]; // Pointer to within lines. char* lines_scan = lines; // Text indexing. for (int t = 0; t < length; t++) { int line_width = 0; // Word indexing. int w = 0; // Stores (from the beginning) a word in ctext (copy). line[0] = '\0'; // Points to the end of the last successfully fitting word in // line. int ll = 0; // Line indexing. for (int l = t; l < length; l++) { // Find word end. for (w = l; w < length && (ctext[w] != ' ' && ctext[w] != '\n'); w++) { // As we are dealing with UTF-8, we must make sure to // copy an entire character if it is more than one byte. // The bit formats of UTF-8 characters are: // 0xxxxxxx // 110xxxxx 10xxxxxx // 1110xxxx 10xxxxxx 10xxxxxx // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // // ... Well, actually it's not THAT simple, because // there are these magical characters which modify other // characters... But it's not worth the effort. if (ctext[l] & 0x80) { // The number of bits in the first byte set to 1 // before the first zero indicate the total number // of bytes to use for the UTF-8 character. for (int bits = ctext[w] << 1; w < length && (bits & 0x80); w++, bits <<= 1); } } // Copy word into line. for (; l < w; l++) { line[l - t] = ctext[l]; } line[l - t] = '\0'; // Test line length. TTF_SizeUTF8(font.font, line, &line_width, NULL); // Part of SDL_ttf bug workaround. line_width+=border; if (line_width <= available_width) { if (line_width > used_width) { used_width = line_width; } // Mark current position as valid. ll = l - t; // If this is the end of a line, or whole text, stop. if (ctext[w] == '\n' || ctext[w] == '\0') { t = l; // Note the string is already null terminated. break; } else { // Replace null terminator with word separator. line[ll] = ctext[w]; } } else { if (ll > 0) { // There are some fittable words. // As the line overflows with the current l, set the // text index to the last fit. t += ll; } else { // There are no separators to break on. // We're going to have to cut a word in half. // Swapped-out character char c; int left = 0; int right = l - t; // Search index within line. int ls; ll = 0; for (ls = (right + left) / 2; ls != ll; ls = (right + left) / 2) { ll = ls; c = line[ls]; line[ls] = 0; TTF_SizeUTF8(font.font, line, &line_width, NULL); // Part of SDL_ttf bug workaround. line_width+=border; if (line_width <= available_width) { if (line_width > used_width) { used_width = line_width; } left = ls; } else { right = ls; } line[ls] = c; } // Don't skip the non-separating character. t += ll - 1; } // Null terminate for rendering. line[ll] = '\0'; break; } } // Copy the line into lines (using lines_scan). int i; for (i = 0; line[i] != '\0'; ++i) { lines_scan[i] = line[i]; } lines_scan[i] = '\0'; lines_scan = &lines_scan[i+1]; ++line_number; if (line[0] == '\0') { // Check that we aren't going to chase our tailes trying to fit an unfittable character. if (ctext[w] != '\n') { LOG(WARNING) << "Cannot render text: character too large."; delete[] line; delete[] lines; throw Text::RenderException("A character is too large"); } else { // It's a blank line. continue; } } } int line_count = line_number; int used_height = line_count * line_height; used_width += border; image = Image(used_width, (used_height < height) ? used_height : height, true); uint8_t clear_colour[4] = {rgba[0], rgba[1], rgba[2], 0x00}; uint8_t clear_mask[4] = {0xff, 0xff, 0xff, 0xff}; image.clear(clear_colour, clear_mask); // image.clear(0xffffff00, 0xffffffff); // Render all lines of text. SDL_Color blank; blank.r = blank.g = blank.b = blank.a = 0; SDL_Color colour; colour.r = rgba[0]; colour.g = rgba[1]; colour.b = rgba[2]; colour.a = rgba[3]; lines_scan = lines; for (int line_number = 0; line_number < line_count; ++line_number) { // Render line VLOG(2) << "Rendering line of text: \"" << lines_scan << "\"."; if (lines_scan[0] == '\0') { // Skip it - it's a new line. lines_scan = &lines_scan[1]; continue; } SDL_Surface* rendered_line; { // It took a whole day to discover that there was a bug in // SDL_ttf. Starting with certain characters on certain // fonts seems to break it. :( // As a hack, prepend and (for balance) append a space. std::stringstream safe; safe << " " << lines_scan << " "; std::string safe_str(safe.str()); if (smooth) { rendered_line = TTF_RenderUTF8_Shaded(font.font, safe_str.c_str(), colour, blank); } else { rendered_line = TTF_RenderUTF8_Solid(font.font, safe_str.c_str(), colour); } } if (rendered_line == nullptr) { LOG(WARNING) << "Cannot render line of text: \"" << lines_scan << "\"."; delete[] line; delete[] lines; throw Text::RenderException("Cannot render line of text"); } #ifdef TEXT_SAFE_SURFACE // This surface has a known format. SDL_Surface* compatible = SDL_CreateRGBSurface(0, // Unsed rendered_line->w, rendered_line->h, 32, 0x00, 0x00, 0x00, 0xff ); SDL_FillRect(compatible, NULL, 0); SDL_SetSurfaceBlendMode(rendered_line, SDL_BLENDMODE_NONE); SDL_BlitSurface(rendered_line, NULL, compatible, NULL); SDL_LockSurface(compatible); // pitch is in bytes, not pixels. RGBA = 4 bytes. int jump = compatible->pitch / 4; #else SDL_LockSurface(rendered_line); int jump = rendered_line->pitch; #endif // "What is this pointless copy?" you might ask. // Well, it is a suggestion to the c++ compiler that smooth // will not change throughout this function, so it can // optimise the if containing _smooth out of the for loop // entirely, rather than checking it every single iteration. int _smooth = smooth; int x_offset; int y_offset; switch (alignment_h) { default: case Alignment::LEFT: x_offset = 0; break; case Alignment::CENTRE: x_offset = (used_width - rendered_line->w) / 2; break; case Alignment::RIGHT: x_offset = used_width - rendered_line->w; break; } switch (alignment_v) { default: case Alignment::TOP: y_offset = line_number * line_height; break; case Alignment::CENTRE: y_offset = line_number * line_height - (used_height - image.height) / 2; break; case Alignment::BOTTOM: y_offset = line_number * line_height - (used_height - image.height); break; } // x surface int xs; // y surface int ys; for (ys = 0; ys < rendered_line->h; ++ys) { int yi = ys + y_offset; if (yi >= image.height) { lost_lines++; break; } else if (yi < 0) { continue; } int begin_xs((x_offset >= 0) ? 0 : -x_offset); int end_xs((rendered_line->w < image.width - x_offset) ? rendered_line->w : image.width - x_offset); for (xs = begin_xs; xs < end_xs; ++xs) { #ifdef TEXT_SAFE_SURFACE image.flipped_pixels[yi][xs + x_offset].a = (((Uint32*)compatible->pixels)[(ys*jump + xs)]); #else if (_smooth) { image.flipped_pixels[yi][xs + x_offset].a = (((Uint8*)rendered_line->pixels)[(ys*jump + xs)]); } else { image.flipped_pixels[yi][xs + x_offset].a = (((Uint8*)rendered_line->pixels)[(ys*jump + xs)]) ? 255 : 0; } #endif } } #ifdef TEXT_SAFE_SURFACE SDL_UnlockSurface(compatible); SDL_FreeSurface(compatible); #else SDL_UnlockSurface(rendered_line); #endif SDL_FreeSurface(rendered_line); if (ys < line_height) { LOG(WARNING) << "Text overflow."; break; } // Set lines_scan to start next line while (lines_scan[0] != '\0') { lines_scan = &lines_scan[1]; } lines_scan = &lines_scan[1]; } this->used_width = used_width; this->used_height = used_height; delete[] line; delete[] lines; generate_texture(); dirty_texture = false; dirty_vbo = true; }
SDL_Surface* SimKit::TTFVFont::render_font(const std::string txt, const SDL_Color textcol, const SDL_Color bg) { return TTF_RenderUTF8_Shaded(this->rfont, txt.c_str(), textcol, bg); };