void SDL_GL_RenderText(char *text, TTF_Font *font, SDL_Color color, SDL_Rect *location) { SDL_Surface *initial; SDL_Surface *intermediary; int w,h; GLuint texture; /* Use SDL_TTF to render our text */ initial = TTF_RenderText_Blended(font, text, color); /* Convert the rendered text to a known format */ w = nextpoweroftwo(initial->w); h = nextpoweroftwo(initial->h); intermediary = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); SDL_BlitSurface(initial, 0, intermediary, 0); /* Tell GL about our new texture */ glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, intermediary->pixels ); /* GL_NEAREST looks horrible, if scaled... */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* prepare to render our texture */ glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glColor3f(1.0f, 1.0f, 1.0f); /* Draw a quad at location */ glBegin(GL_QUADS); /* Recall that the origin is in the lower-left corner That is why the TexCoords specify different corners than the Vertex coors seem to. */ glTexCoord2f(0.0f, 1.0f); glVertex2f(location->x , location->y); glTexCoord2f(1.0f, 1.0f); glVertex2f(location->x + w, location->y); glTexCoord2f(1.0f, 0.0f); glVertex2f(location->x + w, location->y + h); glTexCoord2f(0.0f, 0.0f); glVertex2f(location->x , location->y + h); glEnd(); /* Bad things happen if we delete the texture before it finishes */ glFinish(); /* return the deltas in the unused w,h part of the rect */ location->w = initial->w; location->h = initial->h; /* Clean up */ SDL_FreeSurface(initial); SDL_FreeSurface(intermediary); glDeleteTextures(1, &texture); }
GLuint SDL_GL_MakeTextTexture(const char *text, TTF_Font *font, SDL_Color color, SDL_Rect &offset) { GLuint texture; glGenTextures(1, &texture); glLoadIdentity(); SDL_Surface *initial; SDL_Surface *intermediary; initial = TTF_RenderText_Blended(font, text, color); SDL_SetAlpha(initial, 0, 0); offset.w = nextpoweroftwo(initial->w); offset.h = nextpoweroftwo(initial->h); intermediary = SDL_CreateRGBSurface(SDL_SWSURFACE, offset.w, offset.h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); SDL_BlitSurface(initial, 0, intermediary, 0); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, offset.w, offset.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, intermediary->pixels ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); SDL_FreeSurface(initial); SDL_FreeSurface(intermediary); return texture; }
void SDL_GL_RenderText(const char *text, TTF_Font *font, SDL_Color color, SDL_Rect *location) { glLoadIdentity(); SDL_Surface *initial; SDL_Surface *intermediary; GLuint font_texture; initial = TTF_RenderText_Blended(font, text, color); SDL_SetAlpha(initial, 0, 0); location->w = nextpoweroftwo(initial->w); location->h = nextpoweroftwo(initial->h); intermediary = SDL_CreateRGBSurface(SDL_SWSURFACE, location->w, location->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); SDL_BlitSurface(initial, 0, intermediary, 0); glGenTextures(1, &font_texture); glBindTexture(GL_TEXTURE_2D, font_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, location->w, location->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, intermediary->pixels ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, font_texture); glColor3f(1,1,1); glBegin(GL_QUADS); // Top-left vertex (corner) glTexCoord2d(0, 0); glVertex3f(location->x, location->y, 0); // Bottom-left vertex (corner) glTexCoord2d(1, 0); glVertex3f(location->x + intermediary->w, location->y, 0); // Bottom-right vertex (corner) glTexCoord2d(1, 1); glVertex3f(location->x + intermediary->w, location->y + intermediary->h, 0); // Top-right vertex (corner) glTexCoord2d(0, 1); glVertex3f(location->x, location->y + intermediary->h, 0); glEnd(); glFinish(); SDL_FreeSurface(initial); SDL_FreeSurface(intermediary); glDeleteTextures(1, &font_texture); }
// // Create a texture from a surface. Set the alpha according to the color key. // Pixels that match the color key get an alpha of zero while all other pixels // get an alpha of one. We use black for the color key. // GLuint ttf_set_color_key (SDL_Surface *glyph_surface, GLfloat *texcoord, uint8 ckr, uint8 ckg, uint8 ckb) { SDL_Surface *tmp; uint32 colorkey; GLuint texture; SDL_Rect area; // // Use the surface width and height expanded to powers of 2 // int width = nextpoweroftwo(glyph_surface->w); int height = nextpoweroftwo(glyph_surface->h); texcoord[0] = 0; // Min X texcoord[1] = 0; // Min Y texcoord[2] = (GLfloat)(((float)glyph_surface->w) / ((float)width)); // Max X texcoord[3] = (GLfloat)(((float)glyph_surface->h) / ((float)height)); // Max Y tmp = SDL_CreateRGBSurface(glyph_surface->flags, width, height, glyph_surface->format->BitsPerPixel, #if SDL_BYTEORDER == SDL_LIL_ENDIAN // OpenGL RGBA masks 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 #else 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF #endif ); if (!tmp) { ERR("Failed to make RGB surface"); return (0); } // // Set up so that colorkey pixels become transparent // colorkey = SDL_MapRGBA(tmp->format, 0, 0, 0, 0); SDL_FillRect(tmp, NULL, colorkey); colorkey = SDL_MapRGBA(glyph_surface->format, ckr, ckg, ckb, 0); SDL_SetColorKey(glyph_surface, SDL_SRCCOLORKEY, colorkey); // // Copy the surface into the GL texture image // area.x = 0; area.y = 0; area.w = glyph_surface->w; area.h = glyph_surface->h; SDL_BlitSurface(glyph_surface, &area, tmp, &area); // // Create an OpenGL texture for the tmp // glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmp->pixels); SDL_FreeSurface(tmp); return (texture); }
void SDL_GL_RenderTextCyrillic(char *text, int fontId, SDL_Color color, SDL_Rect *location) { SDL_Surface *initial; SDL_Surface *intermediary; int w,h; GLuint texture; TTF_Font *fnt = NULL; switch (fontId) { case 12: fnt = fnt_12pt; break; case 16: fnt = fnt_16pt; break; case 24: fnt = fnt_24pt; break; case 32: fnt = fnt_32pt; break; case 42: fnt = fnt_42pt; break; default: fnt = fnt_16pt; break; } wchar_t *utext = MultiCharToUniChar(text); /* Use SDL_TTF to render our text */ Uint16* stext = new Uint16[strlen(text)+1]; for (size_t i = 0; i < strlen(text); ++i) { stext[i] = utext[i]; } stext[strlen(text)] = 0; initial = TTF_RenderUNICODE_Blended(fnt,stext,color); delete[] stext; /* Convert the rendered text to a known format */ w = nextpoweroftwo(initial->w); h = nextpoweroftwo(initial->h); intermediary = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); SDL_BlitSurface(initial, 0, intermediary, 0); /* Tell GL about our new texture */ glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, intermediary->pixels ); /* GL_NEAREST looks horrible, if scaled... */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* prepare to render our texture */ glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); glColor3f(1.0f, 1.0f, 1.0f); /* Draw a quad at location */ glBegin(GL_QUADS); glTexCoord2f(0.0f, 1.0f); glVertex2f(location->x , location->y); glTexCoord2f(1.0f, 1.0f); glVertex2f((float)(location->x + w), location->y); glTexCoord2f(1.0f, 0.0f); glVertex2f((float)(location->x + w), (float)(location->y - h)); glTexCoord2f(0.0f, 0.0f); glVertex2f(location->x , (float)(location->y - h)); glEnd(); /* Clean up */ SDL_FreeSurface(initial); SDL_FreeSurface(intermediary); glDeleteTextures(1, &texture); }
void SDL_GL_RenderText(char *text, int fontId, SDL_Color color, SDL_Rect *location) { SDL_Surface *initial; SDL_Surface *intermediary; int w,h; GLuint texture; TTF_Font *fnt = NULL; switch (fontId) { case 12: fnt = fnt_12pt; break; case 16: fnt = fnt_16pt; break; case 24: fnt = fnt_24pt; break; case 32: fnt = fnt_32pt; break; case 42: fnt = fnt_42pt; break; default: fnt = fnt_16pt; break; } initial = TTF_RenderText_Blended(fnt,text,color); /* Convert the rendered text to a known format */ w = nextpoweroftwo(initial->w); h = nextpoweroftwo(initial->h); intermediary = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); SDL_BlitSurface(initial, 0, intermediary, 0); /* Tell GL about our new texture */ glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, intermediary->pixels ); /* GL_NEAREST looks horrible, if scaled... */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* prepare to render our texture */ glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); glColor3f(1.0f, 1.0f, 1.0f); /* Draw a quad at location */ glBegin(GL_QUADS); /* Recall that the origin is in the lower-left corner That is why the TexCoords specify different corners than the Vertex coors seem to. */ glTexCoord2f(0.0f, 1.0f); glVertex2f(location->x , location->y); glTexCoord2f(1.0f, 1.0f); glVertex2f((float)(location->x + w), location->y); glTexCoord2f(1.0f, 0.0f); glVertex2f((float)(location->x + w), (float)(location->y - h)); glTexCoord2f(0.0f, 0.0f); glVertex2f(location->x , (float)(location->y - h)); glEnd(); /* Bad things happen if we delete the texture before it finishes */ // glFinish(); /* return the deltas in the unused w,h part of the rect */ // location->w = initial->w; // location->h = initial->h; SDL_FreeSurface(initial); SDL_FreeSurface(intermediary); glDeleteTextures(1, &texture); }
font * ttf_write_tga (char *name, int32_t pointsize) { uint32_t rmask, gmask, bmask, amask; double glyph_per_row; char filename[200]; SDL_Surface *dst; uint32_t height; uint32_t width; double maxx; double maxy[TTF_GLYPH_MAX]; uint32_t c; int x; int y; double h; font *f; snprintf(filename, sizeof(filename), "%s_pointsize%u.tga", name, pointsize); if (tex_find(filename)) { return (0); } /* * x glyphs horizontally and y vertically. */ glyph_per_row = 16; f = ttf_new(name, pointsize, TTF_STYLE_NORMAL); if (!f) { ERR("could not create font %s", name); } maxx = 0; memset(maxy, 0, sizeof(maxy)); /* * Find the largest font glyph pointsize. */ x = 0; y = 0; height = 0; for (c = TTF_GLYPH_MIN; c < TTF_GLYPH_MAX; c++) { if (f->tex[c].image) { maxx = max(maxx, f->tex[c].image->w); maxy[y] = max(maxy[y], f->tex[c].image->h); } if (++x >= glyph_per_row) { x = 0; height += maxy[y]; y++; } } if (!maxx) { ERR("no glyphs in font %s", name); } width = glyph_per_row * maxx; if (MULTIPLE_BITS(width)) { width = nextpoweroftwo(width); } height += 40; if (MULTIPLE_BITS(height)) { height = nextpoweroftwo(height); } /* * Make a large surface for all glyphs. */ #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif dst = SDL_CreateRGBSurface(0, width, height, 32, rmask, gmask, bmask, amask); if (!dst) { ERR("no surface created for size %dx%d font %s", width, height, name); } newptr(dst, "SDL_CreateRGBSurface"); /* * Blit each glyph to the large surface. */ x = 0; y = 0; h = 0; for (c = TTF_GLYPH_MIN; c < TTF_GLYPH_MAX; c++) { if (f->tex[c].image) { SDL_Rect dstrect = { maxx * x, h, maxx, maxy[y] }; SDL_BlitSurface(f->tex[c].image, 0, dst, &dstrect); } if (++x >= glyph_per_row) { x = 0; h += maxy[y]; y++; } } /* * Convert the black border smoothing that ttf adds into alpha. */ { double x; double y; for (x = 0; x < dst->w; x++) { for (y = 0; y < dst->h; y++) { color c; c = getPixel(dst, x, y); if ((c.a == 255) && (c.r == 255) && (c.g == 255) && (c.b == 255)) { /* * Do nothing. */ } else if ((c.a == 0) && (c.r == 0) && (c.g == 0) && (c.b == 0)) { /* * Do nothing. */ } else { /* * Convery gray to white with alpha. */ c.a = (c.r + c.g + c.b) / 3; c.r = 255; c.g = 255; c.b = 255; } putPixel(dst, x, y, c); } } } #define MAX_TEXTURE_HEIGHT 4096 if (dst->h > MAX_TEXTURE_HEIGHT) { ERR("ttf is too large"); } uint8_t filled_pixel_row[MAX_TEXTURE_HEIGHT] = {0}; /* * What the hell am I doing here? The ttf library returns incorrect * boounds for the top and bottom of glyphs, so I'm looking for a line of * no pixels above and below each glyph so I can really find the texture * bounds of a glyph. This allows squeezing of text together. */ { int x; int y; for (y = 0; y < dst->h; y++) { for (x = 0; x < dst->w; x++) { color c; c = getPixel(dst, x, y); if (c.r || c.g || c.b || c.a) { filled_pixel_row[y] = true; break; } } } } /* * Work our the tex co-ords for each glyph in the large tex. */ x = 0; y = 0; h = 0; int d1_max = 0; int d2_max = 0; for (c = TTF_GLYPH_MIN; c < TTF_GLYPH_MAX; c++) { { int y = (h + (h + f->glyphs[c].height)) / 2; int miny = y; int maxy = y; for (;;) { if (!filled_pixel_row[miny]) { break; } miny--; if (miny <= 0) { break; } } for (;;) { if (!filled_pixel_row[maxy]) { break; } maxy++; if (maxy >= MAX_TEXTURE_HEIGHT - 1) { break; } } int d1 = y - miny; if (d1 > d1_max) { d1_max = d1; } int d2 = maxy - y; if (d2 > d2_max) { d2_max = d2; } } if (++x >= glyph_per_row) { x = 0; h += maxy[y]; y++; } } x = 0; y = 0; h = 0; for (c = TTF_GLYPH_MIN; c < TTF_GLYPH_MAX; c++) { f->glyphs[c].texMinX = (double)(x * maxx) / (double)dst->w; f->glyphs[c].texMaxX = (double)((x * maxx) + f->glyphs[c].width) / (double)dst->w; { int y = (h + (h + f->glyphs[c].height)) / 2; int y1 = y - d1_max; int y2 = y + d2_max; if (y1 < 0) { y1 = 0; } f->glyphs[c].texMinY = (double)(y1) / (double)dst->h; f->glyphs[c].texMaxY = (double)(y2) / (double)dst->h; } if (++x >= glyph_per_row) { x = 0; h += maxy[y]; y++; } } SDL_LockSurface(dst); stbi_write_tga(filename, dst->w, dst->h, STBI_rgb_alpha, dst->pixels); SDL_UnlockSurface(dst); texp tex; tex = tex_from_surface(dst, filename, filename); if (!tex) { ERR("could not convert %s to tex", filename); } /* * Work our the tex co-ords for each glyph in the large tex. */ x = 0; y = 0; h = 0; for (c = TTF_GLYPH_MIN; c < TTF_GLYPH_MAX; c++) { f->tex[c].image = dst; f->tex[c].tex = tex_get_gl_binding(tex); } /* * Save the glyph data. */ snprintf(filename, sizeof(filename), "%s_pointsize%u.data", name, pointsize); FILE *out = fopen(filename, "w"); fwrite(f->glyphs, sizeof(f->glyphs), 1, out); fclose(out); printf("wrote %s\n",filename); return (f); }