mirror of
https://github.com/libretro/RetroArch
synced 2025-03-14 01:19:01 +00:00
Progress on font rendering. :)
This commit is contained in:
parent
f4778c42e1
commit
2211dc73e1
6
Makefile
6
Makefile
@ -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)
|
||||
|
2
driver.h
2
driver.h
@ -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);
|
||||
|
10
gfx/fonts.c
10
gfx/fonts.c
@ -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
155
gfx/gl.c
@ -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())
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
14
ssnes.c
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user