#include #include #include #include "render.h" #include "Text.h" #include "report.h" #include "opengl.h" // TODO: convert Text to use Glyphs struct Text *newText(TTF_Font *font, const char *string) { if (font == NULL) { report(ERROR, "newText", "passed font is NULL"); return NULL; } if (string == NULL) { report(ERROR, "newText", "passed string is NULL"); return NULL; } struct Text *text = malloc(sizeof(struct Text)); if (text == NULL) { report(ERROR, "newText", "could not malloc Text!"); return NULL; } text->font = font; int size = strlen(string)+1; text->string = malloc(sizeof(char)*size); if (text->string == NULL) { report(ERROR, "newText", "could not malloc string %s", string); free(text); return NULL; } memcpy(text->string, string, size); text->color.r = 55; text->color.g = 55; text->color.b = 55; text->color.a = 55; text->width = 0; text->height = 0; text->texture = 0; updateText(text); return text; } int freeText(struct Text *text) { glDeleteTextures(1, &text->texture); free(text->string); free(text); return 0; } int changeText(struct Text *text, const char *string, ...) { char buf[32]; // hmm char *buffer; int overflow; va_list args; free(text->string); buffer = buf; va_start(args, string); overflow = vsnprintf(buf, 32, string, args); va_end(args); // did we overflow? if (overflow >= 32) { buffer = (char*)malloc(overflow+1); va_start(args, string); overflow = vsnprintf(buffer, overflow+1, string, args); va_end(args); } text->string = malloc(overflow+1); memcpy(text->string, buffer, overflow+1); // if we did overflow, free here if (buffer != buf) { free(buffer); } updateText(text); return 0; } int setTextColor(struct Text *text, SDL_Color color) { text->color = color; return(updateText(text)); } int updateText(struct Text *text) { if (text == NULL) { report(ERROR, "updateText", "passed Text is NULL"); return 1; } if (text->string == NULL) { report(ERROR, "updateText", "string is NULL"); return 1; } if (text->font == NULL) { report(ERROR, "updateText", "font is NULL"); return 1; } SDL_Surface *surface = TTF_RenderText_Blended(text->font, text->string, text->color); if (surface == NULL) { report(ERROR, "updateText", "%s", TTF_GetError()); return 1; } text->width = surface->w; text->height = surface->h; // delete old texture if (text->texture != -1) { glDeleteTextures(1, &text->texture); } text->texture = createTexture(surface); SDL_FreeSurface(surface); return 0; } int renderText(struct Text *text, int x, int y) { if (text == NULL) return 1; renderTexture(text->texture, x - text->width/2, y - text->height/2, text->width, text->height); return 0; } int renderString(TTF_Font *font, SDL_Color color, const char *string, int x, int y) { if (font == NULL) return 1; if (string == NULL) return 2; SDL_Surface *surface = TTF_RenderText_Blended(font, string, color); if (surface == NULL) { report(ERROR, "renderString", "%s", TTF_GetError()); return 3; } GLuint texture = createTexture(surface); renderTexture(texture, x, y, surface->w, surface->h); glDeleteTextures(1, &texture); SDL_FreeSurface(surface); return 0; } int renderGlyphString(struct Glyphs *glyphs, SDL_Color color, int x, int y, const char *string) { if (glyphs == NULL) return 1; char ch; int i = 0; glLoadIdentity(); // colors float r = color.r / 255.0f; float g = color.g / 255.0f; float b = color.b / 255.0f; glColor3f(r, g, b); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBindTexture(GL_TEXTURE_2D, glyphs->texture); glTranslated(x, y, 0.0f); while((ch = string[i++]) != '\0') { if (ch < 32 || ch > 127) continue; int gw = glyphs->ch_w[ch-32]; int gh = glyphs->ch_h[ch-32]; float f_gw = (float)gw / (float)glyphs->w; float f_gh = (float)gh / (float)glyphs->h; float gx = ((float)glyphs->offsetx[ch-32] / (float)glyphs->w); float gy = 0.0f; glBegin(GL_QUADS); glTexCoord2d(gx, gy); glVertex2f(0.0f, 0.0f); glTexCoord2d(gx+f_gw, gy); glVertex2f(gw, 0.0f); glTexCoord2d(gx+f_gw, gy+f_gh); glVertex2f(gw, gh); glTexCoord2d(gx, gy+f_gh); glVertex2f(0, gh); glEnd(); glTranslated(gw, 0.0f, 0.0f); } return 0; } int renderGlyphStringF(struct Glyphs *glyphs, SDL_Color color, int x, int y, const char *string, ...) { char buf[128]; char *buffer; int overflow; va_list args; buffer = buf; va_start(args, string); overflow = vsnprintf(buffer, 128, string, args); va_end(args); // did we overflow? if (overflow >= 128) { buffer = (char*)malloc(overflow+1); va_start(args, string); overflow = vsnprintf(buffer, overflow+1, string, args); va_end(args); } renderGlyphString(glyphs, color, x, y, buffer); if (buffer != buf) { free(buffer); } return 0; } int renderGlyph(struct Glyphs *glyphs, SDL_Color color, char ch, int x, int y) { if (glyphs == NULL) return 1; if (ch < 32 || ch > 127) return 2; int gw = glyphs->ch_w[ch-32]; int gh = glyphs->ch_h[ch-32]; float gx = ((float)glyphs->offsetx[ch-32] / (float)glyphs->w); float gy = 0.0f; // colors float r = color.r / 255.0f; float g = color.g / 255.0f; float b = color.b / 255.0f; glColor3f(r, g, b); glLoadIdentity(); glBindTexture(GL_TEXTURE_2D, glyphs->texture); glTranslated(x, y, 0.0f); glBegin(GL_QUADS); glTexCoord2d(gx, gy); glVertex2f(0.0f, 0.0f); glTexCoord2d(gx+((float)gw / (float)glyphs->w), gy); glVertex2f(gw, 0.0f); glTexCoord2d(gx+((float)gw / (float)glyphs->w), gy+((float)gh / (float)glyphs->h)); glVertex2f(gw, gh); glTexCoord2d(gx, gy+((float)gh / (float)glyphs->h)); glVertex2f(0.0f, gh); glEnd(); return 0; } int getGlyphStringW(struct Glyphs *glyphs, const char *string) { if (glyphs == NULL) return -1; if (string == NULL) return -2; int ch; int i = 0; int width = 0; while ((ch = string[i++]) != '\0') { if (ch < 32 || ch > 127) continue; width += glyphs->ch_w[ch-32]; } return width; } int loadGlyphs(struct Glyphs *glyphs, TTF_Font *font) { if (glyphs == NULL) return 1; if (font == NULL) return 2; int ch_start = 32; int ch_end = 127; SDL_Color color = {255, 255, 255}; SDL_Surface *glyph_surfaces[ch_end-ch_start]; Uint16 ch; int texture_width = 0; int texture_height = 0; for (ch = ch_start; ch < ch_end; ++ch) { //printf("glyph: %c(%d)\n", ch, ch); if (TTF_GlyphMetrics(font, ch, &glyphs->minx[ch-ch_start], &glyphs->maxx[ch-ch_start], &glyphs->miny[ch-ch_start], &glyphs->maxy[ch-ch_start], &glyphs->advance[ch-ch_start]) == -1) { report(ERROR, "loadGlyphs", "couldn't get %c's GlyphMetrics: %s", ch, TTF_GetError()); } glyph_surfaces[ch-ch_start] = TTF_RenderGlyph_Blended(font, ch, color); if (glyph_surfaces[ch-ch_start] == NULL) { report(ERROR, "loadGlyphs", "could not create surface for %c: %s", ch, TTF_GetError()); // TODO: free glyphs up until now } //printf("\t minx:%d,maxx:%d,miny:%d,maxy:%d,w:%d,h:%d\n", glyphs->minx[ch-ch_start], glyphs->maxx[ch-ch_start], glyphs->miny[ch-ch_start], glyphs->maxy[ch-ch_start], glyph_surfaces[ch-ch_start]->w, glyph_surfaces[ch-ch_start]->h); glyphs->ch_w[ch-ch_start] = glyph_surfaces[ch-ch_start]->w; glyphs->ch_h[ch-ch_start] = glyph_surfaces[ch-ch_start]->h; texture_width += glyph_surfaces[ch-ch_start]->w; if (glyph_surfaces[ch-ch_start]->h > texture_height) { texture_height = glyph_surfaces[ch-ch_start]->h; } } // blit o'clock SDL_Surface *surface = SDL_CreateRGBSurface(0, texture_width, texture_height, glyph_surfaces[0]->format->BitsPerPixel, glyph_surfaces[0]->format->Rmask, glyph_surfaces[0]->format->Gmask, glyph_surfaces[0]->format->Bmask, glyph_surfaces[0]->format->Amask); //SDL_Surface *surface = SDL_CreateRGBSurface(0, texture_width, texture_height, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); if (surface == NULL) { report(ERROR, "loadGlyphs", "couldn't create GlyphTable surface: %s", SDL_GetError()); // TODO: free glyphs } SDL_Rect offset = { 0, 0, 0, 0 }; for (ch = ch_start; ch < ch_end; ++ch) { if (SDL_BlitSurface(glyph_surfaces[ch-ch_start], NULL, surface, &offset) != 0) { report(ERROR, "loadGlyphs", "Error while blitting glyph %c to GlyphTable: %s", ch, SDL_GetError()); } glyphs->offsetx[ch-ch_start] = offset.x; offset.x += glyph_surfaces[ch-ch_start]->w; // might as well free in one swoop SDL_FreeSurface(glyph_surfaces[ch-ch_start]); } // okay, we should have our surface w/ all glyphs here glyphs->texture = createTexture(surface); glyphs->w = texture_width; glyphs->h = texture_height; // finally, free our glyph surface SDL_FreeSurface(surface); return 0; }