kettek2/wiki/games/newsboy/Newsboy_0x00/engine/Text.c

289 lines
8.7 KiB
C

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#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;
}