From e8ed98b69d874fbd4f489adcbda4047969d2a424 Mon Sep 17 00:00:00 2001 From: Allanis Date: Sat, 2 Feb 2013 06:15:51 +0000 Subject: [PATCH] [Add] gl_print (FreeType fonts). --- bin/Makefile | 6 +- src/main.c | 34 ++++++- src/opengl.c | 254 +++++++++++++++++++++++++++++++++++++++++++-------- src/opengl.h | 20 +++- src/pilot.h | 2 +- src/ship.c | 2 +- src/space.c | 2 +- 7 files changed, 269 insertions(+), 51 deletions(-) diff --git a/bin/Makefile b/bin/Makefile index 5d51494..1416a00 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -12,8 +12,9 @@ DATAFILES = $(shell find ../gfx/ ../dat/ -name '*.png' -o -name '*.xml' -print) CLUA = -I/usr/include/lua5.1 CSDL = `sdl-config --cflags` CXML = `xml2-config --cflags` +CTTF = `freetype-config --cflags` CGL = -CFLAGS = -Wall $(CLUA) $(CSDL) $(CXML) $(CGL) $(VERSION) +CFLAGS = -Wall $(CLUA) $(CSDL) $(CXML) $(CTTF) $(CGL) $(VERSION) ifdef DEBUG CFLAGS += -g3 -DDEBUG else @@ -23,8 +24,9 @@ endif LDLUA = -llua5.1 LDSDL = `sdl-config --libs` -lSDL_image LDXML = `xml2-config --libs` +LDTTF = `freetype-config --libs` LDGL = -lGL -LDFLAGS = -lm $(LDLUA) $(LDSDL) $(LDXML) $(LDGL) +LDFLAGS = -lm $(LDLUA) $(LDSDL) $(LDXML) $(LDTTF) $(LDGL) %.o: ../src/%.c @gcc -c $(CFLAGS) -o $@ $< diff --git a/src/main.c b/src/main.c index 99ebd0a..b74f273 100644 --- a/src/main.c +++ b/src/main.c @@ -15,23 +15,27 @@ #include "joystick.h" #include "space.h" #include "rng.h" +#include "ai.h" #include "pilot.h" #define CONF_FILE "conf" +static gl_font fdefault; + static int quit = 0; static unsigned int time = 0; // Prototypes. -void print_usage(char** argv); +static void print_usage(char** argv); +static void display_fps(const double dt); // Update. static void update_all(void); // Usage. -void print_usage(char** argv) { +static void print_usage(char** argv) { LOG("USAGE: %s [-f] [-j n | -J s] [-hv]", argv[0]); LOG("Options are:"); LOG("\t-f - Fullscreen"); @@ -120,6 +124,12 @@ int main(int argc, char** argv) { joystick_use(indjoystick); } + // Misc. + if(ai_init()) + WARN("Error initializing AI"); + + gl_fontInit(&fdefault, "/usr/share/fonts/truetype/freefont/FreeSans.ttf", 16); + // Data loading. ships_load(); @@ -144,9 +154,13 @@ int main(int argc, char** argv) { update_all(); } space_exit(); + // Unload data. pilots_free(); ships_free(); + + gl_freeFont(&fdefault); + // Exit subsystems. joystick_exit(); gl_exit(); // Kills video output. @@ -165,6 +179,22 @@ static void update_all(void) { space_render(dt); pilots_update(dt); + display_fps(dt); + SDL_GL_SwapBuffers(); } +static double fps = 0.; +static double fps_cur = 0.; +static double fps_dt = 1.; +static void display_fps(const double dt) { + fps_dt += dt; + fps_cur += 1.; + if(fps_dt > 1.) { + fps = fps_cur; + fps_dt = fps_cur = 0.; + } + Vec2 pos = { .x = 10., .y = (double)(gl_screen.h-20) }; + gl_print(&fdefault, &pos, "%3.2f", fps); +} + diff --git a/src/opengl.c b/src/opengl.c index 32049dc..9c3501b 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -1,6 +1,12 @@ #include #include +#include +#include +#include #include +#include +#include + #include "def.h" #include "log.h" #include "opengl.h" @@ -14,7 +20,25 @@ gl_info gl_screen; // Our precious camera. Vec2* gl_camera; +// Misc. static int flip_surface(SDL_Surface* surface); +static int pot(int n); +// gl_texture. +static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh); +// Gl font. +static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* tex_base); + +// ================ +// MISC! +// ================ + +// Get me the closest power of two plox. +static int pot(int n) { + int i = 1; + while( i < n) + i<<=1; + return i; +} // Flips the surface vertically. Return 0 on success. static int flip_surface(SDL_Surface* surface) { @@ -42,38 +66,22 @@ static int flip_surface(SDL_Surface* surface) { return 0; } -// Load the SDL_Surface to an opengl texture. -gl_texture* gl_loadImage(SDL_Surface* surface) { +// ================ +// TEXTURE! +// ================ + +// Returns the texture ID. +// Stores real sizes in rw/rh (from POT padding). +static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh) { + GLuint texture; SDL_Surface* tmp; Uint32 saved_flags; Uint8 saved_alpha; - int potw, poth; - - // Set up the texture defaults. - gl_texture* texture = MALLOC_L(gl_texture); - texture->w = (FP)surface->w; - texture->h = (FP)surface->h; - texture->sx = 1.; - texture->sy = 1.; - - // Ensure size is power of two. - potw = surface->w; - if((potw &(potw-1)) != 0) { - potw = 1; - while(potw < surface->w) - potw <<= 1; - } - texture->rw = potw; - poth = surface->h; - if((poth &(poth-1)) != 0) { - poth = 1; - while(poth < surface->h) - poth <<= 1; - } - texture->rh = poth; + if(rw)*rw = pot(surface->w); + if(rh)*rh = pot(surface->h); - if(surface->w != potw || surface->h != poth) { + if(surface->w != *rw || surface->h != *rh) { // Size isn't original. SDL_Rect rtemp; rtemp.x = rtemp.y = 0; @@ -88,14 +96,14 @@ gl_texture* gl_loadImage(SDL_Surface* surface) { // Create the temp POT surface. tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, - texture->rw, texture->rh, surface->format->BytesPerPixel*8, RGBMASK); + *rw, *rh, surface->format->BytesPerPixel*8, RGBMASK); if(tmp == NULL) { WARN("Unable to create POT surface %s", SDL_GetError()); - return NULL; + return 0; } if(SDL_FillRect(tmp, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, SDL_ALPHA_TRANSPARENT))) { WARN("Unable to fill rect: %s", SDL_GetError()); - return NULL; + return 0; } SDL_BlitSurface(surface, &rtemp, tmp, &rtemp); @@ -109,14 +117,14 @@ gl_texture* gl_loadImage(SDL_Surface* surface) { // Create the temp POT surface. tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, - texture->rw, texture->rh, surface->format->BytesPerPixel*8, RGBMASK); + *rw, *rh, surface->format->BytesPerPixel*8, RGBMASK); if(tmp == NULL) { WARN("Unable to create POT surface %s", SDL_GetError()); - return NULL; + return 0; } if(SDL_FillRect(tmp, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, SDL_ALPHA_TRANSPARENT))) { WARN("Unable to fill rect: %s", SDL_GetError()); - return NULL; + return 0; } SDL_BlitSurface(surface, &rtemp, tmp, &rtemp); @@ -129,8 +137,8 @@ gl_texture* gl_loadImage(SDL_Surface* surface) { SDL_SetAlpha(surface, saved_flags, saved_alpha); } - glGenTextures(1, &texture->texture); // Create the texure. - glBindTexture(GL_TEXTURE_2D, texture->texture); // Load the texture. + glGenTextures(1, &texture); // Create the texure. + glBindTexture(GL_TEXTURE_2D, texture); // Load the texture. // Filtering, LINEAR is better for scaling, nearest looks nicer, LINEAR // also seems to create a bit of artifacts around the edges. @@ -144,8 +152,24 @@ gl_texture* gl_loadImage(SDL_Surface* surface) { SDL_UnlockSurface(surface); SDL_FreeSurface(surface); + return texture; +} + +// Load the SDL_Surface to an openGL texture. +gl_texture* gl_loadImage(SDL_Surface* surface) { + int rw, rh; + + // Set up the texture defaults. + gl_texture* texture = MALLOC_L(gl_texture); + texture->w = (FP)surface->w; + texture->h = (FP)surface->h; texture->sx = 1.; texture->sy = 1.; + + texture->texture = gl_loadSurface(surface, &rw, &rh); + + texture->rw = (FP)rw; + texture->rh = (FP)rh; texture->sw = texture->w; texture->sh = texture->h; @@ -190,13 +214,17 @@ gl_texture* gl_newSprite(const char* path, const int sx, const int sy) { } // Free the texture. -void gl_free(gl_texture* texture) { +void gl_freeTexture(gl_texture* texture) { glDeleteTextures(1, &texture->texture); free(texture); } +// ================ +// BLITTING! +// ================ + // Blit the sprite at given position. -void gl_blitSprite(gl_texture* sprite, Vec2* pos, const int sx, const int sy) { +void gl_blitSprite(const gl_texture* sprite, const Vec2* pos, const int sx, const int sy) { // Don't bother drawing if offscreen -- waste of cycles. if(fabs(pos->x - gl_camera->x) > gl_screen.w / 2 + sprite->sw / 2 || fabs(pos->y-gl_camera->y) > gl_screen.h / 2 + sprite->sh / 2) @@ -232,7 +260,7 @@ void gl_blitSprite(gl_texture* sprite, Vec2* pos, const int sx, const int sy) { } // Just straight out blit the thing at position. -void gl_blitStatic(gl_texture* texture, Vec2* pos) { +void gl_blitStatic(const gl_texture* texture, const Vec2* pos) { glMatrixMode(GL_PROJECTION); glPushMatrix(); // Set up translation matrix. glTranslatef(pos->x - (FP)gl_screen.w/2., pos->y - (FP)gl_screen.h/2., 0); @@ -255,10 +283,156 @@ void gl_blitStatic(gl_texture* texture, Vec2* pos) { } // Bind our precious camera to a vector. -void gl_bindCamera(Vec2* pos) { - gl_camera = pos; +void gl_bindCamera(const Vec2* pos) { + gl_camera = (Vec2*)pos; } +// Print text on screen! YES!!!! Just like printf! But different! +void gl_print(const gl_font* ft_font, Vec2* pos, const char* fmt, ...) { + //float h = ft_font->h / .63; // Slightly increases font size. + char text[256]; + va_list ap; + //int i; + + if(fmt == NULL) + *text = 0; + else { + // convert the symbols to text. + va_start(ap, fmt); + vsprintf(text, fmt, ap); + va_end(ap); + } + + glListBase(ft_font->list_base); + + glMatrixMode(GL_PROJECTION); + //for(i = 0; i < strlen(text); i++) { + glPushMatrix(); + glTranslatef(pos->x - (FP)gl_screen.w/2., pos->y - (FP)gl_screen.h/2., 0); + glCallLists(strlen(text), GL_UNSIGNED_BYTE, &text); + glPopMatrix(); + //} +} + +// ================ +// FONT! +// ================ +static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* tex_base) { + FT_Glyph glyph; + FT_Bitmap bitmap; + GLubyte* expanded_data; + int w, h; + int i, j; + + if(FT_Load_Glyph(face, FT_Get_Char_Index(face, ch), FT_LOAD_DEFAULT)) + WARN("FT_Load_Glyph failed"); + + if(FT_Get_Glyph(face->glyph, &glyph)) + WARN("FT_Ge_Glyph failed"); + + // Convert your glyph to a bitmap. + FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1); + FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph; + + bitmap = bitmap_glyph->bitmap; // To simplify. + + // Need the POT wrapping for GL. + w = pot(bitmap.width); + h = pot(bitmap.rows); + + // Memory for textured data. + // Bitmap is useing two channels, one for luminosity and one for alpha. + expanded_data = (GLubyte*)malloc(sizeof(GLubyte)*2*w*h); + for(j = 0; j < h; j++) { + for(i = 0; i < w; i++) { + expanded_data[2*(i+j*w)] = expanded_data[2*(i+j*w)+1] = + (i >= bitmap.width || j >= bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j]; + } + } + // Create the GL texture. + glBindTexture(GL_TEXTURE_2D, tex_base[(int)ch]); + 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, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data); + + free(expanded_data); // No need for this now. + + // Create the display lists. + glNewList(list_base+ch, GL_COMPILE); + + glBindTexture(GL_TEXTURE_2D, tex_base[(int)ch]); + + glPushMatrix(); + + // Corrects a spacing flaw between letters. + glTranslatef(bitmap_glyph->left, 0,0); + + // Downwards correction for letters like g or y. + glTranslatef(0, bitmap_glyph->top-bitmap.rows,0); + + // Take the opengl POT wrapping into account. + FP x = (FP)bitmap.width/(FP)w; + FP y = (FP)bitmap.rows/(FP)h; + + // Draw the texture mapped quad. + glBegin(GL_QUADS); + glTexCoord2d(0, 0); + glVertex2f(0, bitmap.rows); + glTexCoord2d(x, y); + glVertex2f(bitmap.width, 0); + glTexCoord2d(x, 0); + glVertex2f(bitmap.width, bitmap.rows); + glEnd(); + + glPopMatrix(); + glTranslatef(face->glyph->advance.x >> 6, 0,0); + + // End of the display list. + glEndList(); +} + +void gl_fontInit(gl_font* font, const char* fname, unsigned int h) { + font->textures = malloc(sizeof(GLuint)*128); + font->h = h; + + // Create a FreeType font library. + FT_Library library; + if(FT_Init_FreeType(&library)) { + WARN("FT_Init_FreeType failed"); + } + + // Objects that freetype uses to store font info. + FT_Face face; + if(FT_New_Face(library, fname, 0, &face)) + WARN("FT_New_Face failed loading library from %s", fname); + + // FreeType is pretty nice and measures using 1/64 of a pixel, therfore expand. + FT_Set_Char_Size(face, h << 6, h << 6, 96, 96); + + // Have OpenGL allocate space for the textures / display lists. + font->list_base = glGenLists(128); + glGenTextures(128, font->textures); + + // Create each of the font display lists. + unsigned char i; + for(i = 0; i < 128; i++) + gl_fontMakeDList(face, i, font->list_base, font->textures); + + // We can now free the face and library. + FT_Done_Face(face); + FT_Done_FreeType(library); +} + +void gl_freeFont(gl_font* font) { + glDeleteLists(font->list_base, 128); + glDeleteTextures(128, font->textures); + free(font->textures); +} + +// ================ +// GLOBAL. +// ================ + // Initialize SDL/OpenGL etc. int gl_init(void) { int depth, i, supported = 0; diff --git a/src/opengl.h b/src/opengl.h index 42e8770..7141a01 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -39,16 +39,28 @@ typedef struct { GLuint texture; // The opengl texture itself. } gl_texture; +// Font info. +typedef struct { + float h; // Height. + GLuint* textures; + GLuint list_base; +} gl_font; + +// gl_font loading/freeing. +void gl_fontInit(gl_font* font, const char* fname, unsigned int h); +void gl_freeFont(gl_font* font); + // gl_texute loading/freeing. gl_texture* gl_loadImage(SDL_Surface* surface); // Frees the surface. gl_texture* gl_newImage(const char* path); gl_texture* gl_newSprite(const char* path, const int sx, const int sy); -void gl_free(gl_texture* texture); +void gl_freeTexture(gl_texture* texture); // Rendering. -void gl_blitSprite(gl_texture* sprite, Vec2* pos, const int sx, const int sy); -void gl_blitStatic(gl_texture* texture, Vec2* pos); -void gl_bindCamera(Vec2* pos); +void gl_blitSprite(const gl_texture* sprite, const Vec2* pos, const int sx, const int sy); +void gl_blitStatic(const gl_texture* texture, const Vec2* pos); +void gl_bindCamera(const Vec2* pos); +void gl_print(const gl_font* ft_font, Vec2* pos, const char* fmt, ...); // Initialize/cleanup. int gl_init(void); diff --git a/src/pilot.h b/src/pilot.h index 8fb3e0f..8794e1d 100644 --- a/src/pilot.h +++ b/src/pilot.h @@ -53,7 +53,7 @@ unsigned int pilot_create(Ship* ship, char* name, const Vec2* vel, const Vec2* pos, const int flags); // Cleanup. -void pilot_free(void); +void pilots_free(void); // Update. void pilots_update(FP dt); diff --git a/src/ship.c b/src/ship.c index 6475133..056dba7 100644 --- a/src/ship.c +++ b/src/ship.c @@ -145,7 +145,7 @@ void ships_free(void) { for(i = 0; i < ships; i++) { if((ship_stack+i)->name) free((ship_stack+i)->name); - gl_free((ship_stack+i)->gfx_ship); + gl_freeTexture((ship_stack+i)->gfx_ship); } free(ship_stack); ship_stack = NULL; diff --git a/src/space.c b/src/space.c index 170ee0c..e7f70ec 100644 --- a/src/space.c +++ b/src/space.c @@ -151,6 +151,6 @@ void space_render(FP dt) { void space_exit(void) { int i; for(i = 0; i < STAR_LAYERS; i++) - gl_free(starBG[i]); + gl_freeTexture(starBG[i]); }