289 lines
8.7 KiB
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;
|
|
}
|