Progress on font rendering. :)

This commit is contained in:
Themaister 2011-01-23 00:27:20 +01:00
parent f4778c42e1
commit 2211dc73e1
7 changed files with 172 additions and 20 deletions

View File

@ -68,6 +68,12 @@ ifeq ($(HAVE_FILTER), 1)
OBJ += hqflt/snes_ntsc/snes_ntsc.o
endif
ifeq ($(HAVE_FREETYPE), 1)
OBJ += gfx/fonts.o
LIBS += $(FREETYPE_LIBS)
DEFINES += $(FREETYPE_CFLAGS)
endif
ifeq ($(HAVE_FFMPEG), 1)
OBJ += record/ffemu.o
LIBS += $(AVCODEC_LIBS) $(AVCORE_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS)

View File

@ -99,7 +99,7 @@ typedef struct video_driver
{
void* (*init)(video_info_t *video, const input_driver_t **input, void **input_data);
// Should the video driver act as an input driver as well? :) The video init might preinitialize an input driver to override the settings in case the video driver relies on input driver for event handling, e.g.
bool (*frame)(void* data, const uint16_t* frame, int width, int height, int pitch);
bool (*frame)(void* data, const uint16_t* frame, unsigned width, unsigned height, unsigned pitch, const char *msg); // msg is for showing a message on the screen along with the video frame.
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding.
// Is the window still active?
bool (*alive)(void *data);

View File

@ -45,11 +45,7 @@ font_renderer_t *font_renderer_new(const char *font_path, unsigned font_size)
if (err)
goto error;
err = FT_Set_Char_Size(handle->face, 0, 64*64, 1024, 1024);
if (err)
goto error;
err = FT_Set_Pixel_Sizes(handle->face, 0, 64);
err = FT_Set_Pixel_Sizes(handle->face, 0, font_size);
if (err)
goto error;
@ -82,6 +78,8 @@ void font_renderer_msg(font_renderer_t *handle, const char *msg, struct font_out
struct font_output *tmp = calloc(1, sizeof(*tmp));
assert(tmp);
//fprintf(stderr, "Char: %c, off_x: %d, off_y: %d, bmp_left: %d, bmp_top: %d\n", msg[i], off_x, off_y, slot->bitmap_left, slot->bitmap_top);
tmp->output = malloc(slot->bitmap.pitch * slot->bitmap.rows);
assert(tmp->output);
memcpy(tmp->output, slot->bitmap.buffer, slot->bitmap.pitch * slot->bitmap.rows);
@ -90,7 +88,7 @@ void font_renderer_msg(font_renderer_t *handle, const char *msg, struct font_out
tmp->height = slot->bitmap.rows;
tmp->pitch = slot->bitmap.pitch;
tmp->off_x = off_x + slot->bitmap_left;
tmp->off_y = off_y - slot->bitmap_top;
tmp->off_y = off_y + slot->bitmap_top - slot->bitmap.rows;
tmp->next = NULL;
if (i == 0)

155
gfx/gl.c
View File

@ -51,6 +51,10 @@
#include "gl_common.h"
#ifdef HAVE_FREETYPE
#include "fonts.h"
#endif
static const GLfloat vertexes[] = {
0, 0, 0,
0, 1, 0,
@ -65,7 +69,6 @@ static const GLfloat tex_coords[] = {
1, 1
};
static bool keep_aspect = true;
typedef struct gl
{
bool vsync;
@ -74,6 +77,7 @@ typedef struct gl
bool should_resize;
bool quitting;
bool keep_aspect;
unsigned win_width;
unsigned win_height;
@ -83,9 +87,15 @@ typedef struct gl
unsigned last_height;
unsigned tex_w, tex_h;
GLfloat tex_coords[8];
#ifdef HAVE_FREETYPE
font_renderer_t *font;
GLuint font_tex;
#endif
} gl_t;
////////////////// Shaders
static inline bool gl_shader_init(void)
{
if (strlen(g_settings.video.cg_shader_path) > 0 && strlen(g_settings.video.bsnes_shader_path) > 0)
@ -104,6 +114,32 @@ static inline bool gl_shader_init(void)
return true;
}
/*
static inline void gl_shader_deactivate(void)
{
#ifdef HAVE_CG
gl_cg_deactivate();
#endif
#ifdef HAVE_XML
gl_glsl_deactivate();
#endif
}
*/
/*
static inline void gl_shader_activate(void)
{
#ifdef HAVE_CG
gl_cg_activate();
#endif
#ifdef HAVE_XML
gl_glsl_activate();
#endif
}
*/
static inline void gl_shader_deinit(void)
{
#ifdef HAVE_CG
@ -138,6 +174,109 @@ static inline void gl_shader_set_params(unsigned width, unsigned height,
gl_glsl_set_params(width, height, tex_width, tex_height, out_width, out_height);
#endif
}
///////////////////
//////////////// Message rendering
static inline void gl_init_font(gl_t *gl, const char *font_path)
{
#ifdef HAVE_FREETYPE
gl->font = font_renderer_new(font_path, 16);
if (gl->font)
{
glGenTextures(1, &gl->font_tex);
glBindTexture(GL_TEXTURE_2D, gl->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, gl->texture);
}
else
SSNES_WARN("Couldn't init font renderer...\n");
#endif
}
static inline void gl_deinit_font(gl_t *gl)
{
#ifdef HAVE_FREETYPE
if (gl->font)
{
font_renderer_free(gl->font);
glDeleteTextures(1, &gl->font_tex);
}
#endif
}
static inline unsigned get_alignment(unsigned pitch)
{
if (pitch & 1)
return 1;
if (pitch & 2)
return 2;
if (pitch & 4)
return 4;
return 8;
}
static void gl_render_msg(gl_t *gl, const char *msg)
{
#ifdef HAVE_FREETYPE
if (!gl->font)
return;
GLfloat font_vertex[12];
// Deactivate custom shaders. Enable the font texture.
//gl_shader_deactivate();
glBindTexture(GL_TEXTURE_2D, gl->font_tex);
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), font_vertex);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), tex_coords); // Use the static one (uses whole texture).
// Need blending.
// Using fixed function pipeline here since we cannot guarantee presence of shaders (would be kinda overkill anyways).
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
struct font_output_list out;
font_renderer_msg(gl->font, msg, &out);
struct font_output *head = out.head;
while (head != NULL)
{
GLfloat lx = (GLfloat)head->off_x / gl->vp_width + 0.200;
GLfloat hx = (GLfloat)(head->off_x + head->width) / gl->vp_width + 0.200;
GLfloat ly = (GLfloat)head->off_y / gl->vp_height + 0.200;
GLfloat hy = (GLfloat)(head->off_y + head->height) / gl->vp_height + 0.200;
font_vertex[0] = lx;
font_vertex[1] = ly;
font_vertex[3] = lx;
font_vertex[4] = hy;
font_vertex[6] = hx;
font_vertex[7] = hy;
font_vertex[9] = hx;
font_vertex[10] = ly;
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(head->pitch));
glPixelStorei(GL_UNPACK_ROW_LENGTH, head->pitch);
glTexImage2D(GL_TEXTURE_2D,
0, GL_RGBA, head->width, head->height, 0, GL_LUMINANCE,
GL_UNSIGNED_BYTE, head->output);
head = head->next;
glDrawArrays(GL_QUADS, 0, 4);
}
font_renderer_free_output(&out);
// Go back to old rendering path.
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords);
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), vertexes);
glBindTexture(GL_TEXTURE_2D, gl->texture);
glDisable(GL_BLEND);
//gl_shader_activate();
#endif
}
//////////////
static void set_viewport(gl_t *gl)
{
@ -145,7 +284,7 @@ static void set_viewport(gl_t *gl)
glLoadIdentity();
GLuint out_width = gl->win_width, out_height = gl->win_height;
if ( keep_aspect )
if (gl->keep_aspect)
{
float desired_aspect = g_settings.video.aspect_ratio;
float device_aspect = (float)gl->win_width / gl->win_height;
@ -212,7 +351,7 @@ static void show_fps(void)
frames++;
}
static bool gl_frame(void *data, const uint16_t* frame, int width, int height, int pitch)
static bool gl_frame(void *data, const uint16_t* frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
{
gl_t *gl = data;
@ -231,6 +370,7 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height, i
{
gl->last_width = width;
gl->last_height = height;
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(pitch));
glPixelStorei(GL_UNPACK_ROW_LENGTH, gl->tex_w);
uint8_t *tmp = calloc(1, gl->tex_w * gl->tex_h * sizeof(uint16_t));
glTexSubImage2D(GL_TEXTURE_2D,
@ -255,6 +395,8 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height, i
GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
glDrawArrays(GL_QUADS, 0, 4);
gl_render_msg(gl, "hei paa deg");
show_fps();
glFlush();
SDL_GL_SwapBuffers();
@ -266,6 +408,7 @@ static void gl_free(void *data)
{
gl_t *gl = data;
gl_deinit_font(gl);
gl_shader_deinit();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@ -325,6 +468,7 @@ static void* gl_init(video_info_t *video, const input_driver_t **input, void **i
gl->win_width = video->width;
gl->win_height = video->height;
gl->vsync = video->vsync;
gl->keep_aspect = video->force_aspect;
set_viewport(gl);
if (!gl_shader_init())
@ -338,7 +482,6 @@ static void* gl_init(video_info_t *video, const input_driver_t **input, void **i
// Remove that ugly mouse :D
SDL_ShowCursor(SDL_DISABLE);
keep_aspect = video->force_aspect;
if ( video->smooth )
gl->tex_filter = GL_LINEAR;
else
@ -394,6 +537,8 @@ static void* gl_init(video_info_t *video, const input_driver_t **input, void **i
}
else
*input = NULL;
gl_init_font(gl, "/usr/share/fonts/TTF/DroidSans.ttf");
if (!gl_check_error())
{

View File

@ -43,8 +43,10 @@ check_critical SRC "Cannot find libsamplerate."
check_lib DYNAMIC -ldl dlopen
check_pkgconf FREETYPE freetype2
# Creates config.mk and config.h.
VARS="ALSA OSS AL RSOUND ROAR JACK SDL FILTER CG XML DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE"
VARS="ALSA OSS AL RSOUND ROAR JACK SDL FILTER CG XML DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE"
create_config_make config.mk $VARS
create_config_header config.h $VARS

View File

@ -20,3 +20,4 @@ add_command_line_enable RSOUND "Enable RSound support" auto
add_command_line_enable ROAR "Enable RoarAudio support" auto
add_command_line_enable AL "Enable OpenAL support" auto
add_command_line_enable JACK "Enable JACK support" auto
add_command_line_enable FREETYPE "Enable FreeType support" auto

14
ssnes.c
View File

@ -108,35 +108,35 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
{
case FILTER_HQ2X:
ProcessHQ2x(output, output_filter);
if ( !driver.video->frame(driver.video_data, output_filter, width << 1, height << 1, width << 2) )
if (!driver.video->frame(driver.video_data, output_filter, width << 1, height << 1, width << 2, NULL))
g_extern.video_active = false;
break;
case FILTER_HQ4X:
ProcessHQ4x(output, output_filter);
if ( !driver.video->frame(driver.video_data, output_filter, width << 2, height << 2, width << 3) )
if (!driver.video->frame(driver.video_data, output_filter, width << 2, height << 2, width << 3, NULL))
g_extern.video_active = false;
break;
case FILTER_GRAYSCALE:
grayscale_filter(output, width, height);
if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) )
if (!driver.video->frame(driver.video_data, output, width, height, width << 1, NULL))
g_extern.video_active = false;
break;
case FILTER_BLEED:
bleed_filter(output, width, height);
if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) )
if (!driver.video->frame(driver.video_data, output, width, height, width << 1, NULL))
g_extern.video_active = false;
break;
case FILTER_NTSC:
ntsc_filter(output_filter, output, width, height);
if ( !driver.video->frame(driver.video_data, output_filter, SNES_NTSC_OUT_WIDTH(width), height, SNES_NTSC_OUT_WIDTH(width) << 1) )
if (!driver.video->frame(driver.video_data, output_filter, SNES_NTSC_OUT_WIDTH(width), height, SNES_NTSC_OUT_WIDTH(width) << 1, NULL))
g_extern.video_active = false;
break;
default:
if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) )
if (!driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048, NULL))
g_extern.video_active = false;
}
#else
if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) )
if (!driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048, NULL))
g_extern.video_active = false;
#endif
}